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