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