diff options
Diffstat (limited to 'clang/lib/Index/IndexBody.cpp')
| -rw-r--r-- | clang/lib/Index/IndexBody.cpp | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/clang/lib/Index/IndexBody.cpp b/clang/lib/Index/IndexBody.cpp new file mode 100644 index 0000000000000..07a94f30c883d --- /dev/null +++ b/clang/lib/Index/IndexBody.cpp @@ -0,0 +1,479 @@ +//===- IndexBody.cpp - Indexing statements --------------------------------===// +// +// 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/RecursiveASTVisitor.h" +#include "clang/AST/ASTLambda.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; + + Stmt *getParentStmt() const { + return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2]; + } +public: + BodyIndexer(IndexingContext &indexCtx, + const NamedDecl *Parent, const DeclContext *DC) + : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool dataTraverseStmtPre(Stmt *S) { + StmtStack.push_back(S); + return true; + } + + bool dataTraverseStmtPost(Stmt *S) { + assert(StmtStack.back() == S); + StmtStack.pop_back(); + return true; + } + + 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) { + addCallRole(Roles, Relations); + 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; + } + + void addCallRole(SymbolRoleSet &Roles, + SmallVectorImpl<SymbolRelation> &Relations) { + Roles |= (unsigned)SymbolRole::Call; + if (auto *FD = dyn_cast<FunctionDecl>(ParentDC)) + Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD); + else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC)) + Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD); + } + + 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->getBeginLoc(); + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getMemberDecl(), Loc, + Parent, ParentDC, Roles, Relations, E); + } + + bool indexDependentReference( + const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo, + llvm::function_ref<bool(const NamedDecl *ND)> Filter) { + if (!T) + return true; + const TemplateSpecializationType *TST = + T->getAs<TemplateSpecializationType>(); + if (!TST) + return true; + TemplateName TN = TST->getTemplateName(); + const ClassTemplateDecl *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()); + if (!TD) + return true; + CXXRecordDecl *RD = TD->getTemplatedDecl(); + if (!RD->hasDefinition()) + return true; + RD = RD->getDefinition(); + std::vector<const NamedDecl *> Symbols = + RD->lookupDependentName(NameInfo.getName(), Filter); + // FIXME: Improve overload handling. + if (Symbols.size() != 1) + return true; + SourceLocation Loc = NameInfo.getLoc(); + if (Loc.isInvalid()) + Loc = E->getBeginLoc(); + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(Symbols[0], Loc, Parent, ParentDC, Roles, + Relations, E); + } + + bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { + const DeclarationNameInfo &Info = E->getMemberNameInfo(); + return indexDependentReference( + E, E->getBaseType().getTypePtrOrNull(), Info, + [](const NamedDecl *D) { return D->isCXXInstanceMember(); }); + } + + bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { + const DeclarationNameInfo &Info = E->getNameInfo(); + const NestedNameSpecifier *NNS = E->getQualifier(); + return indexDependentReference( + E, NNS->getAsType(), Info, + [](const NamedDecl *D) { return !D->isCXXInstanceMember(); }); + } + + bool VisitDesignatedInitExpr(DesignatedInitExpr *E) { + for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) { + if (D.isFieldDesignator() && D.getField()) + 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{}; + SmallVector<SymbolRelation, 2> Relations; + addCallRole(Roles, Relations); + Stmt *Containing = getParentStmt(); + + auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool { + const auto *E = POE->getSyntacticForm(); + if (const auto *BinOp = dyn_cast<BinaryOperator>(E)) + E = BinOp->getLHS(); + const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E); + if (!PRE) + return false; + if (PRE->isExplicitProperty()) + return false; + if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) { + // Class properties that are explicitly defined using @property + // declarations are represented implicitly as there is no ivar for + // class properties. + if (Getter->isClassMethod() && + Getter->getCanonicalDecl()->findPropertyDecl()) + return false; + } + return true; + }; + bool IsPropCall = Containing && isa<PseudoObjectExpr>(Containing); + // Implicit property message sends are not 'implicit'. + if ((E->isImplicit() || IsPropCall) && + !(IsPropCall && + IsImplicitProperty(cast<PseudoObjectExpr>(Containing)))) + Roles |= (unsigned)SymbolRole::Implicit; + + if (isDynamic(E)) { + Roles |= (unsigned)SymbolRole::Dynamic; + + auto addReceivers = [&](const ObjCObjectType *Ty) { + if (!Ty) + return; + if (const auto *clsD = Ty->getInterface()) { + Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, + clsD); + } + for (const auto *protD : Ty->quals()) { + Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, + protD); + } + }; + QualType recT = E->getReceiverType(); + if (const auto *Ptr = recT->getAs<ObjCObjectPointerType>()) + addReceivers(Ptr->getObjectType()); + else + addReceivers(recT->getAs<ObjCObjectType>()); + } + + return IndexCtx.handleReference(MD, E->getSelectorStartLoc(), + Parent, ParentDC, Roles, Relations, E); + } + return true; + } + + bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + if (E->isClassReceiver()) + IndexCtx.handleReference(E->getClassReceiver(), E->getReceiverLocation(), + Parent, ParentDC); + if (E->isExplicitProperty()) { + SmallVector<SymbolRelation, 2> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(), + Parent, ParentDC, Roles, Relations, E); + } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) { + // Class properties that are explicitly defined using @property + // declarations are represented implicitly as there is no ivar for class + // properties. + if (Getter->isClassMethod()) { + if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) { + SmallVector<SymbolRelation, 2> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(PD, E->getLocation(), Parent, + ParentDC, Roles, Relations, 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 passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) { + SymbolRoleSet Roles{}; + SmallVector<SymbolRelation, 2> Relations; + addCallRole(Roles, Relations); + Roles |= (unsigned)SymbolRole::Implicit; + return IndexCtx.handleReference(MD, E->getBeginLoc(), Parent, ParentDC, + Roles, Relations, E); + } + + bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) { + if (ObjCMethodDecl *MD = E->getBoxingMethod()) { + return passObjCLiteralMethodCall(MD, E); + } + return true; + } + + bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { + if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) { + return passObjCLiteralMethodCall(MD, E); + } + return true; + } + + bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) { + if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) { + return passObjCLiteralMethodCall(MD, E); + } + return true; + } + + bool VisitCXXConstructExpr(CXXConstructExpr *E) { + SymbolRoleSet Roles{}; + SmallVector<SymbolRelation, 2> Relations; + addCallRole(Roles, Relations); + return IndexCtx.handleReference(E->getConstructor(), E->getLocation(), + Parent, ParentDC, Roles, Relations, E); + } + + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E, + DataRecursionQueue *Q = nullptr) { + if (E->getOperatorLoc().isInvalid()) + return true; // implicit. + return base::TraverseCXXOperatorCallExpr(E, Q); + } + + 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 (!isFunctionLocalSymbol(D)) + IndexCtx.indexTopLevelDecl(D); + } + + return true; + } + + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, + Expr *Init) { + 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) { + auto visitForm = [&](InitListExpr *Form) { + for (Stmt *SubStmt : Form->children()) { + if (!TraverseStmt(SubStmt, Q)) + return false; + } + return true; + }; + + auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool { + for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) { + if (D.isFieldDesignator()) + return IndexCtx.handleReference(D.getField(), D.getFieldLoc(), + Parent, ParentDC, SymbolRoleSet(), + {}, E); + } + 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) { + for (Expr *init : SyntaxForm->inits()) { + if (auto *DIE = dyn_cast<DesignatedInitExpr>(init)) + visitSyntacticDesignatedInitExpr(DIE); + } + } + return visitForm(SemaForm); + } + + // No semantic, try the syntactic. + if (SyntaxForm) { + return visitForm(SyntaxForm); + } + + return true; + } + + bool VisitOffsetOfExpr(OffsetOfExpr *S) { + for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) { + const OffsetOfNode &Component = S->getComponent(I); + if (Component.getKind() == OffsetOfNode::Field) + IndexCtx.handleReference(Component.getField(), Component.getEndLoc(), + Parent, ParentDC, SymbolRoleSet(), {}); + // FIXME: Try to resolve dependent field references. + } + return true; + } + + bool VisitParmVarDecl(ParmVarDecl* D) { + // Index the parameters of lambda expression. + if (IndexCtx.shouldIndexFunctionLocalSymbols()) { + const auto *DC = D->getDeclContext(); + if (DC && isLambdaCallOperator(DC)) + IndexCtx.handleDecl(D); + } + 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)); +} |
