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