10b57cec5SDimitry Andric //===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines the ASTImporterLookupTable class which implements a
100b57cec5SDimitry Andric //  lookup procedure for the import mechanism.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/AST/ASTImporterLookupTable.h"
150b57cec5SDimitry Andric #include "clang/AST/Decl.h"
160b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
17349cc55cSDimitry Andric #include "llvm/Support/FormatVariadic.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace clang {
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric namespace {
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric struct Builder : RecursiveASTVisitor<Builder> {
240b57cec5SDimitry Andric   ASTImporterLookupTable &LT;
Builderclang::__anonc38beeb50111::Builder250b57cec5SDimitry Andric   Builder(ASTImporterLookupTable &LT) : LT(LT) {}
26e8d8bef9SDimitry Andric 
VisitTypedefNameDeclclang::__anonc38beeb50111::Builder27e8d8bef9SDimitry Andric   bool VisitTypedefNameDecl(TypedefNameDecl *D) {
28e8d8bef9SDimitry Andric     QualType Ty = D->getUnderlyingType();
29e8d8bef9SDimitry Andric     Ty = Ty.getCanonicalType();
30e8d8bef9SDimitry Andric     if (const auto *RTy = dyn_cast<RecordType>(Ty)) {
31e8d8bef9SDimitry Andric       LT.add(RTy->getAsRecordDecl());
32e8d8bef9SDimitry Andric       // iterate over the field decls, adding them
33e8d8bef9SDimitry Andric       for (auto *it : RTy->getAsRecordDecl()->fields()) {
34e8d8bef9SDimitry Andric         LT.add(it);
35e8d8bef9SDimitry Andric       }
36e8d8bef9SDimitry Andric     }
37e8d8bef9SDimitry Andric     return true;
38e8d8bef9SDimitry Andric   }
39e8d8bef9SDimitry Andric 
VisitNamedDeclclang::__anonc38beeb50111::Builder400b57cec5SDimitry Andric   bool VisitNamedDecl(NamedDecl *D) {
410b57cec5SDimitry Andric     LT.add(D);
420b57cec5SDimitry Andric     return true;
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric   // In most cases the FriendDecl contains the declaration of the befriended
450b57cec5SDimitry Andric   // class as a child node, so it is discovered during the recursive
460b57cec5SDimitry Andric   // visitation. However, there are cases when the befriended class is not a
470b57cec5SDimitry Andric   // child, thus it must be fetched explicitly from the FriendDecl, and only
480b57cec5SDimitry Andric   // then can we add it to the lookup table.
VisitFriendDeclclang::__anonc38beeb50111::Builder490b57cec5SDimitry Andric   bool VisitFriendDecl(FriendDecl *D) {
500b57cec5SDimitry Andric     if (D->getFriendType()) {
510b57cec5SDimitry Andric       QualType Ty = D->getFriendType()->getType();
520b57cec5SDimitry Andric       if (isa<ElaboratedType>(Ty))
530b57cec5SDimitry Andric         Ty = cast<ElaboratedType>(Ty)->getNamedType();
540b57cec5SDimitry Andric       // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
550b57cec5SDimitry Andric       // always has that decl as child node.
560b57cec5SDimitry Andric       // However, there are non-dependent cases which does not have the
570b57cec5SDimitry Andric       // type as a child node. We have to dig up that type now.
580b57cec5SDimitry Andric       if (!Ty->isDependentType()) {
590b57cec5SDimitry Andric         if (const auto *RTy = dyn_cast<RecordType>(Ty))
600b57cec5SDimitry Andric           LT.add(RTy->getAsCXXRecordDecl());
610b57cec5SDimitry Andric         else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
620b57cec5SDimitry Andric           LT.add(SpecTy->getAsCXXRecordDecl());
635ffd83dbSDimitry Andric         else if (const auto *SubstTy =
645ffd83dbSDimitry Andric                      dyn_cast<SubstTemplateTypeParmType>(Ty)) {
655ffd83dbSDimitry Andric           if (SubstTy->getAsCXXRecordDecl())
665ffd83dbSDimitry Andric             LT.add(SubstTy->getAsCXXRecordDecl());
675ffd83dbSDimitry Andric         } else if (isa<TypedefType>(Ty)) {
680b57cec5SDimitry Andric           // We do not put friend typedefs to the lookup table because
690b57cec5SDimitry Andric           // ASTImporter does not organize typedefs into redecl chains.
7006c3fb27SDimitry Andric         } else if (isa<UsingType>(Ty)) {
7106c3fb27SDimitry Andric           // Similar to TypedefType, not putting into lookup table.
720b57cec5SDimitry Andric         } else {
730b57cec5SDimitry Andric           llvm_unreachable("Unhandled type of friend class");
740b57cec5SDimitry Andric         }
750b57cec5SDimitry Andric       }
760b57cec5SDimitry Andric     }
770b57cec5SDimitry Andric     return true;
780b57cec5SDimitry Andric   }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   // Override default settings of base.
shouldVisitTemplateInstantiationsclang::__anonc38beeb50111::Builder810b57cec5SDimitry Andric   bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCodeclang::__anonc38beeb50111::Builder820b57cec5SDimitry Andric   bool shouldVisitImplicitCode() const { return true; }
830b57cec5SDimitry Andric };
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric } // anonymous namespace
860b57cec5SDimitry Andric 
ASTImporterLookupTable(TranslationUnitDecl & TU)870b57cec5SDimitry Andric ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
880b57cec5SDimitry Andric   Builder B(*this);
890b57cec5SDimitry Andric   B.TraverseDecl(&TU);
9006c3fb27SDimitry Andric   // The VaList declaration may be created on demand only or not traversed.
9106c3fb27SDimitry Andric   // To ensure it is present and found during import, add it to the table now.
9206c3fb27SDimitry Andric   if (auto *D =
9306c3fb27SDimitry Andric           dyn_cast_or_null<NamedDecl>(TU.getASTContext().getVaListTagDecl())) {
9406c3fb27SDimitry Andric     // On some platforms (AArch64) the VaList declaration can be inside a 'std'
9506c3fb27SDimitry Andric     // namespace. This is handled specially and not visible by AST traversal.
9606c3fb27SDimitry Andric     // ASTImporter must be able to find this namespace to import the VaList
9706c3fb27SDimitry Andric     // declaration (and the namespace) correctly.
9806c3fb27SDimitry Andric     if (auto *Ns = dyn_cast<NamespaceDecl>(D->getDeclContext()))
9906c3fb27SDimitry Andric       add(&TU, Ns);
10006c3fb27SDimitry Andric     add(D->getDeclContext(), D);
10106c3fb27SDimitry Andric   }
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
add(DeclContext * DC,NamedDecl * ND)1040b57cec5SDimitry Andric void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
1050b57cec5SDimitry Andric   DeclList &Decls = LookupTable[DC][ND->getDeclName()];
1060b57cec5SDimitry Andric   // Inserts if and only if there is no element in the container equal to it.
1070b57cec5SDimitry Andric   Decls.insert(ND);
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
remove(DeclContext * DC,NamedDecl * ND)1100b57cec5SDimitry Andric void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
111349cc55cSDimitry Andric   const DeclarationName Name = ND->getDeclName();
112349cc55cSDimitry Andric   DeclList &Decls = LookupTable[DC][Name];
1130b57cec5SDimitry Andric   bool EraseResult = Decls.remove(ND);
1140b57cec5SDimitry Andric   (void)EraseResult;
115349cc55cSDimitry Andric #ifndef NDEBUG
116349cc55cSDimitry Andric   if (!EraseResult) {
117349cc55cSDimitry Andric     std::string Message =
118349cc55cSDimitry Andric         llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}",
119349cc55cSDimitry Andric                       Name.getAsString(), DC->getDeclKindName())
120349cc55cSDimitry Andric             .str();
121349cc55cSDimitry Andric     llvm_unreachable(Message.c_str());
122349cc55cSDimitry Andric   }
123349cc55cSDimitry Andric #endif
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
add(NamedDecl * ND)1260b57cec5SDimitry Andric void ASTImporterLookupTable::add(NamedDecl *ND) {
1270b57cec5SDimitry Andric   assert(ND);
1280b57cec5SDimitry Andric   DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
1290b57cec5SDimitry Andric   add(DC, ND);
1300b57cec5SDimitry Andric   DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
1310b57cec5SDimitry Andric   if (DC != ReDC)
1320b57cec5SDimitry Andric     add(ReDC, ND);
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric 
remove(NamedDecl * ND)1350b57cec5SDimitry Andric void ASTImporterLookupTable::remove(NamedDecl *ND) {
1360b57cec5SDimitry Andric   assert(ND);
1370b57cec5SDimitry Andric   DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
1380b57cec5SDimitry Andric   remove(DC, ND);
1390b57cec5SDimitry Andric   DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
1400b57cec5SDimitry Andric   if (DC != ReDC)
1410b57cec5SDimitry Andric     remove(ReDC, ND);
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
update(NamedDecl * ND,DeclContext * OldDC)144fe6060f1SDimitry Andric void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {
145fe6060f1SDimitry Andric   assert(OldDC != ND->getDeclContext() &&
146fe6060f1SDimitry Andric          "DeclContext should be changed before update");
147fe6060f1SDimitry Andric   if (contains(ND->getDeclContext(), ND)) {
148fe6060f1SDimitry Andric     assert(!contains(OldDC, ND) &&
149fe6060f1SDimitry Andric            "Decl should not be found in the old context if already in the new");
150fe6060f1SDimitry Andric     return;
151fe6060f1SDimitry Andric   }
152fe6060f1SDimitry Andric 
153fe6060f1SDimitry Andric   remove(OldDC, ND);
154fe6060f1SDimitry Andric   add(ND);
155fe6060f1SDimitry Andric }
156fe6060f1SDimitry Andric 
updateForced(NamedDecl * ND,DeclContext * OldDC)1570eae32dcSDimitry Andric void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) {
1580eae32dcSDimitry Andric   LookupTable[OldDC][ND->getDeclName()].remove(ND);
1590eae32dcSDimitry Andric   add(ND);
1600eae32dcSDimitry Andric }
1610eae32dcSDimitry Andric 
1620b57cec5SDimitry Andric ASTImporterLookupTable::LookupResult
lookup(DeclContext * DC,DeclarationName Name) const1630b57cec5SDimitry Andric ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
1640b57cec5SDimitry Andric   auto DCI = LookupTable.find(DC->getPrimaryContext());
1650b57cec5SDimitry Andric   if (DCI == LookupTable.end())
1660b57cec5SDimitry Andric     return {};
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   const auto &FoundNameMap = DCI->second;
1690b57cec5SDimitry Andric   auto NamesI = FoundNameMap.find(Name);
1700b57cec5SDimitry Andric   if (NamesI == FoundNameMap.end())
1710b57cec5SDimitry Andric     return {};
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   return NamesI->second;
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric 
contains(DeclContext * DC,NamedDecl * ND) const176fe6060f1SDimitry Andric bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
177349cc55cSDimitry Andric   return lookup(DC, ND->getDeclName()).contains(ND);
178fe6060f1SDimitry Andric }
179fe6060f1SDimitry Andric 
dump(DeclContext * DC) const1800b57cec5SDimitry Andric void ASTImporterLookupTable::dump(DeclContext *DC) const {
1810b57cec5SDimitry Andric   auto DCI = LookupTable.find(DC->getPrimaryContext());
1820b57cec5SDimitry Andric   if (DCI == LookupTable.end())
1830b57cec5SDimitry Andric     llvm::errs() << "empty\n";
1840b57cec5SDimitry Andric   const auto &FoundNameMap = DCI->second;
1850b57cec5SDimitry Andric   for (const auto &Entry : FoundNameMap) {
1860b57cec5SDimitry Andric     DeclarationName Name = Entry.first;
1870b57cec5SDimitry Andric     llvm::errs() << "==== Name: ";
1880b57cec5SDimitry Andric     Name.dump();
1890b57cec5SDimitry Andric     const DeclList& List = Entry.second;
1900b57cec5SDimitry Andric     for (NamedDecl *ND : List) {
1910b57cec5SDimitry Andric       ND->dump();
1920b57cec5SDimitry Andric     }
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
dump() const1960b57cec5SDimitry Andric void ASTImporterLookupTable::dump() const {
1970b57cec5SDimitry Andric   for (const auto &Entry : LookupTable) {
1980b57cec5SDimitry Andric     DeclContext *DC = Entry.first;
1990b57cec5SDimitry Andric     StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
2000b57cec5SDimitry Andric     llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
2010b57cec5SDimitry Andric     dump(DC);
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric } // namespace clang
206