blob: 85574d0a314d7deef6f49aeb08a95d55525e8a84 [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) {
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +000053 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000054 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
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000103bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
104 TemplateSpecializationKind TKind = TSK_Undeclared;
105 if (const ClassTemplateSpecializationDecl *
106 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
107 TKind = SD->getSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000108 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000109 TKind = FD->getTemplateSpecializationKind();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000110 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
111 TKind = VD->getTemplateSpecializationKind();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000112 }
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 }
Saleem Abdulrasool9b0ac332016-02-15 00:36:52 +0000122 llvm_unreachable("invalid TemplateSpecializationKind");
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000123}
124
125bool 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
139static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
140 if (const ClassTemplateSpecializationDecl *
141 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
142 return SD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000143 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000144 return FD->getTemplateInstantiationPattern();
Argyrios Kyrtzidis9d8ab722016-11-07 21:20:15 +0000145 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
146 return VD->getTemplateInstantiationPattern();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000147 }
148 return nullptr;
149}
150
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000151static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000152 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))
Argyrios Kyrtzidis66c49f72016-03-31 20:18:22 +0000162 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000163
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
175static 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;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000186 } 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
197static 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
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000207static bool shouldReportOccurrenceForSystemDeclOnlyMode(
208 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
209 if (!IsRef)
210 return true;
211
212 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
213 bool accept = false;
214 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
215 switch (r) {
216 case SymbolRole::RelationChildOf:
217 case SymbolRole::RelationBaseOf:
218 case SymbolRole::RelationOverrideOf:
219 case SymbolRole::RelationExtendedBy:
220 case SymbolRole::RelationAccessorOf:
221 case SymbolRole::RelationIBTypeOf:
222 accept = true;
223 return false;
224 case SymbolRole::Declaration:
225 case SymbolRole::Definition:
226 case SymbolRole::Reference:
227 case SymbolRole::Read:
228 case SymbolRole::Write:
229 case SymbolRole::Call:
230 case SymbolRole::Dynamic:
231 case SymbolRole::AddressOf:
232 case SymbolRole::Implicit:
233 case SymbolRole::RelationReceivedBy:
234 case SymbolRole::RelationCalledBy:
235 case SymbolRole::RelationContainedBy:
Alex Lorenzf6071c32017-04-20 10:43:22 +0000236 case SymbolRole::RelationSpecializationOf:
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000237 return true;
238 }
Simon Pilgrimdfbf0492017-03-24 16:59:14 +0000239 llvm_unreachable("Unsupported SymbolRole value!");
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000240 });
241 return accept;
242 };
243
244 for (auto &Rel : Relations) {
245 if (acceptForRelation(Rel.Roles))
246 return true;
247 }
248
249 return false;
250}
251
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000252bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
253 bool IsRef, const Decl *Parent,
254 SymbolRoleSet Roles,
255 ArrayRef<SymbolRelation> Relations,
256 const Expr *OrigE,
257 const Decl *OrigD,
258 const DeclContext *ContainerDC) {
259 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
260 return true;
261 if (!isa<NamedDecl>(D) ||
262 (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
263 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
264 return true;
265
266 SourceManager &SM = Ctx->getSourceManager();
267 Loc = SM.getFileLoc(Loc);
268 if (Loc.isInvalid())
269 return true;
270
271 FileID FID;
272 unsigned Offset;
273 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
274 if (FID.isInvalid())
275 return true;
276
277 bool Invalid = false;
278 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
279 if (Invalid || !SEntry.isFile())
280 return true;
281
282 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
283 switch (IndexOpts.SystemSymbolFilter) {
284 case IndexingOptions::SystemSymbolFilterKind::None:
285 return true;
286 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
Argyrios Kyrtzidisa9876ca2017-03-23 16:34:47 +0000287 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000288 return true;
289 break;
290 case IndexingOptions::SystemSymbolFilterKind::All:
291 break;
292 }
293 }
294
295 if (isTemplateImplicitInstantiation(D)) {
296 if (!IsRef)
297 return true;
298 D = adjustTemplateImplicitInstantiation(D);
299 if (!D)
300 return true;
301 assert(!isTemplateImplicitInstantiation(D));
302 }
303
304 if (!OrigD)
305 OrigD = D;
306
307 if (IsRef)
308 Roles |= (unsigned)SymbolRole::Reference;
Argyrios Kyrtzidis74790482017-02-17 04:49:41 +0000309 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000310 Roles |= (unsigned)SymbolRole::Definition;
311 else
312 Roles |= (unsigned)SymbolRole::Declaration;
313
314 D = getCanonicalDecl(D);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000315 Parent = adjustParent(Parent);
316 if (Parent)
317 Parent = getCanonicalDecl(Parent);
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000318
319 SmallVector<SymbolRelation, 6> FinalRelations;
320 FinalRelations.reserve(Relations.size()+1);
321
322 auto addRelation = [&](SymbolRelation Rel) {
323 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
324 [&](SymbolRelation Elem)->bool {
325 return Elem.RelatedSymbol == Rel.RelatedSymbol;
326 });
327 if (It != FinalRelations.end()) {
328 It->Roles |= Rel.Roles;
329 } else {
330 FinalRelations.push_back(Rel);
331 }
332 Roles |= Rel.Roles;
333 };
334
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000335 if (Parent) {
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +0000336 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000337 addRelation(SymbolRelation{
338 (unsigned)SymbolRole::RelationContainedBy,
339 Parent
340 });
Argyrios Kyrtzidis6d1a15b22017-02-26 05:37:56 +0000341 } else {
Argyrios Kyrtzidisde0f5082017-01-11 21:01:07 +0000342 addRelation(SymbolRelation{
343 (unsigned)SymbolRole::RelationChildOf,
344 Parent
345 });
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000346 }
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000347 }
Argyrios Kyrtzidisdf60aa82017-01-11 20:51:10 +0000348
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000349 for (auto &Rel : Relations) {
350 addRelation(SymbolRelation(Rel.Roles,
351 Rel.RelatedSymbol->getCanonicalDecl()));
352 }
353
354 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
355 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
356 Node);
357}