10b57cec5SDimitry Andric //===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the ASTImporterLookupTable class which implements a
100b57cec5SDimitry Andric // lookup procedure for the import mechanism.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "clang/AST/ASTImporterLookupTable.h"
150b57cec5SDimitry Andric #include "clang/AST/Decl.h"
160b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
17349cc55cSDimitry Andric #include "llvm/Support/FormatVariadic.h"
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric namespace clang {
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric namespace {
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric struct Builder : RecursiveASTVisitor<Builder> {
240b57cec5SDimitry Andric ASTImporterLookupTable <
Builderclang::__anon860fb6ed0111::Builder250b57cec5SDimitry Andric Builder(ASTImporterLookupTable <) : LT(LT) {}
26e8d8bef9SDimitry Andric
VisitTypedefNameDeclclang::__anon860fb6ed0111::Builder27e8d8bef9SDimitry Andric bool VisitTypedefNameDecl(TypedefNameDecl *D) {
28e8d8bef9SDimitry Andric QualType Ty = D->getUnderlyingType();
29e8d8bef9SDimitry Andric Ty = Ty.getCanonicalType();
30e8d8bef9SDimitry Andric if (const auto *RTy = dyn_cast<RecordType>(Ty)) {
31e8d8bef9SDimitry Andric LT.add(RTy->getAsRecordDecl());
32e8d8bef9SDimitry Andric // iterate over the field decls, adding them
33e8d8bef9SDimitry Andric for (auto *it : RTy->getAsRecordDecl()->fields()) {
34e8d8bef9SDimitry Andric LT.add(it);
35e8d8bef9SDimitry Andric }
36e8d8bef9SDimitry Andric }
37e8d8bef9SDimitry Andric return true;
38e8d8bef9SDimitry Andric }
39e8d8bef9SDimitry Andric
VisitNamedDeclclang::__anon860fb6ed0111::Builder400b57cec5SDimitry Andric bool VisitNamedDecl(NamedDecl *D) {
410b57cec5SDimitry Andric LT.add(D);
420b57cec5SDimitry Andric return true;
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric // In most cases the FriendDecl contains the declaration of the befriended
450b57cec5SDimitry Andric // class as a child node, so it is discovered during the recursive
460b57cec5SDimitry Andric // visitation. However, there are cases when the befriended class is not a
470b57cec5SDimitry Andric // child, thus it must be fetched explicitly from the FriendDecl, and only
480b57cec5SDimitry Andric // then can we add it to the lookup table.
VisitFriendDeclclang::__anon860fb6ed0111::Builder490b57cec5SDimitry Andric bool VisitFriendDecl(FriendDecl *D) {
500b57cec5SDimitry Andric if (D->getFriendType()) {
510b57cec5SDimitry Andric QualType Ty = D->getFriendType()->getType();
520b57cec5SDimitry Andric if (isa<ElaboratedType>(Ty))
530b57cec5SDimitry Andric Ty = cast<ElaboratedType>(Ty)->getNamedType();
540b57cec5SDimitry Andric // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
550b57cec5SDimitry Andric // always has that decl as child node.
560b57cec5SDimitry Andric // However, there are non-dependent cases which does not have the
570b57cec5SDimitry Andric // type as a child node. We have to dig up that type now.
580b57cec5SDimitry Andric if (!Ty->isDependentType()) {
590b57cec5SDimitry Andric if (const auto *RTy = dyn_cast<RecordType>(Ty))
600b57cec5SDimitry Andric LT.add(RTy->getAsCXXRecordDecl());
610b57cec5SDimitry Andric else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
620b57cec5SDimitry Andric LT.add(SpecTy->getAsCXXRecordDecl());
635ffd83dbSDimitry Andric else if (const auto *SubstTy =
645ffd83dbSDimitry Andric dyn_cast<SubstTemplateTypeParmType>(Ty)) {
655ffd83dbSDimitry Andric if (SubstTy->getAsCXXRecordDecl())
665ffd83dbSDimitry Andric LT.add(SubstTy->getAsCXXRecordDecl());
675ffd83dbSDimitry Andric } else if (isa<TypedefType>(Ty)) {
680b57cec5SDimitry Andric // We do not put friend typedefs to the lookup table because
690b57cec5SDimitry Andric // ASTImporter does not organize typedefs into redecl chains.
70*06c3fb27SDimitry Andric } else if (isa<UsingType>(Ty)) {
71*06c3fb27SDimitry Andric // Similar to TypedefType, not putting into lookup table.
720b57cec5SDimitry Andric } else {
730b57cec5SDimitry Andric llvm_unreachable("Unhandled type of friend class");
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric return true;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric // Override default settings of base.
shouldVisitTemplateInstantiationsclang::__anon860fb6ed0111::Builder810b57cec5SDimitry Andric bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCodeclang::__anon860fb6ed0111::Builder820b57cec5SDimitry Andric bool shouldVisitImplicitCode() const { return true; }
830b57cec5SDimitry Andric };
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric } // anonymous namespace
860b57cec5SDimitry Andric
ASTImporterLookupTable(TranslationUnitDecl & TU)870b57cec5SDimitry Andric ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
880b57cec5SDimitry Andric Builder B(*this);
890b57cec5SDimitry Andric B.TraverseDecl(&TU);
90*06c3fb27SDimitry Andric // The VaList declaration may be created on demand only or not traversed.
91*06c3fb27SDimitry Andric // To ensure it is present and found during import, add it to the table now.
92*06c3fb27SDimitry Andric if (auto *D =
93*06c3fb27SDimitry Andric dyn_cast_or_null<NamedDecl>(TU.getASTContext().getVaListTagDecl())) {
94*06c3fb27SDimitry Andric // On some platforms (AArch64) the VaList declaration can be inside a 'std'
95*06c3fb27SDimitry Andric // namespace. This is handled specially and not visible by AST traversal.
96*06c3fb27SDimitry Andric // ASTImporter must be able to find this namespace to import the VaList
97*06c3fb27SDimitry Andric // declaration (and the namespace) correctly.
98*06c3fb27SDimitry Andric if (auto *Ns = dyn_cast<NamespaceDecl>(D->getDeclContext()))
99*06c3fb27SDimitry Andric add(&TU, Ns);
100*06c3fb27SDimitry Andric add(D->getDeclContext(), D);
101*06c3fb27SDimitry Andric }
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric
add(DeclContext * DC,NamedDecl * ND)1040b57cec5SDimitry Andric void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
1050b57cec5SDimitry Andric DeclList &Decls = LookupTable[DC][ND->getDeclName()];
1060b57cec5SDimitry Andric // Inserts if and only if there is no element in the container equal to it.
1070b57cec5SDimitry Andric Decls.insert(ND);
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric
remove(DeclContext * DC,NamedDecl * ND)1100b57cec5SDimitry Andric void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
111349cc55cSDimitry Andric const DeclarationName Name = ND->getDeclName();
112349cc55cSDimitry Andric DeclList &Decls = LookupTable[DC][Name];
1130b57cec5SDimitry Andric bool EraseResult = Decls.remove(ND);
1140b57cec5SDimitry Andric (void)EraseResult;
115349cc55cSDimitry Andric #ifndef NDEBUG
116349cc55cSDimitry Andric if (!EraseResult) {
117349cc55cSDimitry Andric std::string Message =
118349cc55cSDimitry Andric llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}",
119349cc55cSDimitry Andric Name.getAsString(), DC->getDeclKindName())
120349cc55cSDimitry Andric .str();
121349cc55cSDimitry Andric llvm_unreachable(Message.c_str());
122349cc55cSDimitry Andric }
123349cc55cSDimitry Andric #endif
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric
add(NamedDecl * ND)1260b57cec5SDimitry Andric void ASTImporterLookupTable::add(NamedDecl *ND) {
1270b57cec5SDimitry Andric assert(ND);
1280b57cec5SDimitry Andric DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
1290b57cec5SDimitry Andric add(DC, ND);
1300b57cec5SDimitry Andric DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
1310b57cec5SDimitry Andric if (DC != ReDC)
1320b57cec5SDimitry Andric add(ReDC, ND);
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric
remove(NamedDecl * ND)1350b57cec5SDimitry Andric void ASTImporterLookupTable::remove(NamedDecl *ND) {
1360b57cec5SDimitry Andric assert(ND);
1370b57cec5SDimitry Andric DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
1380b57cec5SDimitry Andric remove(DC, ND);
1390b57cec5SDimitry Andric DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
1400b57cec5SDimitry Andric if (DC != ReDC)
1410b57cec5SDimitry Andric remove(ReDC, ND);
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
update(NamedDecl * ND,DeclContext * OldDC)144fe6060f1SDimitry Andric void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {
145fe6060f1SDimitry Andric assert(OldDC != ND->getDeclContext() &&
146fe6060f1SDimitry Andric "DeclContext should be changed before update");
147fe6060f1SDimitry Andric if (contains(ND->getDeclContext(), ND)) {
148fe6060f1SDimitry Andric assert(!contains(OldDC, ND) &&
149fe6060f1SDimitry Andric "Decl should not be found in the old context if already in the new");
150fe6060f1SDimitry Andric return;
151fe6060f1SDimitry Andric }
152fe6060f1SDimitry Andric
153fe6060f1SDimitry Andric remove(OldDC, ND);
154fe6060f1SDimitry Andric add(ND);
155fe6060f1SDimitry Andric }
156fe6060f1SDimitry Andric
updateForced(NamedDecl * ND,DeclContext * OldDC)1570eae32dcSDimitry Andric void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) {
1580eae32dcSDimitry Andric LookupTable[OldDC][ND->getDeclName()].remove(ND);
1590eae32dcSDimitry Andric add(ND);
1600eae32dcSDimitry Andric }
1610eae32dcSDimitry Andric
1620b57cec5SDimitry Andric ASTImporterLookupTable::LookupResult
lookup(DeclContext * DC,DeclarationName Name) const1630b57cec5SDimitry Andric ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
1640b57cec5SDimitry Andric auto DCI = LookupTable.find(DC->getPrimaryContext());
1650b57cec5SDimitry Andric if (DCI == LookupTable.end())
1660b57cec5SDimitry Andric return {};
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric const auto &FoundNameMap = DCI->second;
1690b57cec5SDimitry Andric auto NamesI = FoundNameMap.find(Name);
1700b57cec5SDimitry Andric if (NamesI == FoundNameMap.end())
1710b57cec5SDimitry Andric return {};
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric return NamesI->second;
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric
contains(DeclContext * DC,NamedDecl * ND) const176fe6060f1SDimitry Andric bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
177349cc55cSDimitry Andric return lookup(DC, ND->getDeclName()).contains(ND);
178fe6060f1SDimitry Andric }
179fe6060f1SDimitry Andric
dump(DeclContext * DC) const1800b57cec5SDimitry Andric void ASTImporterLookupTable::dump(DeclContext *DC) const {
1810b57cec5SDimitry Andric auto DCI = LookupTable.find(DC->getPrimaryContext());
1820b57cec5SDimitry Andric if (DCI == LookupTable.end())
1830b57cec5SDimitry Andric llvm::errs() << "empty\n";
1840b57cec5SDimitry Andric const auto &FoundNameMap = DCI->second;
1850b57cec5SDimitry Andric for (const auto &Entry : FoundNameMap) {
1860b57cec5SDimitry Andric DeclarationName Name = Entry.first;
1870b57cec5SDimitry Andric llvm::errs() << "==== Name: ";
1880b57cec5SDimitry Andric Name.dump();
1890b57cec5SDimitry Andric const DeclList& List = Entry.second;
1900b57cec5SDimitry Andric for (NamedDecl *ND : List) {
1910b57cec5SDimitry Andric ND->dump();
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric
dump() const1960b57cec5SDimitry Andric void ASTImporterLookupTable::dump() const {
1970b57cec5SDimitry Andric for (const auto &Entry : LookupTable) {
1980b57cec5SDimitry Andric DeclContext *DC = Entry.first;
1990b57cec5SDimitry Andric StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
2000b57cec5SDimitry Andric llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
2010b57cec5SDimitry Andric dump(DC);
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric } // namespace clang
206