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
14using namespace clang;
15using namespace index;
16
17#define TRY_TO(CALL_EXPR)                                                      \
18  do {                                                                         \
19    if (!CALL_EXPR)                                                            \
20      return false;                                                            \
21  } while (0)
22
23namespace {
24
25class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
26  IndexingContext &IndexCtx;
27
28public:
29  explicit IndexingDeclVisitor(IndexingContext &indexCtx)
30    : IndexCtx(indexCtx) { }
31
32  bool Handled = true;
33
34  bool VisitDecl(const Decl *D) {
35    Handled = false;
36    return true;
37  }
38
39  /// \brief Returns true if the given method has been defined explicitly by the
40  /// user.
41  static bool hasUserDefined(const ObjCMethodDecl *D,
42                             const ObjCImplDecl *Container) {
43    const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
44                                                    D->isInstanceMethod());
45    return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
46  }
47
48  void handleDeclarator(const DeclaratorDecl *D,
49                        const NamedDecl *Parent = nullptr) {
50    if (!Parent) Parent = D;
51
52    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
53    IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
54    if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
55      // Only index parameters in definitions, parameters in declarations are
56      // not useful.
57      if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
58        auto *DC = Parm->getDeclContext();
59        if (auto *FD = dyn_cast<FunctionDecl>(DC)) {
60          if (FD->isThisDeclarationADefinition())
61            IndexCtx.handleDecl(Parm);
62        } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) {
63          if (MD->isThisDeclarationADefinition())
64            IndexCtx.handleDecl(Parm);
65        } else {
66          IndexCtx.handleDecl(Parm);
67        }
68      } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
69        if (FD->isThisDeclarationADefinition()) {
70          for (auto PI : FD->parameters()) {
71            IndexCtx.handleDecl(PI);
72          }
73        }
74      }
75    }
76  }
77
78  bool handleObjCMethod(const ObjCMethodDecl *D) {
79    if (!IndexCtx.handleDecl(D, (unsigned)SymbolRole::Dynamic))
80      return false;
81    IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
82    for (const auto *I : D->parameters())
83      handleDeclarator(I, D);
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 VisitFunctionDecl(const FunctionDecl *D) {
95    if (D->isDeleted())
96      return true;
97
98    SymbolRoleSet Roles{};
99    SmallVector<SymbolRelation, 4> Relations;
100    if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
101      if (CXXMD->isVirtual())
102        Roles |= (unsigned)SymbolRole::Dynamic;
103      for (auto I = CXXMD->begin_overridden_methods(),
104           E = CXXMD->end_overridden_methods(); I != E; ++I) {
105        Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
106      }
107    }
108
109    if (!IndexCtx.handleDecl(D, Roles, Relations))
110      return false;
111    handleDeclarator(D);
112
113    if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
114      // Constructor initializers.
115      for (const auto *Init : Ctor->inits()) {
116        if (Init->isWritten()) {
117          IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
118          if (const FieldDecl *Member = Init->getAnyMember())
119            IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D,
120                                     (unsigned)SymbolRole::Write);
121          IndexCtx.indexBody(Init->getInit(), D, D);
122        }
123      }
124    }
125
126    if (D->isThisDeclarationADefinition()) {
127      const Stmt *Body = D->getBody();
128      if (Body) {
129        IndexCtx.indexBody(Body, D, D);
130      }
131    }
132    return true;
133  }
134
135  bool VisitVarDecl(const VarDecl *D) {
136    if (!IndexCtx.handleDecl(D))
137      return false;
138    handleDeclarator(D);
139    IndexCtx.indexBody(D->getInit(), D);
140    return true;
141  }
142
143  bool VisitFieldDecl(const FieldDecl *D) {
144    if (!IndexCtx.handleDecl(D))
145      return false;
146    handleDeclarator(D);
147    if (D->isBitField())
148      IndexCtx.indexBody(D->getBitWidth(), D);
149    else if (D->hasInClassInitializer())
150      IndexCtx.indexBody(D->getInClassInitializer(), D);
151    return true;
152  }
153
154  bool VisitObjCIvarDecl(const ObjCIvarDecl *D) {
155    if (D->getSynthesize()) {
156      // For synthesized ivars, use the location of the ObjC implementation,
157      // not the location of the property.
158      // Otherwise the header file containing the @interface will have different
159      // indexing contents based on whether the @implementation was present or
160      // not in the translation unit.
161      return IndexCtx.handleDecl(D,
162                                 cast<Decl>(D->getDeclContext())->getLocation(),
163                                 (unsigned)SymbolRole::Implicit);
164    }
165    if (!IndexCtx.handleDecl(D))
166      return false;
167    handleDeclarator(D);
168    return true;
169  }
170
171  bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
172    handleDeclarator(D);
173    return true;
174  }
175
176  bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
177    if (!IndexCtx.handleDecl(D))
178      return false;
179    IndexCtx.indexBody(D->getInitExpr(), D);
180    return true;
181  }
182
183  bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
184    if (!IndexCtx.handleDecl(D))
185      return false;
186    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
187    return true;
188  }
189
190  bool VisitTagDecl(const TagDecl *D) {
191    // Non-free standing tags are handled in indexTypeSourceInfo.
192    if (D->isFreeStanding()) {
193      if (D->isThisDeclarationADefinition()) {
194        IndexCtx.indexTagDecl(D);
195      } else {
196        auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
197        return IndexCtx.handleReference(D, D->getLocation(), Parent,
198                                        D->getLexicalDeclContext(),
199                                        SymbolRoleSet());
200      }
201    }
202    return true;
203  }
204
205  bool handleReferencedProtocols(const ObjCProtocolList &ProtList,
206                                 const ObjCContainerDecl *ContD) {
207    ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
208    for (ObjCInterfaceDecl::protocol_iterator
209         I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
210      SourceLocation Loc = *LI;
211      ObjCProtocolDecl *PD = *I;
212      TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD,
213          SymbolRoleSet(),
214          SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD}));
215    }
216    return true;
217  }
218
219  bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
220    if (D->isThisDeclarationADefinition()) {
221      TRY_TO(IndexCtx.handleDecl(D));
222      if (auto *SuperD = D->getSuperClass()) {
223        TRY_TO(IndexCtx.handleReference(SuperD, D->getSuperClassLoc(), D, D,
224            SymbolRoleSet(),
225            SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D}));
226      }
227      TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
228      TRY_TO(IndexCtx.indexDeclContext(D));
229    } else {
230      return IndexCtx.handleReference(D, D->getLocation(), nullptr,
231                                      D->getDeclContext(), SymbolRoleSet());
232    }
233    return true;
234  }
235
236  bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
237    if (D->isThisDeclarationADefinition()) {
238      TRY_TO(IndexCtx.handleDecl(D));
239      TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
240      TRY_TO(IndexCtx.indexDeclContext(D));
241    } else {
242      return IndexCtx.handleReference(D, D->getLocation(), nullptr,
243                                      D->getDeclContext(), SymbolRoleSet());
244    }
245    return true;
246  }
247
248  bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
249    const ObjCInterfaceDecl *Class = D->getClassInterface();
250    if (!Class)
251      return true;
252
253    if (Class->isImplicitInterfaceDecl())
254      IndexCtx.handleDecl(Class);
255
256    if (!IndexCtx.handleDecl(D))
257      return false;
258
259    // Index the ivars first to make sure the synthesized ivars are indexed
260    // before indexing the methods that can reference them.
261    for (const auto *IvarI : D->ivars())
262      IndexCtx.indexDecl(IvarI);
263    for (const auto *I : D->decls()) {
264      if (!isa<ObjCIvarDecl>(I))
265        IndexCtx.indexDecl(I);
266    }
267
268    return true;
269  }
270
271  bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
272    if (!IndexCtx.handleDecl(D))
273      return false;
274    IndexCtx.indexDeclContext(D);
275    return true;
276  }
277
278  bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
279    const ObjCCategoryDecl *Cat = D->getCategoryDecl();
280    if (!Cat)
281      return true;
282
283    if (!IndexCtx.handleDecl(D))
284      return false;
285    IndexCtx.indexDeclContext(D);
286    return true;
287  }
288
289  bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
290    // Methods associated with a property, even user-declared ones, are
291    // handled when we handle the property.
292    if (D->isPropertyAccessor())
293      return true;
294
295    handleObjCMethod(D);
296    return true;
297  }
298
299  bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
300    if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
301      if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
302        handleObjCMethod(MD);
303    if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
304      if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
305        handleObjCMethod(MD);
306    if (!IndexCtx.handleDecl(D))
307      return false;
308    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
309    return true;
310  }
311
312  bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
313    ObjCPropertyDecl *PD = D->getPropertyDecl();
314    if (!IndexCtx.handleReference(PD, D->getLocation(),
315                             /*Parent=*/cast<NamedDecl>(D->getDeclContext()),
316                             D->getDeclContext(), SymbolRoleSet(), {},
317                             /*RefE=*/nullptr, D))
318      return false;
319
320    if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
321      return true;
322    assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
323
324    if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
325      if (!IvarD->getSynthesize())
326        IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
327                                 D->getDeclContext(), SymbolRoleSet());
328    }
329
330    auto *ImplD = cast<ObjCImplDecl>(D->getDeclContext());
331    if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
332      if (MD->isPropertyAccessor() &&
333          !hasUserDefined(MD, ImplD))
334        IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
335    }
336    if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
337      if (MD->isPropertyAccessor() &&
338          !hasUserDefined(MD, ImplD))
339        IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
340    }
341    return true;
342  }
343
344  bool VisitNamespaceDecl(const NamespaceDecl *D) {
345    if (!IndexCtx.handleDecl(D))
346      return false;
347    IndexCtx.indexDeclContext(D);
348    return true;
349  }
350
351  bool VisitUsingDecl(const UsingDecl *D) {
352    const DeclContext *DC = D->getDeclContext()->getRedeclContext();
353    const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
354
355    IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
356                                         D->getLexicalDeclContext());
357    for (const auto *I : D->shadows())
358      IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent,
359                               D->getLexicalDeclContext(), SymbolRoleSet());
360    return true;
361  }
362
363  bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
364    const DeclContext *DC = D->getDeclContext()->getRedeclContext();
365    const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
366
367    IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
368                                         D->getLexicalDeclContext());
369    return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
370                                    D->getLocation(), Parent,
371                                    D->getLexicalDeclContext(),
372                                    SymbolRoleSet());
373  }
374
375  bool VisitClassTemplateSpecializationDecl(const
376                                           ClassTemplateSpecializationDecl *D) {
377    // FIXME: Notify subsequent callbacks if info comes from implicit
378    // instantiation.
379    if (D->isThisDeclarationADefinition())
380      IndexCtx.indexTagDecl(D);
381    return true;
382  }
383
384  bool VisitTemplateDecl(const TemplateDecl *D) {
385    // FIXME: Template parameters.
386    return Visit(D->getTemplatedDecl());
387  }
388
389  bool VisitFriendDecl(const FriendDecl *D) {
390    if (auto ND = D->getFriendDecl()) {
391      // FIXME: Ignore a class template in a dependent context, these are not
392      // linked properly with their redeclarations, ending up with duplicate
393      // USRs.
394      // See comment "Friend templates are visible in fairly strange ways." in
395      // SemaTemplate.cpp which precedes code that prevents the friend template
396      // from becoming visible from the enclosing context.
397      if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext())
398        return true;
399      return Visit(ND);
400    }
401    if (auto Ty = D->getFriendType()) {
402      IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext()));
403    }
404    return true;
405  }
406
407  bool VisitImportDecl(const ImportDecl *D) {
408    return IndexCtx.importedModule(D);
409  }
410};
411
412} // anonymous namespace
413
414bool IndexingContext::indexDecl(const Decl *D) {
415  if (D->isImplicit() && shouldIgnoreIfImplicit(D))
416    return true;
417
418  if (isTemplateImplicitInstantiation(D))
419    return true;
420
421  IndexingDeclVisitor Visitor(*this);
422  bool ShouldContinue = Visitor.Visit(D);
423  if (!ShouldContinue)
424    return false;
425
426  if (!Visitor.Handled && isa<DeclContext>(D))
427    return indexDeclContext(cast<DeclContext>(D));
428
429  return true;
430}
431
432bool IndexingContext::indexDeclContext(const DeclContext *DC) {
433  for (const auto *I : DC->decls())
434    if (!indexDecl(I))
435      return false;
436  return true;
437}
438
439bool IndexingContext::indexTopLevelDecl(const Decl *D) {
440  if (D->getLocation().isInvalid())
441    return true;
442
443  if (isa<ObjCMethodDecl>(D))
444    return true; // Wait for the objc container.
445
446  return indexDecl(D);
447}
448
449bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
450  for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
451    if (!indexTopLevelDecl(*I))
452      return false;
453  return true;
454}
455