1 //===- 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 
14 using namespace clang;
15 using namespace index;
16 
17 namespace {
18 
19 class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
20   IndexingContext &IndexCtx;
21 
22 public:
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 
389 bool 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 
407 bool IndexingContext::indexDeclContext(const DeclContext *DC) {
408   for (const auto *I : DC->decls())
409     if (!indexDecl(I))
410       return false;
411   return true;
412 }
413 
414 bool 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 
424 bool 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 }
430