1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "IndexingContext.h" |
10 | #include "clang/AST/RecursiveASTVisitor.h" |
11 | #include "clang/AST/ASTLambda.h" |
12 | |
13 | using namespace clang; |
14 | using namespace clang::index; |
15 | |
16 | namespace { |
17 | |
18 | class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> { |
19 | IndexingContext &IndexCtx; |
20 | const NamedDecl *Parent; |
21 | const DeclContext *ParentDC; |
22 | SmallVector<Stmt*, 16> StmtStack; |
23 | |
24 | typedef RecursiveASTVisitor<BodyIndexer> base; |
25 | |
26 | Stmt *getParentStmt() const { |
27 | return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2]; |
28 | } |
29 | public: |
30 | BodyIndexer(IndexingContext &indexCtx, |
31 | const NamedDecl *Parent, const DeclContext *DC) |
32 | : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { } |
33 | |
34 | bool shouldWalkTypesOfTypeLocs() const { return false; } |
35 | |
36 | bool dataTraverseStmtPre(Stmt *S) { |
37 | StmtStack.push_back(S); |
38 | return true; |
39 | } |
40 | |
41 | bool dataTraverseStmtPost(Stmt *S) { |
42 | assert(StmtStack.back() == S); |
43 | StmtStack.pop_back(); |
44 | return true; |
45 | } |
46 | |
47 | bool TraverseTypeLoc(TypeLoc TL) { |
48 | IndexCtx.indexTypeLoc(TL, Parent, ParentDC); |
49 | return true; |
50 | } |
51 | |
52 | bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { |
53 | IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); |
54 | return true; |
55 | } |
56 | |
57 | SymbolRoleSet getRolesForRef(const Expr *E, |
58 | SmallVectorImpl<SymbolRelation> &Relations) { |
59 | SymbolRoleSet Roles{}; |
60 | assert(!StmtStack.empty() && E == StmtStack.back()); |
61 | if (StmtStack.size() == 1) |
62 | return Roles; |
63 | auto It = StmtStack.end()-2; |
64 | while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) { |
65 | if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) { |
66 | if (ICE->getCastKind() == CK_LValueToRValue) |
67 | Roles |= (unsigned)(unsigned)SymbolRole::Read; |
68 | } |
69 | if (It == StmtStack.begin()) |
70 | break; |
71 | --It; |
72 | } |
73 | const Stmt *Parent = *It; |
74 | |
75 | if (auto BO = dyn_cast<BinaryOperator>(Parent)) { |
76 | if (BO->getOpcode() == BO_Assign && BO->getLHS()->IgnoreParenCasts() == E) |
77 | Roles |= (unsigned)SymbolRole::Write; |
78 | |
79 | } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) { |
80 | if (UO->isIncrementDecrementOp()) { |
81 | Roles |= (unsigned)SymbolRole::Read; |
82 | Roles |= (unsigned)SymbolRole::Write; |
83 | } else if (UO->getOpcode() == UO_AddrOf) { |
84 | Roles |= (unsigned)SymbolRole::AddressOf; |
85 | } |
86 | |
87 | } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) { |
88 | if (CA->getLHS()->IgnoreParenCasts() == E) { |
89 | Roles |= (unsigned)SymbolRole::Read; |
90 | Roles |= (unsigned)SymbolRole::Write; |
91 | } |
92 | |
93 | } else if (auto CE = dyn_cast<CallExpr>(Parent)) { |
94 | if (CE->getCallee()->IgnoreParenCasts() == E) { |
95 | addCallRole(Roles, Relations); |
96 | if (auto *ME = dyn_cast<MemberExpr>(E)) { |
97 | if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl())) |
98 | if (CXXMD->isVirtual() && !ME->hasQualifier()) { |
99 | Roles |= (unsigned)SymbolRole::Dynamic; |
100 | auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType(); |
101 | if (!BaseTy.isNull()) |
102 | if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl()) |
103 | Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, |
104 | CXXRD); |
105 | } |
106 | } |
107 | } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) { |
108 | if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) { |
109 | OverloadedOperatorKind Op = CXXOp->getOperator(); |
110 | if (Op == OO_Equal) { |
111 | Roles |= (unsigned)SymbolRole::Write; |
112 | } else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) || |
113 | Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual || |
114 | Op == OO_PlusPlus || Op == OO_MinusMinus) { |
115 | Roles |= (unsigned)SymbolRole::Read; |
116 | Roles |= (unsigned)SymbolRole::Write; |
117 | } else if (Op == OO_Amp) { |
118 | Roles |= (unsigned)SymbolRole::AddressOf; |
119 | } |
120 | } |
121 | } |
122 | } |
123 | |
124 | return Roles; |
125 | } |
126 | |
127 | void addCallRole(SymbolRoleSet &Roles, |
128 | SmallVectorImpl<SymbolRelation> &Relations) { |
129 | Roles |= (unsigned)SymbolRole::Call; |
130 | if (auto *FD = dyn_cast<FunctionDecl>(ParentDC)) |
131 | Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD); |
132 | else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC)) |
133 | Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD); |
134 | } |
135 | |
136 | bool VisitDeclRefExpr(DeclRefExpr *E) { |
137 | SmallVector<SymbolRelation, 4> Relations; |
138 | SymbolRoleSet Roles = getRolesForRef(E, Relations); |
139 | return IndexCtx.handleReference(E->getDecl(), E->getLocation(), |
140 | Parent, ParentDC, Roles, Relations, E); |
141 | } |
142 | |
143 | bool VisitMemberExpr(MemberExpr *E) { |
144 | SourceLocation Loc = E->getMemberLoc(); |
145 | if (Loc.isInvalid()) |
146 | Loc = E->getBeginLoc(); |
147 | SmallVector<SymbolRelation, 4> Relations; |
148 | SymbolRoleSet Roles = getRolesForRef(E, Relations); |
149 | return IndexCtx.handleReference(E->getMemberDecl(), Loc, |
150 | Parent, ParentDC, Roles, Relations, E); |
151 | } |
152 | |
153 | bool indexDependentReference( |
154 | const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo, |
155 | llvm::function_ref<bool(const NamedDecl *ND)> Filter) { |
156 | if (!T) |
157 | return true; |
158 | const TemplateSpecializationType *TST = |
159 | T->getAs<TemplateSpecializationType>(); |
160 | if (!TST) |
161 | return true; |
162 | TemplateName TN = TST->getTemplateName(); |
163 | const ClassTemplateDecl *TD = |
164 | dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()); |
165 | if (!TD) |
166 | return true; |
167 | CXXRecordDecl *RD = TD->getTemplatedDecl(); |
168 | if (!RD->hasDefinition()) |
169 | return true; |
170 | RD = RD->getDefinition(); |
171 | std::vector<const NamedDecl *> Symbols = |
172 | RD->lookupDependentName(NameInfo.getName(), Filter); |
173 | |
174 | if (Symbols.size() != 1) |
175 | return true; |
176 | SourceLocation Loc = NameInfo.getLoc(); |
177 | if (Loc.isInvalid()) |
178 | Loc = E->getBeginLoc(); |
179 | SmallVector<SymbolRelation, 4> Relations; |
180 | SymbolRoleSet Roles = getRolesForRef(E, Relations); |
181 | return IndexCtx.handleReference(Symbols[0], Loc, Parent, ParentDC, Roles, |
182 | Relations, E); |
183 | } |
184 | |
185 | bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { |
186 | const DeclarationNameInfo &Info = E->getMemberNameInfo(); |
187 | return indexDependentReference( |
188 | E, E->getBaseType().getTypePtrOrNull(), Info, |
189 | [](const NamedDecl *D) { return D->isCXXInstanceMember(); }); |
190 | } |
191 | |
192 | bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { |
193 | const DeclarationNameInfo &Info = E->getNameInfo(); |
194 | const NestedNameSpecifier *NNS = E->getQualifier(); |
195 | return indexDependentReference( |
196 | E, NNS->getAsType(), Info, |
197 | [](const NamedDecl *D) { return !D->isCXXInstanceMember(); }); |
198 | } |
199 | |
200 | bool VisitDesignatedInitExpr(DesignatedInitExpr *E) { |
201 | for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) { |
202 | if (D.isFieldDesignator() && D.getField()) |
203 | return IndexCtx.handleReference(D.getField(), D.getFieldLoc(), Parent, |
204 | ParentDC, SymbolRoleSet(), {}, E); |
205 | } |
206 | return true; |
207 | } |
208 | |
209 | bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { |
210 | SmallVector<SymbolRelation, 4> Relations; |
211 | SymbolRoleSet Roles = getRolesForRef(E, Relations); |
212 | return IndexCtx.handleReference(E->getDecl(), E->getLocation(), |
213 | Parent, ParentDC, Roles, Relations, E); |
214 | } |
215 | |
216 | bool VisitObjCMessageExpr(ObjCMessageExpr *E) { |
217 | auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool { |
218 | if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance) |
219 | return false; |
220 | if (auto *RecE = dyn_cast<ObjCMessageExpr>( |
221 | MsgE->getInstanceReceiver()->IgnoreParenCasts())) { |
222 | if (RecE->getMethodFamily() == OMF_alloc) |
223 | return false; |
224 | } |
225 | return true; |
226 | }; |
227 | |
228 | if (ObjCMethodDecl *MD = E->getMethodDecl()) { |
229 | SymbolRoleSet Roles{}; |
230 | SmallVector<SymbolRelation, 2> Relations; |
231 | addCallRole(Roles, Relations); |
232 | Stmt *Containing = getParentStmt(); |
233 | |
234 | auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool { |
235 | const auto *E = POE->getSyntacticForm(); |
236 | if (const auto *BinOp = dyn_cast<BinaryOperator>(E)) |
237 | E = BinOp->getLHS(); |
238 | const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E); |
239 | if (!PRE) |
240 | return false; |
241 | if (PRE->isExplicitProperty()) |
242 | return false; |
243 | if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) { |
244 | |
245 | |
246 | |
247 | if (Getter->isClassMethod() && |
248 | Getter->getCanonicalDecl()->findPropertyDecl()) |
249 | return false; |
250 | } |
251 | return true; |
252 | }; |
253 | bool IsPropCall = Containing && isa<PseudoObjectExpr>(Containing); |
254 | |
255 | if ((E->isImplicit() || IsPropCall) && |
256 | !(IsPropCall && |
257 | IsImplicitProperty(cast<PseudoObjectExpr>(Containing)))) |
258 | Roles |= (unsigned)SymbolRole::Implicit; |
259 | |
260 | if (isDynamic(E)) { |
261 | Roles |= (unsigned)SymbolRole::Dynamic; |
262 | |
263 | auto addReceivers = [&](const ObjCObjectType *Ty) { |
264 | if (!Ty) |
265 | return; |
266 | if (const auto *clsD = Ty->getInterface()) { |
267 | Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, |
268 | clsD); |
269 | } |
270 | for (const auto *protD : Ty->quals()) { |
271 | Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, |
272 | protD); |
273 | } |
274 | }; |
275 | QualType recT = E->getReceiverType(); |
276 | if (const auto *Ptr = recT->getAs<ObjCObjectPointerType>()) |
277 | addReceivers(Ptr->getObjectType()); |
278 | else |
279 | addReceivers(recT->getAs<ObjCObjectType>()); |
280 | } |
281 | |
282 | return IndexCtx.handleReference(MD, E->getSelectorStartLoc(), |
283 | Parent, ParentDC, Roles, Relations, E); |
284 | } |
285 | return true; |
286 | } |
287 | |
288 | bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { |
289 | if (E->isClassReceiver()) |
290 | IndexCtx.handleReference(E->getClassReceiver(), E->getReceiverLocation(), |
291 | Parent, ParentDC); |
292 | if (E->isExplicitProperty()) { |
293 | SmallVector<SymbolRelation, 2> Relations; |
294 | SymbolRoleSet Roles = getRolesForRef(E, Relations); |
295 | return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(), |
296 | Parent, ParentDC, Roles, Relations, E); |
297 | } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) { |
298 | |
299 | |
300 | |
301 | if (Getter->isClassMethod()) { |
302 | if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) { |
303 | SmallVector<SymbolRelation, 2> Relations; |
304 | SymbolRoleSet Roles = getRolesForRef(E, Relations); |
305 | return IndexCtx.handleReference(PD, E->getLocation(), Parent, |
306 | ParentDC, Roles, Relations, E); |
307 | } |
308 | } |
309 | } |
310 | |
311 | |
312 | |
313 | return true; |
314 | } |
315 | |
316 | bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { |
317 | return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(), |
318 | Parent, ParentDC, SymbolRoleSet(), {}, E); |
319 | } |
320 | |
321 | bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) { |
322 | return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(), |
323 | Parent, ParentDC, SymbolRoleSet(), {}, E); |
324 | } |
325 | |
326 | bool passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) { |
327 | SymbolRoleSet Roles{}; |
328 | SmallVector<SymbolRelation, 2> Relations; |
329 | addCallRole(Roles, Relations); |
330 | Roles |= (unsigned)SymbolRole::Implicit; |
331 | return IndexCtx.handleReference(MD, E->getBeginLoc(), Parent, ParentDC, |
332 | Roles, Relations, E); |
333 | } |
334 | |
335 | bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) { |
336 | if (ObjCMethodDecl *MD = E->getBoxingMethod()) { |
337 | return passObjCLiteralMethodCall(MD, E); |
338 | } |
339 | return true; |
340 | } |
341 | |
342 | bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { |
343 | if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) { |
344 | return passObjCLiteralMethodCall(MD, E); |
345 | } |
346 | return true; |
347 | } |
348 | |
349 | bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) { |
350 | if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) { |
351 | return passObjCLiteralMethodCall(MD, E); |
352 | } |
353 | return true; |
354 | } |
355 | |
356 | bool VisitCXXConstructExpr(CXXConstructExpr *E) { |
357 | SymbolRoleSet Roles{}; |
358 | SmallVector<SymbolRelation, 2> Relations; |
359 | addCallRole(Roles, Relations); |
360 | return IndexCtx.handleReference(E->getConstructor(), E->getLocation(), |
361 | Parent, ParentDC, Roles, Relations, E); |
362 | } |
363 | |
364 | bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E, |
365 | DataRecursionQueue *Q = nullptr) { |
366 | if (E->getOperatorLoc().isInvalid()) |
367 | return true; |
368 | return base::TraverseCXXOperatorCallExpr(E, Q); |
369 | } |
370 | |
371 | bool VisitDeclStmt(DeclStmt *S) { |
372 | if (IndexCtx.shouldIndexFunctionLocalSymbols()) { |
373 | IndexCtx.indexDeclGroupRef(S->getDeclGroup()); |
374 | return true; |
375 | } |
376 | |
377 | DeclGroupRef DG = S->getDeclGroup(); |
378 | for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) { |
379 | const Decl *D = *I; |
380 | if (!D) |
381 | continue; |
382 | if (!isFunctionLocalSymbol(D)) |
383 | IndexCtx.indexTopLevelDecl(D); |
384 | } |
385 | |
386 | return true; |
387 | } |
388 | |
389 | bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, |
390 | Expr *Init) { |
391 | if (C->capturesThis() || C->capturesVLAType()) |
392 | return true; |
393 | |
394 | if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols()) |
395 | return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(), |
396 | Parent, ParentDC, SymbolRoleSet()); |
397 | |
398 | |
399 | return true; |
400 | } |
401 | |
402 | |
403 | |
404 | |
405 | |
406 | bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) { |
407 | auto visitForm = [&](InitListExpr *Form) { |
408 | for (Stmt *SubStmt : Form->children()) { |
409 | if (!TraverseStmt(SubStmt, Q)) |
410 | return false; |
411 | } |
412 | return true; |
413 | }; |
414 | |
415 | auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool { |
416 | for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) { |
417 | if (D.isFieldDesignator()) |
418 | return IndexCtx.handleReference(D.getField(), D.getFieldLoc(), |
419 | Parent, ParentDC, SymbolRoleSet(), |
420 | {}, E); |
421 | } |
422 | return true; |
423 | }; |
424 | |
425 | InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm(); |
426 | InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S; |
427 | |
428 | if (SemaForm) { |
429 | |
430 | if (SyntaxForm) { |
431 | for (Expr *init : SyntaxForm->inits()) { |
432 | if (auto *DIE = dyn_cast<DesignatedInitExpr>(init)) |
433 | visitSyntacticDesignatedInitExpr(DIE); |
434 | } |
435 | } |
436 | return visitForm(SemaForm); |
437 | } |
438 | |
439 | |
440 | if (SyntaxForm) { |
441 | return visitForm(SyntaxForm); |
442 | } |
443 | |
444 | return true; |
445 | } |
446 | |
447 | bool VisitOffsetOfExpr(OffsetOfExpr *S) { |
448 | for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) { |
449 | const OffsetOfNode &Component = S->getComponent(I); |
450 | if (Component.getKind() == OffsetOfNode::Field) |
451 | IndexCtx.handleReference(Component.getField(), Component.getEndLoc(), |
452 | Parent, ParentDC, SymbolRoleSet(), {}); |
453 | |
454 | } |
455 | return true; |
456 | } |
457 | |
458 | bool VisitParmVarDecl(ParmVarDecl* D) { |
459 | |
460 | if (IndexCtx.shouldIndexFunctionLocalSymbols()) { |
461 | const auto *DC = D->getDeclContext(); |
462 | if (DC && isLambdaCallOperator(DC)) |
463 | IndexCtx.handleDecl(D); |
464 | } |
465 | return true; |
466 | } |
467 | }; |
468 | |
469 | } |
470 | |
471 | void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent, |
472 | const DeclContext *DC) { |
473 | if (!S) |
474 | return; |
475 | |
476 | if (!DC) |
477 | DC = Parent->getLexicalDeclContext(); |
478 | BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S)); |
479 | } |
480 | |