blob: 254abecd4e4fb9d1da3c0b9ebb68e1d20bf9277e [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
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000031bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
32 return IndexOpts.IndexFunctionLocals;
33}
34
35bool IndexingContext::handleDecl(const Decl *D,
36 SymbolRoleSet Roles,
37 ArrayRef<SymbolRelation> Relations) {
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000038 return handleDecl(D, D->getLocation(), Roles, Relations);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000039}
40
41bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
42 SymbolRoleSet Roles,
43 ArrayRef<SymbolRelation> Relations,
44 const DeclContext *DC) {
45 if (!DC)
46 DC = D->getDeclContext();
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000047
48 const Decl *OrigD = D;
49 if (isa<ObjCPropertyImplDecl>(D)) {
50 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
51 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000052 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
53 Roles, Relations,
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +000054 nullptr, OrigD, DC);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000055}
56
57bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
58 const NamedDecl *Parent,
59 const DeclContext *DC,
60 SymbolRoleSet Roles,
61 ArrayRef<SymbolRelation> Relations,
62 const Expr *RefE,
63 const Decl *RefD) {
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +000064 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000065 return true;
66
67 if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
68 return true;
69
70 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
71 RefE, RefD, DC);
72}
73
74bool IndexingContext::importedModule(const ImportDecl *ImportD) {
Argyrios Kyrtzidis113387e2016-02-29 07:56:07 +000075 SourceLocation Loc;
76 auto IdLocs = ImportD->getIdentifierLocs();
77 if (!IdLocs.empty())
78 Loc = IdLocs.front();
79 else
80 Loc = ImportD->getLocation();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000081 SourceManager &SM = Ctx->getSourceManager();
82 Loc = SM.getFileLoc(Loc);
83 if (Loc.isInvalid())
84 return true;
85
86 FileID FID;
87 unsigned Offset;
88 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
89 if (FID.isInvalid())
90 return true;
91
92 bool Invalid = false;
93 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
94 if (Invalid || !SEntry.isFile())
95 return true;
96
97 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
98 switch (IndexOpts.SystemSymbolFilter) {
99 case IndexingOptions::SystemSymbolFilterKind::None:
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000100 return true;
Ben Langmuir6aed6b42016-07-14 18:51:55 +0000101 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000102 case IndexingOptions::SystemSymbolFilterKind::All:
103 break;
104 }
105 }
106
Ben Langmuir6aed6b42016-07-14 18:51:55 +0000107 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000108 if (ImportD->isImplicit())
109 Roles |= (unsigned)SymbolRole::Implicit;
110
111 return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
112}
113
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000114bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
115 TemplateSpecializationKind TKind = TSK_Undeclared;
116 if (const ClassTemplateSpecializationDecl *
117 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
118 TKind = SD->getSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000119 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000120 TKind = FD->getTemplateSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000121 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
122 TKind = VD->getTemplateSpecializationKind();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000123 }
124 switch (TKind) {
125 case TSK_Undeclared:
126 case TSK_ExplicitSpecialization:
127 return false;
128 case TSK_ImplicitInstantiation:
129 case TSK_ExplicitInstantiationDeclaration:
130 case TSK_ExplicitInstantiationDefinition:
131 return true;
132 }
Saleem Abdulrasool9b0ac332016-02-15 00:36:52 +0000133 llvm_unreachable("invalid TemplateSpecializationKind");
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000134}
135
136bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
137 if (isa<ObjCInterfaceDecl>(D))
138 return false;
139 if (isa<ObjCCategoryDecl>(D))
140 return false;
141 if (isa<ObjCIvarDecl>(D))
142 return false;
143 if (isa<ObjCMethodDecl>(D))
144 return false;
145 if (isa<ImportDecl>(D))
146 return false;
147 return true;
148}
149
150static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
151 if (const ClassTemplateSpecializationDecl *
152 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
153 return SD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000154 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000155 return FD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000156 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
157 return VD->getTemplateInstantiationPattern();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000158 }
159 return nullptr;
160}
161
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000162static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000163 if (auto VD = dyn_cast<VarDecl>(D))
164 return VD->isThisDeclarationADefinition(Ctx);
165
166 if (auto FD = dyn_cast<FunctionDecl>(D))
167 return FD->isThisDeclarationADefinition();
168
169 if (auto TD = dyn_cast<TagDecl>(D))
170 return TD->isThisDeclarationADefinition();
171
172 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000173 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000174
175 if (isa<TypedefNameDecl>(D) ||
176 isa<EnumConstantDecl>(D) ||
177 isa<FieldDecl>(D) ||
178 isa<MSPropertyDecl>(D) ||
179 isa<ObjCImplDecl>(D) ||
180 isa<ObjCPropertyImplDecl>(D))
181 return true;
182
183 return false;
184}
185
186static const Decl *adjustParent(const Decl *Parent) {
187 if (!Parent)
188 return nullptr;
189 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
190 if (isa<TranslationUnitDecl>(Parent))
191 return nullptr;
192 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
193 continue;
194 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
195 if (NS->isAnonymousNamespace())
196 continue;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000197 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
198 if (RD->isAnonymousStructOrUnion())
199 continue;
200 } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
201 if (FD->getDeclName().isEmpty())
202 continue;
203 }
204 return Parent;
205 }
206}
207
208static const Decl *getCanonicalDecl(const Decl *D) {
209 D = D->getCanonicalDecl();
210 if (auto TD = dyn_cast<TemplateDecl>(D)) {
211 D = TD->getTemplatedDecl();
212 assert(D->isCanonicalDecl());
213 }
214
215 return D;
216}
217
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000218static bool shouldReportOccurrenceForSystemDeclOnlyMode(
219 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
220 if (!IsRef)
221 return true;
222
223 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
224 bool accept = false;
225 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
226 switch (r) {
227 case SymbolRole::RelationChildOf:
228 case SymbolRole::RelationBaseOf:
229 case SymbolRole::RelationOverrideOf:
230 case SymbolRole::RelationExtendedBy:
231 case SymbolRole::RelationAccessorOf:
232 case SymbolRole::RelationIBTypeOf:
233 accept = true;
234 return false;
235 case SymbolRole::Declaration:
236 case SymbolRole::Definition:
237 case SymbolRole::Reference:
238 case SymbolRole::Read:
239 case SymbolRole::Write:
240 case SymbolRole::Call:
241 case SymbolRole::Dynamic:
242 case SymbolRole::AddressOf:
243 case SymbolRole::Implicit:
244 case SymbolRole::RelationReceivedBy:
245 case SymbolRole::RelationCalledBy:
246 case SymbolRole::RelationContainedBy:
Alex Lorenzf6071c32017-04-20 10:43:22 +0000247 case SymbolRole::RelationSpecializationOf:
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000248 return true;
249 }
Simon Pilgrimdfbf0492017-03-24 16:59:14 +0000250 llvm_unreachable("Unsupported SymbolRole value!");
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000251 });
252 return accept;
253 };
254
255 for (auto &Rel : Relations) {
256 if (acceptForRelation(Rel.Roles))
257 return true;
258 }
259
260 return false;
261}
262
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000263bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
264 bool IsRef, const Decl *Parent,
265 SymbolRoleSet Roles,
266 ArrayRef<SymbolRelation> Relations,
267 const Expr *OrigE,
268 const Decl *OrigD,
269 const DeclContext *ContainerDC) {
270 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
271 return true;
272 if (!isa<NamedDecl>(D) ||
273 (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
274 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
275 return true;
276
277 SourceManager &SM = Ctx->getSourceManager();
278 Loc = SM.getFileLoc(Loc);
279 if (Loc.isInvalid())
280 return true;
281
282 FileID FID;
283 unsigned Offset;
284 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
285 if (FID.isInvalid())
286 return true;
287
288 bool Invalid = false;
289 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
290 if (Invalid || !SEntry.isFile())
291 return true;
292
293 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
294 switch (IndexOpts.SystemSymbolFilter) {
295 case IndexingOptions::SystemSymbolFilterKind::None:
296 return true;
297 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000298 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000299 return true;
300 break;
301 case IndexingOptions::SystemSymbolFilterKind::All:
302 break;
303 }
304 }
305
306 if (isTemplateImplicitInstantiation(D)) {
307 if (!IsRef)
308 return true;
309 D = adjustTemplateImplicitInstantiation(D);
310 if (!D)
311 return true;
312 assert(!isTemplateImplicitInstantiation(D));
313 }
314
315 if (!OrigD)
316 OrigD = D;
317
318 if (IsRef)
319 Roles |= (unsigned)SymbolRole::Reference;
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +0000320 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000321 Roles |= (unsigned)SymbolRole::Definition;
322 else
323 Roles |= (unsigned)SymbolRole::Declaration;
324
325 D = getCanonicalDecl(D);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000326 Parent = adjustParent(Parent);
327 if (Parent)
328 Parent = getCanonicalDecl(Parent);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000329
330 SmallVector<SymbolRelation, 6> FinalRelations;
331 FinalRelations.reserve(Relations.size()+1);
332
333 auto addRelation = [&](SymbolRelation Rel) {
334 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
335 [&](SymbolRelation Elem)->bool {
336 return Elem.RelatedSymbol == Rel.RelatedSymbol;
337 });
338 if (It != FinalRelations.end()) {
339 It->Roles |= Rel.Roles;
340 } else {
341 FinalRelations.push_back(Rel);
342 }
343 Roles |= Rel.Roles;
344 };
345
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000346 if (Parent) {
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +0000347 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000348 addRelation(SymbolRelation{
349 (unsigned)SymbolRole::RelationContainedBy,
350 Parent
351 });
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +0000352 } else {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000353 addRelation(SymbolRelation{
354 (unsigned)SymbolRole::RelationChildOf,
355 Parent
356 });
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000357 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000358 }
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000359
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000360 for (auto &Rel : Relations) {
361 addRelation(SymbolRelation(Rel.Roles,
362 Rel.RelatedSymbol->getCanonicalDecl()));
363 }
364
365 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
366 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
367 Node);
368}