clang  8.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"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/AST/DeclObjC.h"
17 
18 using namespace clang;
19 using namespace index;
20 
21 static bool isGeneratedDecl(const Decl *D) {
22  if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
23  return attr->getGeneratedDeclaration();
24  }
25  return false;
26 }
27 
29  return !isGeneratedDecl(D);
30 }
31 
33  return Ctx->getLangOpts();
34 }
35 
37  return IndexOpts.IndexFunctionLocals;
38 }
39 
41  return IndexOpts.IndexImplicitInstantiation;
42 }
43 
45  SymbolRoleSet Roles,
46  ArrayRef<SymbolRelation> Relations) {
47  return handleDecl(D, D->getLocation(), Roles, Relations);
48 }
49 
51  SymbolRoleSet Roles,
52  ArrayRef<SymbolRelation> Relations,
53  const DeclContext *DC) {
54  if (!DC)
55  DC = D->getDeclContext();
56 
57  const Decl *OrigD = D;
58  if (isa<ObjCPropertyImplDecl>(D)) {
59  D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
60  }
61  return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
62  Roles, Relations,
63  nullptr, OrigD, DC);
64 }
65 
67  const NamedDecl *Parent,
68  const DeclContext *DC,
69  SymbolRoleSet Roles,
70  ArrayRef<SymbolRelation> Relations,
71  const Expr *RefE,
72  const Decl *RefD) {
74  return true;
75 
76  if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
77  return true;
78 
79  return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
80  RefE, RefD, DC);
81 }
82 
84  SourceLocation Loc;
85  auto IdLocs = ImportD->getIdentifierLocs();
86  if (!IdLocs.empty())
87  Loc = IdLocs.front();
88  else
89  Loc = ImportD->getLocation();
90 
92  FileID FID = SM.getFileID(SM.getFileLoc(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, Loc);
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:
303  return true;
304  }
305  llvm_unreachable("Unsupported SymbolRole value!");
306  });
307  return accept;
308  };
309 
310  for (auto &Rel : Relations) {
311  if (acceptForRelation(Rel.Roles))
312  return true;
313  }
314 
315  return false;
316 }
317 
318 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
319  bool IsRef, const Decl *Parent,
320  SymbolRoleSet Roles,
321  ArrayRef<SymbolRelation> Relations,
322  const Expr *OrigE,
323  const Decl *OrigD,
324  const DeclContext *ContainerDC) {
325  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
326  return true;
327  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
328  return true;
329 
331  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
332  if (FID.isInvalid())
333  return true;
334 
335  bool Invalid = false;
336  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
337  if (Invalid || !SEntry.isFile())
338  return true;
339 
340  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
341  switch (IndexOpts.SystemSymbolFilter) {
343  return true;
345  if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
346  return true;
347  break;
349  break;
350  }
351  }
352 
353  if (!OrigD)
354  OrigD = D;
355 
357  if (!IsRef)
358  return true;
360  if (!D)
361  return true;
363  }
364 
365  if (IsRef)
366  Roles |= (unsigned)SymbolRole::Reference;
367  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
368  Roles |= (unsigned)SymbolRole::Definition;
369  else
370  Roles |= (unsigned)SymbolRole::Declaration;
371 
372  D = getCanonicalDecl(D);
373  Parent = adjustParent(Parent);
374  if (Parent)
375  Parent = getCanonicalDecl(Parent);
376 
377  SmallVector<SymbolRelation, 6> FinalRelations;
378  FinalRelations.reserve(Relations.size()+1);
379 
380  auto addRelation = [&](SymbolRelation Rel) {
381  auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
382  [&](SymbolRelation Elem)->bool {
383  return Elem.RelatedSymbol == Rel.RelatedSymbol;
384  });
385  if (It != FinalRelations.end()) {
386  It->Roles |= Rel.Roles;
387  } else {
388  FinalRelations.push_back(Rel);
389  }
390  Roles |= Rel.Roles;
391  };
392 
393  if (Parent) {
394  if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
395  addRelation(SymbolRelation{
397  Parent
398  });
399  } else {
400  addRelation(SymbolRelation{
401  (unsigned)SymbolRole::RelationChildOf,
402  Parent
403  });
404  }
405  }
406 
407  for (auto &Rel : Relations) {
408  addRelation(SymbolRelation(Rel.Roles,
409  Rel.RelatedSymbol->getCanonicalDecl()));
410  }
411 
412  IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
413  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
414 }
415 
417  SourceLocation Loc,
418  const MacroInfo &MI) {
419  SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
420  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
421 }
422 
424  SourceLocation Loc,
425  const MacroInfo &MI) {
426  SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
427  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
428 }
429 
431  SourceLocation Loc,
432  const MacroInfo &MI) {
433  SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
434  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
435 }
Defines the clang::ASTContext interface.
static const Decl * getCanonicalDecl(const Decl *D)
Represents a function declaration or definition.
Definition: Decl.h:1722
This is a discriminated union of FileInfo and ExpansionInfo.
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:125
static bool shouldReportOccurrenceForSystemDeclOnlyMode(bool IsRef, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations)
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
Defines the C++ template declaration subclasses.
virtual bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations, SourceLocation Loc, ASTNodeInfo ASTNode)
virtual bool handleModuleOccurence(const ImportDecl *ImportD, SymbolRoleSet Roles, SourceLocation Loc)
bool isEmpty() const
Evaluates true when this declaration name is empty.
void handleMacroDefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI)
static const CXXRecordDecl * getDeclContextForTemplateInstationPattern(const Decl *D)
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:297
One of these records is kept for each identifier that is lexed.
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:95
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:153
bool isFunctionLocalSymbol(const Decl *D)
Definition: IndexSymbol.cpp:53
void handleMacroReference(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MD)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:50
bool isInvalid() const
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:4641
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:883
NodeId Parent
Definition: ASTDiff.cpp:192
unsigned SymbolRoleSet
Definition: IndexSymbol.h:122
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:889
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:560
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:1629
DeclContext * getDeclContext()
Definition: DeclBase.h:434
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:152
const SourceManager & SM
Definition: Format.cpp:1475
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:4023
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...
bool shouldIndexImplicitInstantiation() const
This template specialization was instantiated from a template due to an explicit instantiation defini...
Definition: Specifiers.h:164
This template specialization was formed from a template-id but has not yet been declared, defined, or instantiated.
Definition: Specifiers.h:149
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:4120
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:1272
static bool isGeneratedDecl(const Decl *D)
virtual bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI, SymbolRoleSet Roles, SourceLocation Loc)
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition: Specifiers.h:160
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:1575
Represents an enum.
Definition: Decl.h:3305
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition: Specifiers.h:146
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:40
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
void handleMacroUndefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI)
This template specialization was declared or defined by an explicit specialization (C++ [temp...
Definition: Specifiers.h:156
T * getAttr() const
Definition: DeclBase.h:540
bool importedModule(const ImportDecl *ImportD)
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
SourceManager & getSourceManager()
Definition: ASTContext.h:670
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ struct/union/class.
Definition: DeclCXX.h:308
This represents a decl that may have a name.
Definition: Decl.h:248
const LangOptions & getLangOpts() const
Definition: ASTContext.h:715
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Definition: DeclBase.h:425