clang  9.0.0svn
IndexingContext.cpp
Go to the documentation of this file.
1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #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  return IndexOpts.IndexImplicitInstantiation;
41 }
42 
44  return IndexOpts.IndexParametersInDeclarations;
45 }
46 
48  SymbolRoleSet Roles,
49  ArrayRef<SymbolRelation> Relations) {
50  return handleDecl(D, D->getLocation(), Roles, Relations);
51 }
52 
54  SymbolRoleSet Roles,
55  ArrayRef<SymbolRelation> Relations,
56  const DeclContext *DC) {
57  if (!DC)
58  DC = D->getDeclContext();
59 
60  const Decl *OrigD = D;
61  if (isa<ObjCPropertyImplDecl>(D)) {
62  D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
63  }
64  return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
65  Roles, Relations,
66  nullptr, OrigD, DC);
67 }
68 
70  const NamedDecl *Parent,
71  const DeclContext *DC,
72  SymbolRoleSet Roles,
73  ArrayRef<SymbolRelation> Relations,
74  const Expr *RefE,
75  const Decl *RefD) {
77  return true;
78 
79  if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
80  return true;
81 
82  return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
83  RefE, RefD, DC);
84 }
85 
86 static void reportModuleReferences(const Module *Mod,
88  const ImportDecl *ImportD,
89  IndexDataConsumer &DataConsumer) {
90  if (!Mod)
91  return;
92  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
93  DataConsumer);
94  DataConsumer.handleModuleOccurence(ImportD, Mod,
96  IdLocs.back());
97 }
98 
100  if (ImportD->isInvalidDecl())
101  return true;
102 
103  SourceLocation Loc;
104  auto IdLocs = ImportD->getIdentifierLocs();
105  if (!IdLocs.empty())
106  Loc = IdLocs.back();
107  else
108  Loc = ImportD->getLocation();
109 
111  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
112  if (FID.isInvalid())
113  return true;
114 
115  bool Invalid = false;
116  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
117  if (Invalid || !SEntry.isFile())
118  return true;
119 
120  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
121  switch (IndexOpts.SystemSymbolFilter) {
123  return true;
126  break;
127  }
128  }
129 
130  const Module *Mod = ImportD->getImportedModule();
131  if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
132  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
133  DataConsumer);
134  }
135 
136  SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
137  if (ImportD->isImplicit())
138  Roles |= (unsigned)SymbolRole::Implicit;
139 
140  return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc);
141 }
142 
146  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
147  TKind = SD->getSpecializationKind();
148  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
149  TKind = FD->getTemplateSpecializationKind();
150  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
151  TKind = VD->getTemplateSpecializationKind();
152  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
153  if (RD->getInstantiatedFromMemberClass())
154  TKind = RD->getTemplateSpecializationKind();
155  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
156  if (ED->getInstantiatedFromMemberEnum())
157  TKind = ED->getTemplateSpecializationKind();
158  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
159  isa<EnumConstantDecl>(D)) {
160  if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
162  }
163  switch (TKind) {
164  case TSK_Undeclared:
166  return false;
170  return true;
171  }
172  llvm_unreachable("invalid TemplateSpecializationKind");
173 }
174 
175 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
176  if (isa<ObjCInterfaceDecl>(D))
177  return false;
178  if (isa<ObjCCategoryDecl>(D))
179  return false;
180  if (isa<ObjCIvarDecl>(D))
181  return false;
182  if (isa<ObjCMethodDecl>(D))
183  return false;
184  if (isa<ImportDecl>(D))
185  return false;
186  return true;
187 }
188 
189 static const CXXRecordDecl *
191  if (const auto *CTSD =
192  dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
193  return CTSD->getTemplateInstantiationPattern();
194  else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
195  return RD->getInstantiatedFromMemberClass();
196  return nullptr;
197 }
198 
201  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
202  return SD->getTemplateInstantiationPattern();
203  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
204  return FD->getTemplateInstantiationPattern();
205  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
206  return VD->getTemplateInstantiationPattern();
207  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
208  return RD->getInstantiatedFromMemberClass();
209  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
210  return ED->getInstantiatedFromMemberEnum();
211  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
212  const auto *ND = cast<NamedDecl>(D);
213  if (const CXXRecordDecl *Pattern =
215  for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
216  if (BaseND->isImplicit())
217  continue;
218  if (BaseND->getKind() == ND->getKind())
219  return BaseND;
220  }
221  }
222  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
223  if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
224  if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
225  for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
226  return BaseECD;
227  }
228  }
229  }
230  return nullptr;
231 }
232 
233 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
234  if (auto VD = dyn_cast<VarDecl>(D))
235  return VD->isThisDeclarationADefinition(Ctx);
236 
237  if (auto FD = dyn_cast<FunctionDecl>(D))
238  return FD->isThisDeclarationADefinition();
239 
240  if (auto TD = dyn_cast<TagDecl>(D))
241  return TD->isThisDeclarationADefinition();
242 
243  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
244  return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
245 
246  if (isa<TypedefNameDecl>(D) ||
247  isa<EnumConstantDecl>(D) ||
248  isa<FieldDecl>(D) ||
249  isa<MSPropertyDecl>(D) ||
250  isa<ObjCImplDecl>(D) ||
251  isa<ObjCPropertyImplDecl>(D))
252  return true;
253 
254  return false;
255 }
256 
257 /// Whether the given NamedDecl should be skipped because it has no name.
258 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
259  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
260  !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
261 }
262 
263 static const Decl *adjustParent(const Decl *Parent) {
264  if (!Parent)
265  return nullptr;
266  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
267  if (isa<TranslationUnitDecl>(Parent))
268  return nullptr;
269  if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
270  continue;
271  if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
272  if (NS->isAnonymousNamespace())
273  continue;
274  } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
275  if (RD->isAnonymousStructOrUnion())
276  continue;
277  } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
278  if (shouldSkipNamelessDecl(ND))
279  continue;
280  }
281  return Parent;
282  }
283 }
284 
285 static const Decl *getCanonicalDecl(const Decl *D) {
286  D = D->getCanonicalDecl();
287  if (auto TD = dyn_cast<TemplateDecl>(D)) {
288  if (auto TTD = TD->getTemplatedDecl()) {
289  D = TTD;
290  assert(D->isCanonicalDecl());
291  }
292  }
293 
294  return D;
295 }
296 
298  bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
299  if (!IsRef)
300  return true;
301 
302  auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
303  bool accept = false;
304  applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
305  switch (r) {
312  accept = true;
313  return false;
317  case SymbolRole::Read:
318  case SymbolRole::Write:
319  case SymbolRole::Call:
320  case SymbolRole::Dynamic:
328  return true;
329  }
330  llvm_unreachable("Unsupported SymbolRole value!");
331  });
332  return accept;
333  };
334 
335  for (auto &Rel : Relations) {
336  if (acceptForRelation(Rel.Roles))
337  return true;
338  }
339 
340  return false;
341 }
342 
343 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
344  bool IsRef, const Decl *Parent,
345  SymbolRoleSet Roles,
346  ArrayRef<SymbolRelation> Relations,
347  const Expr *OrigE,
348  const Decl *OrigD,
349  const DeclContext *ContainerDC) {
350  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
351  return true;
352  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
353  return true;
354 
356  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
357  if (FID.isInvalid())
358  return true;
359 
360  bool Invalid = false;
361  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
362  if (Invalid || !SEntry.isFile())
363  return true;
364 
365  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
366  switch (IndexOpts.SystemSymbolFilter) {
368  return true;
370  if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
371  return true;
372  break;
374  break;
375  }
376  }
377 
378  if (!OrigD)
379  OrigD = D;
380 
382  if (!IsRef)
383  return true;
385  if (!D)
386  return true;
388  }
389 
390  if (IsRef)
391  Roles |= (unsigned)SymbolRole::Reference;
392  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
393  Roles |= (unsigned)SymbolRole::Definition;
394  else
395  Roles |= (unsigned)SymbolRole::Declaration;
396 
397  D = getCanonicalDecl(D);
398  Parent = adjustParent(Parent);
399  if (Parent)
400  Parent = getCanonicalDecl(Parent);
401 
402  SmallVector<SymbolRelation, 6> FinalRelations;
403  FinalRelations.reserve(Relations.size()+1);
404 
405  auto addRelation = [&](SymbolRelation Rel) {
406  auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
407  [&](SymbolRelation Elem)->bool {
408  return Elem.RelatedSymbol == Rel.RelatedSymbol;
409  });
410  if (It != FinalRelations.end()) {
411  It->Roles |= Rel.Roles;
412  } else {
413  FinalRelations.push_back(Rel);
414  }
415  Roles |= Rel.Roles;
416  };
417 
418  if (Parent) {
419  if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
420  addRelation(SymbolRelation{
422  Parent
423  });
424  } else {
425  addRelation(SymbolRelation{
426  (unsigned)SymbolRole::RelationChildOf,
427  Parent
428  });
429  }
430  }
431 
432  for (auto &Rel : Relations) {
433  addRelation(SymbolRelation(Rel.Roles,
434  Rel.RelatedSymbol->getCanonicalDecl()));
435  }
436 
437  IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
438  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
439 }
440 
442  SourceLocation Loc,
443  const MacroInfo &MI) {
444  SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
445  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
446 }
447 
449  SourceLocation Loc,
450  const MacroInfo &MI) {
451  SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
452  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
453 }
454 
456  SourceLocation Loc,
457  const MacroInfo &MI) {
458  SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
459  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
460 }
Defines the clang::ASTContext interface.
static const Decl * getCanonicalDecl(const Decl *D)
Represents a function declaration or definition.
Definition: Decl.h:1737
This is a discriminated union of FileInfo and ExpansionInfo.
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:126
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)
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:544
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:96
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:52
void handleMacroReference(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MD)
bool shouldIndexParametersInDeclarations() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
Describes a module or submodule.
Definition: Module.h:64
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:90
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:4684
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:872
Module * getImportedModule() const
Retrieve the module that was imported by the import declaration.
Definition: Decl.h:4192
NodeId Parent
Definition: ASTDiff.cpp:191
unsigned SymbolRoleSet
Definition: IndexSymbol.h:123
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:878
This represents one expression.
Definition: Expr.h:108
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:549
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:1662
DeclContext * getDeclContext()
Definition: DeclBase.h:429
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:151
const SourceManager & SM
Definition: Format.cpp:1489
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:4066
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:163
This template specialization was formed from a template-id but has not yet been declared, defined, or instantiated.
Definition: Specifiers.h:148
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:4148
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:1265
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:159
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:1608
Represents an enum.
Definition: Decl.h:3325
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition: Specifiers.h:145
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:39
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:155
T * getAttr() const
Definition: DeclBase.h:529
bool importedModule(const ImportDecl *ImportD)
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
SourceManager & getSourceManager()
Definition: ASTContext.h:661
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ struct/union/class.
Definition: DeclCXX.h:299
This represents a decl that may have a name.
Definition: Decl.h:248
const LangOptions & getLangOpts() const
Definition: ASTContext.h:706
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Definition: DeclBase.h:420