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 #include "llvm/Support/FormatVariadic.h" 18 19 namespace clang { 20 21 namespace { 22 23 struct Builder : RecursiveASTVisitor<Builder> { 24 ASTImporterLookupTable < 25 Builder(ASTImporterLookupTable <) : LT(LT) {} 26 27 bool VisitTypedefNameDecl(TypedefNameDecl *D) { 28 QualType Ty = D->getUnderlyingType(); 29 Ty = Ty.getCanonicalType(); 30 if (const auto *RTy = dyn_cast<RecordType>(Ty)) { 31 LT.add(RTy->getAsRecordDecl()); 32 // iterate over the field decls, adding them 33 for (auto *it : RTy->getAsRecordDecl()->fields()) { 34 LT.add(it); 35 } 36 } 37 return true; 38 } 39 40 bool VisitNamedDecl(NamedDecl *D) { 41 LT.add(D); 42 return true; 43 } 44 // In most cases the FriendDecl contains the declaration of the befriended 45 // class as a child node, so it is discovered during the recursive 46 // visitation. However, there are cases when the befriended class is not a 47 // child, thus it must be fetched explicitly from the FriendDecl, and only 48 // then can we add it to the lookup table. 49 bool VisitFriendDecl(FriendDecl *D) { 50 if (D->getFriendType()) { 51 QualType Ty = D->getFriendType()->getType(); 52 if (isa<ElaboratedType>(Ty)) 53 Ty = cast<ElaboratedType>(Ty)->getNamedType(); 54 // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization) 55 // always has that decl as child node. 56 // However, there are non-dependent cases which does not have the 57 // type as a child node. We have to dig up that type now. 58 if (!Ty->isDependentType()) { 59 if (const auto *RTy = dyn_cast<RecordType>(Ty)) 60 LT.add(RTy->getAsCXXRecordDecl()); 61 else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty)) 62 LT.add(SpecTy->getAsCXXRecordDecl()); 63 else if (const auto *SubstTy = 64 dyn_cast<SubstTemplateTypeParmType>(Ty)) { 65 if (SubstTy->getAsCXXRecordDecl()) 66 LT.add(SubstTy->getAsCXXRecordDecl()); 67 } else if (isa<TypedefType>(Ty)) { 68 // We do not put friend typedefs to the lookup table because 69 // ASTImporter does not organize typedefs into redecl chains. 70 } else if (isa<UsingType>(Ty)) { 71 // Similar to TypedefType, not putting into lookup table. 72 } else { 73 llvm_unreachable("Unhandled type of friend class"); 74 } 75 } 76 } 77 return true; 78 } 79 80 // Override default settings of base. 81 bool shouldVisitTemplateInstantiations() const { return true; } 82 bool shouldVisitImplicitCode() const { return true; } 83 }; 84 85 } // anonymous namespace 86 87 ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) { 88 Builder B(*this); 89 B.TraverseDecl(&TU); 90 // The VaList declaration may be created on demand only or not traversed. 91 // To ensure it is present and found during import, add it to the table now. 92 if (auto *D = 93 dyn_cast_or_null<NamedDecl>(TU.getASTContext().getVaListTagDecl())) { 94 // On some platforms (AArch64) the VaList declaration can be inside a 'std' 95 // namespace. This is handled specially and not visible by AST traversal. 96 // ASTImporter must be able to find this namespace to import the VaList 97 // declaration (and the namespace) correctly. 98 if (auto *Ns = dyn_cast<NamespaceDecl>(D->getDeclContext())) 99 add(&TU, Ns); 100 add(D->getDeclContext(), D); 101 } 102 } 103 104 void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) { 105 DeclList &Decls = LookupTable[DC][ND->getDeclName()]; 106 // Inserts if and only if there is no element in the container equal to it. 107 Decls.insert(ND); 108 } 109 110 void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) { 111 const DeclarationName Name = ND->getDeclName(); 112 DeclList &Decls = LookupTable[DC][Name]; 113 bool EraseResult = Decls.remove(ND); 114 (void)EraseResult; 115 #ifndef NDEBUG 116 if (!EraseResult) { 117 std::string Message = 118 llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}", 119 Name.getAsString(), DC->getDeclKindName()) 120 .str(); 121 llvm_unreachable(Message.c_str()); 122 } 123 #endif 124 } 125 126 void ASTImporterLookupTable::add(NamedDecl *ND) { 127 assert(ND); 128 DeclContext *DC = ND->getDeclContext()->getPrimaryContext(); 129 add(DC, ND); 130 DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext(); 131 if (DC != ReDC) 132 add(ReDC, ND); 133 } 134 135 void ASTImporterLookupTable::remove(NamedDecl *ND) { 136 assert(ND); 137 DeclContext *DC = ND->getDeclContext()->getPrimaryContext(); 138 remove(DC, ND); 139 DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext(); 140 if (DC != ReDC) 141 remove(ReDC, ND); 142 } 143 144 void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) { 145 assert(OldDC != ND->getDeclContext() && 146 "DeclContext should be changed before update"); 147 if (contains(ND->getDeclContext(), ND)) { 148 assert(!contains(OldDC, ND) && 149 "Decl should not be found in the old context if already in the new"); 150 return; 151 } 152 153 remove(OldDC, ND); 154 add(ND); 155 } 156 157 void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) { 158 LookupTable[OldDC][ND->getDeclName()].remove(ND); 159 add(ND); 160 } 161 162 ASTImporterLookupTable::LookupResult 163 ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const { 164 auto DCI = LookupTable.find(DC->getPrimaryContext()); 165 if (DCI == LookupTable.end()) 166 return {}; 167 168 const auto &FoundNameMap = DCI->second; 169 auto NamesI = FoundNameMap.find(Name); 170 if (NamesI == FoundNameMap.end()) 171 return {}; 172 173 return NamesI->second; 174 } 175 176 bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const { 177 return lookup(DC, ND->getDeclName()).contains(ND); 178 } 179 180 void ASTImporterLookupTable::dump(DeclContext *DC) const { 181 auto DCI = LookupTable.find(DC->getPrimaryContext()); 182 if (DCI == LookupTable.end()) 183 llvm::errs() << "empty\n"; 184 const auto &FoundNameMap = DCI->second; 185 for (const auto &Entry : FoundNameMap) { 186 DeclarationName Name = Entry.first; 187 llvm::errs() << "==== Name: "; 188 Name.dump(); 189 const DeclList& List = Entry.second; 190 for (NamedDecl *ND : List) { 191 ND->dump(); 192 } 193 } 194 } 195 196 void ASTImporterLookupTable::dump() const { 197 for (const auto &Entry : LookupTable) { 198 DeclContext *DC = Entry.first; 199 StringRef Primary = DC->getPrimaryContext() ? " primary" : ""; 200 llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n"; 201 dump(DC); 202 } 203 } 204 205 } // namespace clang 206