xref: /freebsd/contrib/llvm-project/clang/lib/AST/ASTImporterLookupTable.cpp (revision 5fb307d29b364982acbde82cbf77db3cae486f8c)
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 &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 
87 ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
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 
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(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(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(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(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(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 
157 void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) {
158   LookupTable[OldDC][ND->getDeclName()].remove(ND);
159   add(ND);
160 }
161 
162 ASTImporterLookupTable::LookupResult
163 ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
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 
176 bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
177   return lookup(DC, ND->getDeclName()).contains(ND);
178 }
179 
180 void ASTImporterLookupTable::dump(DeclContext *DC) const {
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 
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>(DC) << Primary << "\n";
201     dump(DC);
202   }
203 }
204 
205 } // namespace clang
206