summaryrefslogtreecommitdiff
path: root/clang/lib/Index/IndexBody.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Index/IndexBody.cpp')
-rw-r--r--clang/lib/Index/IndexBody.cpp479
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));
+}