diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2016-02-12 23:10:59 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2016-02-12 23:10:59 +0000 |
commit | f4fb85b1c74e88c7b3d4346e5a52348f97bb7ecd (patch) | |
tree | b46847178018a9ac848ee2ef79d776004bc7d4a9 /clang/lib | |
parent | 51699a83cd54680d82b5c0926a22ac7a41354b54 (diff) | |
download | bcm5719-llvm-f4fb85b1c74e88c7b3d4346e5a52348f97bb7ecd.tar.gz bcm5719-llvm-f4fb85b1c74e88c7b3d4346e5a52348f97bb7ecd.zip |
[libclang] Separate the underlying indexing functionality of libclang and introduce it into the clangIndex library.
It is a general goodness for libclang itself to mostly be a wrapper of functionality provided by the libraries.
llvm-svn: 260760
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Index/CMakeLists.txt | 8 | ||||
-rw-r--r-- | clang/lib/Index/IndexBody.cpp | 347 | ||||
-rw-r--r-- | clang/lib/Index/IndexDecl.cpp | 429 | ||||
-rw-r--r-- | clang/lib/Index/IndexSymbol.cpp | 187 | ||||
-rw-r--r-- | clang/lib/Index/IndexTypeSourceInfo.cpp | 202 | ||||
-rw-r--r-- | clang/lib/Index/IndexingAction.cpp | 140 | ||||
-rw-r--r-- | clang/lib/Index/IndexingContext.cpp | 325 | ||||
-rw-r--r-- | clang/lib/Index/IndexingContext.h | 121 |
8 files changed, 1759 insertions, 0 deletions
diff --git a/clang/lib/Index/CMakeLists.txt b/clang/lib/Index/CMakeLists.txt index 3869c32c879..cb2b931235e 100644 --- a/clang/lib/Index/CMakeLists.txt +++ b/clang/lib/Index/CMakeLists.txt @@ -5,14 +5,22 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangIndex CommentToXML.cpp USRGeneration.cpp + IndexBody.cpp + IndexDecl.cpp + IndexingAction.cpp + IndexingContext.cpp + IndexSymbol.cpp + IndexTypeSourceInfo.cpp ADDITIONAL_HEADERS + IndexingContext.h SimpleFormatContext.h LINK_LIBS clangAST clangBasic clangFormat + clangFrontend clangRewrite clangToolingCore ) diff --git a/clang/lib/Index/IndexBody.cpp b/clang/lib/Index/IndexBody.cpp new file mode 100644 index 00000000000..56fba28387d --- /dev/null +++ b/clang/lib/Index/IndexBody.cpp @@ -0,0 +1,347 @@ +//===- IndexBody.cpp - Indexing statements --------------------------------===// +// +// 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/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace clang::index; + +namespace { + +class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + SmallVector<Stmt*, 16> StmtStack; + + typedef RecursiveASTVisitor<BodyIndexer> base; +public: + BodyIndexer(IndexingContext &indexCtx, + const NamedDecl *Parent, const DeclContext *DC) + : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool TraverseStmt(Stmt *S) { + StmtStack.push_back(S); + bool ret = base::TraverseStmt(S); + StmtStack.pop_back(); + return ret; + } + + bool TraverseTypeLoc(TypeLoc TL) { + IndexCtx.indexTypeLoc(TL, Parent, ParentDC); + return true; + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); + return true; + } + + SymbolRoleSet getRolesForRef(const Expr *E, + SmallVectorImpl<SymbolRelation> &Relations) { + SymbolRoleSet Roles{}; + assert(!StmtStack.empty() && E == StmtStack.back()); + if (StmtStack.size() == 1) + return Roles; + auto It = StmtStack.end()-2; + while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) { + if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) { + if (ICE->getCastKind() == CK_LValueToRValue) + Roles |= (unsigned)(unsigned)SymbolRole::Read; + } + if (It == StmtStack.begin()) + break; + --It; + } + const Stmt *Parent = *It; + + if (auto BO = dyn_cast<BinaryOperator>(Parent)) { + if (BO->getOpcode() == BO_Assign && BO->getLHS()->IgnoreParenCasts() == E) + Roles |= (unsigned)SymbolRole::Write; + + } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) { + if (UO->isIncrementDecrementOp()) { + Roles |= (unsigned)SymbolRole::Read; + Roles |= (unsigned)SymbolRole::Write; + } else if (UO->getOpcode() == UO_AddrOf) { + Roles |= (unsigned)SymbolRole::AddressOf; + } + + } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) { + if (CA->getLHS()->IgnoreParenCasts() == E) { + Roles |= (unsigned)SymbolRole::Read; + Roles |= (unsigned)SymbolRole::Write; + } + + } else if (auto CE = dyn_cast<CallExpr>(Parent)) { + if (CE->getCallee()->IgnoreParenCasts() == E) { + Roles |= (unsigned)SymbolRole::Call; + if (auto *ME = dyn_cast<MemberExpr>(E)) { + if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl())) + if (CXXMD->isVirtual() && !ME->hasQualifier()) { + Roles |= (unsigned)SymbolRole::Dynamic; + auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType(); + if (!BaseTy.isNull()) + if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl()) + Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, + CXXRD); + } + } + } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) { + if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) { + OverloadedOperatorKind Op = CXXOp->getOperator(); + if (Op == OO_Equal) { + Roles |= (unsigned)SymbolRole::Write; + } else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) || + Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual || + Op == OO_PlusPlus || Op == OO_MinusMinus) { + Roles |= (unsigned)SymbolRole::Read; + Roles |= (unsigned)SymbolRole::Write; + } else if (Op == OO_Amp) { + Roles |= (unsigned)SymbolRole::AddressOf; + } + } + } + } + + return Roles; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getDecl(), E->getLocation(), + Parent, ParentDC, Roles, Relations, E); + } + + bool VisitMemberExpr(MemberExpr *E) { + SourceLocation Loc = E->getMemberLoc(); + if (Loc.isInvalid()) + Loc = E->getLocStart(); + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getMemberDecl(), Loc, + Parent, ParentDC, Roles, Relations, E); + } + + bool VisitDesignatedInitExpr(DesignatedInitExpr *E) { + for (DesignatedInitExpr::reverse_designators_iterator + D = E->designators_rbegin(), DEnd = E->designators_rend(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) + return IndexCtx.handleReference(D->getField(), D->getFieldLoc(), + Parent, ParentDC, SymbolRoleSet(), + {}, E); + } + return true; + } + + bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getDecl(), E->getLocation(), + Parent, ParentDC, Roles, Relations, E); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool { + if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance) + return false; + if (auto *RecE = dyn_cast<ObjCMessageExpr>( + MsgE->getInstanceReceiver()->IgnoreParenCasts())) { + if (RecE->getMethodFamily() == OMF_alloc) + return false; + } + return true; + }; + + if (ObjCMethodDecl *MD = E->getMethodDecl()) { + SymbolRoleSet Roles = (unsigned)SymbolRole::Call; + if (E->isImplicit()) + Roles |= (unsigned)SymbolRole::Implicit; + + SmallVector<SymbolRelation, 2> Relations; + if (isDynamic(E)) { + Roles |= (unsigned)SymbolRole::Dynamic; + if (auto *RecD = E->getReceiverInterface()) + Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, RecD); + } + + return IndexCtx.handleReference(MD, E->getSelectorStartLoc(), + Parent, ParentDC, Roles, Relations, E); + } + return true; + } + + bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + if (E->isExplicitProperty()) + return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(), + Parent, ParentDC, SymbolRoleSet(), {}, E); + + // No need to do a handleReference for the objc method, because there will + // be a message expr as part of PseudoObjectExpr. + return true; + } + + bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(), + Parent, ParentDC, SymbolRoleSet(), {}, E); + } + + bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(), + Parent, ParentDC, SymbolRoleSet(), {}, E); + } + + bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) { + if (ObjCMethodDecl *MD = E->getBoxingMethod()) { + SymbolRoleSet Roles = (unsigned)SymbolRole::Call; + Roles |= (unsigned)SymbolRole::Implicit; + return IndexCtx.handleReference(MD, E->getLocStart(), + Parent, ParentDC, Roles, {}, E); + } + return true; + } + + bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { + if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) { + SymbolRoleSet Roles = (unsigned)SymbolRole::Call; + Roles |= (unsigned)SymbolRole::Implicit; + return IndexCtx.handleReference(MD, E->getLocStart(), + Parent, ParentDC, Roles, {}, E); + } + return true; + } + + bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) { + if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) { + SymbolRoleSet Roles = (unsigned)SymbolRole::Call; + Roles |= (unsigned)SymbolRole::Implicit; + return IndexCtx.handleReference(MD, E->getLocStart(), + Parent, ParentDC, Roles, {}, E); + } + return true; + } + + bool VisitCXXConstructExpr(CXXConstructExpr *E) { + return IndexCtx.handleReference(E->getConstructor(), E->getLocation(), + Parent, ParentDC, (unsigned)SymbolRole::Call, {}, E); + } + + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E, + DataRecursionQueue *Q = nullptr) { + if (E->getOperatorLoc().isInvalid()) + return true; // implicit. + return base::TraverseCXXOperatorCallExpr(E); + } + + bool VisitDeclStmt(DeclStmt *S) { + if (IndexCtx.shouldIndexFunctionLocalSymbols()) { + IndexCtx.indexDeclGroupRef(S->getDeclGroup()); + return true; + } + + DeclGroupRef DG = S->getDeclGroup(); + for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) { + const Decl *D = *I; + if (!D) + continue; + if (!IndexCtx.isFunctionLocalDecl(D)) + IndexCtx.indexTopLevelDecl(D); + } + + return true; + } + + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) { + if (C->capturesThis() || C->capturesVLAType()) + return true; + + if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols()) + return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(), + Parent, ParentDC, SymbolRoleSet()); + + // FIXME: Lambda init-captures. + return true; + } + + // RecursiveASTVisitor visits both syntactic and semantic forms, duplicating + // the things that we visit. Make sure to only visit the semantic form. + // Also visit things that are in the syntactic form but not the semantic one, + // for example the indices in DesignatedInitExprs. + bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) { + + class SyntacticFormIndexer : + public RecursiveASTVisitor<SyntacticFormIndexer> { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + + public: + SyntacticFormIndexer(IndexingContext &indexCtx, + const NamedDecl *Parent, const DeclContext *DC) + : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool VisitDesignatedInitExpr(DesignatedInitExpr *E) { + for (DesignatedInitExpr::reverse_designators_iterator + D = E->designators_rbegin(), DEnd = E->designators_rend(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) + return IndexCtx.handleReference(D->getField(), D->getFieldLoc(), + Parent, ParentDC, SymbolRoleSet(), + {}, E); + } + return true; + } + }; + + auto visitForm = [&](InitListExpr *Form) { + for (Stmt *SubStmt : Form->children()) { + if (!TraverseStmt(SubStmt)) + return false; + } + return true; + }; + + InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm(); + InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S; + + if (SemaForm) { + // Visit things present in syntactic form but not the semantic form. + if (SyntaxForm) { + SyntacticFormIndexer(IndexCtx, Parent, ParentDC).TraverseStmt(SyntaxForm); + } + return visitForm(SemaForm); + } + + // No semantic, try the syntactic. + if (SyntaxForm) { + return visitForm(SyntaxForm); + } + + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent, + const DeclContext *DC) { + if (!S) + return; + + if (!DC) + DC = Parent->getLexicalDeclContext(); + BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S)); +} diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp new file mode 100644 index 00000000000..76f68e564c9 --- /dev/null +++ b/clang/lib/Index/IndexDecl.cpp @@ -0,0 +1,429 @@ +//===- 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; + +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->params()) { + 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->params()) + 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 VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { + if (D->isThisDeclarationADefinition()) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexDeclContext(D); + } else { + return IndexCtx.handleReference(D, D->getLocation(), nullptr, nullptr, + SymbolRoleSet()); + } + return true; + } + + bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { + if (D->isThisDeclarationADefinition()) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexDeclContext(D); + } else { + return IndexCtx.handleReference(D, D->getLocation(), nullptr, nullptr, + 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; +} diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp new file mode 100644 index 00000000000..c7c3c8c4d64 --- /dev/null +++ b/clang/lib/Index/IndexSymbol.cpp @@ -0,0 +1,187 @@ +//===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexSymbol.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" + +using namespace clang; +using namespace clang::index; + +SymbolInfo index::getSymbolInfo(const Decl *D) { + assert(D); + SymbolInfo Info; + Info.Kind = SymbolKind::Unknown; + Info.TemplateKind = SymbolCXXTemplateKind::NonTemplate; + Info.Lang = SymbolLanguage::C; + + if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { + switch (TD->getTagKind()) { + case TTK_Struct: + Info.Kind = SymbolKind::Struct; break; + case TTK_Union: + Info.Kind = SymbolKind::Union; break; + case TTK_Class: + Info.Kind = SymbolKind::CXXClass; + Info.Lang = SymbolLanguage::CXX; + break; + case TTK_Interface: + Info.Kind = SymbolKind::CXXInterface; + Info.Lang = SymbolLanguage::CXX; + break; + case TTK_Enum: + Info.Kind = SymbolKind::Enum; break; + } + + if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) + if (!CXXRec->isCLike()) + Info.Lang = SymbolLanguage::CXX; + + if (isa<ClassTemplatePartialSpecializationDecl>(D)) { + Info.TemplateKind = SymbolCXXTemplateKind::TemplatePartialSpecialization; + } else if (isa<ClassTemplateSpecializationDecl>(D)) { + Info.TemplateKind = SymbolCXXTemplateKind::TemplateSpecialization; + } + + } else { + switch (D->getKind()) { + case Decl::Typedef: + Info.Kind = SymbolKind::Typedef; break; + case Decl::Function: + Info.Kind = SymbolKind::Function; + break; + case Decl::ParmVar: + Info.Kind = SymbolKind::Variable; + break; + case Decl::Var: + Info.Kind = SymbolKind::Variable; + if (isa<CXXRecordDecl>(D->getDeclContext())) { + Info.Kind = SymbolKind::CXXStaticVariable; + Info.Lang = SymbolLanguage::CXX; + } + break; + case Decl::Field: + Info.Kind = SymbolKind::Field; + if (const CXXRecordDecl * + CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { + if (!CXXRec->isCLike()) + Info.Lang = SymbolLanguage::CXX; + } + break; + case Decl::EnumConstant: + Info.Kind = SymbolKind::EnumConstant; break; + case Decl::ObjCInterface: + case Decl::ObjCImplementation: + Info.Kind = SymbolKind::ObjCClass; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::ObjCProtocol: + Info.Kind = SymbolKind::ObjCProtocol; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + Info.Kind = SymbolKind::ObjCCategory; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::ObjCMethod: + if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) + Info.Kind = SymbolKind::ObjCInstanceMethod; + else + Info.Kind = SymbolKind::ObjCClassMethod; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::ObjCProperty: + Info.Kind = SymbolKind::ObjCProperty; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::ObjCIvar: + Info.Kind = SymbolKind::ObjCIvar; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::Namespace: + Info.Kind = SymbolKind::CXXNamespace; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::NamespaceAlias: + Info.Kind = SymbolKind::CXXNamespaceAlias; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::CXXConstructor: + Info.Kind = SymbolKind::CXXConstructor; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::CXXDestructor: + Info.Kind = SymbolKind::CXXDestructor; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::CXXConversion: + Info.Kind = SymbolKind::CXXConversionFunction; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::CXXMethod: { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); + if (MD->isStatic()) + Info.Kind = SymbolKind::CXXStaticMethod; + else + Info.Kind = SymbolKind::CXXInstanceMethod; + Info.Lang = SymbolLanguage::CXX; + break; + } + case Decl::ClassTemplate: + Info.Kind = SymbolKind::CXXClass; + Info.TemplateKind = SymbolCXXTemplateKind::Template; + break; + case Decl::FunctionTemplate: + Info.Kind = SymbolKind::Function; + Info.TemplateKind = SymbolCXXTemplateKind::Template; + if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>( + cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) { + if (isa<CXXConstructorDecl>(MD)) + Info.Kind = SymbolKind::CXXConstructor; + else if (isa<CXXDestructorDecl>(MD)) + Info.Kind = SymbolKind::CXXDestructor; + else if (isa<CXXConversionDecl>(MD)) + Info.Kind = SymbolKind::CXXConversionFunction; + else { + if (MD->isStatic()) + Info.Kind = SymbolKind::CXXStaticMethod; + else + Info.Kind = SymbolKind::CXXInstanceMethod; + } + } + break; + case Decl::TypeAliasTemplate: + Info.Kind = SymbolKind::CXXTypeAlias; + Info.TemplateKind = SymbolCXXTemplateKind::Template; + break; + case Decl::TypeAlias: + Info.Kind = SymbolKind::CXXTypeAlias; + Info.Lang = SymbolLanguage::CXX; + break; + default: + break; + } + } + + if (Info.Kind == SymbolKind::Unknown) + return Info; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) + Info.TemplateKind = SymbolCXXTemplateKind::TemplateSpecialization; + } + + if (Info.TemplateKind != SymbolCXXTemplateKind::NonTemplate) + Info.Lang = SymbolLanguage::CXX; + + return Info; +} diff --git a/clang/lib/Index/IndexTypeSourceInfo.cpp b/clang/lib/Index/IndexTypeSourceInfo.cpp new file mode 100644 index 00000000000..619a9a48bef --- /dev/null +++ b/clang/lib/Index/IndexTypeSourceInfo.cpp @@ -0,0 +1,202 @@ +//===- IndexTypeSourceInfo.cpp - Indexing types ---------------------------===// +// +// 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/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace index; + +namespace { + +class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + bool IsBase; + SmallVector<SymbolRelation, 3> Relations; + + typedef RecursiveASTVisitor<TypeIndexer> base; + +public: + TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent, + const DeclContext *DC, bool isBase) + : IndexCtx(indexCtx), Parent(parent), ParentDC(DC), IsBase(isBase) { + if (IsBase) { + assert(Parent); + Relations.emplace_back((unsigned)SymbolRole::RelationBaseOf, Parent); + } + } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { + return IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(), + Parent, ParentDC, SymbolRoleSet(), + Relations); + } + +#define TRY_TO(CALL_EXPR) \ + do { \ + if (!CALL_EXPR) \ + return false; \ + } while (0) + + bool traverseParamVarHelper(ParmVarDecl *D) { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + if (D->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + return true; + } + + bool TraverseParmVarDecl(ParmVarDecl *D) { + // Avoid visiting default arguments from the definition that were already + // visited in the declaration. + // FIXME: A free function definition can have default arguments. + // Avoiding double visitaiton of default arguments should be handled by the + // visitor probably with a bit in the AST to indicate if the attached + // default argument was 'inherited' or written in source. + if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) { + if (FD->isThisDeclarationADefinition()) { + return traverseParamVarHelper(D); + } + } + + return base::TraverseParmVarDecl(D); + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); + return true; + } + + bool VisitTagTypeLoc(TagTypeLoc TL) { + TagDecl *D = TL.getDecl(); + if (D->getParentFunctionOrMethod()) + return true; + + if (TL.isDefinition()) { + IndexCtx.indexTagDecl(D); + return true; + } + + return IndexCtx.handleReference(D, TL.getNameLoc(), + Parent, ParentDC, SymbolRoleSet(), + Relations); + } + + bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(), + Parent, ParentDC, SymbolRoleSet()); + } + + bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) { + IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i), + Parent, ParentDC, SymbolRoleSet()); + } + return true; + } + + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { + if (const TemplateSpecializationType *T = TL.getTypePtr()) { + if (IndexCtx.shouldIndexImplicitTemplateInsts()) { + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + IndexCtx.handleReference(RD, TL.getTemplateNameLoc(), + Parent, ParentDC, SymbolRoleSet(), Relations); + } else { + if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl()) + IndexCtx.handleReference(D, TL.getTemplateNameLoc(), + Parent, ParentDC, SymbolRoleSet(), Relations); + } + } + return true; + } + + bool TraverseStmt(Stmt *S) { + IndexCtx.indexBody(S, Parent, ParentDC); + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo, + const NamedDecl *Parent, + const DeclContext *DC, + bool isBase) { + if (!TInfo || TInfo->getTypeLoc().isNull()) + return; + + indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase); +} + +void IndexingContext::indexTypeLoc(TypeLoc TL, + const NamedDecl *Parent, + const DeclContext *DC, + bool isBase) { + if (TL.isNull()) + return; + + if (!DC) + DC = Parent->getLexicalDeclContext(); + TypeIndexer(*this, Parent, DC, isBase).TraverseTypeLoc(TL); +} + +void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const NamedDecl *Parent, + const DeclContext *DC) { + if (!NNS) + return; + + if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) + indexNestedNameSpecifierLoc(Prefix, Parent, DC); + + if (!DC) + DC = Parent->getLexicalDeclContext(); + SourceLocation Loc = NNS.getSourceRange().getBegin(); + + switch (NNS.getNestedNameSpecifier()->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + break; + + case NestedNameSpecifier::Namespace: + handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(), + Loc, Parent, DC, SymbolRoleSet()); + break; + case NestedNameSpecifier::NamespaceAlias: + handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), + Loc, Parent, DC, SymbolRoleSet()); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + indexTypeLoc(NNS.getTypeLoc(), Parent, DC); + break; + } +} + +void IndexingContext::indexTagDecl(const TagDecl *D) { + if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) + return; + + if (handleDecl(D)) { + if (D->isThisDeclarationADefinition()) { + indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); + if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) { + for (const auto &I : CXXRD->bases()) { + indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true); + } + } + indexDeclContext(D); + } + } +} diff --git a/clang/lib/Index/IndexingAction.cpp b/clang/lib/Index/IndexingAction.cpp new file mode 100644 index 00000000000..3f7ef43e7dc --- /dev/null +++ b/clang/lib/Index/IndexingAction.cpp @@ -0,0 +1,140 @@ +//===- IndexingAction.cpp - Frontend index action -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexingAction.h" +#include "clang/Index/IndexDataConsumer.h" +#include "IndexingContext.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang; +using namespace clang::index; + +void IndexDataConsumer::_anchor() {} + +bool IndexDataConsumer::handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + FileID FID, unsigned Offset, + ASTNodeInfo ASTNode) { + return true; +} + +bool IndexDataConsumer::handleMacroOccurence(const IdentifierInfo *Name, + const MacroInfo *MI, SymbolRoleSet Roles, + FileID FID, unsigned Offset) { + return true; +} + +bool IndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD, + SymbolRoleSet Roles, + FileID FID, unsigned Offset) { + return true; +} + +namespace { + +class IndexASTConsumer : public ASTConsumer { + IndexingContext &IndexCtx; + +public: + IndexASTConsumer(IndexingContext &IndexCtx) + : IndexCtx(IndexCtx) {} + +protected: + void Initialize(ASTContext &Context) override { + IndexCtx.setASTContext(Context); + } + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + return IndexCtx.indexDeclGroupRef(DG); + } + + void HandleInterestingDecl(DeclGroupRef DG) override { + // Ignore deserialized decls. + } + + void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { + IndexCtx.indexDeclGroupRef(DG); + } + + void HandleTranslationUnit(ASTContext &Ctx) override { + } +}; + +class IndexAction : public WrapperFrontendAction { + IndexingOptions IndexOpts; + std::shared_ptr<IndexDataConsumer> DataConsumer; + std::unique_ptr<IndexingContext> IndexCtx; + +public: + IndexAction(std::unique_ptr<FrontendAction> WrappedAction, + std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts) + : WrapperFrontendAction(std::move(WrappedAction)), + IndexOpts(Opts), + DataConsumer(std::move(DataConsumer)) {} + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + void EndSourceFileAction() override; +}; + +} // anonymous namespace + +void IndexAction::EndSourceFileAction() { + // Invoke wrapped action's method. + WrapperFrontendAction::EndSourceFileAction(); + + bool IndexActionFailed = !IndexCtx; + if (!IndexActionFailed) + DataConsumer->finish(); +} + +std::unique_ptr<ASTConsumer> +IndexAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); + if (!OtherConsumer) + return nullptr; + + IndexCtx.reset(new IndexingContext(IndexOpts, *DataConsumer)); + + std::vector<std::unique_ptr<ASTConsumer>> Consumers; + Consumers.push_back(std::move(OtherConsumer)); + Consumers.push_back(llvm::make_unique<IndexASTConsumer>(*IndexCtx)); + return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); +} + +std::unique_ptr<FrontendAction> +index::createIndexingAction(std::unique_ptr<FrontendAction> WrappedAction, + std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts) { + return llvm::make_unique<IndexAction>(std::move(WrappedAction), + std::move(DataConsumer), + Opts); +} + + +static bool topLevelDeclVisitor(void *context, const Decl *D) { + IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context); + return IndexCtx.indexTopLevelDecl(D); +} + +static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) { + Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor); +} + +void index::indexASTUnit(ASTUnit &Unit, + std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts) { + IndexingContext IndexCtx(Opts, *DataConsumer); + IndexCtx.setASTContext(Unit.getASTContext()); + indexTranslationUnit(Unit, IndexCtx); +} diff --git a/clang/lib/Index/IndexingContext.cpp b/clang/lib/Index/IndexingContext.cpp new file mode 100644 index 00000000000..91fbbfb2684 --- /dev/null +++ b/clang/lib/Index/IndexingContext.cpp @@ -0,0 +1,325 @@ +//===- IndexingContext.cpp - Indexing context data ------------------------===// +// +// 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/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; +using namespace index; + +bool IndexingContext::shouldIndexFunctionLocalSymbols() const { + return IndexOpts.IndexFunctionLocals; +} + +bool IndexingContext::handleDecl(const Decl *D, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations) { + return handleDeclOccurrence(D, D->getLocation(), /*IsRef=*/false, + cast<Decl>(D->getDeclContext()), Roles, Relations, + nullptr, nullptr, D->getDeclContext()); +} + +bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const DeclContext *DC) { + if (!DC) + DC = D->getDeclContext(); + return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC), + Roles, Relations, + nullptr, nullptr, DC); +} + +bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const Expr *RefE, + const Decl *RefD) { + if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) + return true; + + if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D)) + return true; + + return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations, + RefE, RefD, DC); +} + +bool IndexingContext::importedModule(const ImportDecl *ImportD) { + SourceLocation Loc = ImportD->getLocation(); + SourceManager &SM = Ctx->getSourceManager(); + Loc = SM.getFileLoc(Loc); + if (Loc.isInvalid()) + return true; + + FileID FID; + unsigned Offset; + std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); + if (FID.isInvalid()) + return true; + + bool Invalid = false; + const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); + if (Invalid || !SEntry.isFile()) + return true; + + if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { + switch (IndexOpts.SystemSymbolFilter) { + case IndexingOptions::SystemSymbolFilterKind::None: + case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: + return true; + case IndexingOptions::SystemSymbolFilterKind::All: + break; + } + } + + SymbolRoleSet Roles{}; + if (ImportD->isImplicit()) + Roles |= (unsigned)SymbolRole::Implicit; + + return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset); +} + +bool IndexingContext::isFunctionLocalDecl(const Decl *D) { + assert(D); + + if (isa<TemplateTemplateParmDecl>(D)) + return true; + + if (!D->getParentFunctionOrMethod()) + return false; + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + switch (ND->getFormalLinkage()) { + case NoLinkage: + case VisibleNoLinkage: + case InternalLinkage: + return true; + case UniqueExternalLinkage: + llvm_unreachable("Not a sema linkage"); + case ExternalLinkage: + return false; + } + } + + return true; +} + +bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { + TemplateSpecializationKind TKind = TSK_Undeclared; + if (const ClassTemplateSpecializationDecl * + SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + TKind = SD->getSpecializationKind(); + } + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + TKind = FD->getTemplateSpecializationKind(); + } + switch (TKind) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return false; + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + return true; + } +} + +bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { + if (isa<ObjCInterfaceDecl>(D)) + return false; + if (isa<ObjCCategoryDecl>(D)) + return false; + if (isa<ObjCIvarDecl>(D)) + return false; + if (isa<ObjCMethodDecl>(D)) + return false; + if (isa<ImportDecl>(D)) + return false; + return true; +} + +static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { + if (const ClassTemplateSpecializationDecl * + SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + return SD->getTemplateInstantiationPattern(); + } + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + return FD->getTemplateInstantiationPattern(); + } + return nullptr; +} + +static bool isDeclADefinition(const Decl *D, ASTContext &Ctx) { + if (auto VD = dyn_cast<VarDecl>(D)) + return VD->isThisDeclarationADefinition(Ctx); + + if (auto FD = dyn_cast<FunctionDecl>(D)) + return FD->isThisDeclarationADefinition(); + + if (auto TD = dyn_cast<TagDecl>(D)) + return TD->isThisDeclarationADefinition(); + + if (auto MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->isThisDeclarationADefinition(); + + if (isa<TypedefNameDecl>(D) || + isa<EnumConstantDecl>(D) || + isa<FieldDecl>(D) || + isa<MSPropertyDecl>(D) || + isa<ObjCImplDecl>(D) || + isa<ObjCPropertyImplDecl>(D)) + return true; + + return false; +} + +static const Decl *adjustParent(const Decl *Parent) { + if (!Parent) + return nullptr; + for (;; Parent = cast<Decl>(Parent->getDeclContext())) { + if (isa<TranslationUnitDecl>(Parent)) + return nullptr; + if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent)) + continue; + if (auto NS = dyn_cast<NamespaceDecl>(Parent)) { + if (NS->isAnonymousNamespace()) + continue; + } else if (auto EnumD = dyn_cast<EnumDecl>(Parent)) { + // Move enumerators under anonymous enum to the enclosing parent. + if (EnumD->getDeclName().isEmpty()) + continue; + } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { + if (RD->isAnonymousStructOrUnion()) + continue; + } else if (auto FD = dyn_cast<FieldDecl>(Parent)) { + if (FD->getDeclName().isEmpty()) + continue; + } + return Parent; + } +} + +static const Decl *getCanonicalDecl(const Decl *D) { + D = D->getCanonicalDecl(); + if (auto TD = dyn_cast<TemplateDecl>(D)) { + D = TD->getTemplatedDecl(); + assert(D->isCanonicalDecl()); + } + + return D; +} + +bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, + bool IsRef, const Decl *Parent, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const Expr *OrigE, + const Decl *OrigD, + const DeclContext *ContainerDC) { + if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) + return true; + if (!isa<NamedDecl>(D) || + (cast<NamedDecl>(D)->getDeclName().isEmpty() && + !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D))) + return true; + + SourceManager &SM = Ctx->getSourceManager(); + Loc = SM.getFileLoc(Loc); + if (Loc.isInvalid()) + return true; + + FileID FID; + unsigned Offset; + std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); + if (FID.isInvalid()) + return true; + + bool Invalid = false; + const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); + if (Invalid || !SEntry.isFile()) + return true; + + if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { + switch (IndexOpts.SystemSymbolFilter) { + case IndexingOptions::SystemSymbolFilterKind::None: + return true; + case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: + if (IsRef) + return true; + break; + case IndexingOptions::SystemSymbolFilterKind::All: + break; + } + } + + if (isTemplateImplicitInstantiation(D)) { + if (!IsRef) + return true; + D = adjustTemplateImplicitInstantiation(D); + if (!D) + return true; + assert(!isTemplateImplicitInstantiation(D)); + } + + if (!OrigD) + OrigD = D; + + if (IsRef) + Roles |= (unsigned)SymbolRole::Reference; + else if (isDeclADefinition(D, *Ctx)) + Roles |= (unsigned)SymbolRole::Definition; + else + Roles |= (unsigned)SymbolRole::Declaration; + + D = getCanonicalDecl(D); + if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) { + // operator new declarations will link to the implicit one as canonical. + return true; + } + Parent = adjustParent(Parent); + if (Parent) + Parent = getCanonicalDecl(Parent); + assert(!Parent || !Parent->isImplicit() || + isa<ObjCInterfaceDecl>(Parent) || isa<ObjCMethodDecl>(Parent)); + + SmallVector<SymbolRelation, 6> FinalRelations; + FinalRelations.reserve(Relations.size()+1); + + auto addRelation = [&](SymbolRelation Rel) { + auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(), + [&](SymbolRelation Elem)->bool { + return Elem.RelatedSymbol == Rel.RelatedSymbol; + }); + if (It != FinalRelations.end()) { + It->Roles |= Rel.Roles; + } else { + FinalRelations.push_back(Rel); + } + Roles |= Rel.Roles; + }; + + if (!IsRef && Parent && !cast<DeclContext>(Parent)->isFunctionOrMethod()) { + addRelation(SymbolRelation{(unsigned)SymbolRole::RelationChildOf, Parent}); + } + for (auto &Rel : Relations) { + addRelation(SymbolRelation(Rel.Roles, + Rel.RelatedSymbol->getCanonicalDecl())); + } + + IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC }; + return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset, + Node); +} diff --git a/clang/lib/Index/IndexingContext.h b/clang/lib/Index/IndexingContext.h new file mode 100644 index 00000000000..774650547f8 --- /dev/null +++ b/clang/lib/Index/IndexingContext.h @@ -0,0 +1,121 @@ +//===- IndexingContext.h - Indexing context data ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_INDEXINGCONTEXT_H +#define LLVM_CLANG_LIB_INDEX_INDEXINGCONTEXT_H + +#include "clang/Basic/LLVM.h" +#include "clang/Index/IndexSymbol.h" +#include "clang/Index/IndexingAction.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { + class ASTContext; + class Decl; + class DeclGroupRef; + class ImportDecl; + class TagDecl; + class TypeSourceInfo; + class NamedDecl; + class ObjCMethodDecl; + class DeclContext; + class NestedNameSpecifierLoc; + class Stmt; + class Expr; + class TypeLoc; + class SourceLocation; + +namespace index { + class IndexDataConsumer; + +class IndexingContext { + IndexingOptions IndexOpts; + IndexDataConsumer &DataConsumer; + ASTContext *Ctx = nullptr; + +public: + IndexingContext(IndexingOptions IndexOpts, IndexDataConsumer &DataConsumer) + : IndexOpts(IndexOpts), DataConsumer(DataConsumer) {} + + const IndexingOptions &getIndexOpts() const { return IndexOpts; } + IndexDataConsumer &getDataConsumer() { return DataConsumer; } + + void setASTContext(ASTContext &ctx) { Ctx = &ctx; } + + bool shouldSuppressRefs() const { + return false; + } + + bool shouldIndexFunctionLocalSymbols() const; + + bool shouldIndexImplicitTemplateInsts() const { + return false; + } + + static bool isFunctionLocalDecl(const Decl *D); + static bool isTemplateImplicitInstantiation(const Decl *D); + + bool handleDecl(const Decl *D, SymbolRoleSet Roles = SymbolRoleSet(), + ArrayRef<SymbolRelation> Relations = {}); + + bool handleDecl(const Decl *D, SourceLocation Loc, + SymbolRoleSet Roles = SymbolRoleSet(), + ArrayRef<SymbolRelation> Relations = {}, + const DeclContext *DC = nullptr); + + bool handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations = {}, + const Expr *RefE = nullptr, + const Decl *RefD = nullptr); + + bool importedModule(const ImportDecl *ImportD); + + bool indexDecl(const Decl *D); + + void indexTagDecl(const TagDecl *D); + + void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, + const DeclContext *DC = nullptr, + bool isBase = false); + + void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent, + const DeclContext *DC = nullptr, + bool isBase = false); + + void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const NamedDecl *Parent, + const DeclContext *DC = nullptr); + + bool indexDeclContext(const DeclContext *DC); + + void indexBody(const Stmt *S, const NamedDecl *Parent, + const DeclContext *DC = nullptr); + + bool indexTopLevelDecl(const Decl *D); + bool indexDeclGroupRef(DeclGroupRef DG); + +private: + bool shouldIgnoreIfImplicit(const Decl *D); + + bool handleDeclOccurrence(const Decl *D, SourceLocation Loc, + bool IsRef, const Decl *Parent, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const Expr *RefE, + const Decl *RefD, + const DeclContext *ContainerDC); +}; + +} // end namespace index +} // end namespace clang + +#endif |