1 //===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the ASTImporterLookupTable class which implements a 10 // lookup procedure for the import mechanism. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/AST/ASTImporterLookupTable.h" 15 #include "clang/AST/Decl.h" 16 #include "clang/AST/RecursiveASTVisitor.h" 17 18 namespace clang { 19 20 namespace { 21 22 struct Builder : RecursiveASTVisitor<Builder> { 23 ASTImporterLookupTable < 24 Builder(ASTImporterLookupTable <) : LT(LT) {} 25 26 bool VisitTypedefNameDecl(TypedefNameDecl *D) { 27 QualType Ty = D->getUnderlyingType(); 28 Ty = Ty.getCanonicalType(); 29 if (const auto *RTy = dyn_cast<RecordType>(Ty)) { 30 LT.add(RTy->getAsRecordDecl()); 31 // iterate over the field decls, adding them 32 for (auto *it : RTy->getAsRecordDecl()->fields()) { 33 LT.add(it); 34 } 35 } 36 return true; 37 } 38 39 bool VisitNamedDecl(NamedDecl *D) { 40 LT.add(D); 41 return true; 42 } 43 // In most cases the FriendDecl contains the declaration of the befriended 44 // class as a child node, so it is discovered during the recursive 45 // visitation. However, there are cases when the befriended class is not a 46 // child, thus it must be fetched explicitly from the FriendDecl, and only 47 // then can we add it to the lookup table. 48 bool VisitFriendDecl(FriendDecl *D) { 49 if (D->getFriendType()) { 50 QualType Ty = D->getFriendType()->getType(); 51 if (isa<ElaboratedType>(Ty)) 52 Ty = cast<ElaboratedType>(Ty)->getNamedType(); 53 // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization) 54 // always has that decl as child node. 55 // However, there are non-dependent cases which does not have the 56 // type as a child node. We have to dig up that type now. 57 if (!Ty->isDependentType()) { 58 if (const auto *RTy = dyn_cast<RecordType>(Ty)) 59 LT.add(RTy->getAsCXXRecordDecl()); 60 else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty)) 61 LT.add(SpecTy->getAsCXXRecordDecl()); 62 else if (const auto *SubstTy = 63 dyn_cast<SubstTemplateTypeParmType>(Ty)) { 64 if (SubstTy->getAsCXXRecordDecl()) 65 LT.add(SubstTy->getAsCXXRecordDecl()); 66 } else if (isa<TypedefType>(Ty)) { 67 // We do not put friend typedefs to the lookup table because 68 // ASTImporter does not organize typedefs into redecl chains. 69 } else { 70 llvm_unreachable("Unhandled type of friend class"); 71 } 72 } 73 } 74 return true; 75 } 76 77 // Override default settings of base. 78 bool shouldVisitTemplateInstantiations() const { return true; } 79 bool shouldVisitImplicitCode() const { return true; } 80 }; 81 82 } // anonymous namespace 83 84 ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) { 85 Builder B(*this); 86 B.TraverseDecl(&TU); 87 } 88 89 void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) { 90 DeclList &Decls = LookupTable[DC][ND->getDeclName()]; 91 // Inserts if and only if there is no element in the container equal to it. 92 Decls.insert(ND); 93 } 94 95 void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) { 96 DeclList &Decls = LookupTable[DC][ND->getDeclName()]; 97 bool EraseResult = Decls.remove(ND); 98 (void)EraseResult; 99 assert(EraseResult == true && "Trying to remove not contained Decl"); 100 } 101 102 void ASTImporterLookupTable::add(NamedDecl *ND) { 103 assert(ND); 104 DeclContext *DC = ND->getDeclContext()->getPrimaryContext(); 105 add(DC, ND); 106 DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext(); 107 if (DC != ReDC) 108 add(ReDC, ND); 109 } 110 111 void ASTImporterLookupTable::remove(NamedDecl *ND) { 112 assert(ND); 113 DeclContext *DC = ND->getDeclContext()->getPrimaryContext(); 114 remove(DC, ND); 115 DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext(); 116 if (DC != ReDC) 117 remove(ReDC, ND); 118 } 119 120 ASTImporterLookupTable::LookupResult 121 ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const { 122 auto DCI = LookupTable.find(DC->getPrimaryContext()); 123 if (DCI == LookupTable.end()) 124 return {}; 125 126 const auto &FoundNameMap = DCI->second; 127 auto NamesI = FoundNameMap.find(Name); 128 if (NamesI == FoundNameMap.end()) 129 return {}; 130 131 return NamesI->second; 132 } 133 134 void ASTImporterLookupTable::dump(DeclContext *DC) const { 135 auto DCI = LookupTable.find(DC->getPrimaryContext()); 136 if (DCI == LookupTable.end()) 137 llvm::errs() << "empty\n"; 138 const auto &FoundNameMap = DCI->second; 139 for (const auto &Entry : FoundNameMap) { 140 DeclarationName Name = Entry.first; 141 llvm::errs() << "==== Name: "; 142 Name.dump(); 143 const DeclList& List = Entry.second; 144 for (NamedDecl *ND : List) { 145 ND->dump(); 146 } 147 } 148 } 149 150 void ASTImporterLookupTable::dump() const { 151 for (const auto &Entry : LookupTable) { 152 DeclContext *DC = Entry.first; 153 StringRef Primary = DC->getPrimaryContext() ? " primary" : ""; 154 llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n"; 155 dump(DC); 156 } 157 } 158 159 } // namespace clang 160