1 //===- IndexDecl.cpp - Indexing declarations ------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "IndexingContext.h" 11 #include "clang/Index/IndexDataConsumer.h" 12 #include "clang/AST/DeclVisitor.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: 36 explicit IndexingDeclVisitor(IndexingContext &indexCtx) 37 : IndexCtx(indexCtx) { } 38 39 bool Handled = true; 40 41 bool VisitDecl(const Decl *D) { 42 Handled = false; 43 return true; 44 } 45 46 /// \brief Returns true if the given method has been defined explicitly by the 47 /// user. 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(); 53 } 54 55 void handleDeclarator(const DeclaratorDecl *D, 56 const NamedDecl *Parent = nullptr, 57 bool isIBType = false) { 58 if (!Parent) Parent = D; 59 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 66 // not useful. 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); 75 } else { 76 IndexCtx.handleDecl(Parm); 77 } 78 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 79 if (FD->isThisDeclarationADefinition()) { 80 for (auto PI : FD->parameters()) { 81 IndexCtx.handleDecl(PI); 82 } 83 } 84 } 85 } 86 } 87 88 bool handleObjCMethod(const ObjCMethodDecl *D, 89 const ObjCPropertyDecl *AssociatedProp = nullptr) { 90 SmallVector<SymbolRelation, 4> Relations; 91 SmallVector<const ObjCMethodDecl*, 4> Overriden; 92 93 D->getOverriddenMethods(Overriden); 94 for(auto overridden: Overriden) { 95 Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf, 96 overridden); 97 } 98 if (AssociatedProp) 99 Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf, 100 AssociatedProp); 101 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(); 107 108 SourceLocation AttrLoc; 109 110 // check for (getter=/setter=) 111 if (AssociatedProp) { 112 bool isGetter = !D->param_size(); 113 AttrLoc = isGetter ? 114 AssociatedProp->getGetterNameLoc(): 115 AssociatedProp->getSetterNameLoc(); 116 } 117 118 SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic; 119 if (D->isImplicit()) { 120 if (AttrLoc.isValid()) { 121 MethodLoc = AttrLoc; 122 } else { 123 Roles |= (SymbolRoleSet)SymbolRole::Implicit; 124 } 125 } else if (AttrLoc.isValid()) { 126 IndexCtx.handleReference(D, AttrLoc, cast<NamedDecl>(D->getDeclContext()), 127 D->getDeclContext(), 0); 128 } 129 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; 136 } 137 138 if (D->isThisDeclarationADefinition()) { 139 const Stmt *Body = D->getBody(); 140 if (Body) { 141 IndexCtx.indexBody(Body, D, D); 142 } 143 } 144 return true; 145 } 146 147 bool VisitFunctionDecl(const FunctionDecl *D) { 148 if (D->isDeleted()) 149 return true; 150 151 SymbolRoleSet Roles{}; 152 SmallVector<SymbolRelation, 4> Relations; 153 if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) { 154 if (CXXMD->isVirtual()) 155 Roles |= (unsigned)SymbolRole::Dynamic; 156 for (auto I = CXXMD->begin_overridden_methods(), 157 E = CXXMD->end_overridden_methods(); I != E; ++I) { 158 Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I); 159 } 160 } 161 162 TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations)); 163 handleDeclarator(D); 164 165 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { 166 IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(), 167 Ctor->getParent(), Ctor->getDeclContext()); 168 169 // Constructor initializers. 170 for (const auto *Init : Ctor->inits()) { 171 if (Init->isWritten()) { 172 IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D); 173 if (const FieldDecl *Member = Init->getAnyMember()) 174 IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D, 175 (unsigned)SymbolRole::Write); 176 IndexCtx.indexBody(Init->getInit(), D, D); 177 } 178 } 179 } else if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(D)) { 180 if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) { 181 IndexCtx.handleReference(Dtor->getParent(), 182 TypeNameInfo->getTypeLoc().getLocStart(), 183 Dtor->getParent(), Dtor->getDeclContext()); 184 } 185 } 186 187 if (D->isThisDeclarationADefinition()) { 188 const Stmt *Body = D->getBody(); 189 if (Body) { 190 IndexCtx.indexBody(Body, D, D); 191 } 192 } 193 return true; 194 } 195 196 bool VisitVarDecl(const VarDecl *D) { 197 TRY_DECL(D, IndexCtx.handleDecl(D)); 198 handleDeclarator(D); 199 IndexCtx.indexBody(D->getInit(), D); 200 return true; 201 } 202 203 bool VisitFieldDecl(const FieldDecl *D) { 204 TRY_DECL(D, IndexCtx.handleDecl(D)); 205 handleDeclarator(D); 206 if (D->isBitField()) 207 IndexCtx.indexBody(D->getBitWidth(), D); 208 else if (D->hasInClassInitializer()) 209 IndexCtx.indexBody(D->getInClassInitializer(), D); 210 return true; 211 } 212 213 bool VisitObjCIvarDecl(const ObjCIvarDecl *D) { 214 if (D->getSynthesize()) { 215 // handled in VisitObjCPropertyImplDecl 216 return true; 217 } 218 TRY_DECL(D, IndexCtx.handleDecl(D)); 219 handleDeclarator(D); 220 return true; 221 } 222 223 bool VisitMSPropertyDecl(const MSPropertyDecl *D) { 224 handleDeclarator(D); 225 return true; 226 } 227 228 bool VisitEnumConstantDecl(const EnumConstantDecl *D) { 229 TRY_DECL(D, IndexCtx.handleDecl(D)); 230 IndexCtx.indexBody(D->getInitExpr(), D); 231 return true; 232 } 233 234 bool VisitTypedefNameDecl(const TypedefNameDecl *D) { 235 if (!D->isTransparentTag()) { 236 TRY_DECL(D, IndexCtx.handleDecl(D)); 237 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); 238 } 239 return true; 240 } 241 242 bool VisitTagDecl(const TagDecl *D) { 243 // Non-free standing tags are handled in indexTypeSourceInfo. 244 if (D->isFreeStanding()) { 245 if (D->isThisDeclarationADefinition()) { 246 IndexCtx.indexTagDecl(D); 247 } else { 248 auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext()); 249 return IndexCtx.handleReference(D, D->getLocation(), Parent, 250 D->getLexicalDeclContext(), 251 SymbolRoleSet()); 252 } 253 } 254 return true; 255 } 256 257 bool handleReferencedProtocols(const ObjCProtocolList &ProtList, 258 const ObjCContainerDecl *ContD, 259 SourceLocation SuperLoc) { 260 ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); 261 for (ObjCInterfaceDecl::protocol_iterator 262 I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { 263 SourceLocation Loc = *LI; 264 ObjCProtocolDecl *PD = *I; 265 SymbolRoleSet roles{}; 266 if (Loc == SuperLoc) 267 roles |= (SymbolRoleSet)SymbolRole::Implicit; 268 TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles, 269 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); 270 } 271 return true; 272 } 273 274 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { 275 if (D->isThisDeclarationADefinition()) { 276 TRY_DECL(D, IndexCtx.handleDecl(D)); 277 SourceLocation SuperLoc = D->getSuperClassLoc(); 278 if (auto *SuperD = D->getSuperClass()) { 279 bool hasSuperTypedef = false; 280 if (auto *TInfo = D->getSuperClassTInfo()) { 281 if (auto *TT = TInfo->getType()->getAs<TypedefType>()) { 282 if (auto *TD = TT->getDecl()) { 283 hasSuperTypedef = true; 284 TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D, 285 SymbolRoleSet())); 286 } 287 } 288 } 289 SymbolRoleSet superRoles{}; 290 if (hasSuperTypedef) 291 superRoles |= (SymbolRoleSet)SymbolRole::Implicit; 292 TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles, 293 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); 294 } 295 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, 296 SuperLoc)); 297 TRY_TO(IndexCtx.indexDeclContext(D)); 298 } else { 299 return IndexCtx.handleReference(D, D->getLocation(), nullptr, 300 D->getDeclContext(), SymbolRoleSet()); 301 } 302 return true; 303 } 304 305 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { 306 if (D->isThisDeclarationADefinition()) { 307 TRY_DECL(D, IndexCtx.handleDecl(D)); 308 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, 309 /*superLoc=*/SourceLocation())); 310 TRY_TO(IndexCtx.indexDeclContext(D)); 311 } else { 312 return IndexCtx.handleReference(D, D->getLocation(), nullptr, 313 D->getDeclContext(), SymbolRoleSet()); 314 } 315 return true; 316 } 317 318 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { 319 const ObjCInterfaceDecl *Class = D->getClassInterface(); 320 if (!Class) 321 return true; 322 323 if (Class->isImplicitInterfaceDecl()) 324 IndexCtx.handleDecl(Class); 325 326 TRY_DECL(D, IndexCtx.handleDecl(D)); 327 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); 334 } 335 for (const auto *I : D->decls()) { 336 if (!isa<ObjCPropertyImplDecl>(I) || 337 cast<ObjCPropertyImplDecl>(I)->getLocation().isValid()) 338 IndexCtx.indexDecl(I); 339 } 340 341 return true; 342 } 343 344 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { 345 if (!IndexCtx.shouldIndex(D)) 346 return true; 347 const ObjCInterfaceDecl *C = D->getClassInterface(); 348 if (!C) 349 return true; 350 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(), 351 SymbolRelation{ 352 (unsigned)SymbolRole::RelationExtendedBy, D 353 })); 354 SourceLocation CategoryLoc = D->getCategoryNameLoc(); 355 if (!CategoryLoc.isValid()) 356 CategoryLoc = D->getLocation(); 357 TRY_TO(IndexCtx.handleDecl(D, CategoryLoc)); 358 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, 359 /*superLoc=*/SourceLocation())); 360 TRY_TO(IndexCtx.indexDeclContext(D)); 361 return true; 362 } 363 364 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { 365 const ObjCCategoryDecl *Cat = D->getCategoryDecl(); 366 if (!Cat) 367 return true; 368 const ObjCInterfaceDecl *C = D->getClassInterface(); 369 if (C) 370 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, 371 SymbolRoleSet())); 372 SourceLocation CategoryLoc = D->getCategoryNameLoc(); 373 if (!CategoryLoc.isValid()) 374 CategoryLoc = D->getLocation(); 375 TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc)); 376 IndexCtx.indexDeclContext(D); 377 return true; 378 } 379 380 bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { 381 // Methods associated with a property, even user-declared ones, are 382 // handled when we handle the property. 383 if (D->isPropertyAccessor()) 384 return true; 385 386 handleObjCMethod(D); 387 return true; 388 } 389 390 bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { 391 if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) 392 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) 393 handleObjCMethod(MD, D); 394 if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) 395 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) 396 handleObjCMethod(MD, D); 397 TRY_DECL(D, 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); 402 return true; 403 } 404 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; 411 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; 417 } 418 TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations)); 419 420 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) 421 return true; 422 423 assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); 424 if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { 425 if (MD->isPropertyAccessor() && 426 !hasUserDefined(MD, Container)) 427 IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, 428 Container); 429 } 430 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { 431 if (MD->isPropertyAccessor() && 432 !hasUserDefined(MD, Container)) 433 IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, 434 Container); 435 } 436 if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { 437 if (IvarD->getSynthesize()) { 438 // For synthesized ivars, use the location of its name in the 439 // corresponding @synthesize. If there isn't one, use the containing 440 // @implementation's location, rather than the property's location, 441 // otherwise the header file containing the @interface will have different 442 // indexing contents based on whether the @implementation was present or 443 // not in the translation unit. 444 SymbolRoleSet IvarRoles = 0; 445 SourceLocation IvarLoc = D->getPropertyIvarDeclLoc(); 446 if (D->getLocation().isInvalid()) { 447 IvarLoc = Container->getLocation(); 448 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; 449 } else if (D->getLocation() == IvarLoc) { 450 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; 451 } 452 TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles)); 453 } else { 454 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr, 455 D->getDeclContext(), SymbolRoleSet()); 456 } 457 } 458 return true; 459 } 460 461 bool VisitNamespaceDecl(const NamespaceDecl *D) { 462 TRY_DECL(D, IndexCtx.handleDecl(D)); 463 IndexCtx.indexDeclContext(D); 464 return true; 465 } 466 467 bool VisitUsingDecl(const UsingDecl *D) { 468 const DeclContext *DC = D->getDeclContext()->getRedeclContext(); 469 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); 470 471 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, 472 D->getLexicalDeclContext()); 473 for (const auto *I : D->shadows()) 474 IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent, 475 D->getLexicalDeclContext(), SymbolRoleSet()); 476 return true; 477 } 478 479 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { 480 const DeclContext *DC = D->getDeclContext()->getRedeclContext(); 481 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); 482 483 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, 484 D->getLexicalDeclContext()); 485 return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), 486 D->getLocation(), Parent, 487 D->getLexicalDeclContext(), 488 SymbolRoleSet()); 489 } 490 491 bool VisitClassTemplateSpecializationDecl(const 492 ClassTemplateSpecializationDecl *D) { 493 // FIXME: Notify subsequent callbacks if info comes from implicit 494 // instantiation. 495 if (D->isThisDeclarationADefinition()) { 496 llvm::PointerUnion<ClassTemplateDecl *, 497 ClassTemplatePartialSpecializationDecl *> 498 Template = D->getSpecializedTemplateOrPartial(); 499 const Decl *SpecializationOf = 500 Template.is<ClassTemplateDecl *>() 501 ? (Decl *)Template.get<ClassTemplateDecl *>() 502 : Template.get<ClassTemplatePartialSpecializationDecl *>(); 503 IndexCtx.indexTagDecl( 504 D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), 505 SpecializationOf)); 506 } 507 return true; 508 } 509 510 bool VisitTemplateDecl(const TemplateDecl *D) { 511 // FIXME: Template parameters. 512 return Visit(D->getTemplatedDecl()); 513 } 514 515 bool VisitFriendDecl(const FriendDecl *D) { 516 if (auto ND = D->getFriendDecl()) { 517 // FIXME: Ignore a class template in a dependent context, these are not 518 // linked properly with their redeclarations, ending up with duplicate 519 // USRs. 520 // See comment "Friend templates are visible in fairly strange ways." in 521 // SemaTemplate.cpp which precedes code that prevents the friend template 522 // from becoming visible from the enclosing context. 523 if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext()) 524 return true; 525 return Visit(ND); 526 } 527 if (auto Ty = D->getFriendType()) { 528 IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext())); 529 } 530 return true; 531 } 532 533 bool VisitImportDecl(const ImportDecl *D) { 534 return IndexCtx.importedModule(D); 535 } 536 }; 537 538 } // anonymous namespace 539 540 bool IndexingContext::indexDecl(const Decl *D) { 541 if (D->isImplicit() && shouldIgnoreIfImplicit(D)) 542 return true; 543 544 if (isTemplateImplicitInstantiation(D)) 545 return true; 546 547 IndexingDeclVisitor Visitor(*this); 548 bool ShouldContinue = Visitor.Visit(D); 549 if (!ShouldContinue) 550 return false; 551 552 if (!Visitor.Handled && isa<DeclContext>(D)) 553 return indexDeclContext(cast<DeclContext>(D)); 554 555 return true; 556 } 557 558 bool IndexingContext::indexDeclContext(const DeclContext *DC) { 559 for (const auto *I : DC->decls()) 560 if (!indexDecl(I)) 561 return false; 562 return true; 563 } 564 565 bool IndexingContext::indexTopLevelDecl(const Decl *D) { 566 if (D->getLocation().isInvalid()) 567 return true; 568 569 if (isa<ObjCMethodDecl>(D)) 570 return true; // Wait for the objc container. 571 572 return indexDecl(D); 573 } 574 575 bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { 576 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 577 if (!indexTopLevelDecl(*I)) 578 return false; 579 return true; 580 } 581