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