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 <
Builderclang::__anon199479a40111::Builder25 Builder(ASTImporterLookupTable <) : LT(LT) {}
26
VisitTypedefNameDeclclang::__anon199479a40111::Builder27 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
VisitNamedDeclclang::__anon199479a40111::Builder40 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.
VisitFriendDeclclang::__anon199479a40111::Builder49 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 {
71 llvm_unreachable("Unhandled type of friend class");
72 }
73 }
74 }
75 return true;
76 }
77
78 // Override default settings of base.
shouldVisitTemplateInstantiationsclang::__anon199479a40111::Builder79 bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCodeclang::__anon199479a40111::Builder80 bool shouldVisitImplicitCode() const { return true; }
81 };
82
83 } // anonymous namespace
84
ASTImporterLookupTable(TranslationUnitDecl & TU)85 ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
86 Builder B(*this);
87 B.TraverseDecl(&TU);
88 }
89
add(DeclContext * DC,NamedDecl * ND)90 void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
91 DeclList &Decls = LookupTable[DC][ND->getDeclName()];
92 // Inserts if and only if there is no element in the container equal to it.
93 Decls.insert(ND);
94 }
95
remove(DeclContext * DC,NamedDecl * ND)96 void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
97 const DeclarationName Name = ND->getDeclName();
98 DeclList &Decls = LookupTable[DC][Name];
99 bool EraseResult = Decls.remove(ND);
100 (void)EraseResult;
101 #ifndef NDEBUG
102 if (!EraseResult) {
103 std::string Message =
104 llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}",
105 Name.getAsString(), DC->getDeclKindName())
106 .str();
107 llvm_unreachable(Message.c_str());
108 }
109 #endif
110 }
111
add(NamedDecl * ND)112 void ASTImporterLookupTable::add(NamedDecl *ND) {
113 assert(ND);
114 DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
115 add(DC, ND);
116 DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
117 if (DC != ReDC)
118 add(ReDC, ND);
119 }
120
remove(NamedDecl * ND)121 void ASTImporterLookupTable::remove(NamedDecl *ND) {
122 assert(ND);
123 DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
124 remove(DC, ND);
125 DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
126 if (DC != ReDC)
127 remove(ReDC, ND);
128 }
129
update(NamedDecl * ND,DeclContext * OldDC)130 void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {
131 assert(OldDC != ND->getDeclContext() &&
132 "DeclContext should be changed before update");
133 if (contains(ND->getDeclContext(), ND)) {
134 assert(!contains(OldDC, ND) &&
135 "Decl should not be found in the old context if already in the new");
136 return;
137 }
138
139 remove(OldDC, ND);
140 add(ND);
141 }
142
updateForced(NamedDecl * ND,DeclContext * OldDC)143 void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) {
144 LookupTable[OldDC][ND->getDeclName()].remove(ND);
145 add(ND);
146 }
147
148 ASTImporterLookupTable::LookupResult
lookup(DeclContext * DC,DeclarationName Name) const149 ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
150 auto DCI = LookupTable.find(DC->getPrimaryContext());
151 if (DCI == LookupTable.end())
152 return {};
153
154 const auto &FoundNameMap = DCI->second;
155 auto NamesI = FoundNameMap.find(Name);
156 if (NamesI == FoundNameMap.end())
157 return {};
158
159 return NamesI->second;
160 }
161
contains(DeclContext * DC,NamedDecl * ND) const162 bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
163 return lookup(DC, ND->getDeclName()).contains(ND);
164 }
165
dump(DeclContext * DC) const166 void ASTImporterLookupTable::dump(DeclContext *DC) const {
167 auto DCI = LookupTable.find(DC->getPrimaryContext());
168 if (DCI == LookupTable.end())
169 llvm::errs() << "empty\n";
170 const auto &FoundNameMap = DCI->second;
171 for (const auto &Entry : FoundNameMap) {
172 DeclarationName Name = Entry.first;
173 llvm::errs() << "==== Name: ";
174 Name.dump();
175 const DeclList& List = Entry.second;
176 for (NamedDecl *ND : List) {
177 ND->dump();
178 }
179 }
180 }
181
dump() const182 void ASTImporterLookupTable::dump() const {
183 for (const auto &Entry : LookupTable) {
184 DeclContext *DC = Entry.first;
185 StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
186 llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
187 dump(DC);
188 }
189 }
190
191 } // namespace clang
192