/*
|
* Copyright (C) 2016 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#pragma once
|
|
#include <stdio.h>
|
|
#include <map>
|
#include <mutex>
|
#include <set>
|
#include <string>
|
#include <vector>
|
|
#include <llvm/ADT/StringRef.h>
|
|
#include "Arch.h"
|
#include "CompilationType.h"
|
#include "Utils.h"
|
|
namespace clang {
|
class ASTContext;
|
class Decl;
|
}
|
|
enum class DeclarationType {
|
function,
|
variable,
|
inconsistent,
|
};
|
|
struct AvailabilityValues {
|
int introduced = 0;
|
int deprecated = 0;
|
int obsoleted = 0;
|
|
bool empty() const {
|
return !(introduced || deprecated || obsoleted);
|
}
|
|
bool operator==(const AvailabilityValues& rhs) const {
|
return std::tie(introduced, deprecated, obsoleted) ==
|
std::tie(rhs.introduced, rhs.deprecated, rhs.obsoleted);
|
}
|
|
bool operator!=(const AvailabilityValues& rhs) const {
|
return !(*this == rhs);
|
}
|
};
|
|
std::string to_string(const AvailabilityValues& av);
|
|
struct DeclarationAvailability {
|
AvailabilityValues global_availability;
|
ArchMap<AvailabilityValues> arch_availability;
|
|
bool empty() const {
|
if (!global_availability.empty()) {
|
return false;
|
}
|
|
for (const auto& it : arch_availability) {
|
if (!it.second.empty()) {
|
return false;
|
}
|
}
|
|
return true;
|
}
|
|
bool operator==(const DeclarationAvailability& rhs) const {
|
return std::tie(global_availability, arch_availability) ==
|
std::tie(rhs.global_availability, rhs.arch_availability);
|
}
|
|
bool operator!=(const DeclarationAvailability& rhs) const {
|
return !(*this == rhs);
|
}
|
|
// Returns false if the availability declarations conflict.
|
bool merge(const DeclarationAvailability& other);
|
};
|
|
std::string to_string(const DeclarationAvailability& decl_av);
|
|
struct FileLocation {
|
unsigned line;
|
unsigned column;
|
|
bool operator<(const FileLocation& rhs) const {
|
return std::tie(line, column) < std::tie(rhs.line, rhs.column);
|
}
|
|
bool operator==(const FileLocation& rhs) const {
|
return std::tie(line, column) == std::tie(rhs.line, rhs.column);
|
}
|
};
|
|
struct Location {
|
std::string filename;
|
FileLocation start;
|
FileLocation end;
|
|
bool operator<(const Location& rhs) const {
|
return std::tie(filename, start, end) < std::tie(rhs.filename, rhs.start, rhs.end);
|
}
|
};
|
|
std::string to_string(const Location& loc);
|
|
struct Declaration {
|
std::string name;
|
Location location;
|
|
bool is_extern;
|
bool is_definition;
|
bool no_guard;
|
std::map<CompilationType, DeclarationAvailability> availability;
|
|
bool calculateAvailability(DeclarationAvailability* output) const;
|
bool operator<(const Declaration& rhs) const {
|
return location < rhs.location;
|
}
|
|
void dump(const std::string& base_path = "", FILE* out = stdout, unsigned indent = 0) const {
|
std::string indent_str(indent, ' ');
|
fprintf(out, "%s", indent_str.c_str());
|
|
fprintf(out, "%s ", is_extern ? "extern" : "static");
|
fprintf(out, "%s ", is_definition ? "definition" : "declaration");
|
if (no_guard) {
|
fprintf(out, "no_guard ");
|
}
|
fprintf(out, "@ %s:%u:%u", StripPrefix(location.filename, base_path).str().c_str(),
|
location.start.line, location.start.column);
|
|
if (!availability.empty()) {
|
DeclarationAvailability avail;
|
|
fprintf(out, "\n%s ", indent_str.c_str());
|
if (!calculateAvailability(&avail)) {
|
fprintf(out, "invalid availability\n");
|
} else {
|
fprintf(out, "%s\n", to_string(avail).c_str());
|
}
|
}
|
}
|
};
|
|
struct Symbol {
|
std::string name;
|
std::map<Location, Declaration> declarations;
|
|
bool calculateAvailability(DeclarationAvailability* output) const;
|
bool hasDeclaration(const CompilationType& type) const;
|
|
bool operator<(const Symbol& rhs) const {
|
return name < rhs.name;
|
}
|
|
bool operator==(const Symbol& rhs) const {
|
return name == rhs.name;
|
}
|
|
void dump(const std::string& base_path = "", FILE* out = stdout) const {
|
DeclarationAvailability availability;
|
bool valid_availability = calculateAvailability(&availability);
|
fprintf(out, " %s: ", name.c_str());
|
|
if (valid_availability) {
|
fprintf(out, "%s\n", to_string(availability).c_str());
|
} else {
|
fprintf(out, "invalid\n");
|
}
|
|
for (auto& it : declarations) {
|
it.second.dump(base_path, out, 4);
|
}
|
}
|
};
|
|
class HeaderDatabase {
|
std::mutex mutex;
|
|
public:
|
std::map<std::string, Symbol> symbols;
|
|
void parseAST(CompilationType type, clang::ASTContext& ast);
|
|
void dump(const std::string& base_path = "", FILE* out = stdout) const {
|
fprintf(out, "HeaderDatabase contains %zu symbols:\n", symbols.size());
|
for (const auto& pair : symbols) {
|
pair.second.dump(base_path, out);
|
}
|
}
|
};
|