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