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