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 case TSK_ExplicitSpecialization: 173 return false; 174 case TSK_ImplicitInstantiation: 175 case TSK_ExplicitInstantiationDeclaration: 176 case TSK_ExplicitInstantiationDefinition: 177 return true; 178 } 179 llvm_unreachable("invalid TemplateSpecializationKind"); 180 } 181 182 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { 183 if (isa<ObjCInterfaceDecl>(D)) 184 return false; 185 if (isa<ObjCCategoryDecl>(D)) 186 return false; 187 if (isa<ObjCIvarDecl>(D)) 188 return false; 189 if (isa<ObjCMethodDecl>(D)) 190 return false; 191 if (isa<ImportDecl>(D)) 192 return false; 193 return true; 194 } 195 196 static const CXXRecordDecl * 197 getDeclContextForTemplateInstationPattern(const Decl *D) { 198 if (const auto *CTSD = 199 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) 200 return CTSD->getTemplateInstantiationPattern(); 201 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) 202 return RD->getInstantiatedFromMemberClass(); 203 return nullptr; 204 } 205 206 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { 207 if (const ClassTemplateSpecializationDecl * 208 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 209 return SD->getTemplateInstantiationPattern(); 210 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 211 return FD->getTemplateInstantiationPattern(); 212 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 213 return VD->getTemplateInstantiationPattern(); 214 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { 215 return RD->getInstantiatedFromMemberClass(); 216 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { 217 return ED->getInstantiatedFromMemberEnum(); 218 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) { 219 const auto *ND = cast<NamedDecl>(D); 220 if (const CXXRecordDecl *Pattern = 221 getDeclContextForTemplateInstationPattern(ND)) { 222 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) { 223 if (BaseND->isImplicit()) 224 continue; 225 if (BaseND->getKind() == ND->getKind()) 226 return BaseND; 227 } 228 } 229 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) { 230 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) { 231 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) { 232 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName())) 233 return BaseECD; 234 } 235 } 236 } 237 return nullptr; 238 } 239 240 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) { 241 if (auto VD = dyn_cast<VarDecl>(D)) 242 return VD->isThisDeclarationADefinition(Ctx); 243 244 if (auto FD = dyn_cast<FunctionDecl>(D)) 245 return FD->isThisDeclarationADefinition(); 246 247 if (auto TD = dyn_cast<TagDecl>(D)) 248 return TD->isThisDeclarationADefinition(); 249 250 if (auto MD = dyn_cast<ObjCMethodDecl>(D)) 251 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC); 252 253 if (isa<TypedefNameDecl>(D) || 254 isa<EnumConstantDecl>(D) || 255 isa<FieldDecl>(D) || 256 isa<MSPropertyDecl>(D) || 257 isa<ObjCImplDecl>(D) || 258 isa<ObjCPropertyImplDecl>(D)) 259 return true; 260 261 return false; 262 } 263 264 /// Whether the given NamedDecl should be skipped because it has no name. 265 static bool shouldSkipNamelessDecl(const NamedDecl *ND) { 266 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) && 267 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND); 268 } 269 270 static const Decl *adjustParent(const Decl *Parent) { 271 if (!Parent) 272 return nullptr; 273 for (;; Parent = cast<Decl>(Parent->getDeclContext())) { 274 if (isa<TranslationUnitDecl>(Parent)) 275 return nullptr; 276 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent)) 277 continue; 278 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) { 279 if (NS->isAnonymousNamespace()) 280 continue; 281 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { 282 if (RD->isAnonymousStructOrUnion()) 283 continue; 284 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) { 285 if (shouldSkipNamelessDecl(ND)) 286 continue; 287 } 288 return Parent; 289 } 290 } 291 292 static const Decl *getCanonicalDecl(const Decl *D) { 293 D = D->getCanonicalDecl(); 294 if (auto TD = dyn_cast<TemplateDecl>(D)) { 295 if (auto TTD = TD->getTemplatedDecl()) { 296 D = TTD; 297 assert(D->isCanonicalDecl()); 298 } 299 } 300 301 return D; 302 } 303 304 static bool shouldReportOccurrenceForSystemDeclOnlyMode( 305 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) { 306 if (!IsRef) 307 return true; 308 309 auto acceptForRelation = [](SymbolRoleSet roles) -> bool { 310 bool accept = false; 311 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool { 312 switch (r) { 313 case SymbolRole::RelationChildOf: 314 case SymbolRole::RelationBaseOf: 315 case SymbolRole::RelationOverrideOf: 316 case SymbolRole::RelationExtendedBy: 317 case SymbolRole::RelationAccessorOf: 318 case SymbolRole::RelationIBTypeOf: 319 accept = true; 320 return false; 321 case SymbolRole::Declaration: 322 case SymbolRole::Definition: 323 case SymbolRole::Reference: 324 case SymbolRole::Read: 325 case SymbolRole::Write: 326 case SymbolRole::Call: 327 case SymbolRole::Dynamic: 328 case SymbolRole::AddressOf: 329 case SymbolRole::Implicit: 330 case SymbolRole::Undefinition: 331 case SymbolRole::RelationReceivedBy: 332 case SymbolRole::RelationCalledBy: 333 case SymbolRole::RelationContainedBy: 334 case SymbolRole::RelationSpecializationOf: 335 case SymbolRole::NameReference: 336 return true; 337 } 338 llvm_unreachable("Unsupported SymbolRole value!"); 339 }); 340 return accept; 341 }; 342 343 for (auto &Rel : Relations) { 344 if (acceptForRelation(Rel.Roles)) 345 return true; 346 } 347 348 return false; 349 } 350 351 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, 352 bool IsRef, const Decl *Parent, 353 SymbolRoleSet Roles, 354 ArrayRef<SymbolRelation> Relations, 355 const Expr *OrigE, 356 const Decl *OrigD, 357 const DeclContext *ContainerDC) { 358 if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) 359 return true; 360 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D))) 361 return true; 362 363 SourceManager &SM = Ctx->getSourceManager(); 364 FileID FID = SM.getFileID(SM.getFileLoc(Loc)); 365 if (FID.isInvalid()) 366 return true; 367 368 bool Invalid = false; 369 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); 370 if (Invalid || !SEntry.isFile()) 371 return true; 372 373 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { 374 switch (IndexOpts.SystemSymbolFilter) { 375 case IndexingOptions::SystemSymbolFilterKind::None: 376 return true; 377 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: 378 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations)) 379 return true; 380 break; 381 case IndexingOptions::SystemSymbolFilterKind::All: 382 break; 383 } 384 } 385 386 if (!OrigD) 387 OrigD = D; 388 389 if (isTemplateImplicitInstantiation(D)) { 390 if (!IsRef) 391 return true; 392 D = adjustTemplateImplicitInstantiation(D); 393 if (!D) 394 return true; 395 assert(!isTemplateImplicitInstantiation(D)); 396 } 397 398 if (IsRef) 399 Roles |= (unsigned)SymbolRole::Reference; 400 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx)) 401 Roles |= (unsigned)SymbolRole::Definition; 402 else 403 Roles |= (unsigned)SymbolRole::Declaration; 404 405 D = getCanonicalDecl(D); 406 Parent = adjustParent(Parent); 407 if (Parent) 408 Parent = getCanonicalDecl(Parent); 409 410 SmallVector<SymbolRelation, 6> FinalRelations; 411 FinalRelations.reserve(Relations.size()+1); 412 413 auto addRelation = [&](SymbolRelation Rel) { 414 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool { 415 return Elem.RelatedSymbol == Rel.RelatedSymbol; 416 }); 417 if (It != FinalRelations.end()) { 418 It->Roles |= Rel.Roles; 419 } else { 420 FinalRelations.push_back(Rel); 421 } 422 Roles |= Rel.Roles; 423 }; 424 425 if (Parent) { 426 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) { 427 addRelation(SymbolRelation{ 428 (unsigned)SymbolRole::RelationContainedBy, 429 Parent 430 }); 431 } else { 432 addRelation(SymbolRelation{ 433 (unsigned)SymbolRole::RelationChildOf, 434 Parent 435 }); 436 } 437 } 438 439 for (auto &Rel : Relations) { 440 addRelation(SymbolRelation(Rel.Roles, 441 Rel.RelatedSymbol->getCanonicalDecl())); 442 } 443 444 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC}; 445 return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node); 446 } 447 448 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name, 449 SourceLocation Loc, 450 const MacroInfo &MI) { 451 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition; 452 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); 453 } 454 455 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name, 456 SourceLocation Loc, 457 const MacroInfo &MI) { 458 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition; 459 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); 460 } 461 462 void IndexingContext::handleMacroReference(const IdentifierInfo &Name, 463 SourceLocation Loc, 464 const MacroInfo &MI) { 465 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference; 466 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); 467 } 468