diff options
Diffstat (limited to 'clang/lib/Index/IndexDecl.cpp')
| -rw-r--r-- | clang/lib/Index/IndexDecl.cpp | 770 |
1 files changed, 770 insertions, 0 deletions
diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp new file mode 100644 index 000000000000..5bbbb0d32bf4 --- /dev/null +++ b/clang/lib/Index/IndexDecl.cpp @@ -0,0 +1,770 @@ +//===- 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/Index/IndexDataConsumer.h" +#include "clang/AST/DeclVisitor.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<IndexingDeclVisitor, bool> { + IndexingContext &IndexCtx; + +public: + explicit IndexingDeclVisitor(IndexingContext &indexCtx) + : IndexCtx(indexCtx) { } + + bool Handled = true; + + bool VisitDecl(const Decl *D) { + Handled = false; + return true; + } + + /// 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(); + } + + 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; + } + } + + 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); + if (IndexCtx.shouldIndexFunctionLocalSymbols()) { + if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { + auto *DC = Parm->getDeclContext(); + if (auto *FD = dyn_cast<FunctionDecl>(DC)) { + if (IndexCtx.shouldIndexParametersInDeclarations() || + FD->isThisDeclarationADefinition()) + IndexCtx.handleDecl(Parm); + } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) { + if (MD->isThisDeclarationADefinition()) + IndexCtx.handleDecl(Parm); + } else { + IndexCtx.handleDecl(Parm); + } + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (IndexCtx.shouldIndexParametersInDeclarations() || + FD->isThisDeclarationADefinition()) { + for (auto PI : FD->parameters()) { + IndexCtx.handleDecl(PI); + } + } + } + } else { + // Index the default parameter value for function definitions. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isThisDeclarationADefinition()) { + for (const auto *PV : FD->parameters()) { + if (PV->hasDefaultArg() && !PV->hasUninstantiatedDefaultArg() && + !PV->hasUnparsedDefaultArg()) + IndexCtx.indexBody(PV->getDefaultArg(), D); + } + } + } + } + } + + bool handleObjCMethod(const ObjCMethodDecl *D, + const ObjCPropertyDecl *AssociatedProp = nullptr) { + SmallVector<SymbolRelation, 4> Relations; + SmallVector<const ObjCMethodDecl*, 4> 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<NamedDecl>(D->getDeclContext()), + D->getDeclContext(), 0); + } + + TRY_DECL(D, IndexCtx.handleDecl(D, MethodLoc, Roles, Relations)); + IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D); + bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>(); + 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<SymbolRelation> &Relations) { + if (!IndexCtx.getLangOpts().CPlusPlus) + return; + const auto *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(D->getLexicalDeclContext()); + if (!CTSD) + return; + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + Template = CTSD->getSpecializedTemplateOrPartial(); + if (const auto *CTD = Template.dyn_cast<ClassTemplateDecl *>()) { + const CXXRecordDecl *Pattern = CTD->getTemplatedDecl(); + bool TypeOverride = isa<TypeDecl>(D); + for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) { + if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND)) + ND = CTD->getTemplatedDecl(); + if (ND->isImplicit()) + continue; + // Types can override other types. + if (!TypeOverride) { + if (ND->getKind() != D->getKind()) + continue; + } else if (!isa<TypeDecl>(ND)) + continue; + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { + const auto *DFD = cast<FunctionDecl>(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<SymbolRelation, 4> Relations; + if (auto *CXXMD = dyn_cast<CXXMethodDecl>(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<CXXConstructorDecl>(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<CXXDestructorDecl>(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<CXXDeductionGuideDecl>(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<SymbolRelation, 4> 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<SymbolRelation, 4> 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<SymbolRelation, 4> 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<SymbolRelation, 4> Relations; + gatherTemplatePseudoOverrides(D, Relations); + IndexCtx.indexTagDecl(D, Relations); + } else { + SmallVector<SymbolRelation, 1> Relations; + gatherTemplatePseudoOverrides(D, Relations); + return IndexCtx.handleDecl(D, D->getLocation(), SymbolRoleSet(), + Relations, D->getLexicalDeclContext()); + } + } + 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<TypedefType>()) { + 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<ObjCPropertyImplDecl>(I) || + cast<ObjCPropertyImplDecl>(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<IBOutletCollectionAttr>()) + 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<ObjCImplDecl>(D->getDeclContext()); + SourceLocation Loc = D->getLocation(); + SymbolRoleSet Roles = 0; + SmallVector<SymbolRelation, 1> 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<NamedDecl>(DC); + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, + D->getLexicalDeclContext()); + for (const auto *I : D->shadows()) + 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<NamedDecl>(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<NamedDecl>(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<NamedDecl>(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<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + Template = D->getSpecializedTemplateOrPartial(); + const Decl *SpecializationOf = + Template.is<ClassTemplateDecl *>() + ? (Decl *)Template.get<ClassTemplateDecl *>() + : Template.get<ClassTemplatePartialSpecializationDecl *>(); + if (!D->isThisDeclarationADefinition()) + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); + IndexCtx.indexTagDecl( + D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), + SpecializationOf)); + if (TypeSourceInfo *TSI = D->getTypeAsWritten()) + IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr, + 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<FunctionDecl>(D)) + return FD->getCanonicalDecl() == FD; + else if (const auto *TD = dyn_cast<TagDecl>(D)) + return TD->getCanonicalDecl() == TD; + else if (const auto *VD = dyn_cast<VarDecl>(D)) + return VD->getCanonicalDecl() == VD; + return true; + } + + bool VisitTemplateDecl(const TemplateDecl *D) { + + const NamedDecl *Parent = D->getTemplatedDecl(); + if (!Parent) + return true; + + // Index the default values for the template parameters. + if (D->getTemplateParameters() && + shouldIndexTemplateParameterDefaultValue(Parent)) { + const TemplateParameterList *Params = D->getTemplateParameters(); + for (const NamedDecl *TP : *Params) { + if (IndexCtx.shouldIndexTemplateParameters()) + IndexCtx.handleDecl(TP); + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(TP)) { + if (TTP->hasDefaultArgument()) + IndexCtx.indexTypeSourceInfo(TTP->getDefaultArgumentInfo(), Parent); + } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TP)) { + if (NTTP->hasDefaultArgument()) + IndexCtx.indexBody(NTTP->getDefaultArgument(), Parent); + } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(TP)) { + if (TTPD->hasDefaultArgument()) + handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent, + TP->getLexicalDeclContext()); + } + } + } + + return Visit(Parent); + } + + 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<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext()) + return true; + return Visit(ND); + } + if (auto Ty = D->getFriendType()) { + IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext())); + } + return true; + } + + bool VisitImportDecl(const ImportDecl *D) { + return IndexCtx.importedModule(D); + } + + bool VisitStaticAssertDecl(const StaticAssertDecl *D) { + IndexCtx.indexBody(D->getAssertExpr(), + dyn_cast<NamedDecl>(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<DeclContext>(D)) + return indexDeclContext(cast<DeclContext>(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->getLocation().isInvalid()) + return true; + + if (isa<ObjCMethodDecl>(D)) + return true; // Wait for the objc container. + + 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; +} |
