Path: blob/main/contrib/llvm-project/clang/lib/AST/ASTImporterLookupTable.cpp
35260 views
//===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the ASTImporterLookupTable class which implements a9// lookup procedure for the import mechanism.10//11//===----------------------------------------------------------------------===//1213#include "clang/AST/ASTImporterLookupTable.h"14#include "clang/AST/Decl.h"15#include "clang/AST/RecursiveASTVisitor.h"16#include "llvm/Support/FormatVariadic.h"1718namespace clang {1920namespace {2122struct Builder : RecursiveASTVisitor<Builder> {23ASTImporterLookupTable <24Builder(ASTImporterLookupTable <) : LT(LT) {}2526bool VisitTypedefNameDecl(TypedefNameDecl *D) {27QualType Ty = D->getUnderlyingType();28Ty = Ty.getCanonicalType();29if (const auto *RTy = dyn_cast<RecordType>(Ty)) {30LT.add(RTy->getAsRecordDecl());31// iterate over the field decls, adding them32for (auto *it : RTy->getAsRecordDecl()->fields()) {33LT.add(it);34}35}36return true;37}3839bool VisitNamedDecl(NamedDecl *D) {40LT.add(D);41return true;42}43// In most cases the FriendDecl contains the declaration of the befriended44// class as a child node, so it is discovered during the recursive45// visitation. However, there are cases when the befriended class is not a46// child, thus it must be fetched explicitly from the FriendDecl, and only47// then can we add it to the lookup table.48bool VisitFriendDecl(FriendDecl *D) {49if (D->getFriendType()) {50QualType Ty = D->getFriendType()->getType();51if (isa<ElaboratedType>(Ty))52Ty = cast<ElaboratedType>(Ty)->getNamedType();53// A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)54// always has that decl as child node.55// However, there are non-dependent cases which does not have the56// type as a child node. We have to dig up that type now.57if (!Ty->isDependentType()) {58if (const auto *RTy = dyn_cast<RecordType>(Ty))59LT.add(RTy->getAsCXXRecordDecl());60else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))61LT.add(SpecTy->getAsCXXRecordDecl());62else if (const auto *SubstTy =63dyn_cast<SubstTemplateTypeParmType>(Ty)) {64if (SubstTy->getAsCXXRecordDecl())65LT.add(SubstTy->getAsCXXRecordDecl());66} else if (isa<TypedefType>(Ty)) {67// We do not put friend typedefs to the lookup table because68// ASTImporter does not organize typedefs into redecl chains.69} else if (isa<UsingType>(Ty)) {70// Similar to TypedefType, not putting into lookup table.71} else {72llvm_unreachable("Unhandled type of friend class");73}74}75}76return true;77}7879// Override default settings of base.80bool shouldVisitTemplateInstantiations() const { return true; }81bool shouldVisitImplicitCode() const { return true; }82};8384} // anonymous namespace8586ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {87Builder B(*this);88B.TraverseDecl(&TU);89// The VaList declaration may be created on demand only or not traversed.90// To ensure it is present and found during import, add it to the table now.91if (auto *D =92dyn_cast_or_null<NamedDecl>(TU.getASTContext().getVaListTagDecl())) {93// On some platforms (AArch64) the VaList declaration can be inside a 'std'94// namespace. This is handled specially and not visible by AST traversal.95// ASTImporter must be able to find this namespace to import the VaList96// declaration (and the namespace) correctly.97if (auto *Ns = dyn_cast<NamespaceDecl>(D->getDeclContext()))98add(&TU, Ns);99add(D->getDeclContext(), D);100}101}102103void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {104DeclList &Decls = LookupTable[DC][ND->getDeclName()];105// Inserts if and only if there is no element in the container equal to it.106Decls.insert(ND);107}108109void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {110const DeclarationName Name = ND->getDeclName();111DeclList &Decls = LookupTable[DC][Name];112bool EraseResult = Decls.remove(ND);113(void)EraseResult;114#ifndef NDEBUG115if (!EraseResult) {116std::string Message =117llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}",118Name.getAsString(), DC->getDeclKindName())119.str();120llvm_unreachable(Message.c_str());121}122#endif123}124125void ASTImporterLookupTable::add(NamedDecl *ND) {126assert(ND);127DeclContext *DC = ND->getDeclContext()->getPrimaryContext();128add(DC, ND);129DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();130if (DC != ReDC)131add(ReDC, ND);132}133134void ASTImporterLookupTable::remove(NamedDecl *ND) {135assert(ND);136DeclContext *DC = ND->getDeclContext()->getPrimaryContext();137remove(DC, ND);138DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();139if (DC != ReDC)140remove(ReDC, ND);141}142143void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {144assert(OldDC != ND->getDeclContext() &&145"DeclContext should be changed before update");146if (contains(ND->getDeclContext(), ND)) {147assert(!contains(OldDC, ND) &&148"Decl should not be found in the old context if already in the new");149return;150}151152remove(OldDC, ND);153add(ND);154}155156void ASTImporterLookupTable::updateForced(NamedDecl *ND, DeclContext *OldDC) {157LookupTable[OldDC][ND->getDeclName()].remove(ND);158add(ND);159}160161ASTImporterLookupTable::LookupResult162ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {163auto DCI = LookupTable.find(DC->getPrimaryContext());164if (DCI == LookupTable.end())165return {};166167const auto &FoundNameMap = DCI->second;168auto NamesI = FoundNameMap.find(Name);169if (NamesI == FoundNameMap.end())170return {};171172return NamesI->second;173}174175bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {176return lookup(DC, ND->getDeclName()).contains(ND);177}178179void ASTImporterLookupTable::dump(DeclContext *DC) const {180auto DCI = LookupTable.find(DC->getPrimaryContext());181if (DCI == LookupTable.end())182llvm::errs() << "empty\n";183const auto &FoundNameMap = DCI->second;184for (const auto &Entry : FoundNameMap) {185DeclarationName Name = Entry.first;186llvm::errs() << "==== Name: ";187Name.dump();188const DeclList& List = Entry.second;189for (NamedDecl *ND : List) {190ND->dump();191}192}193}194195void ASTImporterLookupTable::dump() const {196for (const auto &Entry : LookupTable) {197DeclContext *DC = Entry.first;198StringRef Primary = DC->getPrimaryContext() ? " primary" : "";199llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";200dump(DC);201}202}203204} // namespace clang205206207