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 &LT;
24   Builder(ASTImporterLookupTable &LT) : 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