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