clang 20.0.0git
ASTImporterLookupTable.cpp
Go to the documentation of this file.
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
15#include "clang/AST/Decl.h"
17#include "llvm/Support/FormatVariadic.h"
18
19namespace clang {
20
21namespace {
22
23struct Builder : RecursiveASTVisitor<Builder> {
24 ASTImporterLookupTable &LT;
25 Builder(ASTImporterLookupTable &LT) : 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>(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
40 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.
49 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 if (isa<UsingType>(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
88 Builder B(*this);
89 B.TraverseDecl(&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>(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>(D->getDeclContext()))
99 add(&TU, Ns);
100 add(D->getDeclContext(), D);
101 }
102}
103
104void 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(ND);
108}
109
110void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
111 const DeclarationName Name = ND->getDeclName();
112 DeclList &Decls = LookupTable[DC][Name];
113 bool EraseResult = Decls.remove(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
126void ASTImporterLookupTable::add(NamedDecl *ND) {
127 assert(ND);
129 add(DC, ND);
131 if (DC != ReDC)
132 add(ReDC, ND);
133}
134
135void ASTImporterLookupTable::remove(NamedDecl *ND) {
136 assert(ND);
138 remove(DC, ND);
140 if (DC != ReDC)
141 remove(ReDC, ND);
142}
143
145 assert(OldDC != ND->getDeclContext() &&
146 "DeclContext should be changed before update");
147 if (contains(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(OldDC, ND);
154 add(ND);
155}
156
158 LookupTable[OldDC][ND->getDeclName()].remove(ND);
159 add(ND);
160}
161
164 auto DCI = LookupTable.find(DC->getPrimaryContext());
165 if (DCI == LookupTable.end())
166 return {};
167
168 const auto &FoundNameMap = DCI->second;
169 auto NamesI = FoundNameMap.find(Name);
170 if (NamesI == FoundNameMap.end())
171 return {};
172
173 return NamesI->second;
174}
175
177 return lookup(DC, ND->getDeclName()).contains(ND);
178}
179
181 auto DCI = LookupTable.find(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
197 for (const auto &Entry : LookupTable) {
198 DeclContext *DC = Entry.first;
199 StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
200 llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
201 dump(DC);
202 }
203}
204
205} // namespace clang
ASTImporterLookupTable & LT
const Decl * D
Decl * getVaListTagDecl() const
Retrieve the C type declaration corresponding to the predefined __va_list_tag type used to help defin...
void update(NamedDecl *ND, DeclContext *OldDC)
LookupResult lookup(DeclContext *DC, DeclarationName Name) const
void updateForced(NamedDecl *ND, DeclContext *OldDC)
ASTImporterLookupTable(TranslationUnitDecl &TU)
bool contains(DeclContext *DC, NamedDecl *ND) const
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
DeclContext * getRedeclContext()
getRedeclContext - Retrieve the context in which an entity conflicts with other entities of the same ...
Definition: DeclBase.cpp:1988
DeclContext * getPrimaryContext()
getPrimaryContext - There may be many different declarations of the same entity (including forward de...
Definition: DeclBase.cpp:1423
DeclContext * getDeclContext()
Definition: DeclBase.h:455
The name of a declaration.
This represents a decl that may have a name.
Definition: Decl.h:249
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:315
The top declaration context.
Definition: Decl.h:84
ASTContext & getASTContext() const
Definition: Decl.h:120
The JSON file list parser is used to communicate input to InstallAPI.