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