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 SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic; 102 if (D->isImplicit()) 103 Roles |= (SymbolRoleSet)SymbolRole::Implicit; 104 if (!IndexCtx.handleDecl(D, MethodLoc, Roles, Relations)) 105 return false; 106 IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D); 107 bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>(); 108 for (const auto *I : D->parameters()) { 109 handleDeclarator(I, D, /*isIBType=*/hasIBActionAndFirst); 110 hasIBActionAndFirst = false; 111 } 112 113 if (D->isThisDeclarationADefinition()) { 114 const Stmt *Body = D->getBody(); 115 if (Body) { 116 IndexCtx.indexBody(Body, D, D); 117 } 118 } 119 return true; 120 } 121 122 bool VisitFunctionDecl(const FunctionDecl *D) { 123 if (D->isDeleted()) 124 return true; 125 126 SymbolRoleSet Roles{}; 127 SmallVector<SymbolRelation, 4> Relations; 128 if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) { 129 if (CXXMD->isVirtual()) 130 Roles |= (unsigned)SymbolRole::Dynamic; 131 for (auto I = CXXMD->begin_overridden_methods(), 132 E = CXXMD->end_overridden_methods(); I != E; ++I) { 133 Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I); 134 } 135 } 136 137 if (!IndexCtx.handleDecl(D, Roles, Relations)) 138 return false; 139 handleDeclarator(D); 140 141 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { 142 // Constructor initializers. 143 for (const auto *Init : Ctor->inits()) { 144 if (Init->isWritten()) { 145 IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D); 146 if (const FieldDecl *Member = Init->getAnyMember()) 147 IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D, 148 (unsigned)SymbolRole::Write); 149 IndexCtx.indexBody(Init->getInit(), D, D); 150 } 151 } 152 } 153 154 if (D->isThisDeclarationADefinition()) { 155 const Stmt *Body = D->getBody(); 156 if (Body) { 157 IndexCtx.indexBody(Body, D, D); 158 } 159 } 160 return true; 161 } 162 163 bool VisitVarDecl(const VarDecl *D) { 164 if (!IndexCtx.handleDecl(D)) 165 return false; 166 handleDeclarator(D); 167 IndexCtx.indexBody(D->getInit(), D); 168 return true; 169 } 170 171 bool VisitFieldDecl(const FieldDecl *D) { 172 if (!IndexCtx.handleDecl(D)) 173 return false; 174 handleDeclarator(D); 175 if (D->isBitField()) 176 IndexCtx.indexBody(D->getBitWidth(), D); 177 else if (D->hasInClassInitializer()) 178 IndexCtx.indexBody(D->getInClassInitializer(), D); 179 return true; 180 } 181 182 bool VisitObjCIvarDecl(const ObjCIvarDecl *D) { 183 if (D->getSynthesize()) { 184 // handled in VisitObjCPropertyImplDecl 185 return true; 186 } 187 if (!IndexCtx.handleDecl(D)) 188 return false; 189 handleDeclarator(D); 190 return true; 191 } 192 193 bool VisitMSPropertyDecl(const MSPropertyDecl *D) { 194 handleDeclarator(D); 195 return true; 196 } 197 198 bool VisitEnumConstantDecl(const EnumConstantDecl *D) { 199 if (!IndexCtx.handleDecl(D)) 200 return false; 201 IndexCtx.indexBody(D->getInitExpr(), D); 202 return true; 203 } 204 205 bool VisitTypedefNameDecl(const TypedefNameDecl *D) { 206 if (!IndexCtx.handleDecl(D)) 207 return false; 208 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); 209 return true; 210 } 211 212 bool VisitTagDecl(const TagDecl *D) { 213 // Non-free standing tags are handled in indexTypeSourceInfo. 214 if (D->isFreeStanding()) { 215 if (D->isThisDeclarationADefinition()) { 216 IndexCtx.indexTagDecl(D); 217 } else { 218 auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext()); 219 return IndexCtx.handleReference(D, D->getLocation(), Parent, 220 D->getLexicalDeclContext(), 221 SymbolRoleSet()); 222 } 223 } 224 return true; 225 } 226 227 bool handleReferencedProtocols(const ObjCProtocolList &ProtList, 228 const ObjCContainerDecl *ContD) { 229 ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); 230 for (ObjCInterfaceDecl::protocol_iterator 231 I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { 232 SourceLocation Loc = *LI; 233 ObjCProtocolDecl *PD = *I; 234 TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, 235 SymbolRoleSet(), 236 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); 237 } 238 return true; 239 } 240 241 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { 242 if (D->isThisDeclarationADefinition()) { 243 TRY_TO(IndexCtx.handleDecl(D)); 244 if (auto *SuperD = D->getSuperClass()) { 245 TRY_TO(IndexCtx.handleReference(SuperD, D->getSuperClassLoc(), D, D, 246 SymbolRoleSet(), 247 SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); 248 } 249 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); 250 TRY_TO(IndexCtx.indexDeclContext(D)); 251 } else { 252 return IndexCtx.handleReference(D, D->getLocation(), nullptr, 253 D->getDeclContext(), SymbolRoleSet()); 254 } 255 return true; 256 } 257 258 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { 259 if (D->isThisDeclarationADefinition()) { 260 TRY_TO(IndexCtx.handleDecl(D)); 261 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); 262 TRY_TO(IndexCtx.indexDeclContext(D)); 263 } else { 264 return IndexCtx.handleReference(D, D->getLocation(), nullptr, 265 D->getDeclContext(), SymbolRoleSet()); 266 } 267 return true; 268 } 269 270 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { 271 const ObjCInterfaceDecl *Class = D->getClassInterface(); 272 if (!Class) 273 return true; 274 275 if (Class->isImplicitInterfaceDecl()) 276 IndexCtx.handleDecl(Class); 277 278 if (!IndexCtx.handleDecl(D)) 279 return false; 280 281 // Visit implicit @synthesize property implementations first as their 282 // location is reported at the name of the @implementation block. This 283 // serves no purpose other than to simplify the FileCheck-based tests. 284 for (const auto *I : D->property_impls()) { 285 if (I->getLocation().isInvalid()) 286 IndexCtx.indexDecl(I); 287 } 288 for (const auto *I : D->decls()) { 289 if (!isa<ObjCPropertyImplDecl>(I) || 290 cast<ObjCPropertyImplDecl>(I)->getLocation().isValid()) 291 IndexCtx.indexDecl(I); 292 } 293 294 return true; 295 } 296 297 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { 298 const ObjCInterfaceDecl *C = D->getClassInterface(); 299 if (!C) 300 return true; 301 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, SymbolRoleSet(), 302 SymbolRelation{ 303 (unsigned)SymbolRole::RelationExtendedBy, D 304 })); 305 SourceLocation CategoryLoc = D->getCategoryNameLoc(); 306 if (!CategoryLoc.isValid()) 307 CategoryLoc = D->getLocation(); 308 TRY_TO(IndexCtx.handleDecl(D, CategoryLoc)); 309 TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); 310 TRY_TO(IndexCtx.indexDeclContext(D)); 311 return true; 312 } 313 314 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { 315 const ObjCCategoryDecl *Cat = D->getCategoryDecl(); 316 if (!Cat) 317 return true; 318 const ObjCInterfaceDecl *C = D->getClassInterface(); 319 if (C) 320 TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, 321 SymbolRoleSet())); 322 SourceLocation CategoryLoc = D->getCategoryNameLoc(); 323 if (!CategoryLoc.isValid()) 324 CategoryLoc = D->getLocation(); 325 if (!IndexCtx.handleDecl(D, CategoryLoc)) 326 return false; 327 IndexCtx.indexDeclContext(D); 328 return true; 329 } 330 331 bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { 332 // Methods associated with a property, even user-declared ones, are 333 // handled when we handle the property. 334 if (D->isPropertyAccessor()) 335 return true; 336 337 handleObjCMethod(D); 338 return true; 339 } 340 341 bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { 342 if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) 343 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) 344 handleObjCMethod(MD, D); 345 if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) 346 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) 347 handleObjCMethod(MD, D); 348 if (!IndexCtx.handleDecl(D)) 349 return false; 350 if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>()) 351 IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D, 352 D->getLexicalDeclContext(), false, true); 353 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); 354 return true; 355 } 356 357 bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { 358 ObjCPropertyDecl *PD = D->getPropertyDecl(); 359 auto *Container = cast<ObjCImplDecl>(D->getDeclContext()); 360 SourceLocation Loc = D->getLocation(); 361 SymbolRoleSet Roles = 0; 362 SmallVector<SymbolRelation, 1> Relations; 363 364 if (ObjCIvarDecl *ID = D->getPropertyIvarDecl()) 365 Relations.push_back({(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID}); 366 if (Loc.isInvalid()) { 367 Loc = Container->getLocation(); 368 Roles |= (SymbolRoleSet)SymbolRole::Implicit; 369 } 370 if (!IndexCtx.handleDecl(D, Loc, Roles, Relations)) 371 return false; 372 373 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) 374 return true; 375 376 assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); 377 if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { 378 if (MD->isPropertyAccessor() && 379 !hasUserDefined(MD, Container)) 380 IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, 381 Container); 382 } 383 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { 384 if (MD->isPropertyAccessor() && 385 !hasUserDefined(MD, Container)) 386 IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, 387 Container); 388 } 389 if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { 390 if (IvarD->getSynthesize()) { 391 // For synthesized ivars, use the location of its name in the 392 // corresponding @synthesize. If there isn't one, use the containing 393 // @implementation's location, rather than the property's location, 394 // otherwise the header file containing the @interface will have different 395 // indexing contents based on whether the @implementation was present or 396 // not in the translation unit. 397 SymbolRoleSet IvarRoles = 0; 398 SourceLocation IvarLoc = D->getPropertyIvarDeclLoc(); 399 if (D->getLocation().isInvalid()) { 400 IvarLoc = Container->getLocation(); 401 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; 402 } else if (D->getLocation() == IvarLoc) { 403 IvarRoles = (SymbolRoleSet)SymbolRole::Implicit; 404 } 405 if(!IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles)) 406 return false; 407 } else { 408 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr, 409 D->getDeclContext(), SymbolRoleSet()); 410 } 411 } 412 return true; 413 } 414 415 bool VisitNamespaceDecl(const NamespaceDecl *D) { 416 if (!IndexCtx.handleDecl(D)) 417 return false; 418 IndexCtx.indexDeclContext(D); 419 return true; 420 } 421 422 bool VisitUsingDecl(const UsingDecl *D) { 423 const DeclContext *DC = D->getDeclContext()->getRedeclContext(); 424 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); 425 426 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, 427 D->getLexicalDeclContext()); 428 for (const auto *I : D->shadows()) 429 IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent, 430 D->getLexicalDeclContext(), SymbolRoleSet()); 431 return true; 432 } 433 434 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { 435 const DeclContext *DC = D->getDeclContext()->getRedeclContext(); 436 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); 437 438 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, 439 D->getLexicalDeclContext()); 440 return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), 441 D->getLocation(), Parent, 442 D->getLexicalDeclContext(), 443 SymbolRoleSet()); 444 } 445 446 bool VisitClassTemplateSpecializationDecl(const 447 ClassTemplateSpecializationDecl *D) { 448 // FIXME: Notify subsequent callbacks if info comes from implicit 449 // instantiation. 450 if (D->isThisDeclarationADefinition()) 451 IndexCtx.indexTagDecl(D); 452 return true; 453 } 454 455 bool VisitTemplateDecl(const TemplateDecl *D) { 456 // FIXME: Template parameters. 457 return Visit(D->getTemplatedDecl()); 458 } 459 460 bool VisitFriendDecl(const FriendDecl *D) { 461 if (auto ND = D->getFriendDecl()) { 462 // FIXME: Ignore a class template in a dependent context, these are not 463 // linked properly with their redeclarations, ending up with duplicate 464 // USRs. 465 // See comment "Friend templates are visible in fairly strange ways." in 466 // SemaTemplate.cpp which precedes code that prevents the friend template 467 // from becoming visible from the enclosing context. 468 if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext()) 469 return true; 470 return Visit(ND); 471 } 472 if (auto Ty = D->getFriendType()) { 473 IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext())); 474 } 475 return true; 476 } 477 478 bool VisitImportDecl(const ImportDecl *D) { 479 return IndexCtx.importedModule(D); 480 } 481 }; 482 483 } // anonymous namespace 484 485 bool IndexingContext::indexDecl(const Decl *D) { 486 if (D->isImplicit() && shouldIgnoreIfImplicit(D)) 487 return true; 488 489 if (isTemplateImplicitInstantiation(D)) 490 return true; 491 492 IndexingDeclVisitor Visitor(*this); 493 bool ShouldContinue = Visitor.Visit(D); 494 if (!ShouldContinue) 495 return false; 496 497 if (!Visitor.Handled && isa<DeclContext>(D)) 498 return indexDeclContext(cast<DeclContext>(D)); 499 500 return true; 501 } 502 503 bool IndexingContext::indexDeclContext(const DeclContext *DC) { 504 for (const auto *I : DC->decls()) 505 if (!indexDecl(I)) 506 return false; 507 return true; 508 } 509 510 bool IndexingContext::indexTopLevelDecl(const Decl *D) { 511 if (D->getLocation().isInvalid()) 512 return true; 513 514 if (isa<ObjCMethodDecl>(D)) 515 return true; // Wait for the objc container. 516 517 return indexDecl(D); 518 } 519 520 bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { 521 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 522 if (!indexTopLevelDecl(*I)) 523 return false; 524 return true; 525 } 526