blob: 5cebb198460ffc12d29ca094488e53d48bf12aaa [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
Argyrios Kyrtzidis6e5ca5b2017-04-21 05:42:46 +000020static bool isGeneratedDecl(const Decl *D) {
21 if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
22 return attr->getGeneratedDeclaration();
23 }
24 return false;
25}
26
27bool IndexingContext::shouldIndex(const Decl *D) {
28 return !isGeneratedDecl(D);
29}
30
Alex Lorenza352ba02017-04-24 14:04:58 +000031const LangOptions &IndexingContext::getLangOpts() const {
32 return Ctx->getLangOpts();
33}
34
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000035bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
36 return IndexOpts.IndexFunctionLocals;
37}
38
39bool IndexingContext::handleDecl(const Decl *D,
40 SymbolRoleSet Roles,
41 ArrayRef<SymbolRelation> Relations) {
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000042 return handleDecl(D, D->getLocation(), Roles, Relations);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000043}
44
45bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
46 SymbolRoleSet Roles,
47 ArrayRef<SymbolRelation> Relations,
48 const DeclContext *DC) {
49 if (!DC)
50 DC = D->getDeclContext();
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000051
52 const Decl *OrigD = D;
53 if (isa<ObjCPropertyImplDecl>(D)) {
54 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
55 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000056 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
57 Roles, Relations,
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000058 nullptr, OrigD, DC);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000059}
60
61bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
62 const NamedDecl *Parent,
63 const DeclContext *DC,
64 SymbolRoleSet Roles,
65 ArrayRef<SymbolRelation> Relations,
66 const Expr *RefE,
67 const Decl *RefD) {
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +000068 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000069 return true;
70
71 if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
72 return true;
73
74 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
75 RefE, RefD, DC);
76}
77
78bool IndexingContext::importedModule(const ImportDecl *ImportD) {
Argyrios Kyrtzidis113387e2016-02-29 07:56:07 +000079 SourceLocation Loc;
80 auto IdLocs = ImportD->getIdentifierLocs();
81 if (!IdLocs.empty())
82 Loc = IdLocs.front();
83 else
84 Loc = ImportD->getLocation();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000085 SourceManager &SM = Ctx->getSourceManager();
86 Loc = SM.getFileLoc(Loc);
87 if (Loc.isInvalid())
88 return true;
89
90 FileID FID;
91 unsigned Offset;
92 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
93 if (FID.isInvalid())
94 return true;
95
96 bool Invalid = false;
97 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
98 if (Invalid || !SEntry.isFile())
99 return true;
100
101 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
102 switch (IndexOpts.SystemSymbolFilter) {
103 case IndexingOptions::SystemSymbolFilterKind::None:
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000104 return true;
Ben Langmuir6aed6b42016-07-14 18:51:55 +0000105 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000106 case IndexingOptions::SystemSymbolFilterKind::All:
107 break;
108 }
109 }
110
Ben Langmuir6aed6b42016-07-14 18:51:55 +0000111 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000112 if (ImportD->isImplicit())
113 Roles |= (unsigned)SymbolRole::Implicit;
114
115 return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
116}
117
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000118bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
119 TemplateSpecializationKind TKind = TSK_Undeclared;
120 if (const ClassTemplateSpecializationDecl *
121 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
122 TKind = SD->getSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000123 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000124 TKind = FD->getTemplateSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000125 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
126 TKind = VD->getTemplateSpecializationKind();
Alex Lorenz048c8a92017-05-15 14:26:22 +0000127 } else if (isa<FieldDecl>(D)) {
128 if (const auto *Parent =
129 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
130 TKind = Parent->getSpecializationKind();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000131 }
132 switch (TKind) {
133 case TSK_Undeclared:
134 case TSK_ExplicitSpecialization:
135 return false;
136 case TSK_ImplicitInstantiation:
137 case TSK_ExplicitInstantiationDeclaration:
138 case TSK_ExplicitInstantiationDefinition:
139 return true;
140 }
Saleem Abdulrasool9b0ac332016-02-15 00:36:52 +0000141 llvm_unreachable("invalid TemplateSpecializationKind");
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000142}
143
144bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
145 if (isa<ObjCInterfaceDecl>(D))
146 return false;
147 if (isa<ObjCCategoryDecl>(D))
148 return false;
149 if (isa<ObjCIvarDecl>(D))
150 return false;
151 if (isa<ObjCMethodDecl>(D))
152 return false;
153 if (isa<ImportDecl>(D))
154 return false;
155 return true;
156}
157
158static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
159 if (const ClassTemplateSpecializationDecl *
160 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
161 return SD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000162 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000163 return FD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000164 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
165 return VD->getTemplateInstantiationPattern();
Alex Lorenz048c8a92017-05-15 14:26:22 +0000166 } else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
167 if (const auto *Parent =
168 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) {
169 const CXXRecordDecl *Pattern = Parent->getTemplateInstantiationPattern();
170 for (const NamedDecl *ND : Pattern->lookup(FD->getDeclName())) {
171 if (ND->isImplicit())
172 continue;
173 if (isa<FieldDecl>(ND))
174 return ND;
175 }
176 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000177 }
178 return nullptr;
179}
180
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000181static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000182 if (auto VD = dyn_cast<VarDecl>(D))
183 return VD->isThisDeclarationADefinition(Ctx);
184
185 if (auto FD = dyn_cast<FunctionDecl>(D))
186 return FD->isThisDeclarationADefinition();
187
188 if (auto TD = dyn_cast<TagDecl>(D))
189 return TD->isThisDeclarationADefinition();
190
191 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000192 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000193
194 if (isa<TypedefNameDecl>(D) ||
195 isa<EnumConstantDecl>(D) ||
196 isa<FieldDecl>(D) ||
197 isa<MSPropertyDecl>(D) ||
198 isa<ObjCImplDecl>(D) ||
199 isa<ObjCPropertyImplDecl>(D))
200 return true;
201
202 return false;
203}
204
205static const Decl *adjustParent(const Decl *Parent) {
206 if (!Parent)
207 return nullptr;
208 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
209 if (isa<TranslationUnitDecl>(Parent))
210 return nullptr;
211 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
212 continue;
213 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
214 if (NS->isAnonymousNamespace())
215 continue;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000216 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
217 if (RD->isAnonymousStructOrUnion())
218 continue;
219 } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
220 if (FD->getDeclName().isEmpty())
221 continue;
222 }
223 return Parent;
224 }
225}
226
227static const Decl *getCanonicalDecl(const Decl *D) {
228 D = D->getCanonicalDecl();
229 if (auto TD = dyn_cast<TemplateDecl>(D)) {
230 D = TD->getTemplatedDecl();
231 assert(D->isCanonicalDecl());
232 }
233
234 return D;
235}
236
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000237static bool shouldReportOccurrenceForSystemDeclOnlyMode(
238 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
239 if (!IsRef)
240 return true;
241
242 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
243 bool accept = false;
244 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
245 switch (r) {
246 case SymbolRole::RelationChildOf:
247 case SymbolRole::RelationBaseOf:
248 case SymbolRole::RelationOverrideOf:
249 case SymbolRole::RelationExtendedBy:
250 case SymbolRole::RelationAccessorOf:
251 case SymbolRole::RelationIBTypeOf:
252 accept = true;
253 return false;
254 case SymbolRole::Declaration:
255 case SymbolRole::Definition:
256 case SymbolRole::Reference:
257 case SymbolRole::Read:
258 case SymbolRole::Write:
259 case SymbolRole::Call:
260 case SymbolRole::Dynamic:
261 case SymbolRole::AddressOf:
262 case SymbolRole::Implicit:
263 case SymbolRole::RelationReceivedBy:
264 case SymbolRole::RelationCalledBy:
265 case SymbolRole::RelationContainedBy:
Alex Lorenzf6071c32017-04-20 10:43:22 +0000266 case SymbolRole::RelationSpecializationOf:
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000267 return true;
268 }
Simon Pilgrimdfbf0492017-03-24 16:59:14 +0000269 llvm_unreachable("Unsupported SymbolRole value!");
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000270 });
271 return accept;
272 };
273
274 for (auto &Rel : Relations) {
275 if (acceptForRelation(Rel.Roles))
276 return true;
277 }
278
279 return false;
280}
281
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000282bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
283 bool IsRef, const Decl *Parent,
284 SymbolRoleSet Roles,
285 ArrayRef<SymbolRelation> Relations,
286 const Expr *OrigE,
287 const Decl *OrigD,
288 const DeclContext *ContainerDC) {
289 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
290 return true;
291 if (!isa<NamedDecl>(D) ||
292 (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
293 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
294 return true;
295
296 SourceManager &SM = Ctx->getSourceManager();
297 Loc = SM.getFileLoc(Loc);
298 if (Loc.isInvalid())
299 return true;
300
301 FileID FID;
302 unsigned Offset;
303 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
304 if (FID.isInvalid())
305 return true;
306
307 bool Invalid = false;
308 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
309 if (Invalid || !SEntry.isFile())
310 return true;
311
312 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
313 switch (IndexOpts.SystemSymbolFilter) {
314 case IndexingOptions::SystemSymbolFilterKind::None:
315 return true;
316 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000317 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000318 return true;
319 break;
320 case IndexingOptions::SystemSymbolFilterKind::All:
321 break;
322 }
323 }
324
325 if (isTemplateImplicitInstantiation(D)) {
326 if (!IsRef)
327 return true;
328 D = adjustTemplateImplicitInstantiation(D);
329 if (!D)
330 return true;
331 assert(!isTemplateImplicitInstantiation(D));
332 }
333
334 if (!OrigD)
335 OrigD = D;
336
337 if (IsRef)
338 Roles |= (unsigned)SymbolRole::Reference;
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +0000339 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000340 Roles |= (unsigned)SymbolRole::Definition;
341 else
342 Roles |= (unsigned)SymbolRole::Declaration;
343
344 D = getCanonicalDecl(D);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000345 Parent = adjustParent(Parent);
346 if (Parent)
347 Parent = getCanonicalDecl(Parent);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000348
349 SmallVector<SymbolRelation, 6> FinalRelations;
350 FinalRelations.reserve(Relations.size()+1);
351
352 auto addRelation = [&](SymbolRelation Rel) {
353 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
354 [&](SymbolRelation Elem)->bool {
355 return Elem.RelatedSymbol == Rel.RelatedSymbol;
356 });
357 if (It != FinalRelations.end()) {
358 It->Roles |= Rel.Roles;
359 } else {
360 FinalRelations.push_back(Rel);
361 }
362 Roles |= Rel.Roles;
363 };
364
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000365 if (Parent) {
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +0000366 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000367 addRelation(SymbolRelation{
368 (unsigned)SymbolRole::RelationContainedBy,
369 Parent
370 });
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +0000371 } else {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000372 addRelation(SymbolRelation{
373 (unsigned)SymbolRole::RelationChildOf,
374 Parent
375 });
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000376 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000377 }
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000378
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000379 for (auto &Rel : Relations) {
380 addRelation(SymbolRelation(Rel.Roles,
381 Rel.RelatedSymbol->getCanonicalDecl()));
382 }
383
384 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
385 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
386 Node);
387}