1 | //===- IndexDecl.cpp - Indexing declarations ------------------------------===// |
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/Attr.h" |
12 | #include "clang/AST/Decl.h" |
13 | #include "clang/AST/DeclTemplate.h" |
14 | #include "clang/AST/DeclVisitor.h" |
15 | #include "clang/Index/IndexDataConsumer.h" |
16 | #include "clang/Index/IndexSymbol.h" |
17 | |
18 | using namespace clang; |
19 | using namespace index; |
20 | |
21 | #define TRY_DECL(D,CALL_EXPR) \ |
22 | do { \ |
23 | if (!IndexCtx.shouldIndex(D)) return true; \ |
24 | if (!CALL_EXPR) \ |
25 | return false; \ |
26 | } while (0) |
27 | |
28 | #define TRY_TO(CALL_EXPR) \ |
29 | do { \ |
30 | if (!CALL_EXPR) \ |
31 | return false; \ |
32 | } while (0) |
33 | |
34 | namespace { |
35 | |
36 | class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> { |
37 | IndexingContext &IndexCtx; |
38 | |
39 | public: |
40 | explicit IndexingDeclVisitor(IndexingContext &indexCtx) |
41 | : IndexCtx(indexCtx) { } |
42 | |
43 | bool Handled = true; |
44 | |
45 | bool VisitDecl(const Decl *D) { |
46 | Handled = false; |
47 | return true; |
48 | } |
49 | |
50 | void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc, |
51 | const NamedDecl *Parent, |
52 | const DeclContext *DC) { |
53 | const TemplateArgumentLocInfo &LocInfo = TALoc.getLocInfo(); |
54 | switch (TALoc.getArgument().getKind()) { |
55 | case TemplateArgument::Expression: |
56 | IndexCtx.indexBody(S: LocInfo.getAsExpr(), Parent, DC); |
57 | break; |
58 | case TemplateArgument::Type: |
59 | IndexCtx.indexTypeSourceInfo(TInfo: LocInfo.getAsTypeSourceInfo(), Parent, DC); |
60 | break; |
61 | case TemplateArgument::Template: |
62 | case TemplateArgument::TemplateExpansion: |
63 | IndexCtx.indexNestedNameSpecifierLoc(NNS: TALoc.getTemplateQualifierLoc(), |
64 | Parent, DC); |
65 | if (const TemplateDecl *TD = TALoc.getArgument() |
66 | .getAsTemplateOrTemplatePattern() |
67 | .getAsTemplateDecl()) { |
68 | if (const NamedDecl *TTD = TD->getTemplatedDecl()) |
69 | IndexCtx.handleReference(D: TTD, Loc: TALoc.getTemplateNameLoc(), Parent, DC); |
70 | } |
71 | break; |
72 | default: |
73 | break; |
74 | } |
75 | } |
76 | |
77 | /// Returns true if the given method has been defined explicitly by the |
78 | /// user. |
79 | static bool hasUserDefined(const ObjCMethodDecl *D, |
80 | const ObjCImplDecl *Container) { |
81 | const ObjCMethodDecl *MD = Container->getMethod(Sel: D->getSelector(), |
82 | isInstance: D->isInstanceMethod()); |
83 | return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition() && |
84 | !MD->isSynthesizedAccessorStub(); |
85 | } |
86 | |
87 | |
88 | void handleDeclarator(const DeclaratorDecl *D, |
89 | const NamedDecl *Parent = nullptr, |
90 | bool isIBType = false) { |
91 | if (!Parent) Parent = D; |
92 | |
93 | IndexCtx.indexTypeSourceInfo(TInfo: D->getTypeSourceInfo(), Parent, |
94 | DC: Parent->getLexicalDeclContext(), |
95 | /*isBase=*/false, isIBType); |
96 | IndexCtx.indexNestedNameSpecifierLoc(NNS: D->getQualifierLoc(), Parent); |
97 | auto IndexDefaultParmeterArgument = [&](const ParmVarDecl *Parm, |
98 | const NamedDecl *Parent) { |
99 | if (Parm->hasDefaultArg() && !Parm->hasUninstantiatedDefaultArg() && |
100 | !Parm->hasUnparsedDefaultArg()) |
101 | IndexCtx.indexBody(S: Parm->getDefaultArg(), Parent); |
102 | }; |
103 | if (IndexCtx.shouldIndexFunctionLocalSymbols()) { |
104 | if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(Val: D)) { |
105 | auto *DC = Parm->getDeclContext(); |
106 | if (auto *FD = dyn_cast<FunctionDecl>(Val: DC)) { |
107 | if (IndexCtx.shouldIndexParametersInDeclarations() || |
108 | FD->isThisDeclarationADefinition()) |
109 | IndexCtx.handleDecl(D: Parm); |
110 | } else if (auto *MD = dyn_cast<ObjCMethodDecl>(Val: DC)) { |
111 | if (MD->isThisDeclarationADefinition()) |
112 | IndexCtx.handleDecl(D: Parm); |
113 | } else { |
114 | IndexCtx.handleDecl(D: Parm); |
115 | } |
116 | } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Val: D)) { |
117 | if (IndexCtx.shouldIndexParametersInDeclarations() || |
118 | FD->isThisDeclarationADefinition()) { |
119 | for (const auto *PI : FD->parameters()) { |
120 | IndexDefaultParmeterArgument(PI, D); |
121 | IndexCtx.handleDecl(D: PI); |
122 | } |
123 | } |
124 | } |
125 | } else { |
126 | // Index the default parameter value for function definitions. |
127 | if (const auto *FD = dyn_cast<FunctionDecl>(Val: D)) { |
128 | if (FD->isThisDeclarationADefinition()) { |
129 | for (const auto *PV : FD->parameters()) { |
130 | IndexDefaultParmeterArgument(PV, D); |
131 | } |
132 | } |
133 | } |
134 | } |
135 | if (auto *C = D->getTrailingRequiresClause()) |
136 | IndexCtx.indexBody(S: C, Parent); |
137 | } |
138 | |
139 | bool handleObjCMethod(const ObjCMethodDecl *D, |
140 | const ObjCPropertyDecl *AssociatedProp = nullptr) { |
141 | SmallVector<SymbolRelation, 4> Relations; |
142 | SmallVector<const ObjCMethodDecl*, 4> Overriden; |
143 | |
144 | D->getOverriddenMethods(Overridden&: Overriden); |
145 | for(auto overridden: Overriden) { |
146 | Relations.emplace_back(Args: (unsigned) SymbolRole::RelationOverrideOf, |
147 | Args&: overridden); |
148 | } |
149 | if (AssociatedProp) |
150 | Relations.emplace_back(Args: (unsigned)SymbolRole::RelationAccessorOf, |
151 | Args&: AssociatedProp); |
152 | |
153 | // getLocation() returns beginning token of a method declaration, but for |
154 | // indexing purposes we want to point to the base name. |
155 | SourceLocation MethodLoc = D->getSelectorStartLoc(); |
156 | if (MethodLoc.isInvalid()) |
157 | MethodLoc = D->getLocation(); |
158 | |
159 | SourceLocation AttrLoc; |
160 | |
161 | // check for (getter=/setter=) |
162 | if (AssociatedProp) { |
163 | bool isGetter = !D->param_size(); |
164 | AttrLoc = isGetter ? |
165 | AssociatedProp->getGetterNameLoc(): |
166 | AssociatedProp->getSetterNameLoc(); |
167 | } |
168 | |
169 | SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic; |
170 | if (D->isImplicit()) { |
171 | if (AttrLoc.isValid()) { |
172 | MethodLoc = AttrLoc; |
173 | } else { |
174 | Roles |= (SymbolRoleSet)SymbolRole::Implicit; |
175 | } |
176 | } else if (AttrLoc.isValid()) { |
177 | IndexCtx.handleReference(D, Loc: AttrLoc, Parent: cast<NamedDecl>(Val: D->getDeclContext()), |
178 | DC: D->getDeclContext(), Roles: 0); |
179 | } |
180 | |
181 | TRY_DECL(D, IndexCtx.handleDecl(D, MethodLoc, Roles, Relations)); |
182 | IndexCtx.indexTypeSourceInfo(TInfo: D->getReturnTypeSourceInfo(), Parent: D); |
183 | bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>(); |
184 | for (const auto *I : D->parameters()) { |
185 | handleDeclarator(D: I, Parent: D, /*isIBType=*/hasIBActionAndFirst); |
186 | hasIBActionAndFirst = false; |
187 | } |
188 | |
189 | if (D->isThisDeclarationADefinition()) { |
190 | const Stmt *Body = D->getBody(); |
191 | if (Body) { |
192 | IndexCtx.indexBody(S: Body, Parent: D, DC: D); |
193 | } |
194 | } |
195 | return true; |
196 | } |
197 | |
198 | /// Gather the declarations which the given declaration \D overrides in a |
199 | /// pseudo-override manner. |
200 | /// |
201 | /// Pseudo-overrides occur when a class template specialization declares |
202 | /// a declaration that has the same name as a similar declaration in the |
203 | /// non-specialized template. |
204 | void |
205 | gatherTemplatePseudoOverrides(const NamedDecl *D, |
206 | SmallVectorImpl<SymbolRelation> &Relations) { |
207 | if (!IndexCtx.getLangOpts().CPlusPlus) |
208 | return; |
209 | const auto *CTSD = |
210 | dyn_cast<ClassTemplateSpecializationDecl>(Val: D->getLexicalDeclContext()); |
211 | if (!CTSD) |
212 | return; |
213 | llvm::PointerUnion<ClassTemplateDecl *, |
214 | ClassTemplatePartialSpecializationDecl *> |
215 | Template = CTSD->getSpecializedTemplateOrPartial(); |
216 | if (const auto *CTD = Template.dyn_cast<ClassTemplateDecl *>()) { |
217 | const CXXRecordDecl *Pattern = CTD->getTemplatedDecl(); |
218 | bool TypeOverride = isa<TypeDecl>(Val: D); |
219 | for (const NamedDecl *ND : Pattern->lookup(Name: D->getDeclName())) { |
220 | if (const auto *CTD = dyn_cast<ClassTemplateDecl>(Val: ND)) |
221 | ND = CTD->getTemplatedDecl(); |
222 | if (ND->isImplicit()) |
223 | continue; |
224 | // Types can override other types. |
225 | if (!TypeOverride) { |
226 | if (ND->getKind() != D->getKind()) |
227 | continue; |
228 | } else if (!isa<TypeDecl>(Val: ND)) |
229 | continue; |
230 | if (const auto *FD = dyn_cast<FunctionDecl>(Val: ND)) { |
231 | const auto *DFD = cast<FunctionDecl>(Val: D); |
232 | // Function overrides are approximated using the number of parameters. |
233 | if (FD->getStorageClass() != DFD->getStorageClass() || |
234 | FD->getNumParams() != DFD->getNumParams()) |
235 | continue; |
236 | } |
237 | Relations.emplace_back( |
238 | Args: SymbolRoleSet(SymbolRole::RelationSpecializationOf), Args&: ND); |
239 | } |
240 | } |
241 | } |
242 | |
243 | bool VisitFunctionDecl(const FunctionDecl *D) { |
244 | SymbolRoleSet Roles{}; |
245 | SmallVector<SymbolRelation, 4> Relations; |
246 | if (auto *CXXMD = dyn_cast<CXXMethodDecl>(Val: D)) { |
247 | if (CXXMD->isVirtual()) |
248 | Roles |= (unsigned)SymbolRole::Dynamic; |
249 | for (const CXXMethodDecl *O : CXXMD->overridden_methods()) { |
250 | Relations.emplace_back(Args: (unsigned)SymbolRole::RelationOverrideOf, Args&: O); |
251 | } |
252 | } |
253 | gatherTemplatePseudoOverrides(D, Relations); |
254 | if (const auto *Base = D->getPrimaryTemplate()) |
255 | Relations.push_back( |
256 | Elt: SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), |
257 | Base->getTemplatedDecl())); |
258 | |
259 | TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations)); |
260 | handleDeclarator(D); |
261 | |
262 | if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Val: D)) { |
263 | IndexCtx.handleReference(D: Ctor->getParent(), Loc: Ctor->getLocation(), |
264 | Parent: Ctor->getParent(), DC: Ctor->getDeclContext(), |
265 | Roles: (unsigned)SymbolRole::NameReference); |
266 | |
267 | // Constructor initializers. |
268 | for (const auto *Init : Ctor->inits()) { |
269 | if (Init->isWritten()) { |
270 | IndexCtx.indexTypeSourceInfo(TInfo: Init->getTypeSourceInfo(), Parent: D); |
271 | if (const FieldDecl *Member = Init->getAnyMember()) |
272 | IndexCtx.handleReference(D: Member, Loc: Init->getMemberLocation(), Parent: D, DC: D, |
273 | Roles: (unsigned)SymbolRole::Write); |
274 | IndexCtx.indexBody(S: Init->getInit(), Parent: D, DC: D); |
275 | } |
276 | } |
277 | } else if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(Val: D)) { |
278 | if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) { |
279 | IndexCtx.handleReference(D: Dtor->getParent(), |
280 | Loc: TypeNameInfo->getTypeLoc().getBeginLoc(), |
281 | Parent: Dtor->getParent(), DC: Dtor->getDeclContext(), |
282 | Roles: (unsigned)SymbolRole::NameReference); |
283 | } |
284 | } else if (const auto *Guide = dyn_cast<CXXDeductionGuideDecl>(Val: D)) { |
285 | IndexCtx.handleReference(D: Guide->getDeducedTemplate()->getTemplatedDecl(), |
286 | Loc: Guide->getLocation(), Parent: Guide, |
287 | DC: Guide->getDeclContext()); |
288 | } |
289 | // Template specialization arguments. |
290 | if (const ASTTemplateArgumentListInfo *TemplateArgInfo = |
291 | D->getTemplateSpecializationArgsAsWritten()) { |
292 | for (const auto &Arg : TemplateArgInfo->arguments()) |
293 | handleTemplateArgumentLoc(TALoc: Arg, Parent: D, DC: D->getLexicalDeclContext()); |
294 | } |
295 | |
296 | if (D->isThisDeclarationADefinition()) { |
297 | const Stmt *Body = D->getBody(); |
298 | if (Body) { |
299 | IndexCtx.indexBody(S: Body, Parent: D, DC: D); |
300 | } |
301 | } |
302 | return true; |
303 | } |
304 | |
305 | bool VisitVarDecl(const VarDecl *D) { |
306 | SmallVector<SymbolRelation, 4> Relations; |
307 | gatherTemplatePseudoOverrides(D, Relations); |
308 | TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); |
309 | handleDeclarator(D); |
310 | IndexCtx.indexBody(S: D->getInit(), Parent: D); |
311 | return true; |
312 | } |
313 | |
314 | bool VisitDecompositionDecl(const DecompositionDecl *D) { |
315 | for (const auto *Binding : D->bindings()) |
316 | TRY_DECL(Binding, IndexCtx.handleDecl(Binding)); |
317 | return Base::VisitDecompositionDecl(D); |
318 | } |
319 | |
320 | bool VisitFieldDecl(const FieldDecl *D) { |
321 | SmallVector<SymbolRelation, 4> Relations; |
322 | gatherTemplatePseudoOverrides(D, Relations); |
323 | TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); |
324 | handleDeclarator(D); |
325 | if (D->isBitField()) |
326 | IndexCtx.indexBody(S: D->getBitWidth(), Parent: D); |
327 | else if (D->hasInClassInitializer()) |
328 | IndexCtx.indexBody(S: D->getInClassInitializer(), Parent: D); |
329 | return true; |
330 | } |
331 | |
332 | bool VisitObjCIvarDecl(const ObjCIvarDecl *D) { |
333 | if (D->getSynthesize()) { |
334 | // handled in VisitObjCPropertyImplDecl |
335 | return true; |
336 | } |
337 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
338 | handleDeclarator(D); |
339 | return true; |
340 | } |
341 | |
342 | bool VisitMSPropertyDecl(const MSPropertyDecl *D) { |
343 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
344 | handleDeclarator(D); |
345 | return true; |
346 | } |
347 | |
348 | bool VisitEnumConstantDecl(const EnumConstantDecl *D) { |
349 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
350 | IndexCtx.indexBody(S: D->getInitExpr(), Parent: D); |
351 | return true; |
352 | } |
353 | |
354 | bool VisitTypedefNameDecl(const TypedefNameDecl *D) { |
355 | if (!D->isTransparentTag()) { |
356 | SmallVector<SymbolRelation, 4> Relations; |
357 | gatherTemplatePseudoOverrides(D, Relations); |
358 | TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations)); |
359 | IndexCtx.indexTypeSourceInfo(TInfo: D->getTypeSourceInfo(), Parent: D); |
360 | } |
361 | return true; |
362 | } |
363 | |
364 | bool VisitTagDecl(const TagDecl *D) { |
365 | // Non-free standing tags are handled in indexTypeSourceInfo. |
366 | if (D->isFreeStanding()) { |
367 | if (D->isThisDeclarationADefinition()) { |
368 | SmallVector<SymbolRelation, 4> Relations; |
369 | gatherTemplatePseudoOverrides(D, Relations); |
370 | IndexCtx.indexTagDecl(D, Relations); |
371 | } else { |
372 | SmallVector<SymbolRelation, 1> Relations; |
373 | gatherTemplatePseudoOverrides(D, Relations); |
374 | return IndexCtx.handleDecl(D, Loc: D->getLocation(), Roles: SymbolRoleSet(), |
375 | Relations, DC: D->getLexicalDeclContext()); |
376 | } |
377 | } |
378 | return true; |
379 | } |
380 | |
381 | bool VisitEnumDecl(const EnumDecl *ED) { |
382 | TRY_TO(VisitTagDecl(ED)); |
383 | // Indexing for enumdecl itself is handled inside TagDecl, we just want to |
384 | // visit integer-base here, which is different than other TagDecl bases. |
385 | if (auto *TSI = ED->getIntegerTypeSourceInfo()) |
386 | IndexCtx.indexTypeSourceInfo(TInfo: TSI, Parent: ED, DC: ED, /*isBase=*/true); |
387 | return true; |
388 | } |
389 | |
390 | bool handleReferencedProtocols(const ObjCProtocolList &ProtList, |
391 | const ObjCContainerDecl *ContD, |
392 | SourceLocation SuperLoc) { |
393 | ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); |
394 | for (ObjCInterfaceDecl::protocol_iterator |
395 | I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { |
396 | SourceLocation Loc = *LI; |
397 | ObjCProtocolDecl *PD = *I; |
398 | SymbolRoleSet roles{}; |
399 | if (Loc == SuperLoc) |
400 | roles |= (SymbolRoleSet)SymbolRole::Implicit; |
401 | TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles, |
402 | SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); |
403 | } |
404 | return true; |
405 | } |
406 | |
407 | bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { |
408 | if (D->isThisDeclarationADefinition()) { |
409 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
410 | SourceLocation SuperLoc = D->getSuperClassLoc(); |
411 | if (auto *SuperD = D->getSuperClass()) { |
412 | bool hasSuperTypedef = false; |
413 | if (auto *TInfo = D->getSuperClassTInfo()) { |
414 | if (auto *TT = TInfo->getType()->getAs<TypedefType>()) { |
415 | if (auto *TD = TT->getDecl()) { |
416 | hasSuperTypedef = true; |
417 | TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D, |
418 | SymbolRoleSet())); |
419 | } |
420 | } |
421 | } |
422 | SymbolRoleSet superRoles{}; |
423 | if (hasSuperTypedef) |
424 | superRoles |= (SymbolRoleSet)SymbolRole::Implicit; |
425 | TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles, |
426 | SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); |
427 | } |
428 | TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, |
429 | SuperLoc)); |
430 | TRY_TO(IndexCtx.indexDeclContext(D)); |
431 | } else { |
432 | return IndexCtx.handleReference(D, Loc: D->getLocation(), Parent: nullptr, |
433 | DC: D->getDeclContext(), Roles: SymbolRoleSet()); |
434 | } |
435 | return true; |
436 | } |
437 | |
438 | bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { |
439 | if (D->isThisDeclarationADefinition()) { |
440 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
441 | TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, |
442 | /*SuperLoc=*/SourceLocation())); |
443 | TRY_TO(IndexCtx.indexDeclContext(D)); |
444 | } else { |
445 | return IndexCtx.handleReference(D, Loc: D->getLocation(), Parent: nullptr, |
446 | DC: D->getDeclContext(), Roles: SymbolRoleSet()); |
447 | } |
448 | return true; |
449 | } |
450 | |
451 | bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { |
452 | const ObjCInterfaceDecl *Class = D->getClassInterface(); |
453 | if (!Class) |
454 | return true; |
455 | |
456 | if (Class->isImplicitInterfaceDecl()) |
457 | IndexCtx.handleDecl(D: Class); |
458 | |
459 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
460 | |
461 | // Visit implicit @synthesize property implementations first as their |
462 | // location is reported at the name of the @implementation block. This |
463 | // serves no purpose other than to simplify the FileCheck-based tests. |
464 | for (const auto *I : D->property_impls()) { |
465 | if (I->getLocation().isInvalid()) |
466 | IndexCtx.indexDecl(D: I); |
467 | } |
468 | for (const auto *I : D->decls()) { |
469 | if (!isa<ObjCPropertyImplDecl>(Val: I) || |
470 | cast<ObjCPropertyImplDecl>(Val: I)->getLocation().isValid()) |
471 | IndexCtx.indexDecl(D: I); |
472 | } |
473 | |
474 | return true; |
475 | } |
476 | |
477 | bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { |
478 | if (!IndexCtx.shouldIndex(D)) |
479 | return true; |
480 | const ObjCInterfaceDecl *C = D->getClassInterface(); |
481 | if (!C) |
482 | return true; |
483 | TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(), |
484 | SymbolRelation{ |
485 | (unsigned)SymbolRole::RelationExtendedBy, D |
486 | })); |
487 | SourceLocation CategoryLoc = D->getCategoryNameLoc(); |
488 | if (!CategoryLoc.isValid()) |
489 | CategoryLoc = D->getLocation(); |
490 | TRY_TO(IndexCtx.handleDecl(D, CategoryLoc)); |
491 | TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, |
492 | /*SuperLoc=*/SourceLocation())); |
493 | TRY_TO(IndexCtx.indexDeclContext(D)); |
494 | return true; |
495 | } |
496 | |
497 | bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { |
498 | const ObjCCategoryDecl *Cat = D->getCategoryDecl(); |
499 | if (!Cat) |
500 | return true; |
501 | const ObjCInterfaceDecl *C = D->getClassInterface(); |
502 | if (C) |
503 | TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, |
504 | SymbolRoleSet())); |
505 | SourceLocation CategoryLoc = D->getCategoryNameLoc(); |
506 | if (!CategoryLoc.isValid()) |
507 | CategoryLoc = D->getLocation(); |
508 | TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc)); |
509 | IndexCtx.indexDeclContext(DC: D); |
510 | return true; |
511 | } |
512 | |
513 | bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { |
514 | // Methods associated with a property, even user-declared ones, are |
515 | // handled when we handle the property. |
516 | if (D->isPropertyAccessor()) |
517 | return true; |
518 | |
519 | handleObjCMethod(D); |
520 | return true; |
521 | } |
522 | |
523 | bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { |
524 | if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) |
525 | if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) |
526 | handleObjCMethod(D: MD, AssociatedProp: D); |
527 | if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) |
528 | if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) |
529 | handleObjCMethod(D: MD, AssociatedProp: D); |
530 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
531 | if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>()) |
532 | IndexCtx.indexTypeSourceInfo(TInfo: attr->getInterfaceLoc(), Parent: D, |
533 | DC: D->getLexicalDeclContext(), isBase: false, isIBType: true); |
534 | IndexCtx.indexTypeSourceInfo(TInfo: D->getTypeSourceInfo(), Parent: D); |
535 | return true; |
536 | } |
537 | |
538 | bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { |
539 | ObjCPropertyDecl *PD = D->getPropertyDecl(); |
540 | auto *Container = cast<ObjCImplDecl>(Val: D->getDeclContext()); |
541 | SourceLocation Loc = D->getLocation(); |
542 | SymbolRoleSet Roles = 0; |
543 | SmallVector<SymbolRelation, 1> Relations; |
544 | |
545 | if (ObjCIvarDecl *ID = D->getPropertyIvarDecl()) |
546 | Relations.push_back(Elt: {(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID}); |
547 | if (Loc.isInvalid()) { |
548 | Loc = Container->getLocation(); |
549 | Roles |= (SymbolRoleSet)SymbolRole::Implicit; |
550 | } |
551 | TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations)); |
552 | |
553 | if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) |
554 | return true; |
555 | |
556 | assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); |
557 | SymbolRoleSet AccessorMethodRoles = |
558 | SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); |
559 | if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { |
560 | if (MD->isPropertyAccessor() && !hasUserDefined(D: MD, Container)) |
561 | IndexCtx.handleDecl(D: MD, Loc, Roles: AccessorMethodRoles, Relations: {}, DC: Container); |
562 | } |
563 | if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { |
564 | if (MD->isPropertyAccessor() && !hasUserDefined(D: MD, Container)) |
565 | IndexCtx.handleDecl(D: MD, Loc, Roles: AccessorMethodRoles, Relations: {}, DC: Container); |
566 | } |
567 | if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { |
568 | if (IvarD->getSynthesize()) { |
569 | // For synthesized ivars, use the location of its name in the |
570 | // corresponding @synthesize. If there isn't one, use the containing |
571 | // @implementation's location, rather than the property's location, |
572 | // otherwise the header file containing the @interface will have different |
573 | // indexing contents based on whether the @implementation was present or |
574 | // not in the translation unit. |
575 | SymbolRoleSet IvarRoles = 0; |
576 | SourceLocation IvarLoc = D->getPropertyIvarDeclLoc(); |
577 | if (D->getLocation().isInvalid()) { |
578 | IvarLoc = Container->getLocation(); |
579 | IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; |
580 | } else if (D->getLocation() == IvarLoc) { |
581 | IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; |
582 | } |
583 | TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles)); |
584 | } else { |
585 | IndexCtx.handleReference(D: IvarD, Loc: D->getPropertyIvarDeclLoc(), Parent: nullptr, |
586 | DC: D->getDeclContext(), Roles: SymbolRoleSet()); |
587 | } |
588 | } |
589 | return true; |
590 | } |
591 | |
592 | bool VisitNamespaceDecl(const NamespaceDecl *D) { |
593 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
594 | IndexCtx.indexDeclContext(DC: D); |
595 | return true; |
596 | } |
597 | |
598 | bool VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { |
599 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
600 | IndexCtx.indexNestedNameSpecifierLoc(NNS: D->getQualifierLoc(), Parent: D); |
601 | IndexCtx.handleReference(D: D->getAliasedNamespace(), Loc: D->getTargetNameLoc(), Parent: D, |
602 | DC: D->getLexicalDeclContext()); |
603 | return true; |
604 | } |
605 | |
606 | bool VisitUsingDecl(const UsingDecl *D) { |
607 | IndexCtx.handleDecl(D); |
608 | |
609 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
610 | const NamedDecl *Parent = dyn_cast<NamedDecl>(Val: DC); |
611 | IndexCtx.indexNestedNameSpecifierLoc(NNS: D->getQualifierLoc(), Parent, |
612 | DC: D->getLexicalDeclContext()); |
613 | for (const auto *I : D->shadows()) { |
614 | // Skip unresolved using decls - we already have a decl for the using |
615 | // itself, so there's not much point adding another decl or reference to |
616 | // refer to the same location. |
617 | if (isa<UnresolvedUsingIfExistsDecl>(Val: I->getUnderlyingDecl())) |
618 | continue; |
619 | |
620 | IndexCtx.handleReference(D: I->getUnderlyingDecl(), Loc: D->getLocation(), Parent, |
621 | DC: D->getLexicalDeclContext(), Roles: SymbolRoleSet()); |
622 | } |
623 | return true; |
624 | } |
625 | |
626 | bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { |
627 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
628 | const NamedDecl *Parent = dyn_cast<NamedDecl>(Val: DC); |
629 | |
630 | // NNS for the local 'using namespace' directives is visited by the body |
631 | // visitor. |
632 | if (!D->getParentFunctionOrMethod()) |
633 | IndexCtx.indexNestedNameSpecifierLoc(NNS: D->getQualifierLoc(), Parent, |
634 | DC: D->getLexicalDeclContext()); |
635 | |
636 | return IndexCtx.handleReference(D: D->getNominatedNamespaceAsWritten(), |
637 | Loc: D->getLocation(), Parent, |
638 | DC: D->getLexicalDeclContext(), |
639 | Roles: SymbolRoleSet()); |
640 | } |
641 | |
642 | bool VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { |
643 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
644 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
645 | const NamedDecl *Parent = dyn_cast<NamedDecl>(Val: DC); |
646 | IndexCtx.indexNestedNameSpecifierLoc(NNS: D->getQualifierLoc(), Parent, |
647 | DC: D->getLexicalDeclContext()); |
648 | return true; |
649 | } |
650 | |
651 | bool VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { |
652 | TRY_DECL(D, IndexCtx.handleDecl(D)); |
653 | const DeclContext *DC = D->getDeclContext()->getRedeclContext(); |
654 | const NamedDecl *Parent = dyn_cast<NamedDecl>(Val: DC); |
655 | IndexCtx.indexNestedNameSpecifierLoc(NNS: D->getQualifierLoc(), Parent, |
656 | DC: D->getLexicalDeclContext()); |
657 | return true; |
658 | } |
659 | |
660 | bool VisitClassTemplateSpecializationDecl(const |
661 | ClassTemplateSpecializationDecl *D) { |
662 | // FIXME: Notify subsequent callbacks if info comes from implicit |
663 | // instantiation. |
664 | llvm::PointerUnion<ClassTemplateDecl *, |
665 | ClassTemplatePartialSpecializationDecl *> |
666 | Template = D->getSpecializedTemplateOrPartial(); |
667 | const Decl *SpecializationOf = |
668 | Template.is<ClassTemplateDecl *>() |
669 | ? (Decl *)Template.get<ClassTemplateDecl *>() |
670 | : Template.get<ClassTemplatePartialSpecializationDecl *>(); |
671 | if (!D->isThisDeclarationADefinition()) |
672 | IndexCtx.indexNestedNameSpecifierLoc(NNS: D->getQualifierLoc(), Parent: D); |
673 | IndexCtx.indexTagDecl( |
674 | D, Relations: SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), |
675 | SpecializationOf)); |
676 | // Template specialization arguments. |
677 | if (const ASTTemplateArgumentListInfo *TemplateArgInfo = |
678 | D->getTemplateArgsAsWritten()) { |
679 | for (const auto &Arg : TemplateArgInfo->arguments()) |
680 | handleTemplateArgumentLoc(TALoc: Arg, Parent: D, DC: D->getLexicalDeclContext()); |
681 | } |
682 | return true; |
683 | } |
684 | |
685 | static bool shouldIndexTemplateParameterDefaultValue(const NamedDecl *D) { |
686 | // We want to index the template parameters only once when indexing the |
687 | // canonical declaration. |
688 | if (!D) |
689 | return false; |
690 | if (const auto *FD = dyn_cast<FunctionDecl>(Val: D)) |
691 | return FD->getCanonicalDecl() == FD; |
692 | else if (const auto *TD = dyn_cast<TagDecl>(Val: D)) |
693 | return TD->getCanonicalDecl() == TD; |
694 | else if (const auto *VD = dyn_cast<VarDecl>(Val: D)) |
695 | return VD->getCanonicalDecl() == VD; |
696 | return true; |
697 | } |
698 | |
699 | void indexTemplateParameters(TemplateParameterList *Params, |
700 | const NamedDecl *Parent) { |
701 | for (const NamedDecl *TP : *Params) { |
702 | if (IndexCtx.shouldIndexTemplateParameters()) |
703 | IndexCtx.handleDecl(D: TP); |
704 | if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Val: TP)) { |
705 | if (TTP->hasDefaultArgument()) |
706 | handleTemplateArgumentLoc(TALoc: TTP->getDefaultArgument(), Parent, |
707 | DC: TP->getLexicalDeclContext()); |
708 | if (auto *C = TTP->getTypeConstraint()) |
709 | IndexCtx.handleReference(D: C->getNamedConcept(), Loc: C->getConceptNameLoc(), |
710 | Parent, DC: TTP->getLexicalDeclContext()); |
711 | } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Val: TP)) { |
712 | IndexCtx.indexTypeSourceInfo(TInfo: NTTP->getTypeSourceInfo(), Parent); |
713 | if (NTTP->hasDefaultArgument()) |
714 | handleTemplateArgumentLoc(TALoc: NTTP->getDefaultArgument(), Parent, |
715 | DC: TP->getLexicalDeclContext()); |
716 | } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Val: TP)) { |
717 | if (TTPD->hasDefaultArgument()) |
718 | handleTemplateArgumentLoc(TALoc: TTPD->getDefaultArgument(), Parent, |
719 | DC: TP->getLexicalDeclContext()); |
720 | } |
721 | } |
722 | if (auto *R = Params->getRequiresClause()) |
723 | IndexCtx.indexBody(S: R, Parent); |
724 | } |
725 | |
726 | bool VisitTemplateDecl(const TemplateDecl *D) { |
727 | const NamedDecl *Parent = D->getTemplatedDecl(); |
728 | if (!Parent) |
729 | return true; |
730 | |
731 | // Index the default values for the template parameters. |
732 | auto *Params = D->getTemplateParameters(); |
733 | if (Params && shouldIndexTemplateParameterDefaultValue(D: Parent)) { |
734 | indexTemplateParameters(Params, Parent); |
735 | } |
736 | |
737 | return Visit(D: Parent); |
738 | } |
739 | |
740 | bool VisitConceptDecl(const ConceptDecl *D) { |
741 | if (auto *Params = D->getTemplateParameters()) |
742 | indexTemplateParameters(Params, Parent: D); |
743 | if (auto *E = D->getConstraintExpr()) |
744 | IndexCtx.indexBody(S: E, Parent: D); |
745 | return IndexCtx.handleDecl(D); |
746 | } |
747 | |
748 | bool VisitFriendDecl(const FriendDecl *D) { |
749 | if (auto ND = D->getFriendDecl()) { |
750 | // FIXME: Ignore a class template in a dependent context, these are not |
751 | // linked properly with their redeclarations, ending up with duplicate |
752 | // USRs. |
753 | // See comment "Friend templates are visible in fairly strange ways." in |
754 | // SemaTemplate.cpp which precedes code that prevents the friend template |
755 | // from becoming visible from the enclosing context. |
756 | if (isa<ClassTemplateDecl>(Val: ND) && D->getDeclContext()->isDependentContext()) |
757 | return true; |
758 | return Visit(D: ND); |
759 | } |
760 | if (auto Ty = D->getFriendType()) { |
761 | IndexCtx.indexTypeSourceInfo(TInfo: Ty, Parent: cast<NamedDecl>(Val: D->getDeclContext())); |
762 | } |
763 | return true; |
764 | } |
765 | |
766 | bool VisitImportDecl(const ImportDecl *D) { |
767 | return IndexCtx.importedModule(ImportD: D); |
768 | } |
769 | |
770 | bool VisitStaticAssertDecl(const StaticAssertDecl *D) { |
771 | IndexCtx.indexBody(S: D->getAssertExpr(), |
772 | Parent: dyn_cast<NamedDecl>(Val: D->getDeclContext()), |
773 | DC: D->getLexicalDeclContext()); |
774 | return true; |
775 | } |
776 | }; |
777 | |
778 | } // anonymous namespace |
779 | |
780 | bool IndexingContext::indexDecl(const Decl *D) { |
781 | if (D->isImplicit() && shouldIgnoreIfImplicit(D)) |
782 | return true; |
783 | |
784 | if (isTemplateImplicitInstantiation(D) && !shouldIndexImplicitInstantiation()) |
785 | return true; |
786 | |
787 | IndexingDeclVisitor Visitor(*this); |
788 | bool ShouldContinue = Visitor.Visit(D); |
789 | if (!ShouldContinue) |
790 | return false; |
791 | |
792 | if (!Visitor.Handled && isa<DeclContext>(Val: D)) |
793 | return indexDeclContext(DC: cast<DeclContext>(Val: D)); |
794 | |
795 | return true; |
796 | } |
797 | |
798 | bool IndexingContext::indexDeclContext(const DeclContext *DC) { |
799 | for (const auto *I : DC->decls()) |
800 | if (!indexDecl(D: I)) |
801 | return false; |
802 | return true; |
803 | } |
804 | |
805 | bool IndexingContext::indexTopLevelDecl(const Decl *D) { |
806 | if (!D || D->getLocation().isInvalid()) |
807 | return true; |
808 | |
809 | if (isa<ObjCMethodDecl>(Val: D)) |
810 | return true; // Wait for the objc container. |
811 | |
812 | if (IndexOpts.ShouldTraverseDecl && !IndexOpts.ShouldTraverseDecl(D)) |
813 | return true; // skip |
814 | |
815 | return indexDecl(D); |
816 | } |
817 | |
818 | bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { |
819 | for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) |
820 | if (!indexTopLevelDecl(D: *I)) |
821 | return false; |
822 | return true; |
823 | } |
824 | |