blob: 9ac22f85e1de98327ab09f898b23ce74d0ef4a5f [file] [log] [blame]
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +00001//===- 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
17using namespace clang;
18using namespace index;
19
20bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
21 return IndexOpts.IndexFunctionLocals;
22}
23
24bool 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
32bool 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
43bool 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
60bool 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
95bool 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
120bool 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 }
Saleem Abdulrasool9b0ac332016-02-15 00:36:52 +0000138 llvm_unreachable("invalid TemplateSpecializationKind");
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000139}
140
141bool 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
155static 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
166static 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
190static 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
216static 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
226bool 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}