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