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