blob: 06b24cedb35b8dc49ae9db8fd2a4427c316651e9 [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) {
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000027 return handleDecl(D, D->getLocation(), Roles, Relations);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000028}
29
30bool 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();
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000036
37 const Decl *OrigD = D;
38 if (isa<ObjCPropertyImplDecl>(D)) {
39 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
40 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000041 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
42 Roles, Relations,
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000043 nullptr, OrigD, DC);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000044}
45
46bool 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
63bool IndexingContext::importedModule(const ImportDecl *ImportD) {
Argyrios Kyrtzidis113387e2016-02-29 07:56:07 +000064 SourceLocation Loc;
65 auto IdLocs = ImportD->getIdentifierLocs();
66 if (!IdLocs.empty())
67 Loc = IdLocs.front();
68 else
69 Loc = ImportD->getLocation();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000070 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:
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000089 return true;
Ben Langmuir6aed6b42016-07-14 18:51:55 +000090 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000091 case IndexingOptions::SystemSymbolFilterKind::All:
92 break;
93 }
94 }
95
Ben Langmuir6aed6b42016-07-14 18:51:55 +000096 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000097 if (ImportD->isImplicit())
98 Roles |= (unsigned)SymbolRole::Implicit;
99
100 return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
101}
102
103bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
104 assert(D);
105
106 if (isa<TemplateTemplateParmDecl>(D))
107 return true;
108
Argyrios Kyrtzidis8757fc52016-03-04 04:24:32 +0000109 if (isa<ObjCTypeParamDecl>(D))
110 return true;
111
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000112 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
131bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
132 TemplateSpecializationKind TKind = TSK_Undeclared;
133 if (const ClassTemplateSpecializationDecl *
134 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
135 TKind = SD->getSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000136 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000137 TKind = FD->getTemplateSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000138 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
139 TKind = VD->getTemplateSpecializationKind();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000140 }
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 }
Saleem Abdulrasool9b0ac332016-02-15 00:36:52 +0000150 llvm_unreachable("invalid TemplateSpecializationKind");
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000151}
152
153bool 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
167static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
168 if (const ClassTemplateSpecializationDecl *
169 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
170 return SD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000171 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000172 return FD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000173 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
174 return VD->getTemplateInstantiationPattern();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000175 }
176 return nullptr;
177}
178
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000179static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000180 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))
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000190 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000191
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
203static 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;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000214 } 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
225static 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
235bool 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;
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +0000292 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000293 Roles |= (unsigned)SymbolRole::Definition;
294 else
295 Roles |= (unsigned)SymbolRole::Declaration;
296
297 D = getCanonicalDecl(D);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000298 Parent = adjustParent(Parent);
299 if (Parent)
300 Parent = getCanonicalDecl(Parent);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000301
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
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000318 if (Parent) {
319 if (IsRef) {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000320 addRelation(SymbolRelation{
321 (unsigned)SymbolRole::RelationContainedBy,
322 Parent
323 });
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000324 } else if (!cast<DeclContext>(Parent)->isFunctionOrMethod()) {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000325 addRelation(SymbolRelation{
326 (unsigned)SymbolRole::RelationChildOf,
327 Parent
328 });
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000329 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000330 }
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000331
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000332 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}