|  | //===- 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<IndexingDeclVisitor, bool> { | 
|  | 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<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 (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<FunctionDecl>(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<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 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<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()) { | 
|  | // 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<UnresolvedUsingIfExistsDecl>(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<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; | 
|  | } | 
|  |  | 
|  | void indexTemplateParameters(TemplateParameterList *Params, | 
|  | const NamedDecl *Parent) { | 
|  | 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); | 
|  | if (auto *C = TTP->getTypeConstraint()) | 
|  | IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(), | 
|  | Parent, TTP->getLexicalDeclContext()); | 
|  | } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TP)) { | 
|  | IndexCtx.indexTypeSourceInfo(NTTP->getTypeSourceInfo(), Parent); | 
|  | 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()); | 
|  | } | 
|  | } | 
|  | 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<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 || D->getLocation().isInvalid()) | 
|  | return true; | 
|  |  | 
|  | if (isa<ObjCMethodDecl>(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; | 
|  | } |