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/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 bool IndexingContext::shouldIndexFunctionLocalSymbols() const { 32 return IndexOpts.IndexFunctionLocals; 33 } 34 35 bool IndexingContext::handleDecl(const Decl *D, 36 SymbolRoleSet Roles, 37 ArrayRef<SymbolRelation> Relations) { 38 return handleDecl(D, D->getLocation(), Roles, Relations); 39 } 40 41 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc, 42 SymbolRoleSet Roles, 43 ArrayRef<SymbolRelation> Relations, 44 const DeclContext *DC) { 45 if (!DC) 46 DC = D->getDeclContext(); 47 48 const Decl *OrigD = D; 49 if (isa<ObjCPropertyImplDecl>(D)) { 50 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl(); 51 } 52 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC), 53 Roles, Relations, 54 nullptr, OrigD, DC); 55 } 56 57 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, 58 const NamedDecl *Parent, 59 const DeclContext *DC, 60 SymbolRoleSet Roles, 61 ArrayRef<SymbolRelation> Relations, 62 const Expr *RefE, 63 const Decl *RefD) { 64 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D)) 65 return true; 66 67 if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D)) 68 return true; 69 70 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations, 71 RefE, RefD, DC); 72 } 73 74 bool IndexingContext::importedModule(const ImportDecl *ImportD) { 75 SourceLocation Loc; 76 auto IdLocs = ImportD->getIdentifierLocs(); 77 if (!IdLocs.empty()) 78 Loc = IdLocs.front(); 79 else 80 Loc = ImportD->getLocation(); 81 SourceManager &SM = Ctx->getSourceManager(); 82 Loc = SM.getFileLoc(Loc); 83 if (Loc.isInvalid()) 84 return true; 85 86 FileID FID; 87 unsigned Offset; 88 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); 89 if (FID.isInvalid()) 90 return true; 91 92 bool Invalid = false; 93 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); 94 if (Invalid || !SEntry.isFile()) 95 return true; 96 97 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { 98 switch (IndexOpts.SystemSymbolFilter) { 99 case IndexingOptions::SystemSymbolFilterKind::None: 100 return true; 101 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: 102 case IndexingOptions::SystemSymbolFilterKind::All: 103 break; 104 } 105 } 106 107 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration; 108 if (ImportD->isImplicit()) 109 Roles |= (unsigned)SymbolRole::Implicit; 110 111 return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset); 112 } 113 114 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { 115 TemplateSpecializationKind TKind = TSK_Undeclared; 116 if (const ClassTemplateSpecializationDecl * 117 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 118 TKind = SD->getSpecializationKind(); 119 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 120 TKind = FD->getTemplateSpecializationKind(); 121 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 122 TKind = VD->getTemplateSpecializationKind(); 123 } 124 switch (TKind) { 125 case TSK_Undeclared: 126 case TSK_ExplicitSpecialization: 127 return false; 128 case TSK_ImplicitInstantiation: 129 case TSK_ExplicitInstantiationDeclaration: 130 case TSK_ExplicitInstantiationDefinition: 131 return true; 132 } 133 llvm_unreachable("invalid TemplateSpecializationKind"); 134 } 135 136 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { 137 if (isa<ObjCInterfaceDecl>(D)) 138 return false; 139 if (isa<ObjCCategoryDecl>(D)) 140 return false; 141 if (isa<ObjCIvarDecl>(D)) 142 return false; 143 if (isa<ObjCMethodDecl>(D)) 144 return false; 145 if (isa<ImportDecl>(D)) 146 return false; 147 return true; 148 } 149 150 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { 151 if (const ClassTemplateSpecializationDecl * 152 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 153 return SD->getTemplateInstantiationPattern(); 154 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 155 return FD->getTemplateInstantiationPattern(); 156 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 157 return VD->getTemplateInstantiationPattern(); 158 } 159 return nullptr; 160 } 161 162 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) { 163 if (auto VD = dyn_cast<VarDecl>(D)) 164 return VD->isThisDeclarationADefinition(Ctx); 165 166 if (auto FD = dyn_cast<FunctionDecl>(D)) 167 return FD->isThisDeclarationADefinition(); 168 169 if (auto TD = dyn_cast<TagDecl>(D)) 170 return TD->isThisDeclarationADefinition(); 171 172 if (auto MD = dyn_cast<ObjCMethodDecl>(D)) 173 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC); 174 175 if (isa<TypedefNameDecl>(D) || 176 isa<EnumConstantDecl>(D) || 177 isa<FieldDecl>(D) || 178 isa<MSPropertyDecl>(D) || 179 isa<ObjCImplDecl>(D) || 180 isa<ObjCPropertyImplDecl>(D)) 181 return true; 182 183 return false; 184 } 185 186 static const Decl *adjustParent(const Decl *Parent) { 187 if (!Parent) 188 return nullptr; 189 for (;; Parent = cast<Decl>(Parent->getDeclContext())) { 190 if (isa<TranslationUnitDecl>(Parent)) 191 return nullptr; 192 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent)) 193 continue; 194 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) { 195 if (NS->isAnonymousNamespace()) 196 continue; 197 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { 198 if (RD->isAnonymousStructOrUnion()) 199 continue; 200 } else if (auto FD = dyn_cast<FieldDecl>(Parent)) { 201 if (FD->getDeclName().isEmpty()) 202 continue; 203 } 204 return Parent; 205 } 206 } 207 208 static const Decl *getCanonicalDecl(const Decl *D) { 209 D = D->getCanonicalDecl(); 210 if (auto TD = dyn_cast<TemplateDecl>(D)) { 211 D = TD->getTemplatedDecl(); 212 assert(D->isCanonicalDecl()); 213 } 214 215 return D; 216 } 217 218 static bool shouldReportOccurrenceForSystemDeclOnlyMode( 219 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) { 220 if (!IsRef) 221 return true; 222 223 auto acceptForRelation = [](SymbolRoleSet roles) -> bool { 224 bool accept = false; 225 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool { 226 switch (r) { 227 case SymbolRole::RelationChildOf: 228 case SymbolRole::RelationBaseOf: 229 case SymbolRole::RelationOverrideOf: 230 case SymbolRole::RelationExtendedBy: 231 case SymbolRole::RelationAccessorOf: 232 case SymbolRole::RelationIBTypeOf: 233 accept = true; 234 return false; 235 case SymbolRole::Declaration: 236 case SymbolRole::Definition: 237 case SymbolRole::Reference: 238 case SymbolRole::Read: 239 case SymbolRole::Write: 240 case SymbolRole::Call: 241 case SymbolRole::Dynamic: 242 case SymbolRole::AddressOf: 243 case SymbolRole::Implicit: 244 case SymbolRole::RelationReceivedBy: 245 case SymbolRole::RelationCalledBy: 246 case SymbolRole::RelationContainedBy: 247 case SymbolRole::RelationSpecializationOf: 248 return true; 249 } 250 llvm_unreachable("Unsupported SymbolRole value!"); 251 }); 252 return accept; 253 }; 254 255 for (auto &Rel : Relations) { 256 if (acceptForRelation(Rel.Roles)) 257 return true; 258 } 259 260 return false; 261 } 262 263 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, 264 bool IsRef, const Decl *Parent, 265 SymbolRoleSet Roles, 266 ArrayRef<SymbolRelation> Relations, 267 const Expr *OrigE, 268 const Decl *OrigD, 269 const DeclContext *ContainerDC) { 270 if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) 271 return true; 272 if (!isa<NamedDecl>(D) || 273 (cast<NamedDecl>(D)->getDeclName().isEmpty() && 274 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D))) 275 return true; 276 277 SourceManager &SM = Ctx->getSourceManager(); 278 Loc = SM.getFileLoc(Loc); 279 if (Loc.isInvalid()) 280 return true; 281 282 FileID FID; 283 unsigned Offset; 284 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); 285 if (FID.isInvalid()) 286 return true; 287 288 bool Invalid = false; 289 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); 290 if (Invalid || !SEntry.isFile()) 291 return true; 292 293 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { 294 switch (IndexOpts.SystemSymbolFilter) { 295 case IndexingOptions::SystemSymbolFilterKind::None: 296 return true; 297 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: 298 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations)) 299 return true; 300 break; 301 case IndexingOptions::SystemSymbolFilterKind::All: 302 break; 303 } 304 } 305 306 if (isTemplateImplicitInstantiation(D)) { 307 if (!IsRef) 308 return true; 309 D = adjustTemplateImplicitInstantiation(D); 310 if (!D) 311 return true; 312 assert(!isTemplateImplicitInstantiation(D)); 313 } 314 315 if (!OrigD) 316 OrigD = D; 317 318 if (IsRef) 319 Roles |= (unsigned)SymbolRole::Reference; 320 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx)) 321 Roles |= (unsigned)SymbolRole::Definition; 322 else 323 Roles |= (unsigned)SymbolRole::Declaration; 324 325 D = getCanonicalDecl(D); 326 Parent = adjustParent(Parent); 327 if (Parent) 328 Parent = getCanonicalDecl(Parent); 329 330 SmallVector<SymbolRelation, 6> FinalRelations; 331 FinalRelations.reserve(Relations.size()+1); 332 333 auto addRelation = [&](SymbolRelation Rel) { 334 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(), 335 [&](SymbolRelation Elem)->bool { 336 return Elem.RelatedSymbol == Rel.RelatedSymbol; 337 }); 338 if (It != FinalRelations.end()) { 339 It->Roles |= Rel.Roles; 340 } else { 341 FinalRelations.push_back(Rel); 342 } 343 Roles |= Rel.Roles; 344 }; 345 346 if (Parent) { 347 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) { 348 addRelation(SymbolRelation{ 349 (unsigned)SymbolRole::RelationContainedBy, 350 Parent 351 }); 352 } else { 353 addRelation(SymbolRelation{ 354 (unsigned)SymbolRole::RelationChildOf, 355 Parent 356 }); 357 } 358 } 359 360 for (auto &Rel : Relations) { 361 addRelation(SymbolRelation(Rel.Roles, 362 Rel.RelatedSymbol->getCanonicalDecl())); 363 } 364 365 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC }; 366 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset, 367 Node); 368 } 369