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