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