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::RelationSpecializationOf), ND);
192 bool VisitFunctionDecl(const FunctionDecl *D) {
196 SymbolRoleSet Roles{};
197 SmallVector<SymbolRelation, 4> Relations;
198 if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
199 if (CXXMD->isVirtual())
200 Roles |= (unsigned)SymbolRole::Dynamic;
201 for (auto I = CXXMD->begin_overridden_methods(),
202 E = CXXMD->end_overridden_methods(); I != E; ++I) {
203 Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
206 gatherTemplatePseudoOverrides(D, Relations);
207 if (const auto *Base = D->getPrimaryTemplate())
209 SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
210 Base->getTemplatedDecl()));
212 TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations));
215 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
216 IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(),
217 Ctor->getParent(), Ctor->getDeclContext());
219 // Constructor initializers.
220 for (const auto *Init : Ctor->inits()) {
221 if (Init->isWritten()) {
222 IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
223 if (const FieldDecl *Member = Init->getAnyMember())
224 IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D,
225 (unsigned)SymbolRole::Write);
226 IndexCtx.indexBody(Init->getInit(), D, D);
229 } else if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(D)) {
230 if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) {
231 IndexCtx.handleReference(Dtor->getParent(),
232 TypeNameInfo->getTypeLoc().getLocStart(),
233 Dtor->getParent(), Dtor->getDeclContext());
237 if (D->isThisDeclarationADefinition()) {
238 const Stmt *Body = D->getBody();
240 IndexCtx.indexBody(Body, D, D);
246 bool VisitVarDecl(const VarDecl *D) {
247 SmallVector<SymbolRelation, 4> Relations;
248 gatherTemplatePseudoOverrides(D, Relations);
249 TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
251 IndexCtx.indexBody(D->getInit(), D);
255 bool VisitFieldDecl(const FieldDecl *D) {
256 SmallVector<SymbolRelation, 4> Relations;
257 gatherTemplatePseudoOverrides(D, Relations);
258 TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
261 IndexCtx.indexBody(D->getBitWidth(), D);
262 else if (D->hasInClassInitializer())
263 IndexCtx.indexBody(D->getInClassInitializer(), D);
267 bool VisitObjCIvarDecl(const ObjCIvarDecl *D) {
268 if (D->getSynthesize()) {
269 // handled in VisitObjCPropertyImplDecl
272 TRY_DECL(D, IndexCtx.handleDecl(D));
277 bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
282 bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
283 TRY_DECL(D, IndexCtx.handleDecl(D));
284 IndexCtx.indexBody(D->getInitExpr(), D);
288 bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
289 if (!D->isTransparentTag()) {
290 SmallVector<SymbolRelation, 4> Relations;
291 gatherTemplatePseudoOverrides(D, Relations);
292 TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
293 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
298 bool VisitTagDecl(const TagDecl *D) {
299 // Non-free standing tags are handled in indexTypeSourceInfo.
300 if (D->isFreeStanding()) {
301 if (D->isThisDeclarationADefinition()) {
302 SmallVector<SymbolRelation, 4> Relations;
303 gatherTemplatePseudoOverrides(D, Relations);
304 IndexCtx.indexTagDecl(D, Relations);
306 auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
307 return IndexCtx.handleReference(D, D->getLocation(), Parent,
308 D->getLexicalDeclContext(),
315 bool handleReferencedProtocols(const ObjCProtocolList &ProtList,
316 const ObjCContainerDecl *ContD,
317 SourceLocation SuperLoc) {
318 ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
319 for (ObjCInterfaceDecl::protocol_iterator
320 I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
321 SourceLocation Loc = *LI;
322 ObjCProtocolDecl *PD = *I;
323 SymbolRoleSet roles{};
325 roles |= (SymbolRoleSet)SymbolRole::Implicit;
326 TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles,
327 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD}));
332 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
333 if (D->isThisDeclarationADefinition()) {
334 TRY_DECL(D, IndexCtx.handleDecl(D));
335 SourceLocation SuperLoc = D->getSuperClassLoc();
336 if (auto *SuperD = D->getSuperClass()) {
337 bool hasSuperTypedef = false;
338 if (auto *TInfo = D->getSuperClassTInfo()) {
339 if (auto *TT = TInfo->getType()->getAs<TypedefType>()) {
340 if (auto *TD = TT->getDecl()) {
341 hasSuperTypedef = true;
342 TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D,
347 SymbolRoleSet superRoles{};
349 superRoles |= (SymbolRoleSet)SymbolRole::Implicit;
350 TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles,
351 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D}));
353 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
355 TRY_TO(IndexCtx.indexDeclContext(D));
357 return IndexCtx.handleReference(D, D->getLocation(), nullptr,
358 D->getDeclContext(), SymbolRoleSet());
363 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
364 if (D->isThisDeclarationADefinition()) {
365 TRY_DECL(D, IndexCtx.handleDecl(D));
366 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
367 /*superLoc=*/SourceLocation()));
368 TRY_TO(IndexCtx.indexDeclContext(D));
370 return IndexCtx.handleReference(D, D->getLocation(), nullptr,
371 D->getDeclContext(), SymbolRoleSet());
376 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
377 const ObjCInterfaceDecl *Class = D->getClassInterface();
381 if (Class->isImplicitInterfaceDecl())
382 IndexCtx.handleDecl(Class);
384 TRY_DECL(D, IndexCtx.handleDecl(D));
386 // Visit implicit @synthesize property implementations first as their
387 // location is reported at the name of the @implementation block. This
388 // serves no purpose other than to simplify the FileCheck-based tests.
389 for (const auto *I : D->property_impls()) {
390 if (I->getLocation().isInvalid())
391 IndexCtx.indexDecl(I);
393 for (const auto *I : D->decls()) {
394 if (!isa<ObjCPropertyImplDecl>(I) ||
395 cast<ObjCPropertyImplDecl>(I)->getLocation().isValid())
396 IndexCtx.indexDecl(I);
402 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
403 if (!IndexCtx.shouldIndex(D))
405 const ObjCInterfaceDecl *C = D->getClassInterface();
408 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(),
410 (unsigned)SymbolRole::RelationExtendedBy, D
412 SourceLocation CategoryLoc = D->getCategoryNameLoc();
413 if (!CategoryLoc.isValid())
414 CategoryLoc = D->getLocation();
415 TRY_TO(IndexCtx.handleDecl(D, CategoryLoc));
416 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
417 /*superLoc=*/SourceLocation()));
418 TRY_TO(IndexCtx.indexDeclContext(D));
422 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
423 const ObjCCategoryDecl *Cat = D->getCategoryDecl();
426 const ObjCInterfaceDecl *C = D->getClassInterface();
428 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D,
430 SourceLocation CategoryLoc = D->getCategoryNameLoc();
431 if (!CategoryLoc.isValid())
432 CategoryLoc = D->getLocation();
433 TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc));
434 IndexCtx.indexDeclContext(D);
438 bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
439 // Methods associated with a property, even user-declared ones, are
440 // handled when we handle the property.
441 if (D->isPropertyAccessor())
448 bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
449 if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
450 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
451 handleObjCMethod(MD, D);
452 if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
453 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
454 handleObjCMethod(MD, D);
455 TRY_DECL(D, IndexCtx.handleDecl(D));
456 if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>())
457 IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D,
458 D->getLexicalDeclContext(), false, true);
459 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
463 bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
464 ObjCPropertyDecl *PD = D->getPropertyDecl();
465 auto *Container = cast<ObjCImplDecl>(D->getDeclContext());
466 SourceLocation Loc = D->getLocation();
467 SymbolRoleSet Roles = 0;
468 SmallVector<SymbolRelation, 1> Relations;
470 if (ObjCIvarDecl *ID = D->getPropertyIvarDecl())
471 Relations.push_back({(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID});
472 if (Loc.isInvalid()) {
473 Loc = Container->getLocation();
474 Roles |= (SymbolRoleSet)SymbolRole::Implicit;
476 TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations));
478 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
481 assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
482 SymbolRoleSet AccessorMethodRoles =
483 SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit);
484 if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
485 if (MD->isPropertyAccessor() &&
486 !hasUserDefined(MD, Container))
487 IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
489 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
490 if (MD->isPropertyAccessor() &&
491 !hasUserDefined(MD, Container))
492 IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
494 if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
495 if (IvarD->getSynthesize()) {
496 // For synthesized ivars, use the location of its name in the
497 // corresponding @synthesize. If there isn't one, use the containing
498 // @implementation's location, rather than the property's location,
499 // otherwise the header file containing the @interface will have different
500 // indexing contents based on whether the @implementation was present or
501 // not in the translation unit.
502 SymbolRoleSet IvarRoles = 0;
503 SourceLocation IvarLoc = D->getPropertyIvarDeclLoc();
504 if (D->getLocation().isInvalid()) {
505 IvarLoc = Container->getLocation();
506 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
507 } else if (D->getLocation() == IvarLoc) {
508 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
510 TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles));
512 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
513 D->getDeclContext(), SymbolRoleSet());
519 bool VisitNamespaceDecl(const NamespaceDecl *D) {
520 TRY_DECL(D, IndexCtx.handleDecl(D));
521 IndexCtx.indexDeclContext(D);
525 bool VisitUsingDecl(const UsingDecl *D) {
526 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
527 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
529 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
530 D->getLexicalDeclContext());
531 for (const auto *I : D->shadows())
532 IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent,
533 D->getLexicalDeclContext(), SymbolRoleSet());
537 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
538 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
539 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
541 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
542 D->getLexicalDeclContext());
543 return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
544 D->getLocation(), Parent,
545 D->getLexicalDeclContext(),
549 bool VisitClassTemplateSpecializationDecl(const
550 ClassTemplateSpecializationDecl *D) {
551 // FIXME: Notify subsequent callbacks if info comes from implicit
553 if (D->isThisDeclarationADefinition()) {
554 llvm::PointerUnion<ClassTemplateDecl *,
555 ClassTemplatePartialSpecializationDecl *>
556 Template = D->getSpecializedTemplateOrPartial();
557 const Decl *SpecializationOf =
558 Template.is<ClassTemplateDecl *>()
559 ? (Decl *)Template.get<ClassTemplateDecl *>()
560 : Template.get<ClassTemplatePartialSpecializationDecl *>();
561 IndexCtx.indexTagDecl(
562 D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
565 if (TypeSourceInfo *TSI = D->getTypeAsWritten())
566 IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr,
567 D->getLexicalDeclContext());
571 bool VisitTemplateDecl(const TemplateDecl *D) {
572 // FIXME: Template parameters.
573 return Visit(D->getTemplatedDecl());
576 bool VisitFriendDecl(const FriendDecl *D) {
577 if (auto ND = D->getFriendDecl()) {
578 // FIXME: Ignore a class template in a dependent context, these are not
579 // linked properly with their redeclarations, ending up with duplicate
581 // See comment "Friend templates are visible in fairly strange ways." in
582 // SemaTemplate.cpp which precedes code that prevents the friend template
583 // from becoming visible from the enclosing context.
584 if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext())
588 if (auto Ty = D->getFriendType()) {
589 IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext()));
594 bool VisitImportDecl(const ImportDecl *D) {
595 return IndexCtx.importedModule(D);
599 } // anonymous namespace
601 bool IndexingContext::indexDecl(const Decl *D) {
602 if (D->isImplicit() && shouldIgnoreIfImplicit(D))
605 if (isTemplateImplicitInstantiation(D))
608 IndexingDeclVisitor Visitor(*this);
609 bool ShouldContinue = Visitor.Visit(D);
613 if (!Visitor.Handled && isa<DeclContext>(D))
614 return indexDeclContext(cast<DeclContext>(D));
619 bool IndexingContext::indexDeclContext(const DeclContext *DC) {
620 for (const auto *I : DC->decls())
626 bool IndexingContext::indexTopLevelDecl(const Decl *D) {
627 if (D->getLocation().isInvalid())
630 if (isa<ObjCMethodDecl>(D))
631 return true; // Wait for the objc container.
636 bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
637 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
638 if (!indexTopLevelDecl(*I))