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 
83 static void reportModuleReferences(const Module *Mod,
85  const ImportDecl *ImportD,
86  IndexDataConsumer &DataConsumer) {
87  if (!Mod)
88  return;
89  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
90  DataConsumer);
91  DataConsumer.handleModuleOccurence(ImportD, Mod,
93  IdLocs.back());
94 }
95 
97  if (ImportD->isInvalidDecl())
98  return true;
99 
100  SourceLocation Loc;
101  auto IdLocs = ImportD->getIdentifierLocs();
102  if (!IdLocs.empty())
103  Loc = IdLocs.back();
104  else
105  Loc = ImportD->getLocation();
106 
108  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
109  if (FID.isInvalid())
110  return true;
111 
112  bool Invalid = false;
113  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
114  if (Invalid || !SEntry.isFile())
115  return true;
116 
117  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
118  switch (IndexOpts.SystemSymbolFilter) {
120  return true;
123  break;
124  }
125  }
126 
127  const Module *Mod = ImportD->getImportedModule();
128  if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
129  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
130  DataConsumer);
131  }
132 
133  SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
134  if (ImportD->isImplicit())
135  Roles |= (unsigned)SymbolRole::Implicit;
136 
137  return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc);
138 }
139 
143  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
144  TKind = SD->getSpecializationKind();
145  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
146  TKind = FD->getTemplateSpecializationKind();
147  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
148  TKind = VD->getTemplateSpecializationKind();
149  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
150  if (RD->getInstantiatedFromMemberClass())
151  TKind = RD->getTemplateSpecializationKind();
152  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
153  if (ED->getInstantiatedFromMemberEnum())
154  TKind = ED->getTemplateSpecializationKind();
155  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
156  isa<EnumConstantDecl>(D)) {
157  if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
159  }
160  switch (TKind) {
161  case TSK_Undeclared:
163  return false;
167  return true;
168  }
169  llvm_unreachable("invalid TemplateSpecializationKind");
170 }
171 
172 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
173  if (isa<ObjCInterfaceDecl>(D))
174  return false;
175  if (isa<ObjCCategoryDecl>(D))
176  return false;
177  if (isa<ObjCIvarDecl>(D))
178  return false;
179  if (isa<ObjCMethodDecl>(D))
180  return false;
181  if (isa<ImportDecl>(D))
182  return false;
183  return true;
184 }
185 
186 static const CXXRecordDecl *
188  if (const auto *CTSD =
189  dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
190  return CTSD->getTemplateInstantiationPattern();
191  else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
192  return RD->getInstantiatedFromMemberClass();
193  return nullptr;
194 }
195 
198  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
199  return SD->getTemplateInstantiationPattern();
200  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
201  return FD->getTemplateInstantiationPattern();
202  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
203  return VD->getTemplateInstantiationPattern();
204  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
205  return RD->getInstantiatedFromMemberClass();
206  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
207  return ED->getInstantiatedFromMemberEnum();
208  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
209  const auto *ND = cast<NamedDecl>(D);
210  if (const CXXRecordDecl *Pattern =
212  for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
213  if (BaseND->isImplicit())
214  continue;
215  if (BaseND->getKind() == ND->getKind())
216  return BaseND;
217  }
218  }
219  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
220  if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
221  if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
222  for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
223  return BaseECD;
224  }
225  }
226  }
227  return nullptr;
228 }
229 
230 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
231  if (auto VD = dyn_cast<VarDecl>(D))
232  return VD->isThisDeclarationADefinition(Ctx);
233 
234  if (auto FD = dyn_cast<FunctionDecl>(D))
235  return FD->isThisDeclarationADefinition();
236 
237  if (auto TD = dyn_cast<TagDecl>(D))
238  return TD->isThisDeclarationADefinition();
239 
240  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
241  return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
242 
243  if (isa<TypedefNameDecl>(D) ||
244  isa<EnumConstantDecl>(D) ||
245  isa<FieldDecl>(D) ||
246  isa<MSPropertyDecl>(D) ||
247  isa<ObjCImplDecl>(D) ||
248  isa<ObjCPropertyImplDecl>(D))
249  return true;
250 
251  return false;
252 }
253 
254 /// Whether the given NamedDecl should be skipped because it has no name.
255 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
256  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
257  !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
258 }
259 
260 static const Decl *adjustParent(const Decl *Parent) {
261  if (!Parent)
262  return nullptr;
263  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
264  if (isa<TranslationUnitDecl>(Parent))
265  return nullptr;
266  if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
267  continue;
268  if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
269  if (NS->isAnonymousNamespace())
270  continue;
271  } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
272  if (RD->isAnonymousStructOrUnion())
273  continue;
274  } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
275  if (shouldSkipNamelessDecl(ND))
276  continue;
277  }
278  return Parent;
279  }
280 }
281 
282 static const Decl *getCanonicalDecl(const Decl *D) {
283  D = D->getCanonicalDecl();
284  if (auto TD = dyn_cast<TemplateDecl>(D)) {
285  if (auto TTD = TD->getTemplatedDecl()) {
286  D = TTD;
287  assert(D->isCanonicalDecl());
288  }
289  }
290 
291  return D;
292 }
293 
295  bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
296  if (!IsRef)
297  return true;
298 
299  auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
300  bool accept = false;
301  applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
302  switch (r) {
309  accept = true;
310  return false;
314  case SymbolRole::Read:
315  case SymbolRole::Write:
316  case SymbolRole::Call:
317  case SymbolRole::Dynamic:
325  return true;
326  }
327  llvm_unreachable("Unsupported SymbolRole value!");
328  });
329  return accept;
330  };
331 
332  for (auto &Rel : Relations) {
333  if (acceptForRelation(Rel.Roles))
334  return true;
335  }
336 
337  return false;
338 }
339 
340 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
341  bool IsRef, const Decl *Parent,
342  SymbolRoleSet Roles,
343  ArrayRef<SymbolRelation> Relations,
344  const Expr *OrigE,
345  const Decl *OrigD,
346  const DeclContext *ContainerDC) {
347  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
348  return true;
349  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
350  return true;
351 
353  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
354  if (FID.isInvalid())
355  return true;
356 
357  bool Invalid = false;
358  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
359  if (Invalid || !SEntry.isFile())
360  return true;
361 
362  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
363  switch (IndexOpts.SystemSymbolFilter) {
365  return true;
367  if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
368  return true;
369  break;
371  break;
372  }
373  }
374 
375  if (!OrigD)
376  OrigD = D;
377 
379  if (!IsRef)
380  return true;
382  if (!D)
383  return true;
385  }
386 
387  if (IsRef)
388  Roles |= (unsigned)SymbolRole::Reference;
389  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
390  Roles |= (unsigned)SymbolRole::Definition;
391  else
392  Roles |= (unsigned)SymbolRole::Declaration;
393 
394  D = getCanonicalDecl(D);
395  Parent = adjustParent(Parent);
396  if (Parent)
397  Parent = getCanonicalDecl(Parent);
398 
399  SmallVector<SymbolRelation, 6> FinalRelations;
400  FinalRelations.reserve(Relations.size()+1);
401 
402  auto addRelation = [&](SymbolRelation Rel) {
403  auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
404  [&](SymbolRelation Elem)->bool {
405  return Elem.RelatedSymbol == Rel.RelatedSymbol;
406  });
407  if (It != FinalRelations.end()) {
408  It->Roles |= Rel.Roles;
409  } else {
410  FinalRelations.push_back(Rel);
411  }
412  Roles |= Rel.Roles;
413  };
414 
415  if (Parent) {
416  if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
417  addRelation(SymbolRelation{
419  Parent
420  });
421  } else {
422  addRelation(SymbolRelation{
423  (unsigned)SymbolRole::RelationChildOf,
424  Parent
425  });
426  }
427  }
428 
429  for (auto &Rel : Relations) {
430  addRelation(SymbolRelation(Rel.Roles,
431  Rel.RelatedSymbol->getCanonicalDecl()));
432  }
433 
434  IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
435  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
436 }
437 
439  SourceLocation Loc,
440  const MacroInfo &MI) {
441  SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
442  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
443 }
444 
446  SourceLocation Loc,
447  const MacroInfo &MI) {
448  SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
449  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
450 }
451 
453  SourceLocation Loc,
454  const MacroInfo &MI) {
455  SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
456  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
457 }
Defines the clang::ASTContext interface.
static const Decl * getCanonicalDecl(const Decl *D)
Represents a function declaration or definition.
Definition: Decl.h:1732
This is a discriminated union of FileInfo and ExpansionInfo.
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:127
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:87
Defines the C++ template declaration subclasses.
virtual bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations, SourceLocation Loc, ASTNodeInfo ASTNode)
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)
bool isInvalidDecl() const
Definition: DeclBase.h:542
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:97
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:154
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
Describes a module or submodule.
Definition: Module.h:65
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
Module * Parent
The parent of this module.
Definition: Module.h:91
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:4675
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:870
Module * getImportedModule() const
Retrieve the module that was imported by the import declaration.
Definition: Decl.h:4185
NodeId Parent
Definition: ASTDiff.cpp:192
unsigned SymbolRoleSet
Definition: IndexSymbol.h:124
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:876
This represents one expression.
Definition: Expr.h:105
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:547
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:1652
DeclContext * getDeclContext()
Definition: DeclBase.h:427
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)
static void reportModuleReferences(const Module *Mod, ArrayRef< SourceLocation > IdLocs, const ImportDecl *ImportD, IndexDataConsumer &DataConsumer)
This template specialization was implicitly instantiated from a template.
Definition: Specifiers.h:152
const SourceManager & SM
Definition: Format.cpp:1490
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:4057
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...
virtual bool handleModuleOccurence(const ImportDecl *ImportD, const Module *Mod, SymbolRoleSet Roles, SourceLocation Loc)
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:4141
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:1261
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:1598
Represents an enum.
Definition: Decl.h:3318
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:527
bool importedModule(const ImportDecl *ImportD)
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
SourceManager & getSourceManager()
Definition: ASTContext.h:671
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ struct/union/class.
Definition: DeclCXX.h:300
This represents a decl that may have a name.
Definition: Decl.h:248
const LangOptions & getLangOpts() const
Definition: ASTContext.h:716
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Definition: DeclBase.h:418