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_TO(CALL_EXPR) \
25 class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
26 IndexingContext &IndexCtx;
29 explicit IndexingDeclVisitor(IndexingContext &indexCtx)
30 : IndexCtx(indexCtx) { }
34 bool VisitDecl(const Decl *D) {
39 /// \brief Returns true if the given method has been defined explicitly by the
41 static bool hasUserDefined(const ObjCMethodDecl *D,
42 const ObjCImplDecl *Container) {
43 const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
44 D->isInstanceMethod());
45 return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
48 void handleDeclarator(const DeclaratorDecl *D,
49 const NamedDecl *Parent = nullptr,
50 bool isIBType = false) {
51 if (!Parent) Parent = D;
53 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent,
54 Parent->getLexicalDeclContext(),
55 /*isBase=*/false, isIBType);
56 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
57 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
58 // Only index parameters in definitions, parameters in declarations are
60 if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
61 auto *DC = Parm->getDeclContext();
62 if (auto *FD = dyn_cast<FunctionDecl>(DC)) {
63 if (FD->isThisDeclarationADefinition())
64 IndexCtx.handleDecl(Parm);
65 } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) {
66 if (MD->isThisDeclarationADefinition())
67 IndexCtx.handleDecl(Parm);
69 IndexCtx.handleDecl(Parm);
71 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
72 if (FD->isThisDeclarationADefinition()) {
73 for (auto PI : FD->parameters()) {
74 IndexCtx.handleDecl(PI);
81 bool handleObjCMethod(const ObjCMethodDecl *D,
82 const ObjCPropertyDecl *AssociatedProp = nullptr) {
83 SmallVector<SymbolRelation, 4> Relations;
84 SmallVector<const ObjCMethodDecl*, 4> Overriden;
86 D->getOverriddenMethods(Overriden);
87 for(auto overridden: Overriden) {
88 Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf,
92 Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf,
95 // getLocation() returns beginning token of a method declaration, but for
96 // indexing purposes we want to point to the base name.
97 SourceLocation MethodLoc = D->getSelectorStartLoc();
98 if (MethodLoc.isInvalid())
99 MethodLoc = D->getLocation();
101 SourceLocation AttrLoc;
103 // check for (getter=/setter=)
104 if (AssociatedProp) {
105 bool isGetter = !D->param_size();
107 AssociatedProp->getGetterNameLoc():
108 AssociatedProp->getSetterNameLoc();
111 SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic;
112 if (D->isImplicit()) {
113 if (AttrLoc.isValid()) {
116 Roles |= (SymbolRoleSet)SymbolRole::Implicit;
118 } else if (AttrLoc.isValid()) {
119 IndexCtx.handleReference(D, AttrLoc, cast<NamedDecl>(D->getDeclContext()),
120 D->getDeclContext(), 0);
123 if (!IndexCtx.handleDecl(D, MethodLoc, Roles, Relations))
125 IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
126 bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>();
127 for (const auto *I : D->parameters()) {
128 handleDeclarator(I, D, /*isIBType=*/hasIBActionAndFirst);
129 hasIBActionAndFirst = false;
132 if (D->isThisDeclarationADefinition()) {
133 const Stmt *Body = D->getBody();
135 IndexCtx.indexBody(Body, D, D);
141 bool VisitFunctionDecl(const FunctionDecl *D) {
145 SymbolRoleSet Roles{};
146 SmallVector<SymbolRelation, 4> Relations;
147 if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
148 if (CXXMD->isVirtual())
149 Roles |= (unsigned)SymbolRole::Dynamic;
150 for (auto I = CXXMD->begin_overridden_methods(),
151 E = CXXMD->end_overridden_methods(); I != E; ++I) {
152 Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
156 if (!IndexCtx.handleDecl(D, Roles, Relations))
160 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
161 IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(),
162 Ctor->getParent(), Ctor->getDeclContext());
164 // Constructor initializers.
165 for (const auto *Init : Ctor->inits()) {
166 if (Init->isWritten()) {
167 IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
168 if (const FieldDecl *Member = Init->getAnyMember())
169 IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D,
170 (unsigned)SymbolRole::Write);
171 IndexCtx.indexBody(Init->getInit(), D, D);
174 } else if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(D)) {
175 if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) {
176 IndexCtx.handleReference(Dtor->getParent(),
177 TypeNameInfo->getTypeLoc().getLocStart(),
178 Dtor->getParent(), Dtor->getDeclContext());
182 if (D->isThisDeclarationADefinition()) {
183 const Stmt *Body = D->getBody();
185 IndexCtx.indexBody(Body, D, D);
191 bool VisitVarDecl(const VarDecl *D) {
192 if (!IndexCtx.handleDecl(D))
195 IndexCtx.indexBody(D->getInit(), D);
199 bool VisitFieldDecl(const FieldDecl *D) {
200 if (!IndexCtx.handleDecl(D))
204 IndexCtx.indexBody(D->getBitWidth(), D);
205 else if (D->hasInClassInitializer())
206 IndexCtx.indexBody(D->getInClassInitializer(), D);
210 bool VisitObjCIvarDecl(const ObjCIvarDecl *D) {
211 if (D->getSynthesize()) {
212 // handled in VisitObjCPropertyImplDecl
215 if (!IndexCtx.handleDecl(D))
221 bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
226 bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
227 if (!IndexCtx.handleDecl(D))
229 IndexCtx.indexBody(D->getInitExpr(), D);
233 bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
234 if (!D->isTransparentTag())
235 if (!IndexCtx.handleDecl(D))
237 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
241 bool VisitTagDecl(const TagDecl *D) {
242 // Non-free standing tags are handled in indexTypeSourceInfo.
243 if (D->isFreeStanding()) {
244 if (D->isThisDeclarationADefinition()) {
245 IndexCtx.indexTagDecl(D);
247 auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
248 return IndexCtx.handleReference(D, D->getLocation(), Parent,
249 D->getLexicalDeclContext(),
256 bool handleReferencedProtocols(const ObjCProtocolList &ProtList,
257 const ObjCContainerDecl *ContD,
258 SourceLocation SuperLoc) {
259 ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
260 for (ObjCInterfaceDecl::protocol_iterator
261 I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
262 SourceLocation Loc = *LI;
263 ObjCProtocolDecl *PD = *I;
264 SymbolRoleSet roles{};
266 roles |= (SymbolRoleSet)SymbolRole::Implicit;
267 TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles,
268 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD}));
273 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
274 if (D->isThisDeclarationADefinition()) {
275 TRY_TO(IndexCtx.handleDecl(D));
276 SourceLocation SuperLoc = D->getSuperClassLoc();
277 if (auto *SuperD = D->getSuperClass()) {
278 bool hasSuperTypedef = false;
279 if (auto *TInfo = D->getSuperClassTInfo()) {
280 if (auto *TT = TInfo->getType()->getAs<TypedefType>()) {
281 if (auto *TD = TT->getDecl()) {
282 hasSuperTypedef = true;
283 TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D,
288 SymbolRoleSet superRoles{};
290 superRoles |= (SymbolRoleSet)SymbolRole::Implicit;
291 TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles,
292 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D}));
294 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
296 TRY_TO(IndexCtx.indexDeclContext(D));
298 return IndexCtx.handleReference(D, D->getLocation(), nullptr,
299 D->getDeclContext(), SymbolRoleSet());
304 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
305 if (D->isThisDeclarationADefinition()) {
306 TRY_TO(IndexCtx.handleDecl(D));
307 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
308 /*superLoc=*/SourceLocation()));
309 TRY_TO(IndexCtx.indexDeclContext(D));
311 return IndexCtx.handleReference(D, D->getLocation(), nullptr,
312 D->getDeclContext(), SymbolRoleSet());
317 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
318 const ObjCInterfaceDecl *Class = D->getClassInterface();
322 if (Class->isImplicitInterfaceDecl())
323 IndexCtx.handleDecl(Class);
325 if (!IndexCtx.handleDecl(D))
328 // Visit implicit @synthesize property implementations first as their
329 // location is reported at the name of the @implementation block. This
330 // serves no purpose other than to simplify the FileCheck-based tests.
331 for (const auto *I : D->property_impls()) {
332 if (I->getLocation().isInvalid())
333 IndexCtx.indexDecl(I);
335 for (const auto *I : D->decls()) {
336 if (!isa<ObjCPropertyImplDecl>(I) ||
337 cast<ObjCPropertyImplDecl>(I)->getLocation().isValid())
338 IndexCtx.indexDecl(I);
344 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
345 const ObjCInterfaceDecl *C = D->getClassInterface();
348 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(),
350 (unsigned)SymbolRole::RelationExtendedBy, D
352 SourceLocation CategoryLoc = D->getCategoryNameLoc();
353 if (!CategoryLoc.isValid())
354 CategoryLoc = D->getLocation();
355 TRY_TO(IndexCtx.handleDecl(D, CategoryLoc));
356 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
357 /*superLoc=*/SourceLocation()));
358 TRY_TO(IndexCtx.indexDeclContext(D));
362 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
363 const ObjCCategoryDecl *Cat = D->getCategoryDecl();
366 const ObjCInterfaceDecl *C = D->getClassInterface();
368 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D,
370 SourceLocation CategoryLoc = D->getCategoryNameLoc();
371 if (!CategoryLoc.isValid())
372 CategoryLoc = D->getLocation();
373 if (!IndexCtx.handleDecl(D, CategoryLoc))
375 IndexCtx.indexDeclContext(D);
379 bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
380 // Methods associated with a property, even user-declared ones, are
381 // handled when we handle the property.
382 if (D->isPropertyAccessor())
389 bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
390 if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
391 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
392 handleObjCMethod(MD, D);
393 if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
394 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
395 handleObjCMethod(MD, D);
396 if (!IndexCtx.handleDecl(D))
398 if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>())
399 IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D,
400 D->getLexicalDeclContext(), false, true);
401 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
405 bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
406 ObjCPropertyDecl *PD = D->getPropertyDecl();
407 auto *Container = cast<ObjCImplDecl>(D->getDeclContext());
408 SourceLocation Loc = D->getLocation();
409 SymbolRoleSet Roles = 0;
410 SmallVector<SymbolRelation, 1> Relations;
412 if (ObjCIvarDecl *ID = D->getPropertyIvarDecl())
413 Relations.push_back({(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID});
414 if (Loc.isInvalid()) {
415 Loc = Container->getLocation();
416 Roles |= (SymbolRoleSet)SymbolRole::Implicit;
418 if (!IndexCtx.handleDecl(D, Loc, Roles, Relations))
421 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
424 assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
425 if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
426 if (MD->isPropertyAccessor() &&
427 !hasUserDefined(MD, Container))
428 IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {},
431 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
432 if (MD->isPropertyAccessor() &&
433 !hasUserDefined(MD, Container))
434 IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {},
437 if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
438 if (IvarD->getSynthesize()) {
439 // For synthesized ivars, use the location of its name in the
440 // corresponding @synthesize. If there isn't one, use the containing
441 // @implementation's location, rather than the property's location,
442 // otherwise the header file containing the @interface will have different
443 // indexing contents based on whether the @implementation was present or
444 // not in the translation unit.
445 SymbolRoleSet IvarRoles = 0;
446 SourceLocation IvarLoc = D->getPropertyIvarDeclLoc();
447 if (D->getLocation().isInvalid()) {
448 IvarLoc = Container->getLocation();
449 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
450 } else if (D->getLocation() == IvarLoc) {
451 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
453 if(!IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles))
456 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
457 D->getDeclContext(), SymbolRoleSet());
463 bool VisitNamespaceDecl(const NamespaceDecl *D) {
464 if (!IndexCtx.handleDecl(D))
466 IndexCtx.indexDeclContext(D);
470 bool VisitUsingDecl(const UsingDecl *D) {
471 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
472 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
474 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
475 D->getLexicalDeclContext());
476 for (const auto *I : D->shadows())
477 IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent,
478 D->getLexicalDeclContext(), SymbolRoleSet());
482 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
483 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
484 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
486 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
487 D->getLexicalDeclContext());
488 return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
489 D->getLocation(), Parent,
490 D->getLexicalDeclContext(),
494 bool VisitClassTemplateSpecializationDecl(const
495 ClassTemplateSpecializationDecl *D) {
496 // FIXME: Notify subsequent callbacks if info comes from implicit
498 if (D->isThisDeclarationADefinition())
499 IndexCtx.indexTagDecl(D);
503 bool VisitTemplateDecl(const TemplateDecl *D) {
504 // FIXME: Template parameters.
505 return Visit(D->getTemplatedDecl());
508 bool VisitFriendDecl(const FriendDecl *D) {
509 if (auto ND = D->getFriendDecl()) {
510 // FIXME: Ignore a class template in a dependent context, these are not
511 // linked properly with their redeclarations, ending up with duplicate
513 // See comment "Friend templates are visible in fairly strange ways." in
514 // SemaTemplate.cpp which precedes code that prevents the friend template
515 // from becoming visible from the enclosing context.
516 if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext())
520 if (auto Ty = D->getFriendType()) {
521 IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext()));
526 bool VisitImportDecl(const ImportDecl *D) {
527 return IndexCtx.importedModule(D);
531 } // anonymous namespace
533 bool IndexingContext::indexDecl(const Decl *D) {
534 if (D->isImplicit() && shouldIgnoreIfImplicit(D))
537 if (isTemplateImplicitInstantiation(D))
540 IndexingDeclVisitor Visitor(*this);
541 bool ShouldContinue = Visitor.Visit(D);
545 if (!Visitor.Handled && isa<DeclContext>(D))
546 return indexDeclContext(cast<DeclContext>(D));
551 bool IndexingContext::indexDeclContext(const DeclContext *DC) {
552 for (const auto *I : DC->decls())
558 bool IndexingContext::indexTopLevelDecl(const Decl *D) {
559 if (D->getLocation().isInvalid())
562 if (isa<ObjCMethodDecl>(D))
563 return true; // Wait for the objc container.
568 bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
569 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
570 if (!indexTopLevelDecl(*I))