xref: /freebsd/contrib/llvm-project/clang/lib/Index/IndexBody.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
17 using namespace clang;
18 using namespace clang::index;
19 
20 namespace {
21 
22 class 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 
getParentStmt() const30   Stmt *getParentStmt() const {
31     return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2];
32   }
33 public:
BodyIndexer(IndexingContext & indexCtx,const NamedDecl * Parent,const DeclContext * DC)34   BodyIndexer(IndexingContext &indexCtx,
35               const NamedDecl *Parent, const DeclContext *DC)
36     : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }
37 
shouldWalkTypesOfTypeLocs() const38   bool shouldWalkTypesOfTypeLocs() const { return false; }
39 
dataTraverseStmtPre(Stmt * S)40   bool dataTraverseStmtPre(Stmt *S) {
41     StmtStack.push_back(S);
42     return true;
43   }
44 
dataTraverseStmtPost(Stmt * S)45   bool dataTraverseStmtPost(Stmt *S) {
46     assert(StmtStack.back() == S);
47     StmtStack.pop_back();
48     return true;
49   }
50 
TraverseTypeLoc(TypeLoc TL)51   bool TraverseTypeLoc(TypeLoc TL) {
52     IndexCtx.indexTypeLoc(TL, Parent, ParentDC);
53     return true;
54   }
55 
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)56   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
57     IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
58     return true;
59   }
60 
getRolesForRef(const Expr * E,SmallVectorImpl<SymbolRelation> & Relations)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>(*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 
addCallRole(SymbolRoleSet & Roles,SmallVectorImpl<SymbolRelation> & Relations)131   void addCallRole(SymbolRoleSet &Roles,
132                    SmallVectorImpl<SymbolRelation> &Relations) {
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 
VisitDeclRefExpr(DeclRefExpr * E)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 
VisitGotoStmt(GotoStmt * S)147   bool VisitGotoStmt(GotoStmt *S) {
148     return IndexCtx.handleReference(S->getLabel(), S->getLabelLoc(), Parent,
149                                     ParentDC);
150   }
151 
VisitLabelStmt(LabelStmt * S)152   bool VisitLabelStmt(LabelStmt *S) {
153     if (IndexCtx.shouldIndexFunctionLocalSymbols())
154       return IndexCtx.handleDecl(S->getDecl());
155     return true;
156   }
157 
VisitMemberExpr(MemberExpr * E)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 
indexDependentReference(const Expr * E,const Type * T,const DeclarationNameInfo & NameInfo,llvm::function_ref<bool (const NamedDecl * ND)> Filter)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>(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(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(Symbols[0], Loc, Parent, ParentDC, Roles,
197                                     Relations, E);
198   }
199 
VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr * E)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 
VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr * E)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 
VisitDesignatedInitExpr(DesignatedInitExpr * E)215   bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
216     for (DesignatedInitExpr::Designator &D : llvm::reverse(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 
VisitObjCIvarRefExpr(ObjCIvarRefExpr * E)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 
VisitObjCMessageExpr(ObjCMessageExpr * E)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               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>(E))
255           E = BinOp->getLHS();
256         const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(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 = isa_and_nonnull<PseudoObjectExpr>(Containing);
272       // Implicit property message sends are not 'implicit'.
273       if ((E->isImplicit() || IsPropCall) &&
274           !(IsPropCall &&
275             IsImplicitProperty(cast<PseudoObjectExpr>(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((unsigned)SymbolRole::RelationReceivedBy,
286                                    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 
VisitObjCPropertyRefExpr(ObjCPropertyRefExpr * E)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 
VisitMSPropertyRefExpr(MSPropertyRefExpr * E)331   bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {
332     return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(),
333                                     Parent, ParentDC, SymbolRoleSet(), {}, E);
334   }
335 
VisitObjCProtocolExpr(ObjCProtocolExpr * E)336   bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
337     return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(),
338                                     Parent, ParentDC, SymbolRoleSet(), {}, E);
339   }
340 
passObjCLiteralMethodCall(const ObjCMethodDecl * MD,const Expr * E)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(MD, E->getBeginLoc(), Parent, ParentDC,
347                                     Roles, Relations, E);
348   }
349 
VisitObjCBoxedExpr(ObjCBoxedExpr * E)350   bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
351     if (ObjCMethodDecl *MD = E->getBoxingMethod()) {
352       return passObjCLiteralMethodCall(MD, E);
353     }
354     return true;
355   }
356 
VisitObjCDictionaryLiteral(ObjCDictionaryLiteral * E)357   bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
358     if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) {
359       return passObjCLiteralMethodCall(MD, E);
360     }
361     return true;
362   }
363 
VisitObjCArrayLiteral(ObjCArrayLiteral * E)364   bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
365     if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) {
366       return passObjCLiteralMethodCall(MD, E);
367     }
368     return true;
369   }
370 
VisitCXXConstructExpr(CXXConstructExpr * E)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 
TraverseCXXOperatorCallExpr(CXXOperatorCallExpr * E,DataRecursionQueue * Q=nullptr)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 
VisitDeclStmt(DeclStmt * S)386   bool VisitDeclStmt(DeclStmt *S) {
387     if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
388       IndexCtx.indexDeclGroupRef(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 
TraverseLambdaCapture(LambdaExpr * LE,const LambdaCapture * C,Expr * Init)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.
TraverseInitListExpr(InitListExpr * S,DataRecursionQueue * Q=nullptr)423   bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) {
424     auto visitForm = [&](InitListExpr *Form) {
425       for (Stmt *SubStmt : Form->children()) {
426         if (!TraverseStmt(SubStmt, Q))
427           return false;
428       }
429       return true;
430     };
431 
432     auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool {
433       for (DesignatedInitExpr::Designator &D : llvm::reverse(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>(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 
VisitOffsetOfExpr(OffsetOfExpr * S)467   bool VisitOffsetOfExpr(OffsetOfExpr *S) {
468     for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) {
469       const OffsetOfNode &Component = S->getComponent(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 
VisitParmVarDecl(ParmVarDecl * D)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 
VisitOverloadExpr(OverloadExpr * E)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 
VisitConceptSpecializationExpr(ConceptSpecializationExpr * R)497   bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *R) {
498     IndexCtx.handleReference(R->getNamedConcept(), R->getConceptNameLoc(),
499                              Parent, ParentDC);
500     return true;
501   }
502 
TraverseTypeConstraint(const TypeConstraint * C)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 
indexBody(const Stmt * S,const NamedDecl * Parent,const DeclContext * DC)512 void 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(const_cast<Stmt*>(S));
520 }
521