IndexDecl.cpp revision 651f13cea278ec967336033dd032faef0e9fc2ec
1//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
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/AST/DeclVisitor.h"
12
13using namespace clang;
14using namespace cxindex;
15
16namespace {
17
18class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
19  IndexingContext &IndexCtx;
20
21public:
22  explicit IndexingDeclVisitor(IndexingContext &indexCtx)
23    : IndexCtx(indexCtx) { }
24
25  /// \brief Returns true if the given method has been defined explicitly by the
26  /// user.
27  static bool hasUserDefined(const ObjCMethodDecl *D,
28                             const ObjCImplDecl *Container) {
29    const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
30                                                    D->isInstanceMethod());
31    return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
32  }
33
34  void handleDeclarator(const DeclaratorDecl *D, const NamedDecl *Parent = 0) {
35    if (!Parent) Parent = D;
36
37    if (!IndexCtx.shouldIndexFunctionLocalSymbols()) {
38      IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
39      IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
40    } else {
41      if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
42        IndexCtx.handleVar(Parm);
43      } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
44        for (auto PI : FD->params()) {
45          IndexCtx.handleVar(PI);
46        }
47      }
48    }
49  }
50
51  void handleObjCMethod(const ObjCMethodDecl *D) {
52    IndexCtx.handleObjCMethod(D);
53    if (D->isImplicit())
54      return;
55
56    IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
57    for (const auto *I : D->params())
58      handleDeclarator(I, D);
59
60    if (D->isThisDeclarationADefinition()) {
61      const Stmt *Body = D->getBody();
62      if (Body) {
63        IndexCtx.indexBody(Body, D, D);
64      }
65    }
66  }
67
68  bool VisitFunctionDecl(const FunctionDecl *D) {
69    IndexCtx.handleFunction(D);
70    handleDeclarator(D);
71
72    if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
73      // Constructor initializers.
74      for (const auto *Init : Ctor->inits()) {
75        if (Init->isWritten()) {
76          IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
77          if (const FieldDecl *Member = Init->getAnyMember())
78            IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D);
79          IndexCtx.indexBody(Init->getInit(), D, D);
80        }
81      }
82    }
83
84    if (D->isThisDeclarationADefinition()) {
85      const Stmt *Body = D->getBody();
86      if (Body) {
87        IndexCtx.indexBody(Body, D, D);
88      }
89    }
90    return true;
91  }
92
93  bool VisitVarDecl(const VarDecl *D) {
94    IndexCtx.handleVar(D);
95    handleDeclarator(D);
96    IndexCtx.indexBody(D->getInit(), D);
97    return true;
98  }
99
100  bool VisitFieldDecl(const FieldDecl *D) {
101    IndexCtx.handleField(D);
102    handleDeclarator(D);
103    if (D->isBitField())
104      IndexCtx.indexBody(D->getBitWidth(), D);
105    else if (D->hasInClassInitializer())
106      IndexCtx.indexBody(D->getInClassInitializer(), D);
107    return true;
108  }
109
110  bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
111    handleDeclarator(D);
112    return true;
113  }
114
115  bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
116    IndexCtx.handleEnumerator(D);
117    IndexCtx.indexBody(D->getInitExpr(), D);
118    return true;
119  }
120
121  bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
122    IndexCtx.handleTypedefName(D);
123    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
124    return true;
125  }
126
127  bool VisitTagDecl(const TagDecl *D) {
128    // Non-free standing tags are handled in indexTypeSourceInfo.
129    if (D->isFreeStanding())
130      IndexCtx.indexTagDecl(D);
131    return true;
132  }
133
134  bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
135    IndexCtx.handleObjCInterface(D);
136
137    if (D->isThisDeclarationADefinition()) {
138      IndexCtx.indexTUDeclsInObjCContainer();
139      IndexCtx.indexDeclContext(D);
140    }
141    return true;
142  }
143
144  bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
145    IndexCtx.handleObjCProtocol(D);
146
147    if (D->isThisDeclarationADefinition()) {
148      IndexCtx.indexTUDeclsInObjCContainer();
149      IndexCtx.indexDeclContext(D);
150    }
151    return true;
152  }
153
154  bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
155    const ObjCInterfaceDecl *Class = D->getClassInterface();
156    if (!Class)
157      return true;
158
159    if (Class->isImplicitInterfaceDecl())
160      IndexCtx.handleObjCInterface(Class);
161
162    IndexCtx.handleObjCImplementation(D);
163
164    IndexCtx.indexTUDeclsInObjCContainer();
165
166    // Index the ivars first to make sure the synthesized ivars are indexed
167    // before indexing the methods that can reference them.
168    for (const auto *IvarI : D->ivars())
169      IndexCtx.indexDecl(IvarI);
170    for (const auto *I : D->decls()) {
171      if (!isa<ObjCIvarDecl>(I))
172        IndexCtx.indexDecl(I);
173    }
174
175    return true;
176  }
177
178  bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
179    IndexCtx.handleObjCCategory(D);
180
181    IndexCtx.indexTUDeclsInObjCContainer();
182    IndexCtx.indexDeclContext(D);
183    return true;
184  }
185
186  bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
187    const ObjCCategoryDecl *Cat = D->getCategoryDecl();
188    if (!Cat)
189      return true;
190
191    IndexCtx.handleObjCCategoryImpl(D);
192
193    IndexCtx.indexTUDeclsInObjCContainer();
194    IndexCtx.indexDeclContext(D);
195    return true;
196  }
197
198  bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
199    // Methods associated with a property, even user-declared ones, are
200    // handled when we handle the property.
201    if (D->isPropertyAccessor())
202      return true;
203
204    handleObjCMethod(D);
205    return true;
206  }
207
208  bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
209    if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
210      if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
211        handleObjCMethod(MD);
212    if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
213      if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
214        handleObjCMethod(MD);
215    IndexCtx.handleObjCProperty(D);
216    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
217    return true;
218  }
219
220  bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
221    ObjCPropertyDecl *PD = D->getPropertyDecl();
222    IndexCtx.handleSynthesizedObjCProperty(D);
223
224    if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
225      return true;
226    assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
227
228    if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
229      if (!IvarD->getSynthesize())
230        IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), 0,
231                                 D->getDeclContext());
232    }
233
234    if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
235      if (MD->isPropertyAccessor() &&
236          !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext())))
237        IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
238                                             D->getLexicalDeclContext());
239    }
240    if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
241      if (MD->isPropertyAccessor() &&
242          !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext())))
243        IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
244                                             D->getLexicalDeclContext());
245    }
246    return true;
247  }
248
249  bool VisitNamespaceDecl(const NamespaceDecl *D) {
250    IndexCtx.handleNamespace(D);
251    IndexCtx.indexDeclContext(D);
252    return true;
253  }
254
255  bool VisitUsingDecl(const UsingDecl *D) {
256    // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
257    // we should do better.
258
259    IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
260    for (const auto *I : D->shadows())
261      IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), D,
262                               D->getLexicalDeclContext());
263    return true;
264  }
265
266  bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
267    // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
268    // we should do better.
269
270    IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
271    IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
272                             D->getLocation(), D, D->getLexicalDeclContext());
273    return true;
274  }
275
276  bool VisitClassTemplateDecl(const ClassTemplateDecl *D) {
277    IndexCtx.handleClassTemplate(D);
278    if (D->isThisDeclarationADefinition())
279      IndexCtx.indexDeclContext(D->getTemplatedDecl());
280    return true;
281  }
282
283  bool VisitClassTemplateSpecializationDecl(const
284                                           ClassTemplateSpecializationDecl *D) {
285    // FIXME: Notify subsequent callbacks if info comes from implicit
286    // instantiation.
287    if (D->isThisDeclarationADefinition() &&
288        (IndexCtx.shouldIndexImplicitTemplateInsts() ||
289         !IndexCtx.isTemplateImplicitInstantiation(D)))
290      IndexCtx.indexTagDecl(D);
291    return true;
292  }
293
294  bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
295    IndexCtx.handleFunctionTemplate(D);
296    FunctionDecl *FD = D->getTemplatedDecl();
297    handleDeclarator(FD, D);
298    if (FD->isThisDeclarationADefinition()) {
299      const Stmt *Body = FD->getBody();
300      if (Body) {
301        IndexCtx.indexBody(Body, D, FD);
302      }
303    }
304    return true;
305  }
306
307  bool VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
308    IndexCtx.handleTypeAliasTemplate(D);
309    IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
310    return true;
311  }
312
313  bool VisitImportDecl(const ImportDecl *D) {
314    IndexCtx.importedModule(D);
315    return true;
316  }
317};
318
319} // anonymous namespace
320
321void IndexingContext::indexDecl(const Decl *D) {
322  if (D->isImplicit() && shouldIgnoreIfImplicit(D))
323    return;
324
325  bool Handled = IndexingDeclVisitor(*this).Visit(D);
326  if (!Handled && isa<DeclContext>(D))
327    indexDeclContext(cast<DeclContext>(D));
328}
329
330void IndexingContext::indexDeclContext(const DeclContext *DC) {
331  for (const auto *I : DC->decls())
332    indexDecl(I);
333}
334
335void IndexingContext::indexTopLevelDecl(const Decl *D) {
336  if (isNotFromSourceFile(D->getLocation()))
337    return;
338
339  if (isa<ObjCMethodDecl>(D))
340    return; // Wait for the objc container.
341
342  indexDecl(D);
343}
344
345void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
346  for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
347    indexTopLevelDecl(*I);
348}
349
350void IndexingContext::indexTUDeclsInObjCContainer() {
351  while (!TUDeclsInObjCContainer.empty()) {
352    DeclGroupRef DG = TUDeclsInObjCContainer.front();
353    TUDeclsInObjCContainer.pop_front();
354    indexDeclGroupRef(DG);
355  }
356}
357