diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp new file mode 100644 index 0000000..eb3e151 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp @@ -0,0 +1,454 @@ +//===- IndexDecl.cpp - Indexing declarations ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" +#include "clang/Index/IndexDataConsumer.h" +#include "clang/AST/DeclVisitor.h" + +using namespace clang; +using namespace index; + +#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; + } + + /// \brief 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 handleDeclarator(const DeclaratorDecl *D, + const NamedDecl *Parent = nullptr) { + if (!Parent) Parent = D; + + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent); + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent); + if (IndexCtx.shouldIndexFunctionLocalSymbols()) { + // Only index parameters in definitions, parameters in declarations are + // not useful. + if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { + auto *DC = Parm->getDeclContext(); + if (auto *FD = dyn_cast<FunctionDecl>(DC)) { + if (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 (FD->isThisDeclarationADefinition()) { + for (auto PI : FD->parameters()) { + IndexCtx.handleDecl(PI); + } + } + } + } + } + + bool handleObjCMethod(const ObjCMethodDecl *D) { + if (!IndexCtx.handleDecl(D, (unsigned)SymbolRole::Dynamic)) + return false; + IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D); + for (const auto *I : D->parameters()) + handleDeclarator(I, D); + + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.indexBody(Body, D, D); + } + } + return true; + } + + bool VisitFunctionDecl(const FunctionDecl *D) { + if (D->isDeleted()) + return true; + + SymbolRoleSet Roles{}; + SmallVector<SymbolRelation, 4> Relations; + if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) { + if (CXXMD->isVirtual()) + Roles |= (unsigned)SymbolRole::Dynamic; + for (auto I = CXXMD->begin_overridden_methods(), + E = CXXMD->end_overridden_methods(); I != E; ++I) { + Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I); + } + } + + if (!IndexCtx.handleDecl(D, Roles, Relations)) + return false; + handleDeclarator(D); + + if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { + // 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); + } + } + } + + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.indexBody(Body, D, D); + } + } + return true; + } + + bool VisitVarDecl(const VarDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + handleDeclarator(D); + IndexCtx.indexBody(D->getInit(), D); + return true; + } + + bool VisitFieldDecl(const FieldDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + 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()) { + // For synthesized ivars, use the location of the ObjC implementation, + // not the location of the property. + // 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. + return IndexCtx.handleDecl(D, + cast<Decl>(D->getDeclContext())->getLocation(), + (unsigned)SymbolRole::Implicit); + } + if (!IndexCtx.handleDecl(D)) + return false; + handleDeclarator(D); + return true; + } + + bool VisitMSPropertyDecl(const MSPropertyDecl *D) { + handleDeclarator(D); + return true; + } + + bool VisitEnumConstantDecl(const EnumConstantDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexBody(D->getInitExpr(), D); + return true; + } + + bool VisitTypedefNameDecl(const TypedefNameDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + 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()) { + IndexCtx.indexTagDecl(D); + } else { + auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext()); + return IndexCtx.handleReference(D, D->getLocation(), Parent, + D->getLexicalDeclContext(), + SymbolRoleSet()); + } + } + return true; + } + + bool handleReferencedProtocols(const ObjCProtocolList &ProtList, + const ObjCContainerDecl *ContD) { + 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; + TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, + SymbolRoleSet(), + SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); + } + return true; + } + + bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { + if (D->isThisDeclarationADefinition()) { + TRY_TO(IndexCtx.handleDecl(D)); + if (auto *SuperD = D->getSuperClass()) { + TRY_TO(IndexCtx.handleReference(SuperD, D->getSuperClassLoc(), D, D, + SymbolRoleSet(), + SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); + } + TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); + 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_TO(IndexCtx.handleDecl(D)); + TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); + 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); + + if (!IndexCtx.handleDecl(D)) + return false; + + // Index the ivars first to make sure the synthesized ivars are indexed + // before indexing the methods that can reference them. + for (const auto *IvarI : D->ivars()) + IndexCtx.indexDecl(IvarI); + for (const auto *I : D->decls()) { + if (!isa<ObjCIvarDecl>(I)) + IndexCtx.indexDecl(I); + } + + return true; + } + + bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { + const ObjCCategoryDecl *Cat = D->getCategoryDecl(); + if (!Cat) + return true; + + if (!IndexCtx.handleDecl(D)) + return false; + 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); + if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) + if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) + handleObjCMethod(MD); + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *PD = D->getPropertyDecl(); + if (!IndexCtx.handleReference(PD, D->getLocation(), + /*Parent=*/cast<NamedDecl>(D->getDeclContext()), + D->getDeclContext(), SymbolRoleSet(), {}, + /*RefE=*/nullptr, D)) + return false; + + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return true; + assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); + + if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { + if (!IvarD->getSynthesize()) + IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr, + D->getDeclContext(), SymbolRoleSet()); + } + + auto *ImplD = cast<ObjCImplDecl>(D->getDeclContext()); + if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { + if (MD->isPropertyAccessor() && + !hasUserDefined(MD, ImplD)) + IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD); + } + if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { + if (MD->isPropertyAccessor() && + !hasUserDefined(MD, ImplD)) + IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD); + } + return true; + } + + bool VisitNamespaceDecl(const NamespaceDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitUsingDecl(const UsingDecl *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); + + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, + D->getLexicalDeclContext()); + return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), + D->getLocation(), Parent, + D->getLexicalDeclContext(), + SymbolRoleSet()); + } + + bool VisitClassTemplateSpecializationDecl(const + ClassTemplateSpecializationDecl *D) { + // FIXME: Notify subsequent callbacks if info comes from implicit + // instantiation. + if (D->isThisDeclarationADefinition()) + IndexCtx.indexTagDecl(D); + return true; + } + + bool VisitTemplateDecl(const TemplateDecl *D) { + // FIXME: Template parameters. + return Visit(D->getTemplatedDecl()); + } + + 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); + } +}; + +} // anonymous namespace + +bool IndexingContext::indexDecl(const Decl *D) { + if (D->isImplicit() && shouldIgnoreIfImplicit(D)) + return true; + + if (isTemplateImplicitInstantiation(D)) + 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; +} |