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