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