//===- IndexDecl.cpp - Indexing declarations ------------------------------===// // // 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/ASTConcept.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/Index/IndexDataConsumer.h" #include "clang/Index/IndexSymbol.h" using namespace clang; using namespace index; #define TRY_DECL(D,CALL_EXPR) \ do { \ if (!IndexCtx.shouldIndex(D)) return true; \ if (!CALL_EXPR) \ return false; \ } while (0) #define TRY_TO(CALL_EXPR) \ do { \ if (!CALL_EXPR) \ return false; \ } while (0) namespace { class IndexingDeclVisitor : public ConstDeclVisitor { IndexingContext &IndexCtx; public: explicit IndexingDeclVisitor(IndexingContext &indexCtx) : IndexCtx(indexCtx) { } bool Handled = true; bool VisitDecl(const Decl *D) { Handled = false; return true; } void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc, const NamedDecl *Parent, const DeclContext *DC) { const TemplateArgumentLocInfo &LocInfo = TALoc.getLocInfo(); switch (TALoc.getArgument().getKind()) { case TemplateArgument::Expression: IndexCtx.indexBody(LocInfo.getAsExpr(), Parent, DC); break; case TemplateArgument::Type: IndexCtx.indexTypeSourceInfo(LocInfo.getAsTypeSourceInfo(), Parent, DC); break; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: IndexCtx.indexNestedNameSpecifierLoc(TALoc.getTemplateQualifierLoc(), Parent, DC); if (const TemplateDecl *TD = TALoc.getArgument() .getAsTemplateOrTemplatePattern() .getAsTemplateDecl()) { if (const NamedDecl *TTD = TD->getTemplatedDecl()) IndexCtx.handleReference(TTD, TALoc.getTemplateNameLoc(), Parent, DC); } break; default: break; } } /// Returns true if the given method has been defined explicitly by the /// user. static bool hasUserDefined(const ObjCMethodDecl *D, const ObjCImplDecl *Container) { const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(), D->isInstanceMethod()); return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition() && !MD->isSynthesizedAccessorStub(); } void handleDeclarator(const DeclaratorDecl *D, const NamedDecl *Parent = nullptr, bool isIBType = false) { if (!Parent) Parent = D; IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent, Parent->getLexicalDeclContext(), /*isBase=*/false, isIBType); IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent); auto IndexDefaultParmeterArgument = [&](const ParmVarDecl *Parm, const NamedDecl *Parent) { if (Parm->hasDefaultArg() && !Parm->hasUninstantiatedDefaultArg() && !Parm->hasUnparsedDefaultArg()) IndexCtx.indexBody(Parm->getDefaultArg(), Parent); }; if (IndexCtx.shouldIndexFunctionLocalSymbols()) { if (const ParmVarDecl *Parm = dyn_cast(D)) { auto *DC = Parm->getDeclContext(); if (auto *FD = dyn_cast(DC)) { if (IndexCtx.shouldIndexParametersInDeclarations() || FD->isThisDeclarationADefinition()) IndexCtx.handleDecl(Parm); } else if (auto *MD = dyn_cast(DC)) { if (MD->isThisDeclarationADefinition()) IndexCtx.handleDecl(Parm); } else { IndexCtx.handleDecl(Parm); } } else if (const FunctionDecl *FD = dyn_cast(D)) { if (IndexCtx.shouldIndexParametersInDeclarations() || FD->isThisDeclarationADefinition()) { for (const auto *PI : FD->parameters()) { IndexDefaultParmeterArgument(PI, D); IndexCtx.handleDecl(PI); } } } } else { // Index the default parameter value for function definitions. if (const auto *FD = dyn_cast(D)) { if (FD->isThisDeclarationADefinition()) { for (const auto *PV : FD->parameters()) { IndexDefaultParmeterArgument(PV, D); } } } } if (auto *C = D->getTrailingRequiresClause()) IndexCtx.indexBody(C, Parent); } bool handleObjCMethod(const ObjCMethodDecl *D, const ObjCPropertyDecl *AssociatedProp = nullptr) { SmallVector Relations; SmallVector Overriden; D->getOverriddenMethods(Overriden); for(auto overridden: Overriden) { Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf, overridden); } if (AssociatedProp) Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf, AssociatedProp); // getLocation() returns beginning token of a method declaration, but for // indexing purposes we want to point to the base name. SourceLocation MethodLoc = D->getSelectorStartLoc(); if (MethodLoc.isInvalid()) MethodLoc = D->getLocation(); SourceLocation AttrLoc; // check for (getter=/setter=) if (AssociatedProp) { bool isGetter = !D->param_size(); AttrLoc = isGetter ? AssociatedProp->getGetterNameLoc(): AssociatedProp->getSetterNameLoc(); } SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic; if (D->isImplicit()) { if (AttrLoc.isValid()) { MethodLoc = AttrLoc; } else { Roles |= (SymbolRoleSet)SymbolRole::Implicit; } } else if (AttrLoc.isValid()) { IndexCtx.handleReference(D, AttrLoc, cast(D->getDeclContext()), D->getDeclContext(), 0); } TRY_DECL(D, IndexCtx.handleDecl(D, MethodLoc, Roles, Relations)); IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D); bool hasIBActionAndFirst = D->hasAttr(); for (const auto *I : D->parameters()) { handleDeclarator(I, D, /*isIBType=*/hasIBActionAndFirst); hasIBActionAndFirst = false; } if (D->isThisDeclarationADefinition()) { const Stmt *Body = D->getBody(); if (Body) { IndexCtx.indexBody(Body, D, D); } } return true; } /// Gather the declarations which the given declaration \D overrides in a /// pseudo-override manner. /// /// Pseudo-overrides occur when a class template specialization declares /// a declaration that has the same name as a similar declaration in the /// non-specialized template. void gatherTemplatePseudoOverrides(const NamedDecl *D, SmallVectorImpl &Relations) { if (!IndexCtx.getLangOpts().CPlusPlus) return; const auto *CTSD = dyn_cast(D->getLexicalDeclContext()); if (!CTSD) return; llvm::PointerUnion Template = CTSD->getSpecializedTemplateOrPartial(); if (const auto *CTD = Template.dyn_cast()) { const CXXRecordDecl *Pattern = CTD->getTemplatedDecl(); bool TypeOverride = isa(D); for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) { if (const auto *CTD = dyn_cast(ND)) ND = CTD->getTemplatedDecl(); if (ND->isImplicit()) continue; // Types can override other types. if (!TypeOverride) { if (ND->getKind() != D->getKind()) continue; } else if (!isa(ND)) continue; if (const auto *FD = dyn_cast(ND)) { const auto *DFD = cast(D); // Function overrides are approximated using the number of parameters. if (FD->getStorageClass() != DFD->getStorageClass() || FD->getNumParams() != DFD->getNumParams()) continue; } Relations.emplace_back( SymbolRoleSet(SymbolRole::RelationSpecializationOf), ND); } } } bool VisitFunctionDecl(const FunctionDecl *D) { SymbolRoleSet Roles{}; SmallVector Relations; if (auto *CXXMD = dyn_cast(D)) { if (CXXMD->isVirtual()) Roles |= (unsigned)SymbolRole::Dynamic; for (const CXXMethodDecl *O : CXXMD->overridden_methods()) { Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, O); } } gatherTemplatePseudoOverrides(D, Relations); if (const auto *Base = D->getPrimaryTemplate()) Relations.push_back( SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), Base->getTemplatedDecl())); TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations)); handleDeclarator(D); if (const CXXConstructorDecl *Ctor = dyn_cast(D)) { IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(), Ctor->getParent(), Ctor->getDeclContext(), (unsigned)SymbolRole::NameReference); // Constructor initializers. for (const auto *Init : Ctor->inits()) { if (Init->isWritten()) { IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D); if (const FieldDecl *Member = Init->getAnyMember()) IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D, (unsigned)SymbolRole::Write); IndexCtx.indexBody(Init->getInit(), D, D); } } } else if (const CXXDestructorDecl *Dtor = dyn_cast(D)) { if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) { IndexCtx.handleReference(Dtor->getParent(), TypeNameInfo->getTypeLoc().getBeginLoc(), Dtor->getParent(), Dtor->getDeclContext(), (unsigned)SymbolRole::NameReference); } } else if (const auto *Guide = dyn_cast(D)) { IndexCtx.handleReference(Guide->getDeducedTemplate()->getTemplatedDecl(), Guide->getLocation(), Guide, Guide->getDeclContext()); } // Template specialization arguments. if (const ASTTemplateArgumentListInfo *TemplateArgInfo = D->getTemplateSpecializationArgsAsWritten()) { for (const auto &Arg : TemplateArgInfo->arguments()) handleTemplateArgumentLoc(Arg, D, D->getLexicalDeclContext()); } if (D->isThisDeclarationADefinition()) { const Stmt *Body = D->getBody(); if (Body) { IndexCtx.indexBody(Body, D, D); } } return true; } bool VisitVarDecl(const VarDecl *D) { SmallVector Relations; gatherTemplatePseudoOverrides(D, Relations); TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); handleDeclarator(D); IndexCtx.indexBody(D->getInit(), D); return true; } bool VisitDecompositionDecl(const DecompositionDecl *D) { for (const auto *Binding : D->bindings()) TRY_DECL(Binding, IndexCtx.handleDecl(Binding)); return Base::VisitDecompositionDecl(D); } bool VisitFieldDecl(const FieldDecl *D) { SmallVector Relations; gatherTemplatePseudoOverrides(D, Relations); TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); handleDeclarator(D); if (D->isBitField()) IndexCtx.indexBody(D->getBitWidth(), D); else if (D->hasInClassInitializer()) IndexCtx.indexBody(D->getInClassInitializer(), D); return true; } bool VisitObjCIvarDecl(const ObjCIvarDecl *D) { if (D->getSynthesize()) { // handled in VisitObjCPropertyImplDecl return true; } TRY_DECL(D, IndexCtx.handleDecl(D)); handleDeclarator(D); return true; } bool VisitMSPropertyDecl(const MSPropertyDecl *D) { TRY_DECL(D, IndexCtx.handleDecl(D)); handleDeclarator(D); return true; } bool VisitEnumConstantDecl(const EnumConstantDecl *D) { TRY_DECL(D, IndexCtx.handleDecl(D)); IndexCtx.indexBody(D->getInitExpr(), D); return true; } bool VisitTypedefNameDecl(const TypedefNameDecl *D) { if (!D->isTransparentTag()) { SmallVector Relations; gatherTemplatePseudoOverrides(D, Relations); TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); } return true; } bool VisitTagDecl(const TagDecl *D) { // Non-free standing tags are handled in indexTypeSourceInfo. if (D->isFreeStanding()) { if (D->isThisDeclarationADefinition()) { SmallVector Relations; gatherTemplatePseudoOverrides(D, Relations); IndexCtx.indexTagDecl(D, Relations); } else { SmallVector Relations; gatherTemplatePseudoOverrides(D, Relations); return IndexCtx.handleDecl(D, D->getLocation(), SymbolRoleSet(), Relations, D->getLexicalDeclContext()); } } return true; } bool VisitEnumDecl(const EnumDecl *ED) { TRY_TO(VisitTagDecl(ED)); // Indexing for enumdecl itself is handled inside TagDecl, we just want to // visit integer-base here, which is different than other TagDecl bases. if (auto *TSI = ED->getIntegerTypeSourceInfo()) IndexCtx.indexTypeSourceInfo(TSI, ED, ED, /*isBase=*/true); return true; } bool handleReferencedProtocols(const ObjCProtocolList &ProtList, const ObjCContainerDecl *ContD, SourceLocation SuperLoc) { ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); for (ObjCInterfaceDecl::protocol_iterator I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { SourceLocation Loc = *LI; ObjCProtocolDecl *PD = *I; SymbolRoleSet roles{}; if (Loc == SuperLoc) roles |= (SymbolRoleSet)SymbolRole::Implicit; TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles, SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); } return true; } bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { if (D->isThisDeclarationADefinition()) { TRY_DECL(D, IndexCtx.handleDecl(D)); SourceLocation SuperLoc = D->getSuperClassLoc(); if (auto *SuperD = D->getSuperClass()) { bool hasSuperTypedef = false; if (auto *TInfo = D->getSuperClassTInfo()) { if (auto *TT = TInfo->getType()->getAs()) { if (auto *TD = TT->getDecl()) { hasSuperTypedef = true; TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D, SymbolRoleSet())); } } } SymbolRoleSet superRoles{}; if (hasSuperTypedef) superRoles |= (SymbolRoleSet)SymbolRole::Implicit; TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles, SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); } TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, SuperLoc)); TRY_TO(IndexCtx.indexDeclContext(D)); } else { return IndexCtx.handleReference(D, D->getLocation(), nullptr, D->getDeclContext(), SymbolRoleSet()); } return true; } bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { if (D->isThisDeclarationADefinition()) { TRY_DECL(D, IndexCtx.handleDecl(D)); TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, /*SuperLoc=*/SourceLocation())); TRY_TO(IndexCtx.indexDeclContext(D)); } else { return IndexCtx.handleReference(D, D->getLocation(), nullptr, D->getDeclContext(), SymbolRoleSet()); } return true; } bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { const ObjCInterfaceDecl *Class = D->getClassInterface(); if (!Class) return true; if (Class->isImplicitInterfaceDecl()) IndexCtx.handleDecl(Class); TRY_DECL(D, IndexCtx.handleDecl(D)); // Visit implicit @synthesize property implementations first as their // location is reported at the name of the @implementation block. This // serves no purpose other than to simplify the FileCheck-based tests. for (const auto *I : D->property_impls()) { if (I->getLocation().isInvalid()) IndexCtx.indexDecl(I); } for (const auto *I : D->decls()) { if (!isa(I) || cast(I)->getLocation().isValid()) IndexCtx.indexDecl(I); } return true; } bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { if (!IndexCtx.shouldIndex(D)) return true; const ObjCInterfaceDecl *C = D->getClassInterface(); if (!C) return true; TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(), SymbolRelation{ (unsigned)SymbolRole::RelationExtendedBy, D })); SourceLocation CategoryLoc = D->getCategoryNameLoc(); if (!CategoryLoc.isValid()) CategoryLoc = D->getLocation(); TRY_TO(IndexCtx.handleDecl(D, CategoryLoc)); TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, /*SuperLoc=*/SourceLocation())); TRY_TO(IndexCtx.indexDeclContext(D)); return true; } bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { const ObjCCategoryDecl *Cat = D->getCategoryDecl(); if (!Cat) return true; const ObjCInterfaceDecl *C = D->getClassInterface(); if (C) TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet())); SourceLocation CategoryLoc = D->getCategoryNameLoc(); if (!CategoryLoc.isValid()) CategoryLoc = D->getLocation(); TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc)); IndexCtx.indexDeclContext(D); return true; } bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { // Methods associated with a property, even user-declared ones, are // handled when we handle the property. if (D->isPropertyAccessor()) return true; handleObjCMethod(D); return true; } bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) handleObjCMethod(MD, D); if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) handleObjCMethod(MD, D); TRY_DECL(D, IndexCtx.handleDecl(D)); if (IBOutletCollectionAttr *attr = D->getAttr()) IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D, D->getLexicalDeclContext(), false, true); IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); return true; } bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { ObjCPropertyDecl *PD = D->getPropertyDecl(); auto *Container = cast(D->getDeclContext()); SourceLocation Loc = D->getLocation(); SymbolRoleSet Roles = 0; SmallVector Relations; if (ObjCIvarDecl *ID = D->getPropertyIvarDecl()) Relations.push_back({(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID}); if (Loc.isInvalid()) { Loc = Container->getLocation(); Roles |= (SymbolRoleSet)SymbolRole::Implicit; } TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations)); if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) return true; assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); SymbolRoleSet AccessorMethodRoles = SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { if (IvarD->getSynthesize()) { // For synthesized ivars, use the location of its name in the // corresponding @synthesize. If there isn't one, use the containing // @implementation's location, rather than the property's location, // otherwise the header file containing the @interface will have different // indexing contents based on whether the @implementation was present or // not in the translation unit. SymbolRoleSet IvarRoles = 0; SourceLocation IvarLoc = D->getPropertyIvarDeclLoc(); if (D->getLocation().isInvalid()) { IvarLoc = Container->getLocation(); IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; } else if (D->getLocation() == IvarLoc) { IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; } TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles)); } else { IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr, D->getDeclContext(), SymbolRoleSet()); } } return true; } bool VisitNamespaceDecl(const NamespaceDecl *D) { TRY_DECL(D, IndexCtx.handleDecl(D)); IndexCtx.indexDeclContext(D); return true; } bool VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { TRY_DECL(D, IndexCtx.handleDecl(D)); IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); IndexCtx.handleReference(D->getAliasedNamespace(), D->getTargetNameLoc(), D, D->getLexicalDeclContext()); return true; } bool VisitUsingDecl(const UsingDecl *D) { IndexCtx.handleDecl(D); const DeclContext *DC = D->getDeclContext()->getRedeclContext(); const NamedDecl *Parent = dyn_cast(DC); IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, D->getLexicalDeclContext()); for (const auto *I : D->shadows()) { // Skip unresolved using decls - we already have a decl for the using // itself, so there's not much point adding another decl or reference to // refer to the same location. if (isa(I->getUnderlyingDecl())) continue; IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent, D->getLexicalDeclContext(), SymbolRoleSet()); } return true; } bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { const DeclContext *DC = D->getDeclContext()->getRedeclContext(); const NamedDecl *Parent = dyn_cast(DC); // NNS for the local 'using namespace' directives is visited by the body // visitor. if (!D->getParentFunctionOrMethod()) IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, D->getLexicalDeclContext()); return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), D->getLocation(), Parent, D->getLexicalDeclContext(), SymbolRoleSet()); } bool VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { TRY_DECL(D, IndexCtx.handleDecl(D)); const DeclContext *DC = D->getDeclContext()->getRedeclContext(); const NamedDecl *Parent = dyn_cast(DC); IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, D->getLexicalDeclContext()); return true; } bool VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { TRY_DECL(D, IndexCtx.handleDecl(D)); const DeclContext *DC = D->getDeclContext()->getRedeclContext(); const NamedDecl *Parent = dyn_cast(DC); IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, D->getLexicalDeclContext()); return true; } bool VisitClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl *D) { // FIXME: Notify subsequent callbacks if info comes from implicit // instantiation. llvm::PointerUnion Template = D->getSpecializedTemplateOrPartial(); const Decl *SpecializationOf = Template.is() ? (Decl *)Template.get() : Template.get(); if (!D->isThisDeclarationADefinition()) IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); IndexCtx.indexTagDecl( D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), SpecializationOf)); // Template specialization arguments. if (const ASTTemplateArgumentListInfo *TemplateArgInfo = D->getTemplateArgsAsWritten()) { for (const auto &Arg : TemplateArgInfo->arguments()) handleTemplateArgumentLoc(Arg, D, D->getLexicalDeclContext()); } return true; } static bool shouldIndexTemplateParameterDefaultValue(const NamedDecl *D) { // We want to index the template parameters only once when indexing the // canonical declaration. if (!D) return false; if (const auto *FD = dyn_cast(D)) return FD->getCanonicalDecl() == FD; else if (const auto *TD = dyn_cast(D)) return TD->getCanonicalDecl() == TD; else if (const auto *VD = dyn_cast(D)) return VD->getCanonicalDecl() == VD; return true; } void indexTemplateParameters(TemplateParameterList *Params, const NamedDecl *Parent) { for (const NamedDecl *TP : *Params) { if (IndexCtx.shouldIndexTemplateParameters()) IndexCtx.handleDecl(TP); if (const auto *TTP = dyn_cast(TP)) { if (TTP->hasDefaultArgument()) handleTemplateArgumentLoc(TTP->getDefaultArgument(), Parent, TP->getLexicalDeclContext()); if (auto *C = TTP->getTypeConstraint()) IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(), Parent, TTP->getLexicalDeclContext()); } else if (const auto *NTTP = dyn_cast(TP)) { IndexCtx.indexTypeSourceInfo(NTTP->getTypeSourceInfo(), Parent); if (NTTP->hasDefaultArgument()) handleTemplateArgumentLoc(NTTP->getDefaultArgument(), Parent, TP->getLexicalDeclContext()); } else if (const auto *TTPD = dyn_cast(TP)) { if (TTPD->hasDefaultArgument()) handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent, TP->getLexicalDeclContext()); } } if (auto *R = Params->getRequiresClause()) IndexCtx.indexBody(R, Parent); } bool VisitTemplateDecl(const TemplateDecl *D) { const NamedDecl *Parent = D->getTemplatedDecl(); if (!Parent) return true; // Index the default values for the template parameters. auto *Params = D->getTemplateParameters(); if (Params && shouldIndexTemplateParameterDefaultValue(Parent)) { indexTemplateParameters(Params, Parent); } return Visit(Parent); } bool VisitConceptDecl(const ConceptDecl *D) { if (auto *Params = D->getTemplateParameters()) indexTemplateParameters(Params, D); if (auto *E = D->getConstraintExpr()) IndexCtx.indexBody(E, D); return IndexCtx.handleDecl(D); } bool VisitFriendDecl(const FriendDecl *D) { if (auto ND = D->getFriendDecl()) { // FIXME: Ignore a class template in a dependent context, these are not // linked properly with their redeclarations, ending up with duplicate // USRs. // See comment "Friend templates are visible in fairly strange ways." in // SemaTemplate.cpp which precedes code that prevents the friend template // from becoming visible from the enclosing context. if (isa(ND) && D->getDeclContext()->isDependentContext()) return true; return Visit(ND); } if (auto Ty = D->getFriendType()) { IndexCtx.indexTypeSourceInfo(Ty, cast(D->getDeclContext())); } return true; } bool VisitImportDecl(const ImportDecl *D) { return IndexCtx.importedModule(D); } bool VisitStaticAssertDecl(const StaticAssertDecl *D) { IndexCtx.indexBody(D->getAssertExpr(), dyn_cast(D->getDeclContext()), D->getLexicalDeclContext()); return true; } }; } // anonymous namespace bool IndexingContext::indexDecl(const Decl *D) { if (D->isImplicit() && shouldIgnoreIfImplicit(D)) return true; if (isTemplateImplicitInstantiation(D) && !shouldIndexImplicitInstantiation()) return true; IndexingDeclVisitor Visitor(*this); bool ShouldContinue = Visitor.Visit(D); if (!ShouldContinue) return false; if (!Visitor.Handled && isa(D)) return indexDeclContext(cast(D)); return true; } bool IndexingContext::indexDeclContext(const DeclContext *DC) { for (const auto *I : DC->decls()) if (!indexDecl(I)) return false; return true; } bool IndexingContext::indexTopLevelDecl(const Decl *D) { if (!D || D->getLocation().isInvalid()) return true; if (isa(D)) return true; // Wait for the objc container. if (IndexOpts.ShouldTraverseDecl && !IndexOpts.ShouldTraverseDecl(D)) return true; // skip return indexDecl(D); } bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) if (!indexTopLevelDecl(*I)) return false; return true; }