#include "clang/AST/ASTImporterLookupTable.h"
#include "clang/AST/Decl.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "llvm/Support/FormatVariadic.h"
namespace clang {
namespace {
struct Builder : RecursiveASTVisitor<Builder> {
ASTImporterLookupTable <
Builder(ASTImporterLookupTable <) : LT(LT) {}
bool VisitTypedefNameDecl(TypedefNameDecl *D) {
QualType Ty = D->getUnderlyingType();
Ty = Ty.getCanonicalType();
if (const auto *RTy = dyn_cast<RecordType>(Ty)) {
LT.add(RTy->getAsRecordDecl());
for (auto *it : RTy->getAsRecordDecl()->fields()) {
LT.add(it);
}
}
return true;
}
bool VisitNamedDecl(NamedDecl *D) {
LT.add(D);
return true;
}
bool VisitFriendDecl(FriendDecl *D) {
if (D->getFriendType()) {
QualType Ty = D->getFriendType()->getType();
if (isa<ElaboratedType>(Ty))
Ty = cast<ElaboratedType>(Ty)->getNamedType();
if (!Ty->isDependentType()) {
if (const auto *RTy = dyn_cast<RecordType>(Ty))
LT.add(RTy->getAsCXXRecordDecl());
else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
LT.add(SpecTy->getAsCXXRecordDecl());
else if (const auto *SubstTy =
dyn_cast<SubstTemplateTypeParmType>(Ty)) {
if (SubstTy->getAsCXXRecordDecl())
LT.add(SubstTy->getAsCXXRecordDecl());
} else if (isa<TypedefType>(Ty)) {
} else if (isa<UsingType>(Ty)) {
} else {
llvm_unreachable("Unhandled type of friend class");
}
}
}
return true;
}
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
};
}
ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
Builder B(*this);
B.TraverseDecl(&TU);
if (auto *D =
dyn_cast_or_null<NamedDecl>(TU.getASTContext().getVaListTagDecl())) {
if (auto *Ns = dyn_cast<NamespaceDecl>(D->getDeclContext()))
add(&TU, Ns);
add(D->getDeclContext(), D);
}
}
void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
DeclList &Decls = LookupTable[DC][ND->getDeclName()];
Decls.insert(ND);
}
void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
const DeclarationName Name = ND->getDeclName();
DeclList &Decls = LookupTable[DC][Name];
bool EraseResult = Decls.remove(ND);
(void)EraseResult;
#ifndef NDEBUG
if (!EraseResult) {
std::string Message =
llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}",
Name.getAsString(), DC->getDeclKindName())
.str();
llvm_unreachable(Message.c_str());
}
#endif
}
void ASTImporterLookupTable::add(NamedDecl *ND) {
assert(ND);
DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
add(DC, ND);
DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
if (DC != ReDC)
add(ReDC, ND);
}
void ASTImporterLookupTable::remove(NamedDecl *ND) {
assert(ND);
DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
remove(DC, ND);
DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
if (DC != ReDC)
remove(ReDC, ND);
}
void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {
assert(OldDC != ND->getDeclContext() &&
"DeclContext should be changed before update");
if (contains(ND->getDeclContext(), ND)) {
assert(!contains(OldDC, ND) &&
"Decl should not be found in the old context if already in the new");
return;
}
remove(OldDC, ND);
add(ND);
}
void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) {
LookupTable[OldDC][ND->getDeclName()].remove(ND);
add(ND);
}
ASTImporterLookupTable::LookupResult
ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
auto DCI = LookupTable.find(DC->getPrimaryContext());
if (DCI == LookupTable.end())
return {};
const auto &FoundNameMap = DCI->second;
auto NamesI = FoundNameMap.find(Name);
if (NamesI == FoundNameMap.end())
return {};
return NamesI->second;
}
bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
return lookup(DC, ND->getDeclName()).contains(ND);
}
void ASTImporterLookupTable::dump(DeclContext *DC) const {
auto DCI = LookupTable.find(DC->getPrimaryContext());
if (DCI == LookupTable.end())
llvm::errs() << "empty\n";
const auto &FoundNameMap = DCI->second;
for (const auto &Entry : FoundNameMap) {
DeclarationName Name = Entry.first;
llvm::errs() << "==== Name: ";
Name.dump();
const DeclList& List = Entry.second;
for (NamedDecl *ND : List) {
ND->dump();
}
}
}
void ASTImporterLookupTable::dump() const {
for (const auto &Entry : LookupTable) {
DeclContext *DC = Entry.first;
StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
dump(DC);
}
}
}