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"
10#include "clang/AST/ASTConcept.h"
11#include "clang/AST/ASTLambda.h"
12#include "clang/AST/DeclCXX.h"
13#include "clang/AST/ExprConcepts.h"
14#include "clang/AST/RecursiveASTVisitor.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
28 typedef RecursiveASTVisitor<BodyIndexer> base;
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(Elt: 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, DC: ParentDC);
53 return true;
54 }
55
56 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
57 IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, DC: ParentDC);
58 return true;
59 }
60
61 SymbolRoleSet getRolesForRef(const Expr *E,
62 SmallVectorImpl<SymbolRelation> &Relations) {
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>(Val: *It) || isa<ParenExpr>(Val: *It)) {
69 if (auto ICE = dyn_cast<ImplicitCastExpr>(Val: *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>(Val: 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>(Val: 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>(Val: 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>(Val: Parent)) {
98 if (CE->getCallee()->IgnoreParenCasts() == E) {
99 addCallRole(Roles, Relations);
100 if (auto *ME = dyn_cast<MemberExpr>(Val: E)) {
101 if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(Val: 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(Args: (unsigned)SymbolRole::RelationReceivedBy,
108 Args&: CXXRD);
109 }
110 }
111 } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(Val: 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,
132 SmallVectorImpl<SymbolRelation> &Relations) {
133 Roles |= (unsigned)SymbolRole::Call;
134 if (auto *FD = dyn_cast<FunctionDecl>(Val: ParentDC))
135 Relations.emplace_back(Args: (unsigned)SymbolRole::RelationCalledBy, Args&: FD);
136 else if (auto *MD = dyn_cast<ObjCMethodDecl>(Val: ParentDC))
137 Relations.emplace_back(Args: (unsigned)SymbolRole::RelationCalledBy, Args&: MD);
138 }
139
140 bool VisitDeclRefExpr(DeclRefExpr *E) {
141 SmallVector<SymbolRelation, 4> Relations;
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();
162 SmallVector<SymbolRelation, 4> Relations;
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 =
174 T->getAs<TemplateSpecializationType>();
175 if (!TST)
176 return true;
177 TemplateName TN = TST->getTemplateName();
178 const ClassTemplateDecl *TD =
179 dyn_cast_or_null<ClassTemplateDecl>(Val: TN.getAsTemplateDecl());
180 if (!TD)
181 return true;
182 CXXRecordDecl *RD = TD->getTemplatedDecl();
183 if (!RD->hasDefinition())
184 return true;
185 RD = RD->getDefinition();
186 std::vector<const NamedDecl *> Symbols =
187 RD->lookupDependentName(Name: NameInfo.getName(), Filter);
188 // FIXME: Improve overload handling.
189 if (Symbols.size() != 1)
190 return true;
191 SourceLocation Loc = NameInfo.getLoc();
192 if (Loc.isInvalid())
193 Loc = E->getBeginLoc();
194 SmallVector<SymbolRelation, 4> Relations;
195 SymbolRoleSet Roles = getRolesForRef(E, Relations);
196 return IndexCtx.handleReference(D: Symbols[0], Loc, Parent, DC: ParentDC, Roles,
197 Relations, RefE: E);
198 }
199
200 bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
201 const DeclarationNameInfo &Info = E->getMemberNameInfo();
202 return indexDependentReference(
203 E, E->getBaseType().getTypePtrOrNull(), Info,
204 [](const NamedDecl *D) { return D->isCXXInstanceMember(); });
205 }
206
207 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
208 const DeclarationNameInfo &Info = E->getNameInfo();
209 const NestedNameSpecifier *NNS = E->getQualifier();
210 return indexDependentReference(
211 E, NNS->getAsType(), Info,
212 [](const NamedDecl *D) { return !D->isCXXInstanceMember(); });
213 }
214
215 bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
216 for (DesignatedInitExpr::Designator &D : llvm::reverse(C: E->designators())) {
217 if (D.isFieldDesignator()) {
218 if (const FieldDecl *FD = D.getFieldDecl()) {
219 return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,
220 ParentDC, SymbolRoleSet(), {}, E);
221 }
222 }
223 }
224 return true;
225 }
226
227 bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
228 SmallVector<SymbolRelation, 4> Relations;
229 SymbolRoleSet Roles = getRolesForRef(E, Relations);
230 return IndexCtx.handleReference(E->getDecl(), E->getLocation(),
231 Parent, ParentDC, Roles, Relations, E);
232 }
233
234 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
235 auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool {
236 if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance)
237 return false;
238 if (auto *RecE = dyn_cast<ObjCMessageExpr>(
239 Val: MsgE->getInstanceReceiver()->IgnoreParenCasts())) {
240 if (RecE->getMethodFamily() == OMF_alloc)
241 return false;
242 }
243 return true;
244 };
245
246 if (ObjCMethodDecl *MD = E->getMethodDecl()) {
247 SymbolRoleSet Roles{};
248 SmallVector<SymbolRelation, 2> Relations;
249 addCallRole(Roles, Relations);
250 Stmt *Containing = getParentStmt();
251
252 auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool {
253 const auto *E = POE->getSyntacticForm();
254 if (const auto *BinOp = dyn_cast<BinaryOperator>(Val: E))
255 E = BinOp->getLHS();
256 const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(Val: E);
257 if (!PRE)
258 return false;
259 if (PRE->isExplicitProperty())
260 return false;
261 if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) {
262 // Class properties that are explicitly defined using @property
263 // declarations are represented implicitly as there is no ivar for
264 // class properties.
265 if (Getter->isClassMethod() &&
266 Getter->getCanonicalDecl()->findPropertyDecl())
267 return false;
268 }
269 return true;
270 };
271 bool IsPropCall = Containing && isa<PseudoObjectExpr>(Val: Containing);
272 // Implicit property message sends are not 'implicit'.
273 if ((E->isImplicit() || IsPropCall) &&
274 !(IsPropCall &&
275 IsImplicitProperty(cast<PseudoObjectExpr>(Val: Containing))))
276 Roles |= (unsigned)SymbolRole::Implicit;
277
278 if (isDynamic(E)) {
279 Roles |= (unsigned)SymbolRole::Dynamic;
280
281 auto addReceivers = [&](const ObjCObjectType *Ty) {
282 if (!Ty)
283 return;
284 if (const auto *clsD = Ty->getInterface()) {
285 Relations.emplace_back(Args: (unsigned)SymbolRole::RelationReceivedBy,
286 Args&: clsD);
287 }
288 for (const auto *protD : Ty->quals()) {
289 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
290 protD);
291 }
292 };
293 QualType recT = E->getReceiverType();
294 if (const auto *Ptr = recT->getAs<ObjCObjectPointerType>())
295 addReceivers(Ptr->getObjectType());
296 else
297 addReceivers(recT->getAs<ObjCObjectType>());
298 }
299
300 return IndexCtx.handleReference(MD, E->getSelectorStartLoc(),
301 Parent, ParentDC, Roles, Relations, E);
302 }
303 return true;
304 }
305
306 bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
307 if (E->isExplicitProperty()) {
308 SmallVector<SymbolRelation, 2> Relations;
309 SymbolRoleSet Roles = getRolesForRef(E, Relations);
310 return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
311 Parent, ParentDC, Roles, Relations, E);
312 } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {
313 // Class properties that are explicitly defined using @property
314 // declarations are represented implicitly as there is no ivar for class
315 // properties.
316 if (Getter->isClassMethod()) {
317 if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {
318 SmallVector<SymbolRelation, 2> Relations;
319 SymbolRoleSet Roles = getRolesForRef(E, Relations);
320 return IndexCtx.handleReference(PD, E->getLocation(), Parent,
321 ParentDC, Roles, Relations, E);
322 }
323 }
324 }
325
326 // No need to do a handleReference for the objc method, because there will
327 // be a message expr as part of PseudoObjectExpr.
328 return true;
329 }
330
331 bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {
332 return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(),
333 Parent, ParentDC, SymbolRoleSet(), {}, E);
334 }
335
336 bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
337 return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(),
338 Parent, ParentDC, SymbolRoleSet(), {}, E);
339 }
340
341 bool passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) {
342 SymbolRoleSet Roles{};
343 SmallVector<SymbolRelation, 2> Relations;
344 addCallRole(Roles, Relations);
345 Roles |= (unsigned)SymbolRole::Implicit;
346 return IndexCtx.handleReference(D: MD, Loc: E->getBeginLoc(), Parent, DC: ParentDC,
347 Roles, Relations, RefE: E);
348 }
349
350 bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
351 if (ObjCMethodDecl *MD = E->getBoxingMethod()) {
352 return passObjCLiteralMethodCall(MD, E);
353 }
354 return true;
355 }
356
357 bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
358 if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) {
359 return passObjCLiteralMethodCall(MD, E);
360 }
361 return true;
362 }
363
364 bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
365 if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) {
366 return passObjCLiteralMethodCall(MD, E);
367 }
368 return true;
369 }
370
371 bool VisitCXXConstructExpr(CXXConstructExpr *E) {
372 SymbolRoleSet Roles{};
373 SmallVector<SymbolRelation, 2> Relations;
374 addCallRole(Roles, Relations);
375 return IndexCtx.handleReference(E->getConstructor(), E->getLocation(),
376 Parent, ParentDC, Roles, Relations, E);
377 }
378
379 bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E,
380 DataRecursionQueue *Q = nullptr) {
381 if (E->getOperatorLoc().isInvalid())
382 return true; // implicit.
383 return base::TraverseCXXOperatorCallExpr(E, Q);
384 }
385
386 bool VisitDeclStmt(DeclStmt *S) {
387 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
388 IndexCtx.indexDeclGroupRef(DG: S->getDeclGroup());
389 return true;
390 }
391
392 DeclGroupRef DG = S->getDeclGroup();
393 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
394 const Decl *D = *I;
395 if (!D)
396 continue;
397 if (!isFunctionLocalSymbol(D))
398 IndexCtx.indexTopLevelDecl(D);
399 }
400
401 return true;
402 }
403
404 bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
405 Expr *Init) {
406 if (C->capturesThis() || C->capturesVLAType())
407 return true;
408
409 if (!base::TraverseStmt(Init))
410 return false;
411
412 if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())
413 return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(),
414 Parent, ParentDC, SymbolRoleSet());
415
416 return true;
417 }
418
419 // RecursiveASTVisitor visits both syntactic and semantic forms, duplicating
420 // the things that we visit. Make sure to only visit the semantic form.
421 // Also visit things that are in the syntactic form but not the semantic one,
422 // for example the indices in DesignatedInitExprs.
423 bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) {
424 auto visitForm = [&](InitListExpr *Form) {
425 for (Stmt *SubStmt : Form->children()) {
426 if (!TraverseStmt(S: SubStmt, Queue: Q))
427 return false;
428 }
429 return true;
430 };
431
432 auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool {
433 for (DesignatedInitExpr::Designator &D : llvm::reverse(C: E->designators())) {
434 if (D.isFieldDesignator()) {
435 if (const FieldDecl *FD = D.getFieldDecl()) {
436 return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,
437 ParentDC, SymbolRoleSet(),
438 /*Relations=*/{}, E);
439 }
440 }
441 }
442 return true;
443 };
444
445 InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm();
446 InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S;
447
448 if (SemaForm) {
449 // Visit things present in syntactic form but not the semantic form.
450 if (SyntaxForm) {
451 for (Expr *init : SyntaxForm->inits()) {
452 if (auto *DIE = dyn_cast<DesignatedInitExpr>(Val: init))
453 visitSyntacticDesignatedInitExpr(DIE);
454 }
455 }
456 return visitForm(SemaForm);
457 }
458
459 // No semantic, try the syntactic.
460 if (SyntaxForm) {
461 return visitForm(SyntaxForm);
462 }
463
464 return true;
465 }
466
467 bool VisitOffsetOfExpr(OffsetOfExpr *S) {
468 for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) {
469 const OffsetOfNode &Component = S->getComponent(Idx: I);
470 if (Component.getKind() == OffsetOfNode::Field)
471 IndexCtx.handleReference(Component.getField(), Component.getEndLoc(),
472 Parent, ParentDC, SymbolRoleSet(), {});
473 // FIXME: Try to resolve dependent field references.
474 }
475 return true;
476 }
477
478 bool VisitParmVarDecl(ParmVarDecl* D) {
479 // Index the parameters of lambda expression and requires expression.
480 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
481 const auto *DC = D->getDeclContext();
482 if (DC && (isLambdaCallOperator(DC) || isa<RequiresExprBodyDecl>(DC)))
483 IndexCtx.handleDecl(D);
484 }
485 return true;
486 }
487
488 bool VisitOverloadExpr(OverloadExpr *E) {
489 SmallVector<SymbolRelation, 4> Relations;
490 SymbolRoleSet Roles = getRolesForRef(E, Relations);
491 for (auto *D : E->decls())
492 IndexCtx.handleReference(D, E->getNameLoc(), Parent, ParentDC, Roles,
493 Relations, E);
494 return true;
495 }
496
497 bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *R) {
498 IndexCtx.handleReference(R->getNamedConcept(), R->getConceptNameLoc(),
499 Parent, ParentDC);
500 return true;
501 }
502
503 bool TraverseTypeConstraint(const TypeConstraint *C) {
504 IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(),
505 Parent, ParentDC);
506 return RecursiveASTVisitor::TraverseTypeConstraint(C);
507 }
508};
509
510} // anonymous namespace
511
512void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent,
513 const DeclContext *DC) {
514 if (!S)
515 return;
516
517 if (!DC)
518 DC = Parent->getLexicalDeclContext();
519 BodyIndexer(*this, Parent, DC).TraverseStmt(S: const_cast<Stmt*>(S));
520}
521

source code of clang/lib/Index/IndexBody.cpp