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 #include "clang/Sema/HeuristicResolver.h"
17
18 using namespace clang;
19 using namespace clang::index;
20
21 namespace {
22
23 class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
24 IndexingContext &IndexCtx;
25 const NamedDecl *Parent;
26 const DeclContext *ParentDC;
27 SmallVector<Stmt*, 16> StmtStack;
28
29 typedef RecursiveASTVisitor<BodyIndexer> base;
30
getParentStmt() const31 Stmt *getParentStmt() const {
32 return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2];
33 }
34 public:
BodyIndexer(IndexingContext & indexCtx,const NamedDecl * Parent,const DeclContext * DC)35 BodyIndexer(IndexingContext &indexCtx,
36 const NamedDecl *Parent, const DeclContext *DC)
37 : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }
38
shouldWalkTypesOfTypeLocs() const39 bool shouldWalkTypesOfTypeLocs() const { return false; }
40
dataTraverseStmtPre(Stmt * S)41 bool dataTraverseStmtPre(Stmt *S) {
42 StmtStack.push_back(S);
43 return true;
44 }
45
dataTraverseStmtPost(Stmt * S)46 bool dataTraverseStmtPost(Stmt *S) {
47 assert(StmtStack.back() == S);
48 StmtStack.pop_back();
49 return true;
50 }
51
TraverseTypeLoc(TypeLoc TL)52 bool TraverseTypeLoc(TypeLoc TL) {
53 IndexCtx.indexTypeLoc(TL, Parent, ParentDC);
54 return true;
55 }
56
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)57 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
58 IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
59 return true;
60 }
61
getRolesForRef(const Expr * E,SmallVectorImpl<SymbolRelation> & Relations)62 SymbolRoleSet getRolesForRef(const Expr *E,
63 SmallVectorImpl<SymbolRelation> &Relations) {
64 SymbolRoleSet Roles{};
65 assert(!StmtStack.empty() && E == StmtStack.back());
66 if (StmtStack.size() == 1)
67 return Roles;
68 auto It = StmtStack.end()-2;
69 while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) {
70 if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) {
71 if (ICE->getCastKind() == CK_LValueToRValue)
72 Roles |= (unsigned)SymbolRole::Read;
73 }
74 if (It == StmtStack.begin())
75 break;
76 --It;
77 }
78 const Stmt *Parent = *It;
79
80 if (auto BO = dyn_cast<BinaryOperator>(Parent)) {
81 if (BO->getOpcode() == BO_Assign) {
82 if (BO->getLHS()->IgnoreParenCasts() == E)
83 Roles |= (unsigned)SymbolRole::Write;
84 } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) {
85 if (CA->getLHS()->IgnoreParenCasts() == E) {
86 Roles |= (unsigned)SymbolRole::Read;
87 Roles |= (unsigned)SymbolRole::Write;
88 }
89 }
90 } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) {
91 if (UO->isIncrementDecrementOp()) {
92 Roles |= (unsigned)SymbolRole::Read;
93 Roles |= (unsigned)SymbolRole::Write;
94 } else if (UO->getOpcode() == UO_AddrOf) {
95 Roles |= (unsigned)SymbolRole::AddressOf;
96 }
97
98 } else if (auto CE = dyn_cast<CallExpr>(Parent)) {
99 if (CE->getCallee()->IgnoreParenCasts() == E) {
100 addCallRole(Roles, Relations);
101 if (auto *ME = dyn_cast<MemberExpr>(E)) {
102 if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl()))
103 if (CXXMD->isVirtual() && !ME->hasQualifier()) {
104 Roles |= (unsigned)SymbolRole::Dynamic;
105 auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType();
106 if (!BaseTy.isNull())
107 if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl())
108 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
109 CXXRD);
110 }
111 }
112 } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) {
113 if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) {
114 OverloadedOperatorKind Op = CXXOp->getOperator();
115 if (Op == OO_Equal) {
116 Roles |= (unsigned)SymbolRole::Write;
117 } else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) ||
118 Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual ||
119 Op == OO_PlusPlus || Op == OO_MinusMinus) {
120 Roles |= (unsigned)SymbolRole::Read;
121 Roles |= (unsigned)SymbolRole::Write;
122 } else if (Op == OO_Amp) {
123 Roles |= (unsigned)SymbolRole::AddressOf;
124 }
125 }
126 }
127 }
128
129 return Roles;
130 }
131
addCallRole(SymbolRoleSet & Roles,SmallVectorImpl<SymbolRelation> & Relations)132 void addCallRole(SymbolRoleSet &Roles,
133 SmallVectorImpl<SymbolRelation> &Relations) {
134 if (isa<CXXDeductionGuideDecl>(ParentDC))
135 return;
136
137 Roles |= (unsigned)SymbolRole::Call;
138 if (auto *FD = dyn_cast<FunctionDecl>(ParentDC))
139 Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD);
140 else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC))
141 Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD);
142 }
143
VisitDeclRefExpr(DeclRefExpr * E)144 bool VisitDeclRefExpr(DeclRefExpr *E) {
145 SmallVector<SymbolRelation, 4> Relations;
146 SymbolRoleSet Roles = getRolesForRef(E, Relations);
147 return IndexCtx.handleReference(E->getDecl(), E->getLocation(),
148 Parent, ParentDC, Roles, Relations, E);
149 }
150
VisitGotoStmt(GotoStmt * S)151 bool VisitGotoStmt(GotoStmt *S) {
152 return IndexCtx.handleReference(S->getLabel(), S->getLabelLoc(), Parent,
153 ParentDC);
154 }
155
VisitCXXNewExpr(CXXNewExpr * E)156 bool VisitCXXNewExpr(CXXNewExpr *E) {
157 if (E->isGlobalNew() || !E->getOperatorNew())
158 return true;
159 return IndexCtx.handleReference(E->getOperatorNew(), E->getBeginLoc(),
160 Parent, ParentDC);
161 }
162
VisitCXXDeleteExpr(CXXDeleteExpr * E)163 bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
164 if (E->isGlobalDelete() || !E->getOperatorDelete())
165 return true;
166 return IndexCtx.handleReference(E->getOperatorDelete(), E->getBeginLoc(),
167 Parent, ParentDC);
168 }
169
VisitLabelStmt(LabelStmt * S)170 bool VisitLabelStmt(LabelStmt *S) {
171 if (IndexCtx.shouldIndexFunctionLocalSymbols())
172 return IndexCtx.handleDecl(S->getDecl());
173 return true;
174 }
175
VisitMemberExpr(MemberExpr * E)176 bool VisitMemberExpr(MemberExpr *E) {
177 SourceLocation Loc = E->getMemberLoc();
178 if (Loc.isInvalid())
179 Loc = E->getBeginLoc();
180 SmallVector<SymbolRelation, 4> Relations;
181 SymbolRoleSet Roles = getRolesForRef(E, Relations);
182 return IndexCtx.handleReference(E->getMemberDecl(), Loc,
183 Parent, ParentDC, Roles, Relations, E);
184 }
185
indexDependentReference(const Expr * E,SourceLocation Loc,std::vector<const NamedDecl * > TargetSymbols)186 bool indexDependentReference(const Expr *E, SourceLocation Loc,
187 std::vector<const NamedDecl *> TargetSymbols) {
188 // FIXME: Improve overload handling.
189 if (TargetSymbols.size() != 1)
190 return true;
191 if (Loc.isInvalid())
192 Loc = E->getBeginLoc();
193 SmallVector<SymbolRelation, 4> Relations;
194 SymbolRoleSet Roles = getRolesForRef(E, Relations);
195 return IndexCtx.handleReference(TargetSymbols[0], Loc, Parent, ParentDC,
196 Roles, Relations, E);
197 }
198
VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr * E)199 bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
200 auto *Resolver = IndexCtx.getResolver();
201 assert(Resolver);
202 return indexDependentReference(E, E->getMemberNameInfo().getLoc(),
203 Resolver->resolveMemberExpr(E));
204 }
205
VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr * E)206 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
207 auto *Resolver = IndexCtx.getResolver();
208 assert(Resolver);
209 return indexDependentReference(E, E->getNameInfo().getLoc(),
210 Resolver->resolveDeclRefExpr(E));
211 }
212
VisitDesignatedInitExpr(DesignatedInitExpr * E)213 bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
214 for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {
215 if (D.isFieldDesignator()) {
216 if (const FieldDecl *FD = D.getFieldDecl()) {
217 return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,
218 ParentDC, SymbolRoleSet(), {}, E);
219 }
220 }
221 }
222 return true;
223 }
224
VisitObjCIvarRefExpr(ObjCIvarRefExpr * E)225 bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
226 SmallVector<SymbolRelation, 4> Relations;
227 SymbolRoleSet Roles = getRolesForRef(E, Relations);
228 return IndexCtx.handleReference(E->getDecl(), E->getLocation(),
229 Parent, ParentDC, Roles, Relations, E);
230 }
231
VisitObjCMessageExpr(ObjCMessageExpr * E)232 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
233 auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool {
234 if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance)
235 return false;
236 if (auto *RecE = dyn_cast<ObjCMessageExpr>(
237 MsgE->getInstanceReceiver()->IgnoreParenCasts())) {
238 if (RecE->getMethodFamily() == OMF_alloc)
239 return false;
240 }
241 return true;
242 };
243
244 if (ObjCMethodDecl *MD = E->getMethodDecl()) {
245 SymbolRoleSet Roles{};
246 SmallVector<SymbolRelation, 2> Relations;
247 addCallRole(Roles, Relations);
248 Stmt *Containing = getParentStmt();
249
250 auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool {
251 const auto *E = POE->getSyntacticForm();
252 if (const auto *BinOp = dyn_cast<BinaryOperator>(E))
253 E = BinOp->getLHS();
254 const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E);
255 if (!PRE)
256 return false;
257 if (PRE->isExplicitProperty())
258 return false;
259 if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) {
260 // Class properties that are explicitly defined using @property
261 // declarations are represented implicitly as there is no ivar for
262 // class properties.
263 if (Getter->isClassMethod() &&
264 Getter->getCanonicalDecl()->findPropertyDecl())
265 return false;
266 }
267 return true;
268 };
269 bool IsPropCall = isa_and_nonnull<PseudoObjectExpr>(Containing);
270 // Implicit property message sends are not 'implicit'.
271 if ((E->isImplicit() || IsPropCall) &&
272 !(IsPropCall &&
273 IsImplicitProperty(cast<PseudoObjectExpr>(Containing))))
274 Roles |= (unsigned)SymbolRole::Implicit;
275
276 if (isDynamic(E)) {
277 Roles |= (unsigned)SymbolRole::Dynamic;
278
279 auto addReceivers = [&](const ObjCObjectType *Ty) {
280 if (!Ty)
281 return;
282 if (const auto *clsD = Ty->getInterface()) {
283 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
284 clsD);
285 }
286 for (const auto *protD : Ty->quals()) {
287 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
288 protD);
289 }
290 };
291 QualType recT = E->getReceiverType();
292 if (const auto *Ptr = recT->getAs<ObjCObjectPointerType>())
293 addReceivers(Ptr->getObjectType());
294 else
295 addReceivers(recT->getAs<ObjCObjectType>());
296 }
297
298 return IndexCtx.handleReference(MD, E->getSelectorStartLoc(),
299 Parent, ParentDC, Roles, Relations, E);
300 }
301 return true;
302 }
303
VisitObjCPropertyRefExpr(ObjCPropertyRefExpr * E)304 bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
305 if (E->isExplicitProperty()) {
306 SmallVector<SymbolRelation, 2> Relations;
307 SymbolRoleSet Roles = getRolesForRef(E, Relations);
308 return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
309 Parent, ParentDC, Roles, Relations, E);
310 } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {
311 // Class properties that are explicitly defined using @property
312 // declarations are represented implicitly as there is no ivar for class
313 // properties.
314 if (Getter->isClassMethod()) {
315 if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {
316 SmallVector<SymbolRelation, 2> Relations;
317 SymbolRoleSet Roles = getRolesForRef(E, Relations);
318 return IndexCtx.handleReference(PD, E->getLocation(), Parent,
319 ParentDC, Roles, Relations, E);
320 }
321 }
322 }
323
324 // No need to do a handleReference for the objc method, because there will
325 // be a message expr as part of PseudoObjectExpr.
326 return true;
327 }
328
VisitMSPropertyRefExpr(MSPropertyRefExpr * E)329 bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {
330 return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(),
331 Parent, ParentDC, SymbolRoleSet(), {}, E);
332 }
333
VisitObjCProtocolExpr(ObjCProtocolExpr * E)334 bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
335 return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(),
336 Parent, ParentDC, SymbolRoleSet(), {}, E);
337 }
338
passObjCLiteralMethodCall(const ObjCMethodDecl * MD,const Expr * E)339 bool passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) {
340 SymbolRoleSet Roles{};
341 SmallVector<SymbolRelation, 2> Relations;
342 addCallRole(Roles, Relations);
343 Roles |= (unsigned)SymbolRole::Implicit;
344 return IndexCtx.handleReference(MD, E->getBeginLoc(), Parent, ParentDC,
345 Roles, Relations, E);
346 }
347
VisitObjCBoxedExpr(ObjCBoxedExpr * E)348 bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
349 if (ObjCMethodDecl *MD = E->getBoxingMethod()) {
350 return passObjCLiteralMethodCall(MD, E);
351 }
352 return true;
353 }
354
VisitObjCDictionaryLiteral(ObjCDictionaryLiteral * E)355 bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
356 if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) {
357 return passObjCLiteralMethodCall(MD, E);
358 }
359 return true;
360 }
361
VisitObjCArrayLiteral(ObjCArrayLiteral * E)362 bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
363 if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) {
364 return passObjCLiteralMethodCall(MD, E);
365 }
366 return true;
367 }
368
VisitCXXConstructExpr(CXXConstructExpr * E)369 bool VisitCXXConstructExpr(CXXConstructExpr *E) {
370 SymbolRoleSet Roles{};
371 SmallVector<SymbolRelation, 2> Relations;
372 addCallRole(Roles, Relations);
373 return IndexCtx.handleReference(E->getConstructor(), E->getLocation(),
374 Parent, ParentDC, Roles, Relations, E);
375 }
376
TraverseCXXOperatorCallExpr(CXXOperatorCallExpr * E,DataRecursionQueue * Q=nullptr)377 bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E,
378 DataRecursionQueue *Q = nullptr) {
379 if (E->getOperatorLoc().isInvalid())
380 return true; // implicit.
381 return base::TraverseCXXOperatorCallExpr(E, Q);
382 }
383
VisitDeclStmt(DeclStmt * S)384 bool VisitDeclStmt(DeclStmt *S) {
385 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
386 IndexCtx.indexDeclGroupRef(S->getDeclGroup());
387 return true;
388 }
389
390 DeclGroupRef DG = S->getDeclGroup();
391 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
392 const Decl *D = *I;
393 if (!D)
394 continue;
395 if (!isFunctionLocalSymbol(D))
396 IndexCtx.indexTopLevelDecl(D);
397 }
398
399 return true;
400 }
401
TraverseLambdaCapture(LambdaExpr * LE,const LambdaCapture * C,Expr * Init)402 bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
403 Expr *Init) {
404 if (C->capturesThis() || C->capturesVLAType())
405 return true;
406
407 if (!base::TraverseStmt(Init))
408 return false;
409
410 if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())
411 return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(),
412 Parent, ParentDC, SymbolRoleSet());
413
414 return true;
415 }
416
417 // RecursiveASTVisitor visits both syntactic and semantic forms, duplicating
418 // the things that we visit. Make sure to only visit the semantic form.
419 // Also visit things that are in the syntactic form but not the semantic one,
420 // for example the indices in DesignatedInitExprs.
TraverseInitListExpr(InitListExpr * S,DataRecursionQueue * Q=nullptr)421 bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) {
422 auto visitForm = [&](InitListExpr *Form) {
423 for (Stmt *SubStmt : Form->children()) {
424 if (!TraverseStmt(SubStmt, Q))
425 return false;
426 }
427 return true;
428 };
429
430 auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool {
431 for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {
432 if (D.isFieldDesignator()) {
433 if (const FieldDecl *FD = D.getFieldDecl()) {
434 return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,
435 ParentDC, SymbolRoleSet(),
436 /*Relations=*/{}, E);
437 }
438 } else {
439 if (D.isArrayDesignator())
440 TraverseStmt(E->getArrayIndex(D));
441 else if (D.isArrayRangeDesignator()) {
442 TraverseStmt(E->getArrayRangeStart(D));
443 TraverseStmt(E->getArrayRangeEnd(D));
444 }
445 }
446 }
447 return true;
448 };
449
450 InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm();
451 InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S;
452
453 if (SemaForm) {
454 // Visit things present in syntactic form but not the semantic form.
455 if (SyntaxForm) {
456 for (Expr *init : SyntaxForm->inits()) {
457 if (auto *DIE = dyn_cast<DesignatedInitExpr>(init))
458 visitSyntacticDesignatedInitExpr(DIE);
459 }
460 }
461 return visitForm(SemaForm);
462 }
463
464 // No semantic, try the syntactic.
465 if (SyntaxForm) {
466 return visitForm(SyntaxForm);
467 }
468
469 return true;
470 }
471
VisitOffsetOfExpr(OffsetOfExpr * S)472 bool VisitOffsetOfExpr(OffsetOfExpr *S) {
473 for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) {
474 const OffsetOfNode &Component = S->getComponent(I);
475 if (Component.getKind() == OffsetOfNode::Field)
476 IndexCtx.handleReference(Component.getField(), Component.getEndLoc(),
477 Parent, ParentDC, SymbolRoleSet(), {});
478 // FIXME: Try to resolve dependent field references.
479 }
480 return true;
481 }
482
VisitParmVarDecl(ParmVarDecl * D)483 bool VisitParmVarDecl(ParmVarDecl* D) {
484 // Index the parameters of lambda expression and requires expression.
485 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
486 const auto *DC = D->getDeclContext();
487 if (DC && (isLambdaCallOperator(DC) || isa<RequiresExprBodyDecl>(DC)))
488 IndexCtx.handleDecl(D);
489 }
490 return true;
491 }
492
VisitOverloadExpr(OverloadExpr * E)493 bool VisitOverloadExpr(OverloadExpr *E) {
494 SmallVector<SymbolRelation, 4> Relations;
495 SymbolRoleSet Roles = getRolesForRef(E, Relations);
496 for (auto *D : E->decls())
497 IndexCtx.handleReference(D, E->getNameLoc(), Parent, ParentDC, Roles,
498 Relations, E);
499 return true;
500 }
501
VisitConceptSpecializationExpr(ConceptSpecializationExpr * R)502 bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *R) {
503 IndexCtx.handleReference(R->getNamedConcept(), R->getConceptNameLoc(),
504 Parent, ParentDC);
505 return true;
506 }
507
TraverseTypeConstraint(const TypeConstraint * C)508 bool TraverseTypeConstraint(const TypeConstraint *C) {
509 IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(),
510 Parent, ParentDC);
511 return RecursiveASTVisitor::TraverseTypeConstraint(C);
512 }
513 };
514
515 } // anonymous namespace
516
indexBody(const Stmt * S,const NamedDecl * Parent,const DeclContext * DC)517 void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent,
518 const DeclContext *DC) {
519 if (!S)
520 return;
521
522 if (!DC)
523 DC = Parent->getLexicalDeclContext();
524 BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S));
525 }
526