1 //===- IndexingContext.cpp - Indexing context data ------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "IndexingContext.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/Attr.h" 12 #include "clang/AST/DeclObjC.h" 13 #include "clang/AST/DeclTemplate.h" 14 #include "clang/Basic/SourceLocation.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "clang/Index/IndexDataConsumer.h" 17 18 using namespace clang; 19 using namespace index; 20 21 static bool isGeneratedDecl(const Decl *D) { 22 if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) { 23 return attr->getGeneratedDeclaration(); 24 } 25 return false; 26 } 27 28 bool IndexingContext::shouldIndex(const Decl *D) { 29 return !isGeneratedDecl(D); 30 } 31 32 const LangOptions &IndexingContext::getLangOpts() const { 33 return Ctx->getLangOpts(); 34 } 35 36 bool IndexingContext::shouldIndexFunctionLocalSymbols() const { 37 return IndexOpts.IndexFunctionLocals; 38 } 39 40 bool IndexingContext::shouldIndexImplicitInstantiation() const { 41 return IndexOpts.IndexImplicitInstantiation; 42 } 43 44 bool IndexingContext::shouldIndexParametersInDeclarations() const { 45 return IndexOpts.IndexParametersInDeclarations; 46 } 47 48 bool IndexingContext::shouldIndexTemplateParameters() const { 49 return IndexOpts.IndexTemplateParameters; 50 } 51 52 bool IndexingContext::handleDecl(const Decl *D, 53 SymbolRoleSet Roles, 54 ArrayRef<SymbolRelation> Relations) { 55 return handleDecl(D, D->getLocation(), Roles, Relations); 56 } 57 58 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc, 59 SymbolRoleSet Roles, 60 ArrayRef<SymbolRelation> Relations, 61 const DeclContext *DC) { 62 if (!DC) 63 DC = D->getDeclContext(); 64 65 const Decl *OrigD = D; 66 if (isa<ObjCPropertyImplDecl>(D)) { 67 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl(); 68 } 69 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC), 70 Roles, Relations, 71 nullptr, OrigD, DC); 72 } 73 74 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, 75 const NamedDecl *Parent, 76 const DeclContext *DC, 77 SymbolRoleSet Roles, 78 ArrayRef<SymbolRelation> Relations, 79 const Expr *RefE) { 80 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D)) 81 return true; 82 83 if (!shouldIndexTemplateParameters() && 84 (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || 85 isa<TemplateTemplateParmDecl>(D))) { 86 return true; 87 } 88 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations, 89 RefE, nullptr, DC); 90 } 91 92 static void reportModuleReferences(const Module *Mod, 93 ArrayRef<SourceLocation> IdLocs, 94 const ImportDecl *ImportD, 95 IndexDataConsumer &DataConsumer) { 96 if (!Mod) 97 return; 98 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD, 99 DataConsumer); 100 DataConsumer.handleModuleOccurrence( 101 ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back()); 102 } 103 104 bool IndexingContext::importedModule(const ImportDecl *ImportD) { 105 if (ImportD->isInvalidDecl()) 106 return true; 107 108 SourceLocation Loc; 109 auto IdLocs = ImportD->getIdentifierLocs(); 110 if (!IdLocs.empty()) 111 Loc = IdLocs.back(); 112 else 113 Loc = ImportD->getLocation(); 114 115 SourceManager &SM = Ctx->getSourceManager(); 116 FileID FID = SM.getFileID(SM.getFileLoc(Loc)); 117 if (FID.isInvalid()) 118 return true; 119 120 bool Invalid = false; 121 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); 122 if (Invalid || !SEntry.isFile()) 123 return true; 124 125 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { 126 switch (IndexOpts.SystemSymbolFilter) { 127 case IndexingOptions::SystemSymbolFilterKind::None: 128 return true; 129 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: 130 case IndexingOptions::SystemSymbolFilterKind::All: 131 break; 132 } 133 } 134 135 const Module *Mod = ImportD->getImportedModule(); 136 if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) { 137 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD, 138 DataConsumer); 139 } 140 141 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration; 142 if (ImportD->isImplicit()) 143 Roles |= (unsigned)SymbolRole::Implicit; 144 145 return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc); 146 } 147 148 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { 149 TemplateSpecializationKind TKind = TSK_Undeclared; 150 if (const ClassTemplateSpecializationDecl * 151 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 152 TKind = SD->getSpecializationKind(); 153 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 154 TKind = FD->getTemplateSpecializationKind(); 155 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 156 TKind = VD->getTemplateSpecializationKind(); 157 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { 158 if (RD->getInstantiatedFromMemberClass()) 159 TKind = RD->getTemplateSpecializationKind(); 160 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { 161 if (ED->getInstantiatedFromMemberEnum()) 162 TKind = ED->getTemplateSpecializationKind(); 163 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) || 164 isa<EnumConstantDecl>(D)) { 165 if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext())) 166 return isTemplateImplicitInstantiation(Parent); 167 } 168 switch (TKind) { 169 case TSK_Undeclared: 170 // Instantiation maybe not happen yet when we see a SpecializationDecl, 171 // e.g. when the type doesn't need to be complete, we still treat it as an 172 // instantiation as we'd like to keep the canonicalized result consistent. 173 return isa<ClassTemplateSpecializationDecl>(D); 174 case TSK_ExplicitSpecialization: 175 return false; 176 case TSK_ImplicitInstantiation: 177 case TSK_ExplicitInstantiationDeclaration: 178 case TSK_ExplicitInstantiationDefinition: 179 return true; 180 } 181 llvm_unreachable("invalid TemplateSpecializationKind"); 182 } 183 184 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { 185 if (isa<ObjCInterfaceDecl>(D)) 186 return false; 187 if (isa<ObjCCategoryDecl>(D)) 188 return false; 189 if (isa<ObjCIvarDecl>(D)) 190 return false; 191 if (isa<ObjCMethodDecl>(D)) 192 return false; 193 if (isa<ImportDecl>(D)) 194 return false; 195 return true; 196 } 197 198 static const CXXRecordDecl * 199 getDeclContextForTemplateInstationPattern(const Decl *D) { 200 if (const auto *CTSD = 201 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) 202 return CTSD->getTemplateInstantiationPattern(); 203 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) 204 return RD->getInstantiatedFromMemberClass(); 205 return nullptr; 206 } 207 208 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { 209 if (const ClassTemplateSpecializationDecl * 210 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 211 const auto *Template = SD->getTemplateInstantiationPattern(); 212 if (Template) 213 return Template; 214 // Fallback to primary template if no instantiation is available yet (e.g. 215 // the type doesn't need to be complete). 216 return SD->getSpecializedTemplate()->getTemplatedDecl(); 217 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 218 return FD->getTemplateInstantiationPattern(); 219 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 220 return VD->getTemplateInstantiationPattern(); 221 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { 222 return RD->getInstantiatedFromMemberClass(); 223 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { 224 return ED->getInstantiatedFromMemberEnum(); 225 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) { 226 const auto *ND = cast<NamedDecl>(D); 227 if (const CXXRecordDecl *Pattern = 228 getDeclContextForTemplateInstationPattern(ND)) { 229 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) { 230 if (BaseND->isImplicit()) 231 continue; 232 if (BaseND->getKind() == ND->getKind()) 233 return BaseND; 234 } 235 } 236 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) { 237 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) { 238 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) { 239 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName())) 240 return BaseECD; 241 } 242 } 243 } 244 return nullptr; 245 } 246 247 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) { 248 if (auto VD = dyn_cast<VarDecl>(D)) 249 return VD->isThisDeclarationADefinition(Ctx); 250 251 if (auto FD = dyn_cast<FunctionDecl>(D)) 252 return FD->isThisDeclarationADefinition(); 253 254 if (auto TD = dyn_cast<TagDecl>(D)) 255 return TD->isThisDeclarationADefinition(); 256 257 if (auto MD = dyn_cast<ObjCMethodDecl>(D)) 258 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC); 259 260 if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) || 261 isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) || 262 isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D)) 263 return true; 264 265 return false; 266 } 267 268 /// Whether the given NamedDecl should be skipped because it has no name. 269 static bool shouldSkipNamelessDecl(const NamedDecl *ND) { 270 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) && 271 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND); 272 } 273 274 static const Decl *adjustParent(const Decl *Parent) { 275 if (!Parent) 276 return nullptr; 277 for (;; Parent = cast<Decl>(Parent->getDeclContext())) { 278 if (isa<TranslationUnitDecl>(Parent)) 279 return nullptr; 280 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent)) 281 continue; 282 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) { 283 if (NS->isAnonymousNamespace()) 284 continue; 285 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { 286 if (RD->isAnonymousStructOrUnion()) 287 continue; 288 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) { 289 if (shouldSkipNamelessDecl(ND)) 290 continue; 291 } 292 return Parent; 293 } 294 } 295 296 static const Decl *getCanonicalDecl(const Decl *D) { 297 D = D->getCanonicalDecl(); 298 if (auto TD = dyn_cast<TemplateDecl>(D)) { 299 if (auto TTD = TD->getTemplatedDecl()) { 300 D = TTD; 301 assert(D->isCanonicalDecl()); 302 } 303 } 304 305 return D; 306 } 307 308 static bool shouldReportOccurrenceForSystemDeclOnlyMode( 309 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) { 310 if (!IsRef) 311 return true; 312 313 auto acceptForRelation = [](SymbolRoleSet roles) -> bool { 314 bool accept = false; 315 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool { 316 switch (r) { 317 case SymbolRole::RelationChildOf: 318 case SymbolRole::RelationBaseOf: 319 case SymbolRole::RelationOverrideOf: 320 case SymbolRole::RelationExtendedBy: 321 case SymbolRole::RelationAccessorOf: 322 case SymbolRole::RelationIBTypeOf: 323 accept = true; 324 return false; 325 case SymbolRole::Declaration: 326 case SymbolRole::Definition: 327 case SymbolRole::Reference: 328 case SymbolRole::Read: 329 case SymbolRole::Write: 330 case SymbolRole::Call: 331 case SymbolRole::Dynamic: 332 case SymbolRole::AddressOf: 333 case SymbolRole::Implicit: 334 case SymbolRole::Undefinition: 335 case SymbolRole::RelationReceivedBy: 336 case SymbolRole::RelationCalledBy: 337 case SymbolRole::RelationContainedBy: 338 case SymbolRole::RelationSpecializationOf: 339 case SymbolRole::NameReference: 340 return true; 341 } 342 llvm_unreachable("Unsupported SymbolRole value!"); 343 }); 344 return accept; 345 }; 346 347 for (auto &Rel : Relations) { 348 if (acceptForRelation(Rel.Roles)) 349 return true; 350 } 351 352 return false; 353 } 354 355 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, 356 bool IsRef, const Decl *Parent, 357 SymbolRoleSet Roles, 358 ArrayRef<SymbolRelation> Relations, 359 const Expr *OrigE, 360 const Decl *OrigD, 361 const DeclContext *ContainerDC) { 362 if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) 363 return true; 364 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D))) 365 return true; 366 367 SourceManager &SM = Ctx->getSourceManager(); 368 FileID FID = SM.getFileID(SM.getFileLoc(Loc)); 369 if (FID.isInvalid()) 370 return true; 371 372 bool Invalid = false; 373 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); 374 if (Invalid || !SEntry.isFile()) 375 return true; 376 377 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { 378 switch (IndexOpts.SystemSymbolFilter) { 379 case IndexingOptions::SystemSymbolFilterKind::None: 380 return true; 381 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: 382 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations)) 383 return true; 384 break; 385 case IndexingOptions::SystemSymbolFilterKind::All: 386 break; 387 } 388 } 389 390 if (!OrigD) 391 OrigD = D; 392 393 if (isTemplateImplicitInstantiation(D)) { 394 if (!IsRef) 395 return true; 396 D = adjustTemplateImplicitInstantiation(D); 397 if (!D) 398 return true; 399 assert(!isTemplateImplicitInstantiation(D)); 400 } 401 402 if (IsRef) 403 Roles |= (unsigned)SymbolRole::Reference; 404 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx)) 405 Roles |= (unsigned)SymbolRole::Definition; 406 else 407 Roles |= (unsigned)SymbolRole::Declaration; 408 409 D = getCanonicalDecl(D); 410 Parent = adjustParent(Parent); 411 if (Parent) 412 Parent = getCanonicalDecl(Parent); 413 414 SmallVector<SymbolRelation, 6> FinalRelations; 415 FinalRelations.reserve(Relations.size()+1); 416 417 auto addRelation = [&](SymbolRelation Rel) { 418 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool { 419 return Elem.RelatedSymbol == Rel.RelatedSymbol; 420 }); 421 if (It != FinalRelations.end()) { 422 It->Roles |= Rel.Roles; 423 } else { 424 FinalRelations.push_back(Rel); 425 } 426 Roles |= Rel.Roles; 427 }; 428 429 if (Parent) { 430 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) { 431 addRelation(SymbolRelation{ 432 (unsigned)SymbolRole::RelationContainedBy, 433 Parent 434 }); 435 } else { 436 addRelation(SymbolRelation{ 437 (unsigned)SymbolRole::RelationChildOf, 438 Parent 439 }); 440 } 441 } 442 443 for (auto &Rel : Relations) { 444 addRelation(SymbolRelation(Rel.Roles, 445 Rel.RelatedSymbol->getCanonicalDecl())); 446 } 447 448 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC}; 449 return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node); 450 } 451 452 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name, 453 SourceLocation Loc, 454 const MacroInfo &MI) { 455 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc)) 456 return; 457 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition; 458 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); 459 } 460 461 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name, 462 SourceLocation Loc, 463 const MacroInfo &MI) { 464 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc)) 465 return; 466 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition; 467 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); 468 } 469 470 void IndexingContext::handleMacroReference(const IdentifierInfo &Name, 471 SourceLocation Loc, 472 const MacroInfo &MI) { 473 if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc)) 474 return; 475 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference; 476 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); 477 } 478 479 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef, 480 SourceLocation Loc) { 481 if (!IndexOpts.IndexMacros) 482 return false; 483 484 switch (IndexOpts.SystemSymbolFilter) { 485 case IndexingOptions::SystemSymbolFilterKind::None: 486 break; 487 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: 488 if (!IsRef) 489 return true; 490 break; 491 case IndexingOptions::SystemSymbolFilterKind::All: 492 return true; 493 } 494 495 SourceManager &SM = Ctx->getSourceManager(); 496 FileID FID = SM.getFileID(SM.getFileLoc(Loc)); 497 if (FID.isInvalid()) 498 return false; 499 500 bool Invalid = false; 501 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); 502 if (Invalid || !SEntry.isFile()) 503 return false; 504 505 return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User; 506 } 507