blob: 76f68e564c9319af95d1f4b031ed361d4fd38acc [file] [log] [blame]
Argyrios Kyrtzidisf4fb85b2016-02-12 23:10:59 +00001//===- IndexDecl.cpp - Indexing declarations ------------------------------===//
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/DeclVisitor.h"
13
14using namespace clang;
15using namespace index;
16
17namespace {
18
19class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
20 IndexingContext &IndexCtx;
21
22public:
23 explicit IndexingDeclVisitor(IndexingContext &indexCtx)
24 : IndexCtx(indexCtx) { }
25
26 bool Handled = true;
27
28 bool VisitDecl(const Decl *D) {
29 Handled = false;
30 return true;
31 }
32
33 /// \brief Returns true if the given method has been defined explicitly by the
34 /// user.
35 static bool hasUserDefined(const ObjCMethodDecl *D,
36 const ObjCImplDecl *Container) {
37 const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
38 D->isInstanceMethod());
39 return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
40 }
41
42 void handleDeclarator(const DeclaratorDecl *D,
43 const NamedDecl *Parent = nullptr) {
44 if (!Parent) Parent = D;
45
46 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
47 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
48 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
49 // Only index parameters in definitions, parameters in declarations are
50 // not useful.
51 if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
52 auto *DC = Parm->getDeclContext();
53 if (auto *FD = dyn_cast<FunctionDecl>(DC)) {
54 if (FD->isThisDeclarationADefinition())
55 IndexCtx.handleDecl(Parm);
56 } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) {
57 if (MD->isThisDeclarationADefinition())
58 IndexCtx.handleDecl(Parm);
59 } else {
60 IndexCtx.handleDecl(Parm);
61 }
62 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
63 if (FD->isThisDeclarationADefinition()) {
64 for (auto PI : FD->params()) {
65 IndexCtx.handleDecl(PI);
66 }
67 }
68 }
69 }
70 }
71
72 bool handleObjCMethod(const ObjCMethodDecl *D) {
73 if (!IndexCtx.handleDecl(D, (unsigned)SymbolRole::Dynamic))
74 return false;
75 IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
76 for (const auto *I : D->params())
77 handleDeclarator(I, D);
78
79 if (D->isThisDeclarationADefinition()) {
80 const Stmt *Body = D->getBody();
81 if (Body) {
82 IndexCtx.indexBody(Body, D, D);
83 }
84 }
85 return true;
86 }
87
88 bool VisitFunctionDecl(const FunctionDecl *D) {
89 if (D->isDeleted())
90 return true;
91
92 SymbolRoleSet Roles{};
93 SmallVector<SymbolRelation, 4> Relations;
94 if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
95 if (CXXMD->isVirtual())
96 Roles |= (unsigned)SymbolRole::Dynamic;
97 for (auto I = CXXMD->begin_overridden_methods(),
98 E = CXXMD->end_overridden_methods(); I != E; ++I) {
99 Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
100 }
101 }
102
103 if (!IndexCtx.handleDecl(D, Roles, Relations))
104 return false;
105 handleDeclarator(D);
106
107 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
108 // Constructor initializers.
109 for (const auto *Init : Ctor->inits()) {
110 if (Init->isWritten()) {
111 IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
112 if (const FieldDecl *Member = Init->getAnyMember())
113 IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D,
114 (unsigned)SymbolRole::Write);
115 IndexCtx.indexBody(Init->getInit(), D, D);
116 }
117 }
118 }
119
120 if (D->isThisDeclarationADefinition()) {
121 const Stmt *Body = D->getBody();
122 if (Body) {
123 IndexCtx.indexBody(Body, D, D);
124 }
125 }
126 return true;
127 }
128
129 bool VisitVarDecl(const VarDecl *D) {
130 if (!IndexCtx.handleDecl(D))
131 return false;
132 handleDeclarator(D);
133 IndexCtx.indexBody(D->getInit(), D);
134 return true;
135 }
136
137 bool VisitFieldDecl(const FieldDecl *D) {
138 if (!IndexCtx.handleDecl(D))
139 return false;
140 handleDeclarator(D);
141 if (D->isBitField())
142 IndexCtx.indexBody(D->getBitWidth(), D);
143 else if (D->hasInClassInitializer())
144 IndexCtx.indexBody(D->getInClassInitializer(), D);
145 return true;
146 }
147
148 bool VisitObjCIvarDecl(const ObjCIvarDecl *D) {
149 if (D->getSynthesize()) {
150 // For synthesized ivars, use the location of the ObjC implementation,
151 // not the location of the property.
152 // Otherwise the header file containing the @interface will have different
153 // indexing contents based on whether the @implementation was present or
154 // not in the translation unit.
155 return IndexCtx.handleDecl(D,
156 cast<Decl>(D->getDeclContext())->getLocation(),
157 (unsigned)SymbolRole::Implicit);
158 }
159 if (!IndexCtx.handleDecl(D))
160 return false;
161 handleDeclarator(D);
162 return true;
163 }
164
165 bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
166 handleDeclarator(D);
167 return true;
168 }
169
170 bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
171 if (!IndexCtx.handleDecl(D))
172 return false;
173 IndexCtx.indexBody(D->getInitExpr(), D);
174 return true;
175 }
176
177 bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
178 if (!IndexCtx.handleDecl(D))
179 return false;
180 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
181 return true;
182 }
183
184 bool VisitTagDecl(const TagDecl *D) {
185 // Non-free standing tags are handled in indexTypeSourceInfo.
186 if (D->isFreeStanding()) {
187 if (D->isThisDeclarationADefinition()) {
188 IndexCtx.indexTagDecl(D);
189 } else {
190 auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
191 return IndexCtx.handleReference(D, D->getLocation(), Parent,
192 D->getLexicalDeclContext(),
193 SymbolRoleSet());
194 }
195 }
196 return true;
197 }
198
199 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
200 if (D->isThisDeclarationADefinition()) {
201 if (!IndexCtx.handleDecl(D))
202 return false;
203 IndexCtx.indexDeclContext(D);
204 } else {
205 return IndexCtx.handleReference(D, D->getLocation(), nullptr, nullptr,
206 SymbolRoleSet());
207 }
208 return true;
209 }
210
211 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
212 if (D->isThisDeclarationADefinition()) {
213 if (!IndexCtx.handleDecl(D))
214 return false;
215 IndexCtx.indexDeclContext(D);
216 } else {
217 return IndexCtx.handleReference(D, D->getLocation(), nullptr, nullptr,
218 SymbolRoleSet());
219 }
220 return true;
221 }
222
223 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
224 const ObjCInterfaceDecl *Class = D->getClassInterface();
225 if (!Class)
226 return true;
227
228 if (Class->isImplicitInterfaceDecl())
229 IndexCtx.handleDecl(Class);
230
231 if (!IndexCtx.handleDecl(D))
232 return false;
233
234 // Index the ivars first to make sure the synthesized ivars are indexed
235 // before indexing the methods that can reference them.
236 for (const auto *IvarI : D->ivars())
237 IndexCtx.indexDecl(IvarI);
238 for (const auto *I : D->decls()) {
239 if (!isa<ObjCIvarDecl>(I))
240 IndexCtx.indexDecl(I);
241 }
242
243 return true;
244 }
245
246 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
247 if (!IndexCtx.handleDecl(D))
248 return false;
249 IndexCtx.indexDeclContext(D);
250 return true;
251 }
252
253 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
254 const ObjCCategoryDecl *Cat = D->getCategoryDecl();
255 if (!Cat)
256 return true;
257
258 if (!IndexCtx.handleDecl(D))
259 return false;
260 IndexCtx.indexDeclContext(D);
261 return true;
262 }
263
264 bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
265 // Methods associated with a property, even user-declared ones, are
266 // handled when we handle the property.
267 if (D->isPropertyAccessor())
268 return true;
269
270 handleObjCMethod(D);
271 return true;
272 }
273
274 bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
275 if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
276 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
277 handleObjCMethod(MD);
278 if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
279 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
280 handleObjCMethod(MD);
281 if (!IndexCtx.handleDecl(D))
282 return false;
283 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
284 return true;
285 }
286
287 bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
288 ObjCPropertyDecl *PD = D->getPropertyDecl();
289 if (!IndexCtx.handleReference(PD, D->getLocation(),
290 /*Parent=*/cast<NamedDecl>(D->getDeclContext()),
291 D->getDeclContext(), SymbolRoleSet(), {},
292 /*RefE=*/nullptr, D))
293 return false;
294
295 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
296 return true;
297 assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
298
299 if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
300 if (!IvarD->getSynthesize())
301 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
302 D->getDeclContext(), SymbolRoleSet());
303 }
304
305 auto *ImplD = cast<ObjCImplDecl>(D->getDeclContext());
306 if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
307 if (MD->isPropertyAccessor() &&
308 !hasUserDefined(MD, ImplD))
309 IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
310 }
311 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
312 if (MD->isPropertyAccessor() &&
313 !hasUserDefined(MD, ImplD))
314 IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
315 }
316 return true;
317 }
318
319 bool VisitNamespaceDecl(const NamespaceDecl *D) {
320 if (!IndexCtx.handleDecl(D))
321 return false;
322 IndexCtx.indexDeclContext(D);
323 return true;
324 }
325
326 bool VisitUsingDecl(const UsingDecl *D) {
327 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
328 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
329
330 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
331 D->getLexicalDeclContext());
332 for (const auto *I : D->shadows())
333 IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent,
334 D->getLexicalDeclContext(), SymbolRoleSet());
335 return true;
336 }
337
338 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
339 const DeclContext *DC = D->getDeclContext()->getRedeclContext();
340 const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
341
342 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
343 D->getLexicalDeclContext());
344 return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
345 D->getLocation(), Parent,
346 D->getLexicalDeclContext(),
347 SymbolRoleSet());
348 }
349
350 bool VisitClassTemplateSpecializationDecl(const
351 ClassTemplateSpecializationDecl *D) {
352 // FIXME: Notify subsequent callbacks if info comes from implicit
353 // instantiation.
354 if (D->isThisDeclarationADefinition())
355 IndexCtx.indexTagDecl(D);
356 return true;
357 }
358
359 bool VisitTemplateDecl(const TemplateDecl *D) {
360 // FIXME: Template parameters.
361 return Visit(D->getTemplatedDecl());
362 }
363
364 bool VisitFriendDecl(const FriendDecl *D) {
365 if (auto ND = D->getFriendDecl()) {
366 // FIXME: Ignore a class template in a dependent context, these are not
367 // linked properly with their redeclarations, ending up with duplicate
368 // USRs.
369 // See comment "Friend templates are visible in fairly strange ways." in
370 // SemaTemplate.cpp which precedes code that prevents the friend template
371 // from becoming visible from the enclosing context.
372 if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext())
373 return true;
374 return Visit(ND);
375 }
376 if (auto Ty = D->getFriendType()) {
377 IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext()));
378 }
379 return true;
380 }
381
382 bool VisitImportDecl(const ImportDecl *D) {
383 return IndexCtx.importedModule(D);
384 }
385};
386
387} // anonymous namespace
388
389bool IndexingContext::indexDecl(const Decl *D) {
390 if (D->isImplicit() && shouldIgnoreIfImplicit(D))
391 return true;
392
393 if (isTemplateImplicitInstantiation(D))
394 return true;
395
396 IndexingDeclVisitor Visitor(*this);
397 bool ShouldContinue = Visitor.Visit(D);
398 if (!ShouldContinue)
399 return false;
400
401 if (!Visitor.Handled && isa<DeclContext>(D))
402 return indexDeclContext(cast<DeclContext>(D));
403
404 return true;
405}
406
407bool IndexingContext::indexDeclContext(const DeclContext *DC) {
408 for (const auto *I : DC->decls())
409 if (!indexDecl(I))
410 return false;
411 return true;
412}
413
414bool IndexingContext::indexTopLevelDecl(const Decl *D) {
415 if (D->getLocation().isInvalid())
416 return true;
417
418 if (isa<ObjCMethodDecl>(D))
419 return true; // Wait for the objc container.
420
421 return indexDecl(D);
422}
423
424bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
425 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
426 if (!indexTopLevelDecl(*I))
427 return false;
428 return true;
429}