1//===- IndexingContext.cpp - Indexing context data ------------------------===//
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/ASTContext.h"
13#include "clang/AST/DeclTemplate.h"
14#include "clang/AST/DeclObjC.h"
15#include "clang/Basic/SourceManager.h"
16
17using namespace clang;
18using namespace index;
19
20bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
21  return IndexOpts.IndexFunctionLocals;
22}
23
24bool IndexingContext::handleDecl(const Decl *D,
25                                 SymbolRoleSet Roles,
26                                 ArrayRef<SymbolRelation> Relations) {
27  return handleDeclOccurrence(D, D->getLocation(), /*IsRef=*/false,
28                              cast<Decl>(D->getDeclContext()), Roles, Relations,
29                              nullptr, nullptr, D->getDeclContext());
30}
31
32bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
33                                 SymbolRoleSet Roles,
34                                 ArrayRef<SymbolRelation> Relations,
35                                 const DeclContext *DC) {
36  if (!DC)
37    DC = D->getDeclContext();
38  return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
39                              Roles, Relations,
40                              nullptr, nullptr, DC);
41}
42
43bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
44                                      const NamedDecl *Parent,
45                                      const DeclContext *DC,
46                                      SymbolRoleSet Roles,
47                                      ArrayRef<SymbolRelation> Relations,
48                                      const Expr *RefE,
49                                      const Decl *RefD) {
50  if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
51    return true;
52
53  if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
54    return true;
55
56  return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
57                              RefE, RefD, DC);
58}
59
60bool IndexingContext::importedModule(const ImportDecl *ImportD) {
61  SourceLocation Loc;
62  auto IdLocs = ImportD->getIdentifierLocs();
63  if (!IdLocs.empty())
64    Loc = IdLocs.front();
65  else
66    Loc = ImportD->getLocation();
67  SourceManager &SM = Ctx->getSourceManager();
68  Loc = SM.getFileLoc(Loc);
69  if (Loc.isInvalid())
70    return true;
71
72  FileID FID;
73  unsigned Offset;
74  std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
75  if (FID.isInvalid())
76    return true;
77
78  bool Invalid = false;
79  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
80  if (Invalid || !SEntry.isFile())
81    return true;
82
83  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
84    switch (IndexOpts.SystemSymbolFilter) {
85    case IndexingOptions::SystemSymbolFilterKind::None:
86      return true;
87    case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
88    case IndexingOptions::SystemSymbolFilterKind::All:
89      break;
90    }
91  }
92
93  SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
94  if (ImportD->isImplicit())
95    Roles |= (unsigned)SymbolRole::Implicit;
96
97  return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
98}
99
100bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
101  assert(D);
102
103  if (isa<TemplateTemplateParmDecl>(D))
104    return true;
105
106  if (isa<ObjCTypeParamDecl>(D))
107    return true;
108
109  if (!D->getParentFunctionOrMethod())
110    return false;
111
112  if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
113    switch (ND->getFormalLinkage()) {
114    case NoLinkage:
115    case VisibleNoLinkage:
116    case InternalLinkage:
117      return true;
118    case UniqueExternalLinkage:
119      llvm_unreachable("Not a sema linkage");
120    case ExternalLinkage:
121      return false;
122    }
123  }
124
125  return true;
126}
127
128bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
129  TemplateSpecializationKind TKind = TSK_Undeclared;
130  if (const ClassTemplateSpecializationDecl *
131      SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
132    TKind = SD->getSpecializationKind();
133  }
134  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
135    TKind = FD->getTemplateSpecializationKind();
136  }
137  switch (TKind) {
138    case TSK_Undeclared:
139    case TSK_ExplicitSpecialization:
140      return false;
141    case TSK_ImplicitInstantiation:
142    case TSK_ExplicitInstantiationDeclaration:
143    case TSK_ExplicitInstantiationDefinition:
144      return true;
145  }
146  llvm_unreachable("invalid TemplateSpecializationKind");
147}
148
149bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
150  if (isa<ObjCInterfaceDecl>(D))
151    return false;
152  if (isa<ObjCCategoryDecl>(D))
153    return false;
154  if (isa<ObjCIvarDecl>(D))
155    return false;
156  if (isa<ObjCMethodDecl>(D))
157    return false;
158  if (isa<ImportDecl>(D))
159    return false;
160  return true;
161}
162
163static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
164  if (const ClassTemplateSpecializationDecl *
165      SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
166    return SD->getTemplateInstantiationPattern();
167  }
168  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
169    return FD->getTemplateInstantiationPattern();
170  }
171  return nullptr;
172}
173
174static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
175  if (auto VD = dyn_cast<VarDecl>(D))
176    return VD->isThisDeclarationADefinition(Ctx);
177
178  if (auto FD = dyn_cast<FunctionDecl>(D))
179    return FD->isThisDeclarationADefinition();
180
181  if (auto TD = dyn_cast<TagDecl>(D))
182    return TD->isThisDeclarationADefinition();
183
184  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
185    return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
186
187  if (isa<TypedefNameDecl>(D) ||
188      isa<EnumConstantDecl>(D) ||
189      isa<FieldDecl>(D) ||
190      isa<MSPropertyDecl>(D) ||
191      isa<ObjCImplDecl>(D) ||
192      isa<ObjCPropertyImplDecl>(D))
193    return true;
194
195  return false;
196}
197
198static const Decl *adjustParent(const Decl *Parent) {
199  if (!Parent)
200    return nullptr;
201  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
202    if (isa<TranslationUnitDecl>(Parent))
203      return nullptr;
204    if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
205      continue;
206    if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
207      if (NS->isAnonymousNamespace())
208        continue;
209    } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
210      if (RD->isAnonymousStructOrUnion())
211        continue;
212    } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
213      if (FD->getDeclName().isEmpty())
214        continue;
215    }
216    return Parent;
217  }
218}
219
220static const Decl *getCanonicalDecl(const Decl *D) {
221  D = D->getCanonicalDecl();
222  if (auto TD = dyn_cast<TemplateDecl>(D)) {
223    D = TD->getTemplatedDecl();
224    assert(D->isCanonicalDecl());
225  }
226
227  return D;
228}
229
230bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
231                                           bool IsRef, const Decl *Parent,
232                                           SymbolRoleSet Roles,
233                                           ArrayRef<SymbolRelation> Relations,
234                                           const Expr *OrigE,
235                                           const Decl *OrigD,
236                                           const DeclContext *ContainerDC) {
237  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
238    return true;
239  if (!isa<NamedDecl>(D) ||
240      (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
241       !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
242    return true;
243
244  SourceManager &SM = Ctx->getSourceManager();
245  Loc = SM.getFileLoc(Loc);
246  if (Loc.isInvalid())
247    return true;
248
249  FileID FID;
250  unsigned Offset;
251  std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
252  if (FID.isInvalid())
253    return true;
254
255  bool Invalid = false;
256  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
257  if (Invalid || !SEntry.isFile())
258    return true;
259
260  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
261    switch (IndexOpts.SystemSymbolFilter) {
262    case IndexingOptions::SystemSymbolFilterKind::None:
263      return true;
264    case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
265      if (IsRef)
266        return true;
267      break;
268    case IndexingOptions::SystemSymbolFilterKind::All:
269      break;
270    }
271  }
272
273  if (isTemplateImplicitInstantiation(D)) {
274    if (!IsRef)
275      return true;
276    D = adjustTemplateImplicitInstantiation(D);
277    if (!D)
278      return true;
279    assert(!isTemplateImplicitInstantiation(D));
280  }
281
282  if (!OrigD)
283    OrigD = D;
284
285  if (IsRef)
286    Roles |= (unsigned)SymbolRole::Reference;
287  else if (isDeclADefinition(D, ContainerDC, *Ctx))
288    Roles |= (unsigned)SymbolRole::Definition;
289  else
290    Roles |= (unsigned)SymbolRole::Declaration;
291
292  D = getCanonicalDecl(D);
293  if (D->isImplicit() && !isa<ObjCMethodDecl>(D) &&
294      !(isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->getBuiltinID())) {
295    // operator new declarations will link to the implicit one as canonical.
296    return true;
297  }
298  Parent = adjustParent(Parent);
299  if (Parent)
300    Parent = getCanonicalDecl(Parent);
301  assert((!Parent || !Parent->isImplicit() ||
302          (isa<FunctionDecl>(Parent) &&
303           cast<FunctionDecl>(Parent)->getBuiltinID()) ||
304          isa<ObjCInterfaceDecl>(Parent) || isa<ObjCMethodDecl>(Parent)) &&
305         "unexpected implicit parent!");
306
307  SmallVector<SymbolRelation, 6> FinalRelations;
308  FinalRelations.reserve(Relations.size()+1);
309
310  auto addRelation = [&](SymbolRelation Rel) {
311    auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
312                [&](SymbolRelation Elem)->bool {
313                  return Elem.RelatedSymbol == Rel.RelatedSymbol;
314                });
315    if (It != FinalRelations.end()) {
316      It->Roles |= Rel.Roles;
317    } else {
318      FinalRelations.push_back(Rel);
319    }
320    Roles |= Rel.Roles;
321  };
322
323  if (!IsRef && Parent && !cast<DeclContext>(Parent)->isFunctionOrMethod()) {
324    addRelation(SymbolRelation{(unsigned)SymbolRole::RelationChildOf, Parent});
325  }
326  for (auto &Rel : Relations) {
327    addRelation(SymbolRelation(Rel.Roles,
328                               Rel.RelatedSymbol->getCanonicalDecl()));
329  }
330
331  IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
332  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
333                                          Node);
334}
335