clang  10.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  return IndexOpts.IndexTemplateParameters;
49 }
50 
52  SymbolRoleSet Roles,
53  ArrayRef<SymbolRelation> Relations) {
54  return handleDecl(D, D->getLocation(), Roles, Relations);
55 }
56 
58  SymbolRoleSet Roles,
59  ArrayRef<SymbolRelation> Relations,
60  const DeclContext *DC) {
61  if (!DC)
62  DC = D->getDeclContext();
63 
64  const Decl *OrigD = D;
65  if (isa<ObjCPropertyImplDecl>(D)) {
66  D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
67  }
68  return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
69  Roles, Relations,
70  nullptr, OrigD, DC);
71 }
72 
74  const NamedDecl *Parent,
75  const DeclContext *DC,
76  SymbolRoleSet Roles,
77  ArrayRef<SymbolRelation> Relations,
78  const Expr *RefE,
79  const Decl *RefD) {
81  return true;
82 
84  (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
85  isa<TemplateTemplateParmDecl>(D))) {
86  return true;
87  }
88 
89  return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
90  RefE, RefD, DC);
91 }
92 
93 static void reportModuleReferences(const Module *Mod,
95  const ImportDecl *ImportD,
96  IndexDataConsumer &DataConsumer) {
97  if (!Mod)
98  return;
99  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
100  DataConsumer);
101  DataConsumer.handleModuleOccurence(ImportD, Mod,
103  IdLocs.back());
104 }
105 
107  if (ImportD->isInvalidDecl())
108  return true;
109 
110  SourceLocation Loc;
111  auto IdLocs = ImportD->getIdentifierLocs();
112  if (!IdLocs.empty())
113  Loc = IdLocs.back();
114  else
115  Loc = ImportD->getLocation();
116 
118  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
119  if (FID.isInvalid())
120  return true;
121 
122  bool Invalid = false;
123  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
124  if (Invalid || !SEntry.isFile())
125  return true;
126 
127  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
128  switch (IndexOpts.SystemSymbolFilter) {
130  return true;
133  break;
134  }
135  }
136 
137  const Module *Mod = ImportD->getImportedModule();
138  if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
139  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
140  DataConsumer);
141  }
142 
143  SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
144  if (ImportD->isImplicit())
145  Roles |= (unsigned)SymbolRole::Implicit;
146 
147  return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc);
148 }
149 
153  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
154  TKind = SD->getSpecializationKind();
155  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
156  TKind = FD->getTemplateSpecializationKind();
157  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
158  TKind = VD->getTemplateSpecializationKind();
159  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
160  if (RD->getInstantiatedFromMemberClass())
161  TKind = RD->getTemplateSpecializationKind();
162  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
163  if (ED->getInstantiatedFromMemberEnum())
164  TKind = ED->getTemplateSpecializationKind();
165  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
166  isa<EnumConstantDecl>(D)) {
167  if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
169  }
170  switch (TKind) {
171  case TSK_Undeclared:
173  return false;
177  return true;
178  }
179  llvm_unreachable("invalid TemplateSpecializationKind");
180 }
181 
182 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
183  if (isa<ObjCInterfaceDecl>(D))
184  return false;
185  if (isa<ObjCCategoryDecl>(D))
186  return false;
187  if (isa<ObjCIvarDecl>(D))
188  return false;
189  if (isa<ObjCMethodDecl>(D))
190  return false;
191  if (isa<ImportDecl>(D))
192  return false;
193  return true;
194 }
195 
196 static const CXXRecordDecl *
198  if (const auto *CTSD =
199  dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
200  return CTSD->getTemplateInstantiationPattern();
201  else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
202  return RD->getInstantiatedFromMemberClass();
203  return nullptr;
204 }
205 
208  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
209  return SD->getTemplateInstantiationPattern();
210  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
211  return FD->getTemplateInstantiationPattern();
212  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
213  return VD->getTemplateInstantiationPattern();
214  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
215  return RD->getInstantiatedFromMemberClass();
216  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
217  return ED->getInstantiatedFromMemberEnum();
218  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
219  const auto *ND = cast<NamedDecl>(D);
220  if (const CXXRecordDecl *Pattern =
222  for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
223  if (BaseND->isImplicit())
224  continue;
225  if (BaseND->getKind() == ND->getKind())
226  return BaseND;
227  }
228  }
229  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
230  if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
231  if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
232  for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
233  return BaseECD;
234  }
235  }
236  }
237  return nullptr;
238 }
239 
240 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
241  if (auto VD = dyn_cast<VarDecl>(D))
242  return VD->isThisDeclarationADefinition(Ctx);
243 
244  if (auto FD = dyn_cast<FunctionDecl>(D))
245  return FD->isThisDeclarationADefinition();
246 
247  if (auto TD = dyn_cast<TagDecl>(D))
248  return TD->isThisDeclarationADefinition();
249 
250  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
251  return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
252 
253  if (isa<TypedefNameDecl>(D) ||
254  isa<EnumConstantDecl>(D) ||
255  isa<FieldDecl>(D) ||
256  isa<MSPropertyDecl>(D) ||
257  isa<ObjCImplDecl>(D) ||
258  isa<ObjCPropertyImplDecl>(D))
259  return true;
260 
261  return false;
262 }
263 
264 /// Whether the given NamedDecl should be skipped because it has no name.
265 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
266  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
267  !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
268 }
269 
270 static const Decl *adjustParent(const Decl *Parent) {
271  if (!Parent)
272  return nullptr;
273  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
274  if (isa<TranslationUnitDecl>(Parent))
275  return nullptr;
276  if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
277  continue;
278  if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
279  if (NS->isAnonymousNamespace())
280  continue;
281  } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
282  if (RD->isAnonymousStructOrUnion())
283  continue;
284  } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
285  if (shouldSkipNamelessDecl(ND))
286  continue;
287  }
288  return Parent;
289  }
290 }
291 
292 static const Decl *getCanonicalDecl(const Decl *D) {
293  D = D->getCanonicalDecl();
294  if (auto TD = dyn_cast<TemplateDecl>(D)) {
295  if (auto TTD = TD->getTemplatedDecl()) {
296  D = TTD;
297  assert(D->isCanonicalDecl());
298  }
299  }
300 
301  return D;
302 }
303 
305  bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
306  if (!IsRef)
307  return true;
308 
309  auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
310  bool accept = false;
311  applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
312  switch (r) {
319  accept = true;
320  return false;
324  case SymbolRole::Read:
325  case SymbolRole::Write:
326  case SymbolRole::Call:
327  case SymbolRole::Dynamic:
336  return true;
337  }
338  llvm_unreachable("Unsupported SymbolRole value!");
339  });
340  return accept;
341  };
342 
343  for (auto &Rel : Relations) {
344  if (acceptForRelation(Rel.Roles))
345  return true;
346  }
347 
348  return false;
349 }
350 
351 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
352  bool IsRef, const Decl *Parent,
353  SymbolRoleSet Roles,
354  ArrayRef<SymbolRelation> Relations,
355  const Expr *OrigE,
356  const Decl *OrigD,
357  const DeclContext *ContainerDC) {
358  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
359  return true;
360  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
361  return true;
362 
364  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
365  if (FID.isInvalid())
366  return true;
367 
368  bool Invalid = false;
369  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
370  if (Invalid || !SEntry.isFile())
371  return true;
372 
373  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
374  switch (IndexOpts.SystemSymbolFilter) {
376  return true;
378  if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
379  return true;
380  break;
382  break;
383  }
384  }
385 
386  if (!OrigD)
387  OrigD = D;
388 
390  if (!IsRef)
391  return true;
393  if (!D)
394  return true;
396  }
397 
398  if (IsRef)
399  Roles |= (unsigned)SymbolRole::Reference;
400  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
401  Roles |= (unsigned)SymbolRole::Definition;
402  else
403  Roles |= (unsigned)SymbolRole::Declaration;
404 
405  D = getCanonicalDecl(D);
406  Parent = adjustParent(Parent);
407  if (Parent)
408  Parent = getCanonicalDecl(Parent);
409 
410  SmallVector<SymbolRelation, 6> FinalRelations;
411  FinalRelations.reserve(Relations.size()+1);
412 
413  auto addRelation = [&](SymbolRelation Rel) {
414  auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
415  return Elem.RelatedSymbol == Rel.RelatedSymbol;
416  });
417  if (It != FinalRelations.end()) {
418  It->Roles |= Rel.Roles;
419  } else {
420  FinalRelations.push_back(Rel);
421  }
422  Roles |= Rel.Roles;
423  };
424 
425  if (Parent) {
426  if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
427  addRelation(SymbolRelation{
429  Parent
430  });
431  } else {
432  addRelation(SymbolRelation{
433  (unsigned)SymbolRole::RelationChildOf,
434  Parent
435  });
436  }
437  }
438 
439  for (auto &Rel : Relations) {
440  addRelation(SymbolRelation(Rel.Roles,
441  Rel.RelatedSymbol->getCanonicalDecl()));
442  }
443 
444  IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
445  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
446 }
447 
449  SourceLocation Loc,
450  const MacroInfo &MI) {
451  SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
452  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
453 }
454 
456  SourceLocation Loc,
457  const MacroInfo &MI) {
458  SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
459  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
460 }
461 
463  SourceLocation Loc,
464  const MacroInfo &MI) {
465  SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
466  DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
467 }
Defines the clang::ASTContext interface.
static const Decl * getCanonicalDecl(const Decl *D)
Represents a function declaration or definition.
Definition: Decl.h:1756
This is a discriminated union of FileInfo and ExpansionInfo.
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:130
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:88
Defines the C++ template declaration subclasses.
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:553
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:160
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:92
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:4851
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:877
Module * getImportedModule() const
Retrieve the module that was imported by the import declaration.
Definition: Decl.h:4265
NodeId Parent
Definition: ASTDiff.cpp:191
unsigned SymbolRoleSet
Definition: IndexSymbol.h:127
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:883
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:558
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:1690
DeclContext * getDeclContext()
Definition: DeclBase.h:438
virtual bool handleModuleOccurence(const ImportDecl *ImportD, const Module *Mod, SymbolRoleSet Roles, SourceLocation Loc)
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:181
const SourceManager & SM
Definition: Format.cpp:1616
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:4230
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
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 defini...
Definition: Specifiers.h:193
This template specialization was formed from a template-id but has not yet been declared, defined, or instantiated.
Definition: Specifiers.h:178
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:4221
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:1271
static bool isGeneratedDecl(const Decl *D)
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition: Specifiers.h:189
virtual bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations, SourceLocation Loc, ASTNodeInfo ASTNode)
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:1636
Represents an enum.
Definition: Decl.h:3367
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition: Specifiers.h:175
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:185
T * getAttr() const
Definition: DeclBase.h:538
bool importedModule(const ImportDecl *ImportD)
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
SourceManager & getSourceManager()
Definition: ASTContext.h:675
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ struct/union/class.
Definition: DeclCXX.h:254
This represents a decl that may have a name.
Definition: Decl.h:248
const LangOptions & getLangOpts() const
Definition: ASTContext.h:720
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Definition: DeclBase.h:429