1 //===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the ASTImporterLookupTable class which implements a
10 // lookup procedure for the import mechanism.
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/ASTImporterLookupTable.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/RecursiveASTVisitor.h"
17 #include "llvm/Support/FormatVariadic.h"
23 struct Builder
: RecursiveASTVisitor
<Builder
> {
24 ASTImporterLookupTable
<
;
25 Builder(ASTImporterLookupTable
<
) : LT(LT
) {}
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()) {
40 bool VisitNamedDecl(NamedDecl
*D
) {
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.
73 llvm_unreachable("Unhandled type of friend class");
80 // Override default settings of base.
81 bool shouldVisitTemplateInstantiations() const { return true; }
82 bool shouldVisitImplicitCode() const { return true; }
85 } // anonymous namespace
87 ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl
&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.
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()))
100 add(D
->getDeclContext(), D
);
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.
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
);
117 std::string Message
=
118 llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}",
119 Name
.getAsString(), DC
->getDeclKindName())
121 llvm_unreachable(Message
.c_str());
126 void ASTImporterLookupTable::add(NamedDecl
*ND
) {
128 DeclContext
*DC
= ND
->getDeclContext()->getPrimaryContext();
130 DeclContext
*ReDC
= DC
->getRedeclContext()->getPrimaryContext();
135 void ASTImporterLookupTable::remove(NamedDecl
*ND
) {
137 DeclContext
*DC
= ND
->getDeclContext()->getPrimaryContext();
139 DeclContext
*ReDC
= DC
->getRedeclContext()->getPrimaryContext();
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");
157 void ASTImporterLookupTable::updateForced(NamedDecl
*ND
, DeclContext
*OldDC
) {
158 LookupTable
[OldDC
][ND
->getDeclName()].remove(ND
);
162 ASTImporterLookupTable::LookupResult
163 ASTImporterLookupTable::lookup(DeclContext
*DC
, DeclarationName Name
) const {
164 auto DCI
= LookupTable
.find(DC
->getPrimaryContext());
165 if (DCI
== LookupTable
.end())
168 const auto &FoundNameMap
= DCI
->second
;
169 auto NamesI
= FoundNameMap
.find(Name
);
170 if (NamesI
== FoundNameMap
.end())
173 return NamesI
->second
;
176 bool ASTImporterLookupTable::contains(DeclContext
*DC
, NamedDecl
*ND
) const {
177 return lookup(DC
, ND
->getDeclName()).contains(ND
);
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: ";
189 const DeclList
& List
= Entry
.second
;
190 for (NamedDecl
*ND
: List
) {
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";