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