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 void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) { 121 assert(OldDC != ND->getDeclContext() && 122 "DeclContext should be changed before update"); 123 if (contains(ND->getDeclContext(), ND)) { 124 assert(!contains(OldDC, ND) && 125 "Decl should not be found in the old context if already in the new"); 126 return; 127 } 128 129 remove(OldDC, ND); 130 add(ND); 131 } 132 133 ASTImporterLookupTable::LookupResult 134 ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const { 135 auto DCI = LookupTable.find(DC->getPrimaryContext()); 136 if (DCI == LookupTable.end()) 137 return {}; 138 139 const auto &FoundNameMap = DCI->second; 140 auto NamesI = FoundNameMap.find(Name); 141 if (NamesI == FoundNameMap.end()) 142 return {}; 143 144 return NamesI->second; 145 } 146 147 bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const { 148 return 0 < lookup(DC, ND->getDeclName()).count(ND); 149 } 150 151 void ASTImporterLookupTable::dump(DeclContext *DC) const { 152 auto DCI = LookupTable.find(DC->getPrimaryContext()); 153 if (DCI == LookupTable.end()) 154 llvm::errs() << "empty\n"; 155 const auto &FoundNameMap = DCI->second; 156 for (const auto &Entry : FoundNameMap) { 157 DeclarationName Name = Entry.first; 158 llvm::errs() << "==== Name: "; 159 Name.dump(); 160 const DeclList& List = Entry.second; 161 for (NamedDecl *ND : List) { 162 ND->dump(); 163 } 164 } 165 } 166 167 void ASTImporterLookupTable::dump() const { 168 for (const auto &Entry : LookupTable) { 169 DeclContext *DC = Entry.first; 170 StringRef Primary = DC->getPrimaryContext() ? " primary" : ""; 171 llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n"; 172 dump(DC); 173 } 174 } 175 176 } // namespace clang 177