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() && isFunctionLocalSymbol(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::isTemplateImplicitInstantiation(const Decl *D) { 104 TemplateSpecializationKind TKind = TSK_Undeclared; 105 if (const ClassTemplateSpecializationDecl * 106 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 107 TKind = SD->getSpecializationKind(); 108 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 109 TKind = FD->getTemplateSpecializationKind(); 110 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 111 TKind = VD->getTemplateSpecializationKind(); 112 } 113 switch (TKind) { 114 case TSK_Undeclared: 115 case TSK_ExplicitSpecialization: 116 return false; 117 case TSK_ImplicitInstantiation: 118 case TSK_ExplicitInstantiationDeclaration: 119 case TSK_ExplicitInstantiationDefinition: 120 return true; 121 } 122 llvm_unreachable("invalid TemplateSpecializationKind"); 123 } 124 125 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { 126 if (isa<ObjCInterfaceDecl>(D)) 127 return false; 128 if (isa<ObjCCategoryDecl>(D)) 129 return false; 130 if (isa<ObjCIvarDecl>(D)) 131 return false; 132 if (isa<ObjCMethodDecl>(D)) 133 return false; 134 if (isa<ImportDecl>(D)) 135 return false; 136 return true; 137 } 138 139 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { 140 if (const ClassTemplateSpecializationDecl * 141 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 142 return SD->getTemplateInstantiationPattern(); 143 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 144 return FD->getTemplateInstantiationPattern(); 145 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 146 return VD->getTemplateInstantiationPattern(); 147 } 148 return nullptr; 149 } 150 151 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) { 152 if (auto VD = dyn_cast<VarDecl>(D)) 153 return VD->isThisDeclarationADefinition(Ctx); 154 155 if (auto FD = dyn_cast<FunctionDecl>(D)) 156 return FD->isThisDeclarationADefinition(); 157 158 if (auto TD = dyn_cast<TagDecl>(D)) 159 return TD->isThisDeclarationADefinition(); 160 161 if (auto MD = dyn_cast<ObjCMethodDecl>(D)) 162 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC); 163 164 if (isa<TypedefNameDecl>(D) || 165 isa<EnumConstantDecl>(D) || 166 isa<FieldDecl>(D) || 167 isa<MSPropertyDecl>(D) || 168 isa<ObjCImplDecl>(D) || 169 isa<ObjCPropertyImplDecl>(D)) 170 return true; 171 172 return false; 173 } 174 175 static const Decl *adjustParent(const Decl *Parent) { 176 if (!Parent) 177 return nullptr; 178 for (;; Parent = cast<Decl>(Parent->getDeclContext())) { 179 if (isa<TranslationUnitDecl>(Parent)) 180 return nullptr; 181 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent)) 182 continue; 183 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) { 184 if (NS->isAnonymousNamespace()) 185 continue; 186 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { 187 if (RD->isAnonymousStructOrUnion()) 188 continue; 189 } else if (auto FD = dyn_cast<FieldDecl>(Parent)) { 190 if (FD->getDeclName().isEmpty()) 191 continue; 192 } 193 return Parent; 194 } 195 } 196 197 static const Decl *getCanonicalDecl(const Decl *D) { 198 D = D->getCanonicalDecl(); 199 if (auto TD = dyn_cast<TemplateDecl>(D)) { 200 D = TD->getTemplatedDecl(); 201 assert(D->isCanonicalDecl()); 202 } 203 204 return D; 205 } 206 207 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, 208 bool IsRef, const Decl *Parent, 209 SymbolRoleSet Roles, 210 ArrayRef<SymbolRelation> Relations, 211 const Expr *OrigE, 212 const Decl *OrigD, 213 const DeclContext *ContainerDC) { 214 if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) 215 return true; 216 if (!isa<NamedDecl>(D) || 217 (cast<NamedDecl>(D)->getDeclName().isEmpty() && 218 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D))) 219 return true; 220 221 SourceManager &SM = Ctx->getSourceManager(); 222 Loc = SM.getFileLoc(Loc); 223 if (Loc.isInvalid()) 224 return true; 225 226 FileID FID; 227 unsigned Offset; 228 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); 229 if (FID.isInvalid()) 230 return true; 231 232 bool Invalid = false; 233 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); 234 if (Invalid || !SEntry.isFile()) 235 return true; 236 237 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { 238 switch (IndexOpts.SystemSymbolFilter) { 239 case IndexingOptions::SystemSymbolFilterKind::None: 240 return true; 241 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: 242 if (IsRef) 243 return true; 244 break; 245 case IndexingOptions::SystemSymbolFilterKind::All: 246 break; 247 } 248 } 249 250 if (isTemplateImplicitInstantiation(D)) { 251 if (!IsRef) 252 return true; 253 D = adjustTemplateImplicitInstantiation(D); 254 if (!D) 255 return true; 256 assert(!isTemplateImplicitInstantiation(D)); 257 } 258 259 if (!OrigD) 260 OrigD = D; 261 262 if (IsRef) 263 Roles |= (unsigned)SymbolRole::Reference; 264 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx)) 265 Roles |= (unsigned)SymbolRole::Definition; 266 else 267 Roles |= (unsigned)SymbolRole::Declaration; 268 269 D = getCanonicalDecl(D); 270 Parent = adjustParent(Parent); 271 if (Parent) 272 Parent = getCanonicalDecl(Parent); 273 274 SmallVector<SymbolRelation, 6> FinalRelations; 275 FinalRelations.reserve(Relations.size()+1); 276 277 auto addRelation = [&](SymbolRelation Rel) { 278 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(), 279 [&](SymbolRelation Elem)->bool { 280 return Elem.RelatedSymbol == Rel.RelatedSymbol; 281 }); 282 if (It != FinalRelations.end()) { 283 It->Roles |= Rel.Roles; 284 } else { 285 FinalRelations.push_back(Rel); 286 } 287 Roles |= Rel.Roles; 288 }; 289 290 if (Parent) { 291 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) { 292 addRelation(SymbolRelation{ 293 (unsigned)SymbolRole::RelationContainedBy, 294 Parent 295 }); 296 } else { 297 addRelation(SymbolRelation{ 298 (unsigned)SymbolRole::RelationChildOf, 299 Parent 300 }); 301 } 302 } 303 304 for (auto &Rel : Relations) { 305 addRelation(SymbolRelation(Rel.Roles, 306 Rel.RelatedSymbol->getCanonicalDecl())); 307 } 308 309 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC }; 310 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset, 311 Node); 312 } 313