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_TO(CALL_EXPR) \ 18 do { \ 19 if (!CALL_EXPR) \ 20 return false; \ 21 } while (0) 22 23 namespace { 24 25 class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> { 26 IndexingContext &IndexCtx; 27 28 public: 29 explicit IndexingDeclVisitor(IndexingContext &indexCtx) 30 : IndexCtx(indexCtx) { } 31 32 bool Handled = true; 33 34 bool VisitDecl(const Decl *D) { 35 Handled = false; 36 return true; 37 } 38 39 /// \brief Returns true if the given method has been defined explicitly by the 40 /// user. 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(); 46 } 47 48 void handleDeclarator(const DeclaratorDecl *D, 49 const NamedDecl *Parent = nullptr, 50 bool isIBType = false) { 51 if (!Parent) Parent = D; 52 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 59 // not useful. 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); 68 } else { 69 IndexCtx.handleDecl(Parm); 70 } 71 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 72 if (FD->isThisDeclarationADefinition()) { 73 for (auto PI : FD->parameters()) { 74 IndexCtx.handleDecl(PI); 75 } 76 } 77 } 78 } 79 } 80 81 bool handleObjCMethod(const ObjCMethodDecl *D, 82 const ObjCPropertyDecl *AssociatedProp = nullptr) { 83 SmallVector<SymbolRelation, 4> Relations; 84 SmallVector<const ObjCMethodDecl*, 4> Overriden; 85 86 D->getOverriddenMethods(Overriden); 87 for(auto overridden: Overriden) { 88 Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf, 89 overridden); 90 } 91 if (AssociatedProp) 92 Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf, 93 AssociatedProp); 94 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(); 100 101 SourceLocation AttrLoc; 102 103 // check for (getter=/setter=) 104 if (AssociatedProp) { 105 bool isGetter = !D->param_size(); 106 AttrLoc = isGetter ? 107 AssociatedProp->getGetterNameLoc(): 108 AssociatedProp->getSetterNameLoc(); 109 } 110 111 SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic; 112 if (D->isImplicit()) { 113 if (AttrLoc.isValid()) { 114 MethodLoc = AttrLoc; 115 } else { 116 Roles |= (SymbolRoleSet)SymbolRole::Implicit; 117 } 118 } else if (AttrLoc.isValid()) { 119 IndexCtx.handleReference(D, AttrLoc, cast<NamedDecl>(D->getDeclContext()), 120 D->getDeclContext(), 0); 121 } 122 123 if (!IndexCtx.handleDecl(D, MethodLoc, Roles, Relations)) 124 return false; 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; 130 } 131 132 if (D->isThisDeclarationADefinition()) { 133 const Stmt *Body = D->getBody(); 134 if (Body) { 135 IndexCtx.indexBody(Body, D, D); 136 } 137 } 138 return true; 139 } 140 141 bool VisitFunctionDecl(const FunctionDecl *D) { 142 if (D->isDeleted()) 143 return true; 144 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); 153 } 154 } 155 156 if (!IndexCtx.handleDecl(D, Roles, Relations)) 157 return false; 158 handleDeclarator(D); 159 160 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { 161 IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(), 162 Ctor->getParent(), Ctor->getDeclContext()); 163 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); 172 } 173 } 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()); 179 } 180 } 181 182 if (D->isThisDeclarationADefinition()) { 183 const Stmt *Body = D->getBody(); 184 if (Body) { 185 IndexCtx.indexBody(Body, D, D); 186 } 187 } 188 return true; 189 } 190 191 bool VisitVarDecl(const VarDecl *D) { 192 if (!IndexCtx.handleDecl(D)) 193 return false; 194 handleDeclarator(D); 195 IndexCtx.indexBody(D->getInit(), D); 196 return true; 197 } 198 199 bool VisitFieldDecl(const FieldDecl *D) { 200 if (!IndexCtx.handleDecl(D)) 201 return false; 202 handleDeclarator(D); 203 if (D->isBitField()) 204 IndexCtx.indexBody(D->getBitWidth(), D); 205 else if (D->hasInClassInitializer()) 206 IndexCtx.indexBody(D->getInClassInitializer(), D); 207 return true; 208 } 209 210 bool VisitObjCIvarDecl(const ObjCIvarDecl *D) { 211 if (D->getSynthesize()) { 212 // handled in VisitObjCPropertyImplDecl 213 return true; 214 } 215 if (!IndexCtx.handleDecl(D)) 216 return false; 217 handleDeclarator(D); 218 return true; 219 } 220 221 bool VisitMSPropertyDecl(const MSPropertyDecl *D) { 222 handleDeclarator(D); 223 return true; 224 } 225 226 bool VisitEnumConstantDecl(const EnumConstantDecl *D) { 227 if (!IndexCtx.handleDecl(D)) 228 return false; 229 IndexCtx.indexBody(D->getInitExpr(), D); 230 return true; 231 } 232 233 bool VisitTypedefNameDecl(const TypedefNameDecl *D) { 234 if (!D->isTransparentTag()) 235 if (!IndexCtx.handleDecl(D)) 236 return false; 237 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); 238 return true; 239 } 240 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); 246 } else { 247 auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext()); 248 return IndexCtx.handleReference(D, D->getLocation(), Parent, 249 D->getLexicalDeclContext(), 250 SymbolRoleSet()); 251 } 252 } 253 return true; 254 } 255 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{}; 265 if (Loc == SuperLoc) 266 roles |= (SymbolRoleSet)SymbolRole::Implicit; 267 TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles, 268 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); 269 } 270 return true; 271 } 272 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, 284 SymbolRoleSet())); 285 } 286 } 287 } 288 SymbolRoleSet superRoles{}; 289 if (hasSuperTypedef) 290 superRoles |= (SymbolRoleSet)SymbolRole::Implicit; 291 TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles, 292 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); 293 } 294 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D, 295 SuperLoc)); 296 TRY_TO(IndexCtx.indexDeclContext(D)); 297 } else { 298 return IndexCtx.handleReference(D, D->getLocation(), nullptr, 299 D->getDeclContext(), SymbolRoleSet()); 300 } 301 return true; 302 } 303 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)); 310 } else { 311 return IndexCtx.handleReference(D, D->getLocation(), nullptr, 312 D->getDeclContext(), SymbolRoleSet()); 313 } 314 return true; 315 } 316 317 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { 318 const ObjCInterfaceDecl *Class = D->getClassInterface(); 319 if (!Class) 320 return true; 321 322 if (Class->isImplicitInterfaceDecl()) 323 IndexCtx.handleDecl(Class); 324 325 if (!IndexCtx.handleDecl(D)) 326 return false; 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 const ObjCInterfaceDecl *C = D->getClassInterface(); 346 if (!C) 347 return true; 348 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(), 349 SymbolRelation{ 350 (unsigned)SymbolRole::RelationExtendedBy, D 351 })); 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)); 359 return true; 360 } 361 362 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { 363 const ObjCCategoryDecl *Cat = D->getCategoryDecl(); 364 if (!Cat) 365 return true; 366 const ObjCInterfaceDecl *C = D->getClassInterface(); 367 if (C) 368 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, 369 SymbolRoleSet())); 370 SourceLocation CategoryLoc = D->getCategoryNameLoc(); 371 if (!CategoryLoc.isValid()) 372 CategoryLoc = D->getLocation(); 373 if (!IndexCtx.handleDecl(D, CategoryLoc)) 374 return false; 375 IndexCtx.indexDeclContext(D); 376 return true; 377 } 378 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()) 383 return true; 384 385 handleObjCMethod(D); 386 return true; 387 } 388 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)) 397 return false; 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 if (!IndexCtx.handleDecl(D, Loc, Roles, Relations)) 419 return false; 420 421 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) 422 return true; 423 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), {}, 429 Container); 430 } 431 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { 432 if (MD->isPropertyAccessor() && 433 !hasUserDefined(MD, Container)) 434 IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, 435 Container); 436 } 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; 452 } 453 if(!IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles)) 454 return false; 455 } else { 456 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr, 457 D->getDeclContext(), SymbolRoleSet()); 458 } 459 } 460 return true; 461 } 462 463 bool VisitNamespaceDecl(const NamespaceDecl *D) { 464 if (!IndexCtx.handleDecl(D)) 465 return false; 466 IndexCtx.indexDeclContext(D); 467 return true; 468 } 469 470 bool VisitUsingDecl(const UsingDecl *D) { 471 const DeclContext *DC = D->getDeclContext()->getRedeclContext(); 472 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); 473 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()); 479 return true; 480 } 481 482 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { 483 const DeclContext *DC = D->getDeclContext()->getRedeclContext(); 484 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); 485 486 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, 487 D->getLexicalDeclContext()); 488 return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), 489 D->getLocation(), Parent, 490 D->getLexicalDeclContext(), 491 SymbolRoleSet()); 492 } 493 494 bool VisitClassTemplateSpecializationDecl(const 495 ClassTemplateSpecializationDecl *D) { 496 // FIXME: Notify subsequent callbacks if info comes from implicit 497 // instantiation. 498 if (D->isThisDeclarationADefinition()) { 499 llvm::PointerUnion<ClassTemplateDecl *, 500 ClassTemplatePartialSpecializationDecl *> 501 Template = D->getSpecializedTemplateOrPartial(); 502 const Decl *SpecializationOf = 503 Template.is<ClassTemplateDecl *>() 504 ? (Decl *)Template.get<ClassTemplateDecl *>() 505 : Template.get<ClassTemplatePartialSpecializationDecl *>(); 506 IndexCtx.indexTagDecl( 507 D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), 508 SpecializationOf)); 509 } 510 return true; 511 } 512 513 bool VisitTemplateDecl(const TemplateDecl *D) { 514 // FIXME: Template parameters. 515 return Visit(D->getTemplatedDecl()); 516 } 517 518 bool VisitFriendDecl(const FriendDecl *D) { 519 if (auto ND = D->getFriendDecl()) { 520 // FIXME: Ignore a class template in a dependent context, these are not 521 // linked properly with their redeclarations, ending up with duplicate 522 // USRs. 523 // See comment "Friend templates are visible in fairly strange ways." in 524 // SemaTemplate.cpp which precedes code that prevents the friend template 525 // from becoming visible from the enclosing context. 526 if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext()) 527 return true; 528 return Visit(ND); 529 } 530 if (auto Ty = D->getFriendType()) { 531 IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext())); 532 } 533 return true; 534 } 535 536 bool VisitImportDecl(const ImportDecl *D) { 537 return IndexCtx.importedModule(D); 538 } 539 }; 540 541 } // anonymous namespace 542 543 bool IndexingContext::indexDecl(const Decl *D) { 544 if (D->isImplicit() && shouldIgnoreIfImplicit(D)) 545 return true; 546 547 if (isTemplateImplicitInstantiation(D)) 548 return true; 549 550 IndexingDeclVisitor Visitor(*this); 551 bool ShouldContinue = Visitor.Visit(D); 552 if (!ShouldContinue) 553 return false; 554 555 if (!Visitor.Handled && isa<DeclContext>(D)) 556 return indexDeclContext(cast<DeclContext>(D)); 557 558 return true; 559 } 560 561 bool IndexingContext::indexDeclContext(const DeclContext *DC) { 562 for (const auto *I : DC->decls()) 563 if (!indexDecl(I)) 564 return false; 565 return true; 566 } 567 568 bool IndexingContext::indexTopLevelDecl(const Decl *D) { 569 if (D->getLocation().isInvalid()) 570 return true; 571 572 if (isa<ObjCMethodDecl>(D)) 573 return true; // Wait for the objc container. 574 575 return indexDecl(D); 576 } 577 578 bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { 579 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 580 if (!indexTopLevelDecl(*I)) 581 return false; 582 return true; 583 } 584