xref: /openbsd-src/gnu/llvm/clang/lib/AST/ASTImporterLookupTable.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick //  This file defines the ASTImporterLookupTable class which implements a
10e5dd7070Spatrick //  lookup procedure for the import mechanism.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick 
14e5dd7070Spatrick #include "clang/AST/ASTImporterLookupTable.h"
15e5dd7070Spatrick #include "clang/AST/Decl.h"
16e5dd7070Spatrick #include "clang/AST/RecursiveASTVisitor.h"
17*12c85518Srobert #include "llvm/Support/FormatVariadic.h"
18e5dd7070Spatrick 
19e5dd7070Spatrick namespace clang {
20e5dd7070Spatrick 
21e5dd7070Spatrick namespace {
22e5dd7070Spatrick 
23e5dd7070Spatrick struct Builder : RecursiveASTVisitor<Builder> {
24e5dd7070Spatrick   ASTImporterLookupTable &LT;
Builderclang::__anon199479a40111::Builder25e5dd7070Spatrick   Builder(ASTImporterLookupTable &LT) : LT(LT) {}
26a9ac8606Spatrick 
VisitTypedefNameDeclclang::__anon199479a40111::Builder27a9ac8606Spatrick   bool VisitTypedefNameDecl(TypedefNameDecl *D) {
28a9ac8606Spatrick     QualType Ty = D->getUnderlyingType();
29a9ac8606Spatrick     Ty = Ty.getCanonicalType();
30a9ac8606Spatrick     if (const auto *RTy = dyn_cast<RecordType>(Ty)) {
31a9ac8606Spatrick       LT.add(RTy->getAsRecordDecl());
32a9ac8606Spatrick       // iterate over the field decls, adding them
33a9ac8606Spatrick       for (auto *it : RTy->getAsRecordDecl()->fields()) {
34a9ac8606Spatrick         LT.add(it);
35a9ac8606Spatrick       }
36a9ac8606Spatrick     }
37a9ac8606Spatrick     return true;
38a9ac8606Spatrick   }
39a9ac8606Spatrick 
VisitNamedDeclclang::__anon199479a40111::Builder40e5dd7070Spatrick   bool VisitNamedDecl(NamedDecl *D) {
41e5dd7070Spatrick     LT.add(D);
42e5dd7070Spatrick     return true;
43e5dd7070Spatrick   }
44e5dd7070Spatrick   // In most cases the FriendDecl contains the declaration of the befriended
45e5dd7070Spatrick   // class as a child node, so it is discovered during the recursive
46e5dd7070Spatrick   // visitation. However, there are cases when the befriended class is not a
47e5dd7070Spatrick   // child, thus it must be fetched explicitly from the FriendDecl, and only
48e5dd7070Spatrick   // then can we add it to the lookup table.
VisitFriendDeclclang::__anon199479a40111::Builder49e5dd7070Spatrick   bool VisitFriendDecl(FriendDecl *D) {
50e5dd7070Spatrick     if (D->getFriendType()) {
51e5dd7070Spatrick       QualType Ty = D->getFriendType()->getType();
52e5dd7070Spatrick       if (isa<ElaboratedType>(Ty))
53e5dd7070Spatrick         Ty = cast<ElaboratedType>(Ty)->getNamedType();
54e5dd7070Spatrick       // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
55e5dd7070Spatrick       // always has that decl as child node.
56e5dd7070Spatrick       // However, there are non-dependent cases which does not have the
57e5dd7070Spatrick       // type as a child node. We have to dig up that type now.
58e5dd7070Spatrick       if (!Ty->isDependentType()) {
59e5dd7070Spatrick         if (const auto *RTy = dyn_cast<RecordType>(Ty))
60e5dd7070Spatrick           LT.add(RTy->getAsCXXRecordDecl());
61e5dd7070Spatrick         else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
62e5dd7070Spatrick           LT.add(SpecTy->getAsCXXRecordDecl());
63ec727ea7Spatrick         else if (const auto *SubstTy =
64ec727ea7Spatrick                      dyn_cast<SubstTemplateTypeParmType>(Ty)) {
65ec727ea7Spatrick           if (SubstTy->getAsCXXRecordDecl())
66ec727ea7Spatrick             LT.add(SubstTy->getAsCXXRecordDecl());
67ec727ea7Spatrick         } else if (isa<TypedefType>(Ty)) {
68e5dd7070Spatrick           // We do not put friend typedefs to the lookup table because
69e5dd7070Spatrick           // ASTImporter does not organize typedefs into redecl chains.
70e5dd7070Spatrick         } else {
71e5dd7070Spatrick           llvm_unreachable("Unhandled type of friend class");
72e5dd7070Spatrick         }
73e5dd7070Spatrick       }
74e5dd7070Spatrick     }
75e5dd7070Spatrick     return true;
76e5dd7070Spatrick   }
77e5dd7070Spatrick 
78e5dd7070Spatrick   // Override default settings of base.
shouldVisitTemplateInstantiationsclang::__anon199479a40111::Builder79e5dd7070Spatrick   bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCodeclang::__anon199479a40111::Builder80e5dd7070Spatrick   bool shouldVisitImplicitCode() const { return true; }
81e5dd7070Spatrick };
82e5dd7070Spatrick 
83e5dd7070Spatrick } // anonymous namespace
84e5dd7070Spatrick 
ASTImporterLookupTable(TranslationUnitDecl & TU)85e5dd7070Spatrick ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
86e5dd7070Spatrick   Builder B(*this);
87e5dd7070Spatrick   B.TraverseDecl(&TU);
88e5dd7070Spatrick }
89e5dd7070Spatrick 
add(DeclContext * DC,NamedDecl * ND)90e5dd7070Spatrick void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
91e5dd7070Spatrick   DeclList &Decls = LookupTable[DC][ND->getDeclName()];
92e5dd7070Spatrick   // Inserts if and only if there is no element in the container equal to it.
93e5dd7070Spatrick   Decls.insert(ND);
94e5dd7070Spatrick }
95e5dd7070Spatrick 
remove(DeclContext * DC,NamedDecl * ND)96e5dd7070Spatrick void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
97*12c85518Srobert   const DeclarationName Name = ND->getDeclName();
98*12c85518Srobert   DeclList &Decls = LookupTable[DC][Name];
99e5dd7070Spatrick   bool EraseResult = Decls.remove(ND);
100e5dd7070Spatrick   (void)EraseResult;
101*12c85518Srobert #ifndef NDEBUG
102*12c85518Srobert   if (!EraseResult) {
103*12c85518Srobert     std::string Message =
104*12c85518Srobert         llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}",
105*12c85518Srobert                       Name.getAsString(), DC->getDeclKindName())
106*12c85518Srobert             .str();
107*12c85518Srobert     llvm_unreachable(Message.c_str());
108*12c85518Srobert   }
109*12c85518Srobert #endif
110e5dd7070Spatrick }
111e5dd7070Spatrick 
add(NamedDecl * ND)112e5dd7070Spatrick void ASTImporterLookupTable::add(NamedDecl *ND) {
113e5dd7070Spatrick   assert(ND);
114e5dd7070Spatrick   DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
115e5dd7070Spatrick   add(DC, ND);
116e5dd7070Spatrick   DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
117e5dd7070Spatrick   if (DC != ReDC)
118e5dd7070Spatrick     add(ReDC, ND);
119e5dd7070Spatrick }
120e5dd7070Spatrick 
remove(NamedDecl * ND)121e5dd7070Spatrick void ASTImporterLookupTable::remove(NamedDecl *ND) {
122e5dd7070Spatrick   assert(ND);
123e5dd7070Spatrick   DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
124e5dd7070Spatrick   remove(DC, ND);
125e5dd7070Spatrick   DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
126e5dd7070Spatrick   if (DC != ReDC)
127e5dd7070Spatrick     remove(ReDC, ND);
128e5dd7070Spatrick }
129e5dd7070Spatrick 
update(NamedDecl * ND,DeclContext * OldDC)130a9ac8606Spatrick void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {
131a9ac8606Spatrick   assert(OldDC != ND->getDeclContext() &&
132a9ac8606Spatrick          "DeclContext should be changed before update");
133a9ac8606Spatrick   if (contains(ND->getDeclContext(), ND)) {
134a9ac8606Spatrick     assert(!contains(OldDC, ND) &&
135a9ac8606Spatrick            "Decl should not be found in the old context if already in the new");
136a9ac8606Spatrick     return;
137a9ac8606Spatrick   }
138a9ac8606Spatrick 
139a9ac8606Spatrick   remove(OldDC, ND);
140a9ac8606Spatrick   add(ND);
141a9ac8606Spatrick }
142a9ac8606Spatrick 
updateForced(NamedDecl * ND,DeclContext * OldDC)143*12c85518Srobert void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) {
144*12c85518Srobert   LookupTable[OldDC][ND->getDeclName()].remove(ND);
145*12c85518Srobert   add(ND);
146*12c85518Srobert }
147*12c85518Srobert 
148e5dd7070Spatrick ASTImporterLookupTable::LookupResult
lookup(DeclContext * DC,DeclarationName Name) const149e5dd7070Spatrick ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
150e5dd7070Spatrick   auto DCI = LookupTable.find(DC->getPrimaryContext());
151e5dd7070Spatrick   if (DCI == LookupTable.end())
152e5dd7070Spatrick     return {};
153e5dd7070Spatrick 
154e5dd7070Spatrick   const auto &FoundNameMap = DCI->second;
155e5dd7070Spatrick   auto NamesI = FoundNameMap.find(Name);
156e5dd7070Spatrick   if (NamesI == FoundNameMap.end())
157e5dd7070Spatrick     return {};
158e5dd7070Spatrick 
159e5dd7070Spatrick   return NamesI->second;
160e5dd7070Spatrick }
161e5dd7070Spatrick 
contains(DeclContext * DC,NamedDecl * ND) const162a9ac8606Spatrick bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
163*12c85518Srobert   return lookup(DC, ND->getDeclName()).contains(ND);
164a9ac8606Spatrick }
165a9ac8606Spatrick 
dump(DeclContext * DC) const166e5dd7070Spatrick void ASTImporterLookupTable::dump(DeclContext *DC) const {
167e5dd7070Spatrick   auto DCI = LookupTable.find(DC->getPrimaryContext());
168e5dd7070Spatrick   if (DCI == LookupTable.end())
169e5dd7070Spatrick     llvm::errs() << "empty\n";
170e5dd7070Spatrick   const auto &FoundNameMap = DCI->second;
171e5dd7070Spatrick   for (const auto &Entry : FoundNameMap) {
172e5dd7070Spatrick     DeclarationName Name = Entry.first;
173e5dd7070Spatrick     llvm::errs() << "==== Name: ";
174e5dd7070Spatrick     Name.dump();
175e5dd7070Spatrick     const DeclList& List = Entry.second;
176e5dd7070Spatrick     for (NamedDecl *ND : List) {
177e5dd7070Spatrick       ND->dump();
178e5dd7070Spatrick     }
179e5dd7070Spatrick   }
180e5dd7070Spatrick }
181e5dd7070Spatrick 
dump() const182e5dd7070Spatrick void ASTImporterLookupTable::dump() const {
183e5dd7070Spatrick   for (const auto &Entry : LookupTable) {
184e5dd7070Spatrick     DeclContext *DC = Entry.first;
185e5dd7070Spatrick     StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
186e5dd7070Spatrick     llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
187e5dd7070Spatrick     dump(DC);
188e5dd7070Spatrick   }
189e5dd7070Spatrick }
190e5dd7070Spatrick 
191e5dd7070Spatrick } // namespace clang
192