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 
13 using namespace clang;
14 using namespace cxindex;
15 
16 namespace {
17 
18 class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
19   IndexingContext &IndexCtx;
20 
21 public:
IndexingDeclVisitor(IndexingContext & indexCtx)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.
hasUserDefined(const ObjCMethodDecl * D,const ObjCImplDecl * Container)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 
handleDeclarator(const DeclaratorDecl * D,const NamedDecl * Parent=nullptr)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 
handleObjCMethod(const ObjCMethodDecl * D)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 
VisitFunctionDecl(const FunctionDecl * D)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 
VisitVarDecl(const VarDecl * D)94   bool VisitVarDecl(const VarDecl *D) {
95     IndexCtx.handleVar(D);
96     handleDeclarator(D);
97     IndexCtx.indexBody(D->getInit(), D);
98     return true;
99   }
100 
VisitFieldDecl(const FieldDecl * D)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 
VisitMSPropertyDecl(const MSPropertyDecl * D)111   bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
112     handleDeclarator(D);
113     return true;
114   }
115 
VisitEnumConstantDecl(const EnumConstantDecl * D)116   bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
117     IndexCtx.handleEnumerator(D);
118     IndexCtx.indexBody(D->getInitExpr(), D);
119     return true;
120   }
121 
VisitTypedefNameDecl(const TypedefNameDecl * D)122   bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
123     IndexCtx.handleTypedefName(D);
124     IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
125     return true;
126   }
127 
VisitTagDecl(const TagDecl * D)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 
VisitObjCInterfaceDecl(const ObjCInterfaceDecl * D)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 
VisitObjCProtocolDecl(const ObjCProtocolDecl * D)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 
VisitObjCImplementationDecl(const ObjCImplementationDecl * D)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 
VisitObjCCategoryDecl(const ObjCCategoryDecl * D)179   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
180     IndexCtx.handleObjCCategory(D);
181 
182     IndexCtx.indexTUDeclsInObjCContainer();
183     IndexCtx.indexDeclContext(D);
184     return true;
185   }
186 
VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl * D)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 
VisitObjCMethodDecl(const ObjCMethodDecl * D)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 
VisitObjCPropertyDecl(const ObjCPropertyDecl * D)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 
VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl * D)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 
VisitNamespaceDecl(const NamespaceDecl * D)250   bool VisitNamespaceDecl(const NamespaceDecl *D) {
251     IndexCtx.handleNamespace(D);
252     IndexCtx.indexDeclContext(D);
253     return true;
254   }
255 
VisitUsingDecl(const UsingDecl * D)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 
VisitUsingDirectiveDecl(const UsingDirectiveDecl * D)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 
VisitClassTemplateDecl(const ClassTemplateDecl * D)277   bool VisitClassTemplateDecl(const ClassTemplateDecl *D) {
278     IndexCtx.handleClassTemplate(D);
279     if (D->isThisDeclarationADefinition())
280       IndexCtx.indexDeclContext(D->getTemplatedDecl());
281     return true;
282   }
283 
VisitClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl * D)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 
VisitFunctionTemplateDecl(const FunctionTemplateDecl * D)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 
VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl * D)308   bool VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
309     IndexCtx.handleTypeAliasTemplate(D);
310     IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
311     return true;
312   }
313 
VisitImportDecl(const ImportDecl * D)314   bool VisitImportDecl(const ImportDecl *D) {
315     IndexCtx.importedModule(D);
316     return true;
317   }
318 };
319 
320 } // anonymous namespace
321 
indexDecl(const Decl * D)322 void 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 
indexDeclContext(const DeclContext * DC)331 void IndexingContext::indexDeclContext(const DeclContext *DC) {
332   for (const auto *I : DC->decls())
333     indexDecl(I);
334 }
335 
indexTopLevelDecl(const Decl * D)336 void 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 
indexDeclGroupRef(DeclGroupRef DG)346 void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
347   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
348     indexTopLevelDecl(*I);
349 }
350 
indexTUDeclsInObjCContainer()351 void IndexingContext::indexTUDeclsInObjCContainer() {
352   while (!TUDeclsInObjCContainer.empty()) {
353     DeclGroupRef DG = TUDeclsInObjCContainer.front();
354     TUDeclsInObjCContainer.pop_front();
355     indexDeclGroupRef(DG);
356   }
357 }
358