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 <
Builderclang::__anon199479a40111::Builder25e5dd7070Spatrick Builder(ASTImporterLookupTable <) : 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