Path: blob/main/contrib/llvm-project/clang/lib/Index/IndexingContext.cpp
35234 views
//===- IndexingContext.cpp - Indexing context data ------------------------===//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//===----------------------------------------------------------------------===//78#include "IndexingContext.h"9#include "clang/AST/ASTContext.h"10#include "clang/AST/Attr.h"11#include "clang/AST/DeclObjC.h"12#include "clang/AST/DeclTemplate.h"13#include "clang/Basic/SourceLocation.h"14#include "clang/Basic/SourceManager.h"15#include "clang/Index/IndexDataConsumer.h"1617using namespace clang;18using namespace index;1920static bool isGeneratedDecl(const Decl *D) {21if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {22return attr->getGeneratedDeclaration();23}24return false;25}2627bool IndexingContext::shouldIndex(const Decl *D) {28return !isGeneratedDecl(D);29}3031const LangOptions &IndexingContext::getLangOpts() const {32return Ctx->getLangOpts();33}3435bool IndexingContext::shouldIndexFunctionLocalSymbols() const {36return IndexOpts.IndexFunctionLocals;37}3839bool IndexingContext::shouldIndexImplicitInstantiation() const {40return IndexOpts.IndexImplicitInstantiation;41}4243bool IndexingContext::shouldIndexParametersInDeclarations() const {44return IndexOpts.IndexParametersInDeclarations;45}4647bool IndexingContext::shouldIndexTemplateParameters() const {48return IndexOpts.IndexTemplateParameters;49}5051bool IndexingContext::handleDecl(const Decl *D,52SymbolRoleSet Roles,53ArrayRef<SymbolRelation> Relations) {54return handleDecl(D, D->getLocation(), Roles, Relations);55}5657bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,58SymbolRoleSet Roles,59ArrayRef<SymbolRelation> Relations,60const DeclContext *DC) {61if (!DC)62DC = D->getDeclContext();6364const Decl *OrigD = D;65if (isa<ObjCPropertyImplDecl>(D)) {66D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();67}68return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),69Roles, Relations,70nullptr, OrigD, DC);71}7273bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,74const NamedDecl *Parent,75const DeclContext *DC,76SymbolRoleSet Roles,77ArrayRef<SymbolRelation> Relations,78const Expr *RefE) {79if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))80return true;8182if (!shouldIndexTemplateParameters() &&83(isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||84isa<TemplateTemplateParmDecl>(D))) {85return true;86}87return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,88RefE, nullptr, DC);89}9091static void reportModuleReferences(const Module *Mod,92ArrayRef<SourceLocation> IdLocs,93const ImportDecl *ImportD,94IndexDataConsumer &DataConsumer) {95if (!Mod)96return;97reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,98DataConsumer);99DataConsumer.handleModuleOccurrence(100ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());101}102103bool IndexingContext::importedModule(const ImportDecl *ImportD) {104if (ImportD->isInvalidDecl())105return true;106107SourceLocation Loc;108auto IdLocs = ImportD->getIdentifierLocs();109if (!IdLocs.empty())110Loc = IdLocs.back();111else112Loc = ImportD->getLocation();113114SourceManager &SM = Ctx->getSourceManager();115FileID FID = SM.getFileID(SM.getFileLoc(Loc));116if (FID.isInvalid())117return true;118119bool Invalid = false;120const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);121if (Invalid || !SEntry.isFile())122return true;123124if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {125switch (IndexOpts.SystemSymbolFilter) {126case IndexingOptions::SystemSymbolFilterKind::None:127return true;128case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:129case IndexingOptions::SystemSymbolFilterKind::All:130break;131}132}133134const Module *Mod = ImportD->getImportedModule();135if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {136reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,137DataConsumer);138}139140SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;141if (ImportD->isImplicit())142Roles |= (unsigned)SymbolRole::Implicit;143144return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);145}146147bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {148TemplateSpecializationKind TKind = TSK_Undeclared;149if (const ClassTemplateSpecializationDecl *150SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {151TKind = SD->getSpecializationKind();152} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {153TKind = FD->getTemplateSpecializationKind();154} else if (auto *VD = dyn_cast<VarDecl>(D)) {155TKind = VD->getTemplateSpecializationKind();156} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {157if (RD->getInstantiatedFromMemberClass())158TKind = RD->getTemplateSpecializationKind();159} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {160if (ED->getInstantiatedFromMemberEnum())161TKind = ED->getTemplateSpecializationKind();162} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||163isa<EnumConstantDecl>(D)) {164if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))165return isTemplateImplicitInstantiation(Parent);166}167switch (TKind) {168case TSK_Undeclared:169// Instantiation maybe not happen yet when we see a SpecializationDecl,170// e.g. when the type doesn't need to be complete, we still treat it as an171// instantiation as we'd like to keep the canonicalized result consistent.172return isa<ClassTemplateSpecializationDecl>(D);173case TSK_ExplicitSpecialization:174return false;175case TSK_ImplicitInstantiation:176case TSK_ExplicitInstantiationDeclaration:177case TSK_ExplicitInstantiationDefinition:178return true;179}180llvm_unreachable("invalid TemplateSpecializationKind");181}182183bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {184if (isa<ObjCInterfaceDecl>(D))185return false;186if (isa<ObjCCategoryDecl>(D))187return false;188if (isa<ObjCIvarDecl>(D))189return false;190if (isa<ObjCMethodDecl>(D))191return false;192if (isa<ImportDecl>(D))193return false;194return true;195}196197static const CXXRecordDecl *198getDeclContextForTemplateInstationPattern(const Decl *D) {199if (const auto *CTSD =200dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))201return CTSD->getTemplateInstantiationPattern();202else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))203return RD->getInstantiatedFromMemberClass();204return nullptr;205}206207static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {208if (const ClassTemplateSpecializationDecl *209SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {210const auto *Template = SD->getTemplateInstantiationPattern();211if (Template)212return Template;213// Fallback to primary template if no instantiation is available yet (e.g.214// the type doesn't need to be complete).215return SD->getSpecializedTemplate()->getTemplatedDecl();216} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {217return FD->getTemplateInstantiationPattern();218} else if (auto *VD = dyn_cast<VarDecl>(D)) {219return VD->getTemplateInstantiationPattern();220} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {221return RD->getInstantiatedFromMemberClass();222} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {223return ED->getInstantiatedFromMemberEnum();224} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {225const auto *ND = cast<NamedDecl>(D);226if (const CXXRecordDecl *Pattern =227getDeclContextForTemplateInstationPattern(ND)) {228for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {229if (BaseND->isImplicit())230continue;231if (BaseND->getKind() == ND->getKind())232return BaseND;233}234}235} else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {236if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {237if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {238for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))239return BaseECD;240}241}242}243return nullptr;244}245246static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {247if (auto VD = dyn_cast<VarDecl>(D))248return VD->isThisDeclarationADefinition(Ctx);249250if (auto FD = dyn_cast<FunctionDecl>(D))251return FD->isThisDeclarationADefinition();252253if (auto TD = dyn_cast<TagDecl>(D))254return TD->isThisDeclarationADefinition();255256if (auto MD = dyn_cast<ObjCMethodDecl>(D))257return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);258259if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) ||260isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) ||261isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D))262return true;263264return false;265}266267/// Whether the given NamedDecl should be skipped because it has no name.268static bool shouldSkipNamelessDecl(const NamedDecl *ND) {269return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&270!isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);271}272273static const Decl *adjustParent(const Decl *Parent) {274if (!Parent)275return nullptr;276for (;; Parent = cast<Decl>(Parent->getDeclContext())) {277if (isa<TranslationUnitDecl>(Parent))278return nullptr;279if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))280continue;281if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {282if (NS->isAnonymousNamespace())283continue;284} else if (auto RD = dyn_cast<RecordDecl>(Parent)) {285if (RD->isAnonymousStructOrUnion())286continue;287} else if (auto ND = dyn_cast<NamedDecl>(Parent)) {288if (shouldSkipNamelessDecl(ND))289continue;290}291return Parent;292}293}294295static const Decl *getCanonicalDecl(const Decl *D) {296D = D->getCanonicalDecl();297if (auto TD = dyn_cast<TemplateDecl>(D)) {298if (auto TTD = TD->getTemplatedDecl()) {299D = TTD;300assert(D->isCanonicalDecl());301}302}303304return D;305}306307static bool shouldReportOccurrenceForSystemDeclOnlyMode(308bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {309if (!IsRef)310return true;311312auto acceptForRelation = [](SymbolRoleSet roles) -> bool {313bool accept = false;314applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {315switch (r) {316case SymbolRole::RelationChildOf:317case SymbolRole::RelationBaseOf:318case SymbolRole::RelationOverrideOf:319case SymbolRole::RelationExtendedBy:320case SymbolRole::RelationAccessorOf:321case SymbolRole::RelationIBTypeOf:322accept = true;323return false;324case SymbolRole::Declaration:325case SymbolRole::Definition:326case SymbolRole::Reference:327case SymbolRole::Read:328case SymbolRole::Write:329case SymbolRole::Call:330case SymbolRole::Dynamic:331case SymbolRole::AddressOf:332case SymbolRole::Implicit:333case SymbolRole::Undefinition:334case SymbolRole::RelationReceivedBy:335case SymbolRole::RelationCalledBy:336case SymbolRole::RelationContainedBy:337case SymbolRole::RelationSpecializationOf:338case SymbolRole::NameReference:339return true;340}341llvm_unreachable("Unsupported SymbolRole value!");342});343return accept;344};345346for (auto &Rel : Relations) {347if (acceptForRelation(Rel.Roles))348return true;349}350351return false;352}353354bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,355bool IsRef, const Decl *Parent,356SymbolRoleSet Roles,357ArrayRef<SymbolRelation> Relations,358const Expr *OrigE,359const Decl *OrigD,360const DeclContext *ContainerDC) {361if (D->isImplicit() && !isa<ObjCMethodDecl>(D))362return true;363if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))364return true;365366SourceManager &SM = Ctx->getSourceManager();367FileID FID = SM.getFileID(SM.getFileLoc(Loc));368if (FID.isInvalid())369return true;370371bool Invalid = false;372const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);373if (Invalid || !SEntry.isFile())374return true;375376if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {377switch (IndexOpts.SystemSymbolFilter) {378case IndexingOptions::SystemSymbolFilterKind::None:379return true;380case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:381if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))382return true;383break;384case IndexingOptions::SystemSymbolFilterKind::All:385break;386}387}388389if (!OrigD)390OrigD = D;391392if (isTemplateImplicitInstantiation(D)) {393if (!IsRef)394return true;395D = adjustTemplateImplicitInstantiation(D);396if (!D)397return true;398assert(!isTemplateImplicitInstantiation(D));399}400401if (IsRef)402Roles |= (unsigned)SymbolRole::Reference;403else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))404Roles |= (unsigned)SymbolRole::Definition;405else406Roles |= (unsigned)SymbolRole::Declaration;407408D = getCanonicalDecl(D);409Parent = adjustParent(Parent);410if (Parent)411Parent = getCanonicalDecl(Parent);412413SmallVector<SymbolRelation, 6> FinalRelations;414FinalRelations.reserve(Relations.size()+1);415416auto addRelation = [&](SymbolRelation Rel) {417auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {418return Elem.RelatedSymbol == Rel.RelatedSymbol;419});420if (It != FinalRelations.end()) {421It->Roles |= Rel.Roles;422} else {423FinalRelations.push_back(Rel);424}425Roles |= Rel.Roles;426};427428if (Parent) {429if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {430addRelation(SymbolRelation{431(unsigned)SymbolRole::RelationContainedBy,432Parent433});434} else {435addRelation(SymbolRelation{436(unsigned)SymbolRole::RelationChildOf,437Parent438});439}440}441442for (auto &Rel : Relations) {443addRelation(SymbolRelation(Rel.Roles,444Rel.RelatedSymbol->getCanonicalDecl()));445}446447IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};448return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);449}450451void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,452SourceLocation Loc,453const MacroInfo &MI) {454if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))455return;456SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;457DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);458}459460void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,461SourceLocation Loc,462const MacroInfo &MI) {463if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))464return;465SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;466DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);467}468469void IndexingContext::handleMacroReference(const IdentifierInfo &Name,470SourceLocation Loc,471const MacroInfo &MI) {472if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))473return;474SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;475DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);476}477478bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,479SourceLocation Loc) {480if (!IndexOpts.IndexMacros)481return false;482483switch (IndexOpts.SystemSymbolFilter) {484case IndexingOptions::SystemSymbolFilterKind::None:485break;486case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:487if (!IsRef)488return true;489break;490case IndexingOptions::SystemSymbolFilterKind::All:491return true;492}493494SourceManager &SM = Ctx->getSourceManager();495FileID FID = SM.getFileID(SM.getFileLoc(Loc));496if (FID.isInvalid())497return false;498499bool Invalid = false;500const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);501if (Invalid || !SEntry.isFile())502return false;503504return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;505}506507508