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