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