clang  6.0.0svn
IndexingContext.cpp
Go to the documentation of this file.
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"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "clang/AST/DeclObjC.h"
16 
17 using namespace clang;
18 using namespace index;
19 
20 static bool isGeneratedDecl(const Decl *D) {
21  if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
22  return attr->getGeneratedDeclaration();
23  }
24  return false;
25 }
26 
28  return !isGeneratedDecl(D);
29 }
30 
32  return Ctx->getLangOpts();
33 }
34 
36  return IndexOpts.IndexFunctionLocals;
37 }
38 
40  SymbolRoleSet Roles,
41  ArrayRef<SymbolRelation> Relations) {
42  return handleDecl(D, D->getLocation(), Roles, Relations);
43 }
44 
46  SymbolRoleSet Roles,
47  ArrayRef<SymbolRelation> Relations,
48  const DeclContext *DC) {
49  if (!DC)
50  DC = D->getDeclContext();
51 
52  const Decl *OrigD = D;
53  if (isa<ObjCPropertyImplDecl>(D)) {
54  D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
55  }
56  return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
57  Roles, Relations,
58  nullptr, OrigD, DC);
59 }
60 
62  const NamedDecl *Parent,
63  const DeclContext *DC,
64  SymbolRoleSet Roles,
65  ArrayRef<SymbolRelation> Relations,
66  const Expr *RefE,
67  const Decl *RefD) {
69  return true;
70 
71  if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
72  return true;
73 
74  return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
75  RefE, RefD, DC);
76 }
77 
79  SourceLocation Loc;
80  auto IdLocs = ImportD->getIdentifierLocs();
81  if (!IdLocs.empty())
82  Loc = IdLocs.front();
83  else
84  Loc = ImportD->getLocation();
86  Loc = SM.getFileLoc(Loc);
87  if (Loc.isInvalid())
88  return true;
89 
90  FileID FID;
91  unsigned Offset;
92  std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
93  if (FID.isInvalid())
94  return true;
95 
96  bool Invalid = false;
97  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
98  if (Invalid || !SEntry.isFile())
99  return true;
100 
101  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
102  switch (IndexOpts.SystemSymbolFilter) {
104  return true;
107  break;
108  }
109  }
110 
111  SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
112  if (ImportD->isImplicit())
113  Roles |= (unsigned)SymbolRole::Implicit;
114 
115  return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
116 }
117 
121  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
122  TKind = SD->getSpecializationKind();
123  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
124  TKind = FD->getTemplateSpecializationKind();
125  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
126  TKind = VD->getTemplateSpecializationKind();
127  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
128  if (RD->getInstantiatedFromMemberClass())
129  TKind = RD->getTemplateSpecializationKind();
130  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
131  if (ED->getInstantiatedFromMemberEnum())
132  TKind = ED->getTemplateSpecializationKind();
133  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
134  isa<EnumConstantDecl>(D)) {
135  if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
137  }
138  switch (TKind) {
139  case TSK_Undeclared:
141  return false;
145  return true;
146  }
147  llvm_unreachable("invalid TemplateSpecializationKind");
148 }
149 
150 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
151  if (isa<ObjCInterfaceDecl>(D))
152  return false;
153  if (isa<ObjCCategoryDecl>(D))
154  return false;
155  if (isa<ObjCIvarDecl>(D))
156  return false;
157  if (isa<ObjCMethodDecl>(D))
158  return false;
159  if (isa<ImportDecl>(D))
160  return false;
161  return true;
162 }
163 
164 static const CXXRecordDecl *
166  if (const auto *CTSD =
167  dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
168  return CTSD->getTemplateInstantiationPattern();
169  else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
170  return RD->getInstantiatedFromMemberClass();
171  return nullptr;
172 }
173 
176  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
177  return SD->getTemplateInstantiationPattern();
178  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
179  return FD->getTemplateInstantiationPattern();
180  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
181  return VD->getTemplateInstantiationPattern();
182  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
183  return RD->getInstantiatedFromMemberClass();
184  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
185  return ED->getInstantiatedFromMemberEnum();
186  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
187  const auto *ND = cast<NamedDecl>(D);
188  if (const CXXRecordDecl *Pattern =
190  for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
191  if (BaseND->isImplicit())
192  continue;
193  if (BaseND->getKind() == ND->getKind())
194  return BaseND;
195  }
196  }
197  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
198  if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
199  if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
200  for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
201  return BaseECD;
202  }
203  }
204  }
205  return nullptr;
206 }
207 
208 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
209  if (auto VD = dyn_cast<VarDecl>(D))
210  return VD->isThisDeclarationADefinition(Ctx);
211 
212  if (auto FD = dyn_cast<FunctionDecl>(D))
213  return FD->isThisDeclarationADefinition();
214 
215  if (auto TD = dyn_cast<TagDecl>(D))
216  return TD->isThisDeclarationADefinition();
217 
218  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
219  return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
220 
221  if (isa<TypedefNameDecl>(D) ||
222  isa<EnumConstantDecl>(D) ||
223  isa<FieldDecl>(D) ||
224  isa<MSPropertyDecl>(D) ||
225  isa<ObjCImplDecl>(D) ||
226  isa<ObjCPropertyImplDecl>(D))
227  return true;
228 
229  return false;
230 }
231 
232 /// Whether the given NamedDecl should be skipped because it has no name.
233 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
234  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
235  !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
236 }
237 
238 static const Decl *adjustParent(const Decl *Parent) {
239  if (!Parent)
240  return nullptr;
241  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
242  if (isa<TranslationUnitDecl>(Parent))
243  return nullptr;
244  if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
245  continue;
246  if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
247  if (NS->isAnonymousNamespace())
248  continue;
249  } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
250  if (RD->isAnonymousStructOrUnion())
251  continue;
252  } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
253  if (shouldSkipNamelessDecl(ND))
254  continue;
255  }
256  return Parent;
257  }
258 }
259 
260 static const Decl *getCanonicalDecl(const Decl *D) {
261  D = D->getCanonicalDecl();
262  if (auto TD = dyn_cast<TemplateDecl>(D)) {
263  if (auto TTD = TD->getTemplatedDecl()) {
264  D = TTD;
265  assert(D->isCanonicalDecl());
266  }
267  }
268 
269  return D;
270 }
271 
273  bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
274  if (!IsRef)
275  return true;
276 
277  auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
278  bool accept = false;
279  applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
280  switch (r) {
287  accept = true;
288  return false;
292  case SymbolRole::Read:
293  case SymbolRole::Write:
294  case SymbolRole::Call:
295  case SymbolRole::Dynamic:
302  return true;
303  }
304  llvm_unreachable("Unsupported SymbolRole value!");
305  });
306  return accept;
307  };
308 
309  for (auto &Rel : Relations) {
310  if (acceptForRelation(Rel.Roles))
311  return true;
312  }
313 
314  return false;
315 }
316 
317 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
318  bool IsRef, const Decl *Parent,
319  SymbolRoleSet Roles,
320  ArrayRef<SymbolRelation> Relations,
321  const Expr *OrigE,
322  const Decl *OrigD,
323  const DeclContext *ContainerDC) {
324  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
325  return true;
326  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
327  return true;
328 
330  Loc = SM.getFileLoc(Loc);
331  if (Loc.isInvalid())
332  return true;
333 
334  FileID FID;
335  unsigned Offset;
336  std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
337  if (FID.isInvalid())
338  return true;
339 
340  bool Invalid = false;
341  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
342  if (Invalid || !SEntry.isFile())
343  return true;
344 
345  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
346  switch (IndexOpts.SystemSymbolFilter) {
348  return true;
350  if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
351  return true;
352  break;
354  break;
355  }
356  }
357 
359  if (!IsRef)
360  return true;
362  if (!D)
363  return true;
365  }
366 
367  if (!OrigD)
368  OrigD = D;
369 
370  if (IsRef)
371  Roles |= (unsigned)SymbolRole::Reference;
372  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
373  Roles |= (unsigned)SymbolRole::Definition;
374  else
375  Roles |= (unsigned)SymbolRole::Declaration;
376 
377  D = getCanonicalDecl(D);
378  Parent = adjustParent(Parent);
379  if (Parent)
380  Parent = getCanonicalDecl(Parent);
381 
382  SmallVector<SymbolRelation, 6> FinalRelations;
383  FinalRelations.reserve(Relations.size()+1);
384 
385  auto addRelation = [&](SymbolRelation Rel) {
386  auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
387  [&](SymbolRelation Elem)->bool {
388  return Elem.RelatedSymbol == Rel.RelatedSymbol;
389  });
390  if (It != FinalRelations.end()) {
391  It->Roles |= Rel.Roles;
392  } else {
393  FinalRelations.push_back(Rel);
394  }
395  Roles |= Rel.Roles;
396  };
397 
398  if (Parent) {
399  if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
400  addRelation(SymbolRelation{
402  Parent
403  });
404  } else {
405  addRelation(SymbolRelation{
406  (unsigned)SymbolRole::RelationChildOf,
407  Parent
408  });
409  }
410  }
411 
412  for (auto &Rel : Relations) {
413  addRelation(SymbolRelation(Rel.Roles,
414  Rel.RelatedSymbol->getCanonicalDecl()));
415  }
416 
417  IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
418  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
419  Node);
420 }
Defines the clang::ASTContext interface.
static const Decl * getCanonicalDecl(const Decl *D)
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1698
This is a discriminated union of FileInfo and ExpansionInfo.
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:119
static bool shouldReportOccurrenceForSystemDeclOnlyMode(bool IsRef, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations)
Defines the SourceManager interface.
virtual bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations, FileID FID, unsigned Offset, ASTNodeInfo ASTNode)
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
Defines the C++ template declaration subclasses.
bool isEmpty() const
Evaluates true when this declaration name is empty.
static const CXXRecordDecl * getDeclContextForTemplateInstationPattern(const Decl *D)
DeclarationName getDeclName() const
getDeclName - Get the actual, stored name of the declaration, which may be a special name...
Definition: Decl.h:291
Represents a class template specialization, which refers to a class template with a given set of temp...
bool applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles, llvm::function_ref< bool(SymbolRole)> Fn)
static const Decl * adjustTemplateImplicitInstantiation(const Decl *D)
const LangOptions & getLangOpts() const
SymbolRole
Set of roles that are attributed to symbol occurrences.
Definition: IndexSymbol.h:92
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
bool isFunctionLocalSymbol(const Decl *D)
Definition: IndexSymbol.cpp:52
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:48
bool isInvalid() const
uint32_t Offset
Definition: CacheTokens.cpp:43
const FileInfo & getFile() const
static bool shouldSkipNamelessDecl(const NamedDecl *ND)
Whether the given NamedDecl should be skipped because it has no name.
bool shouldIndexFunctionLocalSymbols() const
ArrayRef< SourceLocation > getIdentifierLocs() const
Retrieves the locations of each of the identifiers that make up the complete module name in the impor...
Definition: Decl.cpp:4464
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:865
NodeId Parent
Definition: ASTDiff.cpp:192
unsigned SymbolRoleSet
Definition: IndexSymbol.h:116
CharacteristicKind getFileCharacteristic() const
Return whether this is a system header or not.
bool isCanonicalDecl() const
Whether this particular Decl is a canonical one.
Definition: DeclBase.h:871
Expr - This represents one expression.
Definition: Expr.h:106
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:551
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:1413
DeclContext * getDeclContext()
Definition: DeclBase.h:425
virtual bool handleModuleOccurence(const ImportDecl *ImportD, SymbolRoleSet Roles, FileID FID, unsigned Offset)
static bool isTemplateImplicitInstantiation(const Decl *D)
bool handleReference(const NamedDecl *D, SourceLocation Loc, const NamedDecl *Parent, const DeclContext *DC, SymbolRoleSet Roles=SymbolRoleSet(), ArrayRef< SymbolRelation > Relations=None, const Expr *RefE=nullptr, const Decl *RefD=nullptr)
This template specialization was implicitly instantiated from a template.
Definition: Specifiers.h:149
const SourceManager & SM
Definition: Format.cpp:1337
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:3871
SystemSymbolFilterKind SystemSymbolFilter
Encodes a location in the source.
static const Decl * adjustParent(const Decl *Parent)
SourceLocation getFileLoc(SourceLocation Loc) const
Given Loc, if it is a macro location return the expansion location or the spelling location...
This template specialization was instantiated from a template due to an explicit instantiation defini...
Definition: Specifiers.h:161
This template specialization was formed from a template-id but has not yet been declared, defined, or instantiated.
Definition: Specifiers.h:146
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:3965
static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx)
ast_type_traits::DynTypedNode Node
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool shouldIndex(const Decl *D)
Dataflow Directional Tag Classes.
bool handleDecl(const Decl *D, SymbolRoleSet Roles=SymbolRoleSet(), ArrayRef< SymbolRelation > Relations=None)
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1252
static bool isGeneratedDecl(const Decl *D)
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition: Specifiers.h:157
CXXRecordDecl * getInstantiatedFromMemberClass() const
If this record is an instantiation of a member class, retrieves the member class from which it was in...
Definition: DeclCXX.cpp:1357
EnumDecl - Represents an enum.
Definition: Decl.h:3233
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition: Specifiers.h:143
This template specialization was declared or defined by an explicit specialization (C++ [temp...
Definition: Specifiers.h:153
T * getAttr() const
Definition: DeclBase.h:531
bool importedModule(const ImportDecl *ImportD)
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
SourceManager & getSourceManager()
Definition: ASTContext.h:643
Represents a C++ struct/union/class.
Definition: DeclCXX.h:299
NamedDecl - This represents a decl with a name.
Definition: Decl.h:245
const LangOptions & getLangOpts() const
Definition: ASTContext.h:688
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Definition: DeclBase.h:416
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.