blob: 1645a9ab0bdcbf191f8d322917477116a7b0acfd [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) {
Argyrios Kyrtzidis113387e2016-02-29 07:56:07 +000061 SourceLocation Loc;
62 auto IdLocs = ImportD->getIdentifierLocs();
63 if (!IdLocs.empty())
64 Loc = IdLocs.front();
65 else
66 Loc = ImportD->getLocation();
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000067 SourceManager &SM = Ctx->getSourceManager();
68 Loc = SM.getFileLoc(Loc);
69 if (Loc.isInvalid())
70 return true;
71
72 FileID FID;
73 unsigned Offset;
74 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
75 if (FID.isInvalid())
76 return true;
77
78 bool Invalid = false;
79 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
80 if (Invalid || !SEntry.isFile())
81 return true;
82
83 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
84 switch (IndexOpts.SystemSymbolFilter) {
85 case IndexingOptions::SystemSymbolFilterKind::None:
86 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
87 return true;
88 case IndexingOptions::SystemSymbolFilterKind::All:
89 break;
90 }
91 }
92
Argyrios Kyrtzidis113387e2016-02-29 07:56:07 +000093 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +000094 if (ImportD->isImplicit())
95 Roles |= (unsigned)SymbolRole::Implicit;
96
97 return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
98}
99
100bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
101 assert(D);
102
103 if (isa<TemplateTemplateParmDecl>(D))
104 return true;
105
106 if (!D->getParentFunctionOrMethod())
107 return false;
108
109 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
110 switch (ND->getFormalLinkage()) {
111 case NoLinkage:
112 case VisibleNoLinkage:
113 case InternalLinkage:
114 return true;
115 case UniqueExternalLinkage:
116 llvm_unreachable("Not a sema linkage");
117 case ExternalLinkage:
118 return false;
119 }
120 }
121
122 return true;
123}
124
125bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
126 TemplateSpecializationKind TKind = TSK_Undeclared;
127 if (const ClassTemplateSpecializationDecl *
128 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
129 TKind = SD->getSpecializationKind();
130 }
131 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
132 TKind = FD->getTemplateSpecializationKind();
133 }
134 switch (TKind) {
135 case TSK_Undeclared:
136 case TSK_ExplicitSpecialization:
137 return false;
138 case TSK_ImplicitInstantiation:
139 case TSK_ExplicitInstantiationDeclaration:
140 case TSK_ExplicitInstantiationDefinition:
141 return true;
142 }
Saleem Abdulrasool9b0ac332016-02-15 00:36:52 +0000143 llvm_unreachable("invalid TemplateSpecializationKind");
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +0000144}
145
146bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
147 if (isa<ObjCInterfaceDecl>(D))
148 return false;
149 if (isa<ObjCCategoryDecl>(D))
150 return false;
151 if (isa<ObjCIvarDecl>(D))
152 return false;
153 if (isa<ObjCMethodDecl>(D))
154 return false;
155 if (isa<ImportDecl>(D))
156 return false;
157 return true;
158}
159
160static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
161 if (const ClassTemplateSpecializationDecl *
162 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
163 return SD->getTemplateInstantiationPattern();
164 }
165 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
166 return FD->getTemplateInstantiationPattern();
167 }
168 return nullptr;
169}
170
171static bool isDeclADefinition(const Decl *D, ASTContext &Ctx) {
172 if (auto VD = dyn_cast<VarDecl>(D))
173 return VD->isThisDeclarationADefinition(Ctx);
174
175 if (auto FD = dyn_cast<FunctionDecl>(D))
176 return FD->isThisDeclarationADefinition();
177
178 if (auto TD = dyn_cast<TagDecl>(D))
179 return TD->isThisDeclarationADefinition();
180
181 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
182 return MD->isThisDeclarationADefinition();
183
184 if (isa<TypedefNameDecl>(D) ||
185 isa<EnumConstantDecl>(D) ||
186 isa<FieldDecl>(D) ||
187 isa<MSPropertyDecl>(D) ||
188 isa<ObjCImplDecl>(D) ||
189 isa<ObjCPropertyImplDecl>(D))
190 return true;
191
192 return false;
193}
194
195static const Decl *adjustParent(const Decl *Parent) {
196 if (!Parent)
197 return nullptr;
198 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
199 if (isa<TranslationUnitDecl>(Parent))
200 return nullptr;
201 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
202 continue;
203 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
204 if (NS->isAnonymousNamespace())
205 continue;
206 } else if (auto EnumD = dyn_cast<EnumDecl>(Parent)) {
207 // Move enumerators under anonymous enum to the enclosing parent.
208 if (EnumD->getDeclName().isEmpty())
209 continue;
210 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
211 if (RD->isAnonymousStructOrUnion())
212 continue;
213 } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
214 if (FD->getDeclName().isEmpty())
215 continue;
216 }
217 return Parent;
218 }
219}
220
221static const Decl *getCanonicalDecl(const Decl *D) {
222 D = D->getCanonicalDecl();
223 if (auto TD = dyn_cast<TemplateDecl>(D)) {
224 D = TD->getTemplatedDecl();
225 assert(D->isCanonicalDecl());
226 }
227
228 return D;
229}
230
231bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
232 bool IsRef, const Decl *Parent,
233 SymbolRoleSet Roles,
234 ArrayRef<SymbolRelation> Relations,
235 const Expr *OrigE,
236 const Decl *OrigD,
237 const DeclContext *ContainerDC) {
238 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
239 return true;
240 if (!isa<NamedDecl>(D) ||
241 (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
242 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
243 return true;
244
245 SourceManager &SM = Ctx->getSourceManager();
246 Loc = SM.getFileLoc(Loc);
247 if (Loc.isInvalid())
248 return true;
249
250 FileID FID;
251 unsigned Offset;
252 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
253 if (FID.isInvalid())
254 return true;
255
256 bool Invalid = false;
257 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
258 if (Invalid || !SEntry.isFile())
259 return true;
260
261 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
262 switch (IndexOpts.SystemSymbolFilter) {
263 case IndexingOptions::SystemSymbolFilterKind::None:
264 return true;
265 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
266 if (IsRef)
267 return true;
268 break;
269 case IndexingOptions::SystemSymbolFilterKind::All:
270 break;
271 }
272 }
273
274 if (isTemplateImplicitInstantiation(D)) {
275 if (!IsRef)
276 return true;
277 D = adjustTemplateImplicitInstantiation(D);
278 if (!D)
279 return true;
280 assert(!isTemplateImplicitInstantiation(D));
281 }
282
283 if (!OrigD)
284 OrigD = D;
285
286 if (IsRef)
287 Roles |= (unsigned)SymbolRole::Reference;
288 else if (isDeclADefinition(D, *Ctx))
289 Roles |= (unsigned)SymbolRole::Definition;
290 else
291 Roles |= (unsigned)SymbolRole::Declaration;
292
293 D = getCanonicalDecl(D);
294 if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) {
295 // operator new declarations will link to the implicit one as canonical.
296 return true;
297 }
298 Parent = adjustParent(Parent);
299 if (Parent)
300 Parent = getCanonicalDecl(Parent);
301 assert(!Parent || !Parent->isImplicit() ||
302 isa<ObjCInterfaceDecl>(Parent) || isa<ObjCMethodDecl>(Parent));
303
304 SmallVector<SymbolRelation, 6> FinalRelations;
305 FinalRelations.reserve(Relations.size()+1);
306
307 auto addRelation = [&](SymbolRelation Rel) {
308 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
309 [&](SymbolRelation Elem)->bool {
310 return Elem.RelatedSymbol == Rel.RelatedSymbol;
311 });
312 if (It != FinalRelations.end()) {
313 It->Roles |= Rel.Roles;
314 } else {
315 FinalRelations.push_back(Rel);
316 }
317 Roles |= Rel.Roles;
318 };
319
320 if (!IsRef && Parent && !cast<DeclContext>(Parent)->isFunctionOrMethod()) {
321 addRelation(SymbolRelation{(unsigned)SymbolRole::RelationChildOf, Parent});
322 }
323 for (auto &Rel : Relations) {
324 addRelation(SymbolRelation(Rel.Roles,
325 Rel.RelatedSymbol->getCanonicalDecl()));
326 }
327
328 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
329 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
330 Node);
331}