Clang Project

clang_source_code/lib/Index/IndexingContext.cpp
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"
10#include "clang/Basic/SourceLocation.h"
11#include "clang/Index/IndexDataConsumer.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/AST/DeclTemplate.h"
14#include "clang/AST/DeclObjC.h"
15#include "clang/Basic/SourceManager.h"
16
17using namespace clang;
18using namespace index;
19
20static bool isGeneratedDecl(const Decl *D) {
21  if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
22    return attr->getGeneratedDeclaration();
23  }
24  return false;
25}
26
27bool IndexingContext::shouldIndex(const Decl *D) {
28  return !isGeneratedDecl(D);
29}
30
31const LangOptions &IndexingContext::getLangOpts() const {
32  return Ctx->getLangOpts();
33}
34
35bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
36  return IndexOpts.IndexFunctionLocals;
37}
38
39bool IndexingContext::shouldIndexImplicitInstantiation() const {
40  return IndexOpts.IndexImplicitInstantiation;
41}
42
43bool IndexingContext::shouldIndexParametersInDeclarations() const {
44  return IndexOpts.IndexParametersInDeclarations;
45}
46
47bool IndexingContext::shouldIndexTemplateParameters() const {
48  return IndexOpts.IndexTemplateParameters;
49}
50
51bool IndexingContext::handleDecl(const Decl *D,
52                                 SymbolRoleSet Roles,
53                                 ArrayRef<SymbolRelationRelations) {
54  return handleDecl(D, D->getLocation(), Roles, Relations);
55}
56
57bool IndexingContext::handleDecl(const Decl *DSourceLocation Loc,
58                                 SymbolRoleSet Roles,
59                                 ArrayRef<SymbolRelationRelations,
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
73bool IndexingContext::handleReference(const NamedDecl *DSourceLocation Loc,
74                                      const NamedDecl *Parent,
75                                      const DeclContext *DC,
76                                      SymbolRoleSet Roles,
77                                      ArrayRef<SymbolRelationRelations,
78                                      const Expr *RefE,
79                                      const Decl *RefD) {
80  if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
81    return true;
82
83  if (!shouldIndexTemplateParameters() &&
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
93static void reportModuleReferences(const Module *Mod,
94                                   ArrayRef<SourceLocationIdLocs,
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,
102                                     (SymbolRoleSet)SymbolRole::Reference,
103                                     IdLocs.back());
104}
105
106bool IndexingContext::importedModule(const ImportDecl *ImportD) {
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
117  SourceManager &SM = Ctx->getSourceManager();
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) {
129    case IndexingOptions::SystemSymbolFilterKind::None:
130      return true;
131    case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
132    case IndexingOptions::SystemSymbolFilterKind::All:
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(ImportDModRolesLoc);
148}
149
150bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
151  TemplateSpecializationKind TKind = TSK_Undeclared;
152  if (const ClassTemplateSpecializationDecl *
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()))
168      return isTemplateImplicitInstantiation(Parent);
169  }
170  switch (TKind) {
171    case TSK_Undeclared:
172    case TSK_ExplicitSpecialization:
173      return false;
174    case TSK_ImplicitInstantiation:
175    case TSK_ExplicitInstantiationDeclaration:
176    case TSK_ExplicitInstantiationDefinition:
177      return true;
178  }
179  llvm_unreachable("invalid TemplateSpecializationKind");
180}
181
182bool 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
196static const CXXRecordDecl *
197getDeclContextForTemplateInstationPattern(const Decl *D) {
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
206static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
207  if (const ClassTemplateSpecializationDecl *
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 =
221            getDeclContextForTemplateInstationPattern(ND)) {
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
240static bool isDeclADefinition(const Decl *Dconst DeclContext *ContainerDCASTContext &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.
265static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
266  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
267          !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
268}
269
270static 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
292static 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      isCanonicalDecl()", "/home/seafit/code_projects/clang_source/clang/lib/Index/IndexingContext.cpp", 297, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(D->isCanonicalDecl());
298    }
299  }
300
301  return D;
302}
303
304static bool shouldReportOccurrenceForSystemDeclOnlyMode(
305    bool IsRefSymbolRoleSet RolesArrayRef<SymbolRelationRelations) {
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) {
313      case SymbolRole::RelationChildOf:
314      case SymbolRole::RelationBaseOf:
315      case SymbolRole::RelationOverrideOf:
316      case SymbolRole::RelationExtendedBy:
317      case SymbolRole::RelationAccessorOf:
318      case SymbolRole::RelationIBTypeOf:
319        accept = true;
320        return false;
321      case SymbolRole::Declaration:
322      case SymbolRole::Definition:
323      case SymbolRole::Reference:
324      case SymbolRole::Read:
325      case SymbolRole::Write:
326      case SymbolRole::Call:
327      case SymbolRole::Dynamic:
328      case SymbolRole::AddressOf:
329      case SymbolRole::Implicit:
330      case SymbolRole::Undefinition:
331      case SymbolRole::RelationReceivedBy:
332      case SymbolRole::RelationCalledBy:
333      case SymbolRole::RelationContainedBy:
334      case SymbolRole::RelationSpecializationOf:
335      case SymbolRole::NameReference:
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
351bool IndexingContext::handleDeclOccurrence(const Decl *DSourceLocation Loc,
352                                           bool IsRefconst Decl *Parent,
353                                           SymbolRoleSet Roles,
354                                           ArrayRef<SymbolRelationRelations,
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
363  SourceManager &SM = Ctx->getSourceManager();
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) {
375    case IndexingOptions::SystemSymbolFilterKind::None:
376      return true;
377    case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
378      if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
379        return true;
380      break;
381    case IndexingOptions::SystemSymbolFilterKind::All:
382      break;
383    }
384  }
385
386  if (!OrigD)
387    OrigD = D;
388
389  if (isTemplateImplicitInstantiation(D)) {
390    if (!IsRef)
391      return true;
392    D = adjustTemplateImplicitInstantiation(D);
393    if (!D)
394      return true;
395    assert(!isTemplateImplicitInstantiation(D));
396  }
397
398  if (IsRef)
399    Roles |= (unsigned)SymbolRole::Reference;
400  else if (isDeclADefinition(OrigDContainerDC*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<SymbolRelation6FinalRelations;
411  FinalRelations.reserve(Relations.size()+1);
412
413  auto addRelation = [&](SymbolRelation Rel) {
414    auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
415                [&](SymbolRelation Elem)->bool {
416                  return Elem.RelatedSymbol == Rel.RelatedSymbol;
417                });
418    if (It != FinalRelations.end()) {
419      It->Roles |= Rel.Roles;
420    } else {
421      FinalRelations.push_back(Rel);
422    }
423    Roles |= Rel.Roles;
424  };
425
426  if (Parent) {
427    if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
428      addRelation(SymbolRelation{
429        (unsigned)SymbolRole::RelationContainedBy,
430        Parent
431      });
432    } else {
433      addRelation(SymbolRelation{
434        (unsigned)SymbolRole::RelationChildOf,
435        Parent
436      });
437    }
438  }
439
440  for (auto &Rel : Relations) {
441    addRelation(SymbolRelation(Rel.Roles,
442                               Rel.RelatedSymbol->getCanonicalDecl()));
443  }
444
445  IndexDataConsumer::ASTNodeInfo Node{OrigEOrigDParentContainerDC};
446  return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
447}
448
449void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
450                                         SourceLocation Loc,
451                                         const MacroInfo &MI) {
452  SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
453  DataConsumer.handleMacroOccurence(&Name, &MIRolesLoc);
454}
455
456void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
457                                           SourceLocation Loc,
458                                           const MacroInfo &MI) {
459  SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
460  DataConsumer.handleMacroOccurence(&Name, &MIRolesLoc);
461}
462
463void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
464                                           SourceLocation Loc,
465                                           const MacroInfo &MI) {
466  SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
467  DataConsumer.handleMacroOccurence(&Name, &MIRolesLoc);
468}
469
clang::index::IndexingContext::shouldIndex
clang::index::IndexingContext::getLangOpts
clang::index::IndexingContext::shouldIndexFunctionLocalSymbols
clang::index::IndexingContext::shouldIndexImplicitInstantiation
clang::index::IndexingContext::shouldIndexParametersInDeclarations
clang::index::IndexingContext::shouldIndexTemplateParameters
clang::index::IndexingContext::handleDecl
clang::index::IndexingContext::handleDecl
clang::index::IndexingContext::handleReference
clang::index::IndexingContext::importedModule
clang::index::IndexingContext::isTemplateImplicitInstantiation
clang::index::IndexingContext::shouldIgnoreIfImplicit
clang::index::IndexingContext::handleDeclOccurrence
clang::index::IndexingContext::handleMacroDefined
clang::index::IndexingContext::handleMacroUndefined
clang::index::IndexingContext::handleMacroReference