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>(Val&: Ty)) { |
31 | LT.add(ND: RTy->getAsRecordDecl()); |
32 | // iterate over the field decls, adding them |
33 | for (auto *it : RTy->getAsRecordDecl()->fields()) { |
34 | LT.add(ND: it); |
35 | } |
36 | } |
37 | return true; |
38 | } |
39 | |
40 | bool VisitNamedDecl(NamedDecl *D) { |
41 | LT.add(ND: 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>(Val: Ty)) |
53 | Ty = cast<ElaboratedType>(Val&: 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>(Val&: Ty)) |
60 | LT.add(ND: RTy->getAsCXXRecordDecl()); |
61 | else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Val&: Ty)) |
62 | LT.add(ND: SpecTy->getAsCXXRecordDecl()); |
63 | else if (const auto *SubstTy = |
64 | dyn_cast<SubstTemplateTypeParmType>(Val&: Ty)) { |
65 | if (SubstTy->getAsCXXRecordDecl()) |
66 | LT.add(ND: SubstTy->getAsCXXRecordDecl()); |
67 | } else if (isa<TypedefType>(Val: 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>(Val: 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(D: &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>(Val: 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>(Val: D->getDeclContext())) |
99 | add(DC: &TU, ND: Ns); |
100 | add(DC: D->getDeclContext(), ND: 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(X: 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(X: 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(DC: 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(DC: 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(DC: 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(DC: OldDC, ND); |
154 | add(ND); |
155 | } |
156 | |
157 | void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) { |
158 | LookupTable[OldDC][ND->getDeclName()].remove(X: ND); |
159 | add(ND); |
160 | } |
161 | |
162 | ASTImporterLookupTable::LookupResult |
163 | ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const { |
164 | auto DCI = LookupTable.find(Val: DC->getPrimaryContext()); |
165 | if (DCI == LookupTable.end()) |
166 | return {}; |
167 | |
168 | const auto &FoundNameMap = DCI->second; |
169 | auto NamesI = FoundNameMap.find(Val: 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, Name: ND->getDeclName()).contains(key: ND); |
178 | } |
179 | |
180 | void ASTImporterLookupTable::dump(DeclContext *DC) const { |
181 | auto DCI = LookupTable.find(Val: 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>(Val: DC) << Primary << "\n" ; |
201 | dump(DC); |
202 | } |
203 | } |
204 | |
205 | } // namespace clang |
206 | |