xref: /openbsd-src/gnu/llvm/clang/lib/AST/ASTImporterLookupTable.cpp (revision a9ac8606c53d55cee9c3a39778b249c51df111ef)
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"
17e5dd7070Spatrick 
18e5dd7070Spatrick namespace clang {
19e5dd7070Spatrick 
20e5dd7070Spatrick namespace {
21e5dd7070Spatrick 
22e5dd7070Spatrick struct Builder : RecursiveASTVisitor<Builder> {
23e5dd7070Spatrick   ASTImporterLookupTable &LT;
24e5dd7070Spatrick   Builder(ASTImporterLookupTable &LT) : LT(LT) {}
25*a9ac8606Spatrick 
26*a9ac8606Spatrick   bool VisitTypedefNameDecl(TypedefNameDecl *D) {
27*a9ac8606Spatrick     QualType Ty = D->getUnderlyingType();
28*a9ac8606Spatrick     Ty = Ty.getCanonicalType();
29*a9ac8606Spatrick     if (const auto *RTy = dyn_cast<RecordType>(Ty)) {
30*a9ac8606Spatrick       LT.add(RTy->getAsRecordDecl());
31*a9ac8606Spatrick       // iterate over the field decls, adding them
32*a9ac8606Spatrick       for (auto *it : RTy->getAsRecordDecl()->fields()) {
33*a9ac8606Spatrick         LT.add(it);
34*a9ac8606Spatrick       }
35*a9ac8606Spatrick     }
36*a9ac8606Spatrick     return true;
37*a9ac8606Spatrick   }
38*a9ac8606Spatrick 
39e5dd7070Spatrick   bool VisitNamedDecl(NamedDecl *D) {
40e5dd7070Spatrick     LT.add(D);
41e5dd7070Spatrick     return true;
42e5dd7070Spatrick   }
43e5dd7070Spatrick   // In most cases the FriendDecl contains the declaration of the befriended
44e5dd7070Spatrick   // class as a child node, so it is discovered during the recursive
45e5dd7070Spatrick   // visitation. However, there are cases when the befriended class is not a
46e5dd7070Spatrick   // child, thus it must be fetched explicitly from the FriendDecl, and only
47e5dd7070Spatrick   // then can we add it to the lookup table.
48e5dd7070Spatrick   bool VisitFriendDecl(FriendDecl *D) {
49e5dd7070Spatrick     if (D->getFriendType()) {
50e5dd7070Spatrick       QualType Ty = D->getFriendType()->getType();
51e5dd7070Spatrick       if (isa<ElaboratedType>(Ty))
52e5dd7070Spatrick         Ty = cast<ElaboratedType>(Ty)->getNamedType();
53e5dd7070Spatrick       // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
54e5dd7070Spatrick       // always has that decl as child node.
55e5dd7070Spatrick       // However, there are non-dependent cases which does not have the
56e5dd7070Spatrick       // type as a child node. We have to dig up that type now.
57e5dd7070Spatrick       if (!Ty->isDependentType()) {
58e5dd7070Spatrick         if (const auto *RTy = dyn_cast<RecordType>(Ty))
59e5dd7070Spatrick           LT.add(RTy->getAsCXXRecordDecl());
60e5dd7070Spatrick         else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
61e5dd7070Spatrick           LT.add(SpecTy->getAsCXXRecordDecl());
62ec727ea7Spatrick         else if (const auto *SubstTy =
63ec727ea7Spatrick                      dyn_cast<SubstTemplateTypeParmType>(Ty)) {
64ec727ea7Spatrick           if (SubstTy->getAsCXXRecordDecl())
65ec727ea7Spatrick             LT.add(SubstTy->getAsCXXRecordDecl());
66ec727ea7Spatrick         } else if (isa<TypedefType>(Ty)) {
67e5dd7070Spatrick           // We do not put friend typedefs to the lookup table because
68e5dd7070Spatrick           // ASTImporter does not organize typedefs into redecl chains.
69e5dd7070Spatrick         } else {
70e5dd7070Spatrick           llvm_unreachable("Unhandled type of friend class");
71e5dd7070Spatrick         }
72e5dd7070Spatrick       }
73e5dd7070Spatrick     }
74e5dd7070Spatrick     return true;
75e5dd7070Spatrick   }
76e5dd7070Spatrick 
77e5dd7070Spatrick   // Override default settings of base.
78e5dd7070Spatrick   bool shouldVisitTemplateInstantiations() const { return true; }
79e5dd7070Spatrick   bool shouldVisitImplicitCode() const { return true; }
80e5dd7070Spatrick };
81e5dd7070Spatrick 
82e5dd7070Spatrick } // anonymous namespace
83e5dd7070Spatrick 
84e5dd7070Spatrick ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
85e5dd7070Spatrick   Builder B(*this);
86e5dd7070Spatrick   B.TraverseDecl(&TU);
87e5dd7070Spatrick }
88e5dd7070Spatrick 
89e5dd7070Spatrick void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
90e5dd7070Spatrick   DeclList &Decls = LookupTable[DC][ND->getDeclName()];
91e5dd7070Spatrick   // Inserts if and only if there is no element in the container equal to it.
92e5dd7070Spatrick   Decls.insert(ND);
93e5dd7070Spatrick }
94e5dd7070Spatrick 
95e5dd7070Spatrick void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
96e5dd7070Spatrick   DeclList &Decls = LookupTable[DC][ND->getDeclName()];
97e5dd7070Spatrick   bool EraseResult = Decls.remove(ND);
98e5dd7070Spatrick   (void)EraseResult;
99e5dd7070Spatrick   assert(EraseResult == true && "Trying to remove not contained Decl");
100e5dd7070Spatrick }
101e5dd7070Spatrick 
102e5dd7070Spatrick void ASTImporterLookupTable::add(NamedDecl *ND) {
103e5dd7070Spatrick   assert(ND);
104e5dd7070Spatrick   DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
105e5dd7070Spatrick   add(DC, ND);
106e5dd7070Spatrick   DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
107e5dd7070Spatrick   if (DC != ReDC)
108e5dd7070Spatrick     add(ReDC, ND);
109e5dd7070Spatrick }
110e5dd7070Spatrick 
111e5dd7070Spatrick void ASTImporterLookupTable::remove(NamedDecl *ND) {
112e5dd7070Spatrick   assert(ND);
113e5dd7070Spatrick   DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
114e5dd7070Spatrick   remove(DC, ND);
115e5dd7070Spatrick   DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
116e5dd7070Spatrick   if (DC != ReDC)
117e5dd7070Spatrick     remove(ReDC, ND);
118e5dd7070Spatrick }
119e5dd7070Spatrick 
120*a9ac8606Spatrick void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {
121*a9ac8606Spatrick   assert(OldDC != ND->getDeclContext() &&
122*a9ac8606Spatrick          "DeclContext should be changed before update");
123*a9ac8606Spatrick   if (contains(ND->getDeclContext(), ND)) {
124*a9ac8606Spatrick     assert(!contains(OldDC, ND) &&
125*a9ac8606Spatrick            "Decl should not be found in the old context if already in the new");
126*a9ac8606Spatrick     return;
127*a9ac8606Spatrick   }
128*a9ac8606Spatrick 
129*a9ac8606Spatrick   remove(OldDC, ND);
130*a9ac8606Spatrick   add(ND);
131*a9ac8606Spatrick }
132*a9ac8606Spatrick 
133e5dd7070Spatrick ASTImporterLookupTable::LookupResult
134e5dd7070Spatrick ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
135e5dd7070Spatrick   auto DCI = LookupTable.find(DC->getPrimaryContext());
136e5dd7070Spatrick   if (DCI == LookupTable.end())
137e5dd7070Spatrick     return {};
138e5dd7070Spatrick 
139e5dd7070Spatrick   const auto &FoundNameMap = DCI->second;
140e5dd7070Spatrick   auto NamesI = FoundNameMap.find(Name);
141e5dd7070Spatrick   if (NamesI == FoundNameMap.end())
142e5dd7070Spatrick     return {};
143e5dd7070Spatrick 
144e5dd7070Spatrick   return NamesI->second;
145e5dd7070Spatrick }
146e5dd7070Spatrick 
147*a9ac8606Spatrick bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
148*a9ac8606Spatrick   return 0 < lookup(DC, ND->getDeclName()).count(ND);
149*a9ac8606Spatrick }
150*a9ac8606Spatrick 
151e5dd7070Spatrick void ASTImporterLookupTable::dump(DeclContext *DC) const {
152e5dd7070Spatrick   auto DCI = LookupTable.find(DC->getPrimaryContext());
153e5dd7070Spatrick   if (DCI == LookupTable.end())
154e5dd7070Spatrick     llvm::errs() << "empty\n";
155e5dd7070Spatrick   const auto &FoundNameMap = DCI->second;
156e5dd7070Spatrick   for (const auto &Entry : FoundNameMap) {
157e5dd7070Spatrick     DeclarationName Name = Entry.first;
158e5dd7070Spatrick     llvm::errs() << "==== Name: ";
159e5dd7070Spatrick     Name.dump();
160e5dd7070Spatrick     const DeclList& List = Entry.second;
161e5dd7070Spatrick     for (NamedDecl *ND : List) {
162e5dd7070Spatrick       ND->dump();
163e5dd7070Spatrick     }
164e5dd7070Spatrick   }
165e5dd7070Spatrick }
166e5dd7070Spatrick 
167e5dd7070Spatrick void ASTImporterLookupTable::dump() const {
168e5dd7070Spatrick   for (const auto &Entry : LookupTable) {
169e5dd7070Spatrick     DeclContext *DC = Entry.first;
170e5dd7070Spatrick     StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
171e5dd7070Spatrick     llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
172e5dd7070Spatrick     dump(DC);
173e5dd7070Spatrick   }
174e5dd7070Spatrick }
175e5dd7070Spatrick 
176e5dd7070Spatrick } // namespace clang
177