Mercurial > hg > CbC > CbC_llvm
view clang/lib/Index/IndexingContext.cpp @ 176:de4ac79aef9d
...
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 25 May 2020 17:13:11 +0900 |
parents | 0572611fdcc8 |
children | 2e18cbf3894f |
line wrap: on
line source
//===- IndexingContext.cpp - Indexing context data ------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "IndexingContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Index/IndexDataConsumer.h" using namespace clang; using namespace index; static bool isGeneratedDecl(const Decl *D) { if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) { return attr->getGeneratedDeclaration(); } return false; } bool IndexingContext::shouldIndex(const Decl *D) { return !isGeneratedDecl(D); } const LangOptions &IndexingContext::getLangOpts() const { return Ctx->getLangOpts(); } bool IndexingContext::shouldIndexFunctionLocalSymbols() const { return IndexOpts.IndexFunctionLocals; } bool IndexingContext::shouldIndexImplicitInstantiation() const { return IndexOpts.IndexImplicitInstantiation; } bool IndexingContext::shouldIndexParametersInDeclarations() const { return IndexOpts.IndexParametersInDeclarations; } bool IndexingContext::shouldIndexTemplateParameters() const { return IndexOpts.IndexTemplateParameters; } bool IndexingContext::handleDecl(const Decl *D, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) { return handleDecl(D, D->getLocation(), Roles, Relations); } bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations, const DeclContext *DC) { if (!DC) DC = D->getDeclContext(); const Decl *OrigD = D; if (isa<ObjCPropertyImplDecl>(D)) { D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl(); } return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC), Roles, Relations, nullptr, OrigD, DC); } bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, const NamedDecl *Parent, const DeclContext *DC, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations, const Expr *RefE, const Decl *RefD) { if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D)) return true; if (!shouldIndexTemplateParameters() && (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D))) { return true; } return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations, RefE, RefD, DC); } static void reportModuleReferences(const Module *Mod, ArrayRef<SourceLocation> IdLocs, const ImportDecl *ImportD, IndexDataConsumer &DataConsumer) { if (!Mod) return; reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD, DataConsumer); DataConsumer.handleModuleOccurrence( ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back()); } bool IndexingContext::importedModule(const ImportDecl *ImportD) { if (ImportD->isInvalidDecl()) return true; SourceLocation Loc; auto IdLocs = ImportD->getIdentifierLocs(); if (!IdLocs.empty()) Loc = IdLocs.back(); else Loc = ImportD->getLocation(); SourceManager &SM = Ctx->getSourceManager(); FileID FID = SM.getFileID(SM.getFileLoc(Loc)); if (FID.isInvalid()) return true; bool Invalid = false; const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); if (Invalid || !SEntry.isFile()) return true; if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { switch (IndexOpts.SystemSymbolFilter) { case IndexingOptions::SystemSymbolFilterKind::None: return true; case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: case IndexingOptions::SystemSymbolFilterKind::All: break; } } const Module *Mod = ImportD->getImportedModule(); if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) { reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD, DataConsumer); } SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration; if (ImportD->isImplicit()) Roles |= (unsigned)SymbolRole::Implicit; return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc); } bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { TemplateSpecializationKind TKind = TSK_Undeclared; if (const ClassTemplateSpecializationDecl * SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { TKind = SD->getSpecializationKind(); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { TKind = FD->getTemplateSpecializationKind(); } else if (auto *VD = dyn_cast<VarDecl>(D)) { TKind = VD->getTemplateSpecializationKind(); } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { if (RD->getInstantiatedFromMemberClass()) TKind = RD->getTemplateSpecializationKind(); } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { if (ED->getInstantiatedFromMemberEnum()) TKind = ED->getTemplateSpecializationKind(); } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D)) { if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext())) return isTemplateImplicitInstantiation(Parent); } switch (TKind) { case TSK_Undeclared: // Instantiation maybe not happen yet when we see a SpecializationDecl, // e.g. when the type doesn't need to be complete, we still treat it as an // instantiation as we'd like to keep the canonicalized result consistent. return isa<ClassTemplateSpecializationDecl>(D); case TSK_ExplicitSpecialization: return false; case TSK_ImplicitInstantiation: case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: return true; } llvm_unreachable("invalid TemplateSpecializationKind"); } bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { if (isa<ObjCInterfaceDecl>(D)) return false; if (isa<ObjCCategoryDecl>(D)) return false; if (isa<ObjCIvarDecl>(D)) return false; if (isa<ObjCMethodDecl>(D)) return false; if (isa<ImportDecl>(D)) return false; return true; } static const CXXRecordDecl * getDeclContextForTemplateInstationPattern(const Decl *D) { if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) return CTSD->getTemplateInstantiationPattern(); else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) return RD->getInstantiatedFromMemberClass(); return nullptr; } static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { if (const ClassTemplateSpecializationDecl * SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { const auto *Template = SD->getTemplateInstantiationPattern(); if (Template) return Template; // Fallback to primary template if no instantiation is available yet (e.g. // the type doesn't need to be complete). return SD->getSpecializedTemplate()->getTemplatedDecl(); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { return FD->getTemplateInstantiationPattern(); } else if (auto *VD = dyn_cast<VarDecl>(D)) { return VD->getTemplateInstantiationPattern(); } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { return RD->getInstantiatedFromMemberClass(); } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { return ED->getInstantiatedFromMemberEnum(); } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) { const auto *ND = cast<NamedDecl>(D); if (const CXXRecordDecl *Pattern = getDeclContextForTemplateInstationPattern(ND)) { for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) { if (BaseND->isImplicit()) continue; if (BaseND->getKind() == ND->getKind()) return BaseND; } } } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) { if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) { if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) { for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName())) return BaseECD; } } } return nullptr; } static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) { if (auto VD = dyn_cast<VarDecl>(D)) return VD->isThisDeclarationADefinition(Ctx); if (auto FD = dyn_cast<FunctionDecl>(D)) return FD->isThisDeclarationADefinition(); if (auto TD = dyn_cast<TagDecl>(D)) return TD->isThisDeclarationADefinition(); if (auto MD = dyn_cast<ObjCMethodDecl>(D)) return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC); if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) || isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) || isa<ObjCPropertyImplDecl>(D)) return true; return false; } /// Whether the given NamedDecl should be skipped because it has no name. static bool shouldSkipNamelessDecl(const NamedDecl *ND) { return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) && !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND); } static const Decl *adjustParent(const Decl *Parent) { if (!Parent) return nullptr; for (;; Parent = cast<Decl>(Parent->getDeclContext())) { if (isa<TranslationUnitDecl>(Parent)) return nullptr; if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent)) continue; if (auto NS = dyn_cast<NamespaceDecl>(Parent)) { if (NS->isAnonymousNamespace()) continue; } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { if (RD->isAnonymousStructOrUnion()) continue; } else if (auto ND = dyn_cast<NamedDecl>(Parent)) { if (shouldSkipNamelessDecl(ND)) continue; } return Parent; } } static const Decl *getCanonicalDecl(const Decl *D) { D = D->getCanonicalDecl(); if (auto TD = dyn_cast<TemplateDecl>(D)) { if (auto TTD = TD->getTemplatedDecl()) { D = TTD; assert(D->isCanonicalDecl()); } } return D; } static bool shouldReportOccurrenceForSystemDeclOnlyMode( bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) { if (!IsRef) return true; auto acceptForRelation = [](SymbolRoleSet roles) -> bool { bool accept = false; applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool { switch (r) { case SymbolRole::RelationChildOf: case SymbolRole::RelationBaseOf: case SymbolRole::RelationOverrideOf: case SymbolRole::RelationExtendedBy: case SymbolRole::RelationAccessorOf: case SymbolRole::RelationIBTypeOf: accept = true; return false; case SymbolRole::Declaration: case SymbolRole::Definition: case SymbolRole::Reference: case SymbolRole::Read: case SymbolRole::Write: case SymbolRole::Call: case SymbolRole::Dynamic: case SymbolRole::AddressOf: case SymbolRole::Implicit: case SymbolRole::Undefinition: case SymbolRole::RelationReceivedBy: case SymbolRole::RelationCalledBy: case SymbolRole::RelationContainedBy: case SymbolRole::RelationSpecializationOf: case SymbolRole::NameReference: return true; } llvm_unreachable("Unsupported SymbolRole value!"); }); return accept; }; for (auto &Rel : Relations) { if (acceptForRelation(Rel.Roles)) return true; } return false; } bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, bool IsRef, const Decl *Parent, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations, const Expr *OrigE, const Decl *OrigD, const DeclContext *ContainerDC) { if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) return true; if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D))) return true; SourceManager &SM = Ctx->getSourceManager(); FileID FID = SM.getFileID(SM.getFileLoc(Loc)); if (FID.isInvalid()) return true; bool Invalid = false; const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); if (Invalid || !SEntry.isFile()) return true; if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { switch (IndexOpts.SystemSymbolFilter) { case IndexingOptions::SystemSymbolFilterKind::None: return true; case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations)) return true; break; case IndexingOptions::SystemSymbolFilterKind::All: break; } } if (!OrigD) OrigD = D; if (isTemplateImplicitInstantiation(D)) { if (!IsRef) return true; D = adjustTemplateImplicitInstantiation(D); if (!D) return true; assert(!isTemplateImplicitInstantiation(D)); } if (IsRef) Roles |= (unsigned)SymbolRole::Reference; else if (isDeclADefinition(OrigD, ContainerDC, *Ctx)) Roles |= (unsigned)SymbolRole::Definition; else Roles |= (unsigned)SymbolRole::Declaration; D = getCanonicalDecl(D); Parent = adjustParent(Parent); if (Parent) Parent = getCanonicalDecl(Parent); SmallVector<SymbolRelation, 6> FinalRelations; FinalRelations.reserve(Relations.size()+1); auto addRelation = [&](SymbolRelation Rel) { auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool { return Elem.RelatedSymbol == Rel.RelatedSymbol; }); if (It != FinalRelations.end()) { It->Roles |= Rel.Roles; } else { FinalRelations.push_back(Rel); } Roles |= Rel.Roles; }; if (Parent) { if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) { addRelation(SymbolRelation{ (unsigned)SymbolRole::RelationContainedBy, Parent }); } else { addRelation(SymbolRelation{ (unsigned)SymbolRole::RelationChildOf, Parent }); } } for (auto &Rel : Relations) { addRelation(SymbolRelation(Rel.Roles, Rel.RelatedSymbol->getCanonicalDecl())); } IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC}; return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node); } void IndexingContext::handleMacroDefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI) { SymbolRoleSet Roles = (unsigned)SymbolRole::Definition; DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); } void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI) { SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition; DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); } void IndexingContext::handleMacroReference(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI) { SymbolRoleSet Roles = (unsigned)SymbolRole::Reference; DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); }