1 //===- IndexDecl.cpp - Indexing declarations ------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "IndexingContext.h"
11 #include "clang/Index/IndexDataConsumer.h"
12 #include "clang/AST/DeclVisitor.h"
14 using namespace clang;
15 using namespace index;
17 #define TRY_DECL(D,CALL_EXPR) \
19 if (!IndexCtx.shouldIndex(D)) return true; \
24 #define TRY_TO(CALL_EXPR) \
32 class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
33 IndexingContext &IndexCtx;
36 explicit IndexingDeclVisitor(IndexingContext &indexCtx)
37 : IndexCtx(indexCtx) { }
41 bool VisitDecl(const Decl *D) {
46 /// \brief Returns true if the given method has been defined explicitly by the
48 static bool hasUserDefined(const ObjCMethodDecl *D,
49 const ObjCImplDecl *Container) {
50 const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
51 D->isInstanceMethod());
52 return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
55 void handleDeclarator(const DeclaratorDecl *D,
56 const NamedDecl *Parent = nullptr,
57 bool isIBType = false) {
58 if (!Parent) Parent = D;
60 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent,
61 Parent->getLexicalDeclContext(),
62 /*isBase=*/false, isIBType);
63 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
64 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
65 // Only index parameters in definitions, parameters in declarations are
67 if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
68 auto *DC = Parm->getDeclContext();
69 if (auto *FD = dyn_cast<FunctionDecl>(DC)) {
70 if (FD->isThisDeclarationADefinition())
71 IndexCtx.handleDecl(Parm);
72 } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) {
73 if (MD->isThisDeclarationADefinition())
74 IndexCtx.handleDecl(Parm);
76 IndexCtx.handleDecl(Parm);
78 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
79 if (FD->isThisDeclarationADefinition()) {
80 for (auto PI : FD->parameters()) {
81 IndexCtx.handleDecl(PI);
88 bool handleObjCMethod(const ObjCMethodDecl *D,
89 const ObjCPropertyDecl *AssociatedProp = nullptr) {
90 SmallVector<SymbolRelation, 4> Relations;
91 SmallVector<const ObjCMethodDecl*, 4> Overriden;
93 D->getOverriddenMethods(Overriden);
94 for(auto overridden: Overriden) {
95 Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf,
99 Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf,
102 // getLocation() returns beginning token of a method declaration, but for
103 // indexing purposes we want to point to the base name.
104 SourceLocation MethodLoc = D->getSelectorStartLoc();
105 if (MethodLoc.isInvalid())
106 MethodLoc = D->getLocation();
108 SourceLocation AttrLoc;
110 // check for (getter=/setter=)
111 if (AssociatedProp) {
112 bool isGetter = !D->param_size();
114 AssociatedProp->getGetterNameLoc():
115 AssociatedProp->getSetterNameLoc();
118 SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic;
119 if (D->isImplicit()) {
120 if (AttrLoc.isValid()) {
123 Roles |= (SymbolRoleSet)SymbolRole::Implicit;
125 } else if (AttrLoc.isValid()) {
126 IndexCtx.handleReference(D, AttrLoc, cast<NamedDecl>(D->getDeclContext()),
127 D->getDeclContext(), 0);
130 TRY_DECL(D, IndexCtx.handleDecl(D, MethodLoc, Roles, Relations));
131 IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
132 bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>();
133 for (const auto *I : D->parameters()) {
134 handleDeclarator(I, D, /*isIBType=*/hasIBActionAndFirst);
135 hasIBActionAndFirst = false;
138 if (D->isThisDeclarationADefinition()) {
139 const Stmt *Body = D->getBody();
141 IndexCtx.indexBody(Body, D, D);
147 /// Gather the declarations which the given declaration \D overrides in a
148 /// pseudo-override manner.
150 /// Pseudo-overrides occur when a class template specialization declares
151 /// a declaration that has the same name as a similar declaration in the
152 /// non-specialized template.
154 gatherTemplatePseudoOverrides(const NamedDecl *D,
155 SmallVectorImpl<SymbolRelation> &Relations) {
156 if (!IndexCtx.getLangOpts().CPlusPlus)
159 dyn_cast<ClassTemplateSpecializationDecl>(D->getLexicalDeclContext());
162 llvm::PointerUnion<ClassTemplateDecl *,
163 ClassTemplatePartialSpecializationDecl *>
164 Template = CTSD->getSpecializedTemplateOrPartial();
165 if (const auto *CTD = Template.dyn_cast<ClassTemplateDecl *>()) {
166 const CXXRecordDecl *Pattern = CTD->getTemplatedDecl();
167 bool TypeOverride = isa<TypeDecl>(D);
168 for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) {
169 if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
170 ND = CTD->getTemplatedDecl();
171 if (ND->isImplicit())
173 // Types can override other types.
175 if (ND->getKind() != D->getKind())
177 } else if (!isa<TypeDecl>(ND))
179 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
180 const auto *DFD = cast<FunctionDecl>(D);
181 // Function overrides are approximated using the number of parameters.
182 if (FD->getStorageClass() != DFD->getStorageClass() ||
183 FD->getNumParams() != DFD->getNumParams())
186 Relations.emplace_back(
187 SymbolRoleSet(SymbolRole::RelationOverrideOf) |
188 SymbolRoleSet(SymbolRole::RelationSpecializationOf),
194 bool VisitFunctionDecl(const FunctionDecl *D) {
198 SymbolRoleSet Roles{};
199 SmallVector<SymbolRelation, 4> Relations;
200 if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
201 if (CXXMD->isVirtual())
202 Roles |= (unsigned)SymbolRole::Dynamic;
203 for (auto I = CXXMD->begin_overridden_methods(),
204 E = CXXMD->end_overridden_methods(); I != E; ++I) {
205 Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
208 gatherTemplatePseudoOverrides(D, Relations);
209 if (const auto *Base = D->getPrimaryTemplate())
211 SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
212 Base->getTemplatedDecl()));
214 TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations));
217 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
218 IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(),
219 Ctor->getParent(), Ctor->getDeclContext());
221 // Constructor initializers.
222 for (const auto *Init : Ctor->inits()) {
223 if (Init->isWritten()) {
224 IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
225 if (const FieldDecl *Member = Init->getAnyMember())
226 IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D,
227 (unsigned)SymbolRole::Write);
228 IndexCtx.indexBody(Init->getInit(), D, D);
231 } else if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(D)) {
232 if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) {
233 IndexCtx.handleReference(Dtor->getParent(),
234 TypeNameInfo->getTypeLoc().getLocStart(),
235 Dtor->getParent(), Dtor->getDeclContext());
239 if (D->isThisDeclarationADefinition()) {
240 const Stmt *Body = D->getBody();
242 IndexCtx.indexBody(Body, D, D);
248 bool VisitVarDecl(const VarDecl *D) {
249 SmallVector<SymbolRelation, 4> Relations;
250 gatherTemplatePseudoOverrides(D, Relations);
251 TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
253 IndexCtx.indexBody(D->getInit(), D);
257 bool VisitFieldDecl(const FieldDecl *D) {
258 SmallVector<SymbolRelation, 4> Relations;
259 gatherTemplatePseudoOverrides(D, Relations);
260 TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
263 IndexCtx.indexBody(D->getBitWidth(), D);
264 else if (D->hasInClassInitializer())
265 IndexCtx.indexBody(D->getInClassInitializer(), D);
269 bool VisitObjCIvarDecl(const ObjCIvarDecl *D) {
270 if (D->getSynthesize()) {
271 // handled in VisitObjCPropertyImplDecl
274 TRY_DECL(D, IndexCtx.handleDecl(D));
279 bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
284 bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
285 TRY_DECL(D, IndexCtx.handleDecl(D));
286 IndexCtx.indexBody(D->getInitExpr(), D);
290 bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
291 if (!D->isTransparentTag()) {
292 SmallVector<SymbolRelation, 4> Relations;
293 gatherTemplatePseudoOverrides(D, Relations);
294 TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
295 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
300 bool VisitTagDecl(const TagDecl *D) {
301 // Non-free standing tags are handled in indexTypeSourceInfo.
302 if (D->isFreeStanding()) {
303 if (D->isThisDeclarationADefinition()) {
304 SmallVector<SymbolRelation, 4> Relations;
305 gatherTemplatePseudoOverrides(D, Relations);
306 IndexCtx.indexTagDecl(D, Relations);
308 auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
309 return IndexCtx.handleReference(D, D->getLocation(), Parent,
310 D->getLexicalDeclContext(),
317 bool handleReferencedProtocols(const ObjCProtocolList &ProtList,
318 const ObjCContainerDecl *ContD,
319 SourceLocation SuperLoc) {
320 ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
321 for (ObjCInterfaceDecl::protocol_iterator
322 I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
323 SourceLocation Loc = *LI;
324 ObjCProtocolDecl *PD = *I;
325 SymbolRoleSet roles{};
327 roles |= (SymbolRoleSet)SymbolRole::Implicit;
328 TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles,
329 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD}));
334 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
335 if (D->isThisDeclarationADefinition()) {
336 TRY_DECL(D, IndexCtx.handleDecl(D));
337 SourceLocation SuperLoc = D->getSuperClassLoc();
338 if (auto *SuperD = D->getSuperClass()) {
339 bool hasSuperTypedef = false;
340 if (auto *TInfo = D->getSuperClassTInfo()) {
341 if (auto *TT = TInfo->getType()->getAs<TypedefType>()) {
342 if (auto *TD = TT->getDecl()) {
343 hasSuperTypedef = true;
344 TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D,
349 SymbolRoleSet superRoles{};
351 superRoles |= (SymbolRoleSet)SymbolRole::Implicit;
352 TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles,
353 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D}));
355 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
357 TRY_TO(IndexCtx.indexDeclContext(D));
359 return IndexCtx.handleReference(D, D->getLocation(), nullptr,
360 D->getDeclContext(), SymbolRoleSet());
365 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
366 if (D->isThisDeclarationADefinition()) {
367 TRY_DECL(D, IndexCtx.handleDecl(D));
368 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
369 /*superLoc=*/SourceLocation()));
370 TRY_TO(IndexCtx.indexDeclContext(D));
372 return IndexCtx.handleReference(D, D->getLocation(), nullptr,
373 D->getDeclContext(), SymbolRoleSet());
378 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
379 const ObjCInterfaceDecl *Class = D->getClassInterface();
383 if (Class->isImplicitInterfaceDecl())
384 IndexCtx.handleDecl(Class);
386 TRY_DECL(D, IndexCtx.handleDecl(D));
388 // Visit implicit @synthesize property implementations first as their
389 // location is reported at the name of the @implementation block. This
390 // serves no purpose other than to simplify the FileCheck-based tests.
391 for (const auto *I : D->property_impls()) {
392 if (I->getLocation().isInvalid())
393 IndexCtx.indexDecl(I);
395 for (const auto *I : D->decls()) {
396 if (!isa<ObjCPropertyImplDecl>(I) ||
397 cast<ObjCPropertyImplDecl>(I)->getLocation().isValid())
398 IndexCtx.indexDecl(I);
404 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
405 if (!IndexCtx.shouldIndex(D))
407 const ObjCInterfaceDecl *C = D->getClassInterface();
410 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(),
412 (unsigned)SymbolRole::RelationExtendedBy, D
414 SourceLocation CategoryLoc = D->getCategoryNameLoc();
415 if (!CategoryLoc.isValid())
416 CategoryLoc = D->getLocation();
417 TRY_TO(IndexCtx.handleDecl(D, CategoryLoc));
418 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
419 /*superLoc=*/SourceLocation()));
420 TRY_TO(IndexCtx.indexDeclContext(D));
424 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
425 const ObjCCategoryDecl *Cat = D->getCategoryDecl();
428 const ObjCInterfaceDecl *C = D->getClassInterface();
430 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D,
432 SourceLocation CategoryLoc = D->getCategoryNameLoc();
433 if (!CategoryLoc.isValid())
434 CategoryLoc = D->getLocation();
435 TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc));
436 IndexCtx.indexDeclContext(D);
440 bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
441 // Methods associated with a property, even user-declared ones, are
442 // handled when we handle the property.
443 if (D->isPropertyAccessor())
450 bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
451 if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
452 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
453 handleObjCMethod(MD, D);
454 if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
455 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
456 handleObjCMethod(MD, D);
457 TRY_DECL(D, IndexCtx.handleDecl(D));
458 if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>())
459 IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D,
460 D->getLexicalDeclContext(), false, true);
461 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
465 bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
466 ObjCPropertyDecl *PD = D->getPropertyDecl();
467 auto *Container = cast<ObjCImplDecl>(D->getDeclContext());
468 SourceLocation Loc = D->getLocation();
469 SymbolRoleSet Roles = 0;
470 SmallVector<SymbolRelation, 1> Relations;
472 if (ObjCIvarDecl *ID = D->getPropertyIvarDecl())
473 Relations.push_back({(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID});
474 if (Loc.isInvalid()) {
475 Loc = Container->getLocation();
476 Roles |= (SymbolRoleSet)SymbolRole::Implicit;
478 TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations));
480 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
483 assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
484 SymbolRoleSet AccessorMethodRoles =
485 SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit);
486 if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
487 if (MD->isPropertyAccessor() &&
488 !hasUserDefined(MD, Container))
489 IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
491 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
492 if (MD->isPropertyAccessor() &&
493 !hasUserDefined(MD, Container))
494 IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
496 if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
497 if (IvarD->getSynthesize()) {
498 // For synthesized ivars, use the location of its name in the
499 // corresponding @synthesize. If there isn't one, use the containing
500 // @implementation's location, rather than the property's location,
501 // otherwise the header file containing the @interface will have different
502 // indexing contents based on whether the @implementation was present or
503 // not in the translation unit.
504 SymbolRoleSet IvarRoles = 0;
505 SourceLocation IvarLoc = D->getPropertyIvarDeclLoc();
506 if (D->getLocation().isInvalid()) {
507 IvarLoc = Container->getLocation();
508 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
509 } else if (D->getLocation() == IvarLoc) {
510 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
512 TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles));
514 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
515 D->getDeclContext(), SymbolRoleSet());
521 bool VisitNamespaceDecl(const NamespaceDecl *D) {
522 TRY_DECL(D, IndexCtx.handleDecl(D));
523 IndexCtx.indexDeclContext(D);
527 bool VisitUsingDecl(const UsingDecl *D) {
528 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
529 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
531 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
532 D->getLexicalDeclContext());
533 for (const auto *I : D->shadows())
534 IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent,
535 D->getLexicalDeclContext(), SymbolRoleSet());
539 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
540 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
541 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
543 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
544 D->getLexicalDeclContext());
545 return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
546 D->getLocation(), Parent,
547 D->getLexicalDeclContext(),
551 bool VisitClassTemplateSpecializationDecl(const
552 ClassTemplateSpecializationDecl *D) {
553 // FIXME: Notify subsequent callbacks if info comes from implicit
555 if (D->isThisDeclarationADefinition()) {
556 llvm::PointerUnion<ClassTemplateDecl *,
557 ClassTemplatePartialSpecializationDecl *>
558 Template = D->getSpecializedTemplateOrPartial();
559 const Decl *SpecializationOf =
560 Template.is<ClassTemplateDecl *>()
561 ? (Decl *)Template.get<ClassTemplateDecl *>()
562 : Template.get<ClassTemplatePartialSpecializationDecl *>();
563 IndexCtx.indexTagDecl(
564 D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
567 if (TypeSourceInfo *TSI = D->getTypeAsWritten())
568 IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr,
569 D->getLexicalDeclContext());
573 bool VisitTemplateDecl(const TemplateDecl *D) {
574 // FIXME: Template parameters.
575 return Visit(D->getTemplatedDecl());
578 bool VisitFriendDecl(const FriendDecl *D) {
579 if (auto ND = D->getFriendDecl()) {
580 // FIXME: Ignore a class template in a dependent context, these are not
581 // linked properly with their redeclarations, ending up with duplicate
583 // See comment "Friend templates are visible in fairly strange ways." in
584 // SemaTemplate.cpp which precedes code that prevents the friend template
585 // from becoming visible from the enclosing context.
586 if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext())
590 if (auto Ty = D->getFriendType()) {
591 IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext()));
596 bool VisitImportDecl(const ImportDecl *D) {
597 return IndexCtx.importedModule(D);
601 } // anonymous namespace
603 bool IndexingContext::indexDecl(const Decl *D) {
604 if (D->isImplicit() && shouldIgnoreIfImplicit(D))
607 if (isTemplateImplicitInstantiation(D))
610 IndexingDeclVisitor Visitor(*this);
611 bool ShouldContinue = Visitor.Visit(D);
615 if (!Visitor.Handled && isa<DeclContext>(D))
616 return indexDeclContext(cast<DeclContext>(D));
621 bool IndexingContext::indexDeclContext(const DeclContext *DC) {
622 for (const auto *I : DC->decls())
628 bool IndexingContext::indexTopLevelDecl(const Decl *D) {
629 if (D->getLocation().isInvalid())
632 if (isa<ObjCMethodDecl>(D))
633 return true; // Wait for the objc container.
638 bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
639 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
640 if (!indexTopLevelDecl(*I))