clang  7.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();
85 
87  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
88  if (FID.isInvalid())
89  return true;
90 
91  bool Invalid = false;
92  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
93  if (Invalid || !SEntry.isFile())
94  return true;
95 
96  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
97  switch (IndexOpts.SystemSymbolFilter) {
99  return true;
102  break;
103  }
104  }
105 
106  SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
107  if (ImportD->isImplicit())
108  Roles |= (unsigned)SymbolRole::Implicit;
109 
110  return DataConsumer.handleModuleOccurence(ImportD, Roles, Loc);
111 }
112 
116  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
117  TKind = SD->getSpecializationKind();
118  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
119  TKind = FD->getTemplateSpecializationKind();
120  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
121  TKind = VD->getTemplateSpecializationKind();
122  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
123  if (RD->getInstantiatedFromMemberClass())
124  TKind = RD->getTemplateSpecializationKind();
125  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
126  if (ED->getInstantiatedFromMemberEnum())
127  TKind = ED->getTemplateSpecializationKind();
128  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
129  isa<EnumConstantDecl>(D)) {
130  if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
132  }
133  switch (TKind) {
134  case TSK_Undeclared:
136  return false;
140  return true;
141  }
142  llvm_unreachable("invalid TemplateSpecializationKind");
143 }
144 
145 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
146  if (isa<ObjCInterfaceDecl>(D))
147  return false;
148  if (isa<ObjCCategoryDecl>(D))
149  return false;
150  if (isa<ObjCIvarDecl>(D))
151  return false;
152  if (isa<ObjCMethodDecl>(D))
153  return false;
154  if (isa<ImportDecl>(D))
155  return false;
156  return true;
157 }
158 
159 static const CXXRecordDecl *
161  if (const auto *CTSD =
162  dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
163  return CTSD->getTemplateInstantiationPattern();
164  else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
165  return RD->getInstantiatedFromMemberClass();
166  return nullptr;
167 }
168 
171  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
172  return SD->getTemplateInstantiationPattern();
173  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
174  return FD->getTemplateInstantiationPattern();
175  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
176  return VD->getTemplateInstantiationPattern();
177  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
178  return RD->getInstantiatedFromMemberClass();
179  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
180  return ED->getInstantiatedFromMemberEnum();
181  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
182  const auto *ND = cast<NamedDecl>(D);
183  if (const CXXRecordDecl *Pattern =
185  for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
186  if (BaseND->isImplicit())
187  continue;
188  if (BaseND->getKind() == ND->getKind())
189  return BaseND;
190  }
191  }
192  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
193  if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
194  if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
195  for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
196  return BaseECD;
197  }
198  }
199  }
200  return nullptr;
201 }
202 
203 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
204  if (auto VD = dyn_cast<VarDecl>(D))
205  return VD->isThisDeclarationADefinition(Ctx);
206 
207  if (auto FD = dyn_cast<FunctionDecl>(D))
208  return FD->isThisDeclarationADefinition();
209 
210  if (auto TD = dyn_cast<TagDecl>(D))
211  return TD->isThisDeclarationADefinition();
212 
213  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
214  return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
215 
216  if (isa<TypedefNameDecl>(D) ||
217  isa<EnumConstantDecl>(D) ||
218  isa<FieldDecl>(D) ||
219  isa<MSPropertyDecl>(D) ||
220  isa<ObjCImplDecl>(D) ||
221  isa<ObjCPropertyImplDecl>(D))
222  return true;
223 
224  return false;
225 }
226 
227 /// Whether the given NamedDecl should be skipped because it has no name.
228 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
229  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
230  !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
231 }
232 
233 static const Decl *adjustParent(const Decl *Parent) {
234  if (!Parent)
235  return nullptr;
236  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
237  if (isa<TranslationUnitDecl>(Parent))
238  return nullptr;
239  if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
240  continue;
241  if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
242  if (NS->isAnonymousNamespace())
243  continue;
244  } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
245  if (RD->isAnonymousStructOrUnion())
246  continue;
247  } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
248  if (shouldSkipNamelessDecl(ND))
249  continue;
250  }
251  return Parent;
252  }
253 }
254 
255 static const Decl *getCanonicalDecl(const Decl *D) {
256  D = D->getCanonicalDecl();
257  if (auto TD = dyn_cast<TemplateDecl>(D)) {
258  if (auto TTD = TD->getTemplatedDecl()) {
259  D = TTD;
260  assert(D->isCanonicalDecl());
261  }
262  }
263 
264  return D;
265 }
266 
268  bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
269  if (!IsRef)
270  return true;
271 
272  auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
273  bool accept = false;
274  applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
275  switch (r) {
282  accept = true;
283  return false;
287  case SymbolRole::Read:
288  case SymbolRole::Write:
289  case SymbolRole::Call:
290  case SymbolRole::Dynamic:
297  return true;
298  }
299  llvm_unreachable("Unsupported SymbolRole value!");
300  });
301  return accept;
302  };
303 
304  for (auto &Rel : Relations) {
305  if (acceptForRelation(Rel.Roles))
306  return true;
307  }
308 
309  return false;
310 }
311 
312 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
313  bool IsRef, const Decl *Parent,
314  SymbolRoleSet Roles,
315  ArrayRef<SymbolRelation> Relations,
316  const Expr *OrigE,
317  const Decl *OrigD,
318  const DeclContext *ContainerDC) {
319  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
320  return true;
321  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
322  return true;
323 
325  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
326  if (FID.isInvalid())
327  return true;
328 
329  bool Invalid = false;
330  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
331  if (Invalid || !SEntry.isFile())
332  return true;
333 
334  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
335  switch (IndexOpts.SystemSymbolFilter) {
337  return true;
339  if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
340  return true;
341  break;
343  break;
344  }
345  }
346 
348  if (!IsRef)
349  return true;
351  if (!D)
352  return true;
354  }
355 
356  if (!OrigD)
357  OrigD = D;
358 
359  if (IsRef)
360  Roles |= (unsigned)SymbolRole::Reference;
361  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
362  Roles |= (unsigned)SymbolRole::Definition;
363  else
364  Roles |= (unsigned)SymbolRole::Declaration;
365 
366  D = getCanonicalDecl(D);
367  Parent = adjustParent(Parent);
368  if (Parent)
369  Parent = getCanonicalDecl(Parent);
370 
371  SmallVector<SymbolRelation, 6> FinalRelations;
372  FinalRelations.reserve(Relations.size()+1);
373 
374  auto addRelation = [&](SymbolRelation Rel) {
375  auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
376  [&](SymbolRelation Elem)->bool {
377  return Elem.RelatedSymbol == Rel.RelatedSymbol;
378  });
379  if (It != FinalRelations.end()) {
380  It->Roles |= Rel.Roles;
381  } else {
382  FinalRelations.push_back(Rel);
383  }
384  Roles |= Rel.Roles;
385  };
386 
387  if (Parent) {
388  if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
389  addRelation(SymbolRelation{
391  Parent
392  });
393  } else {
394  addRelation(SymbolRelation{
395  (unsigned)SymbolRole::RelationChildOf,
396  Parent
397  });
398  }
399  }
400 
401  for (auto &Rel : Relations) {
402  addRelation(SymbolRelation(Rel.Roles,
403  Rel.RelatedSymbol->getCanonicalDecl()));
404  }
405 
406  IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
407  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
408 }
Defines the clang::ASTContext interface.
static const Decl * getCanonicalDecl(const Decl *D)
Represents a function declaration or definition.
Definition: Decl.h:1714
This is a discriminated union of FileInfo and ExpansionInfo.
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:121
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.
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
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:94
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:150
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: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:4552
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:875
NodeId Parent
Definition: ASTDiff.cpp:192
unsigned SymbolRoleSet
Definition: IndexSymbol.h:118
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:881
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:552
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:1618
DeclContext * getDeclContext()
Definition: DeclBase.h:426
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:1468
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:3958
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: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:1262
static bool isGeneratedDecl(const Decl *D)
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:1564
Represents an enum.
Definition: Decl.h:3299
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition: Specifiers.h:146
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
This template specialization was declared or defined by an explicit specialization (C++ [temp...
Definition: Specifiers.h:156
T * getAttr() const
Definition: DeclBase.h:532
bool importedModule(const ImportDecl *ImportD)
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
SourceManager & getSourceManager()
Definition: ASTContext.h:644
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:689
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Definition: DeclBase.h:417