clang 20.0.0git
IndexBody.cpp
Go to the documentation of this file.
1//===- IndexBody.cpp - Indexing statements --------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "IndexingContext.h"
11#include "clang/AST/ASTLambda.h"
12#include "clang/AST/DeclCXX.h"
15#include "clang/AST/Type.h"
16
17using namespace clang;
18using namespace clang::index;
19
20namespace {
21
22class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
23 IndexingContext &IndexCtx;
24 const NamedDecl *Parent;
25 const DeclContext *ParentDC;
26 SmallVector<Stmt*, 16> StmtStack;
27
29
30 Stmt *getParentStmt() const {
31 return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2];
32 }
33public:
34 BodyIndexer(IndexingContext &indexCtx,
35 const NamedDecl *Parent, const DeclContext *DC)
36 : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }
37
38 bool shouldWalkTypesOfTypeLocs() const { return false; }
39
40 bool dataTraverseStmtPre(Stmt *S) {
41 StmtStack.push_back(S);
42 return true;
43 }
44
45 bool dataTraverseStmtPost(Stmt *S) {
46 assert(StmtStack.back() == S);
47 StmtStack.pop_back();
48 return true;
49 }
50
51 bool TraverseTypeLoc(TypeLoc TL) {
52 IndexCtx.indexTypeLoc(TL, Parent, ParentDC);
53 return true;
54 }
55
57 IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
58 return true;
59 }
60
61 SymbolRoleSet getRolesForRef(const Expr *E,
63 SymbolRoleSet Roles{};
64 assert(!StmtStack.empty() && E == StmtStack.back());
65 if (StmtStack.size() == 1)
66 return Roles;
67 auto It = StmtStack.end()-2;
68 while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) {
69 if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) {
70 if (ICE->getCastKind() == CK_LValueToRValue)
71 Roles |= (unsigned)(unsigned)SymbolRole::Read;
72 }
73 if (It == StmtStack.begin())
74 break;
75 --It;
76 }
77 const Stmt *Parent = *It;
78
79 if (auto BO = dyn_cast<BinaryOperator>(Parent)) {
80 if (BO->getOpcode() == BO_Assign) {
81 if (BO->getLHS()->IgnoreParenCasts() == E)
82 Roles |= (unsigned)SymbolRole::Write;
83 } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) {
84 if (CA->getLHS()->IgnoreParenCasts() == E) {
85 Roles |= (unsigned)SymbolRole::Read;
86 Roles |= (unsigned)SymbolRole::Write;
87 }
88 }
89 } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) {
90 if (UO->isIncrementDecrementOp()) {
91 Roles |= (unsigned)SymbolRole::Read;
92 Roles |= (unsigned)SymbolRole::Write;
93 } else if (UO->getOpcode() == UO_AddrOf) {
94 Roles |= (unsigned)SymbolRole::AddressOf;
95 }
96
97 } else if (auto CE = dyn_cast<CallExpr>(Parent)) {
98 if (CE->getCallee()->IgnoreParenCasts() == E) {
99 addCallRole(Roles, Relations);
100 if (auto *ME = dyn_cast<MemberExpr>(E)) {
101 if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl()))
102 if (CXXMD->isVirtual() && !ME->hasQualifier()) {
103 Roles |= (unsigned)SymbolRole::Dynamic;
104 auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType();
105 if (!BaseTy.isNull())
106 if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl())
107 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
108 CXXRD);
109 }
110 }
111 } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) {
112 if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) {
113 OverloadedOperatorKind Op = CXXOp->getOperator();
114 if (Op == OO_Equal) {
115 Roles |= (unsigned)SymbolRole::Write;
116 } else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) ||
117 Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual ||
118 Op == OO_PlusPlus || Op == OO_MinusMinus) {
119 Roles |= (unsigned)SymbolRole::Read;
120 Roles |= (unsigned)SymbolRole::Write;
121 } else if (Op == OO_Amp) {
122 Roles |= (unsigned)SymbolRole::AddressOf;
123 }
124 }
125 }
126 }
127
128 return Roles;
129 }
130
131 void addCallRole(SymbolRoleSet &Roles,
133 Roles |= (unsigned)SymbolRole::Call;
134 if (auto *FD = dyn_cast<FunctionDecl>(ParentDC))
135 Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD);
136 else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC))
137 Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD);
138 }
139
140 bool VisitDeclRefExpr(DeclRefExpr *E) {
142 SymbolRoleSet Roles = getRolesForRef(E, Relations);
143 return IndexCtx.handleReference(E->getDecl(), E->getLocation(),
144 Parent, ParentDC, Roles, Relations, E);
145 }
146
147 bool VisitGotoStmt(GotoStmt *S) {
148 return IndexCtx.handleReference(S->getLabel(), S->getLabelLoc(), Parent,
149 ParentDC);
150 }
151
152 bool VisitLabelStmt(LabelStmt *S) {
153 if (IndexCtx.shouldIndexFunctionLocalSymbols())
154 return IndexCtx.handleDecl(S->getDecl());
155 return true;
156 }
157
158 bool VisitMemberExpr(MemberExpr *E) {
159 SourceLocation Loc = E->getMemberLoc();
160 if (Loc.isInvalid())
161 Loc = E->getBeginLoc();
163 SymbolRoleSet Roles = getRolesForRef(E, Relations);
164 return IndexCtx.handleReference(E->getMemberDecl(), Loc,
165 Parent, ParentDC, Roles, Relations, E);
166 }
167
168 bool indexDependentReference(
169 const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo,
170 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
171 if (!T)
172 return true;
173 const TemplateSpecializationType *TST =