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/AST/ASTContext.h"
11#include "clang/AST/Attr.h"
12#include "clang/AST/DeclObjC.h"
13#include "clang/AST/DeclTemplate.h"
14#include "clang/Basic/SourceLocation.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/Index/IndexDataConsumer.h"
17
18using namespace clang;
19using namespace index;
20
21static bool isGeneratedDecl(const Decl *D) {
22  if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
23    return attr->getGeneratedDeclaration();
24  }
25  return false;
26}
27
28bool IndexingContext::shouldIndex(const Decl *D) {
29  return !isGeneratedDecl(D);
30}
31
32const LangOptions &IndexingContext::getLangOpts() const {
33  return Ctx->getLangOpts();
34}
35
36bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
37  return IndexOpts.IndexFunctionLocals;
38}
39
40bool IndexingContext::shouldIndexImplicitInstantiation() const {
41  return IndexOpts.IndexImplicitInstantiation;
42}
43
44bool IndexingContext::shouldIndexParametersInDeclarations() const {
45  return IndexOpts.IndexParametersInDeclarations;
46}
47
48bool IndexingContext::shouldIndexTemplateParameters() const {
49  return IndexOpts.IndexTemplateParameters;
50}
51
52bool IndexingContext::handleDecl(const Decl *D,
53                                 SymbolRoleSet Roles,
54                                 ArrayRef<SymbolRelation> Relations) {
55  return handleDecl(D, D->getLocation(), Roles, Relations);
56}
57
58bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
59                                 SymbolRoleSet Roles,
60                                 ArrayRef<SymbolRelation> Relations,
61                                 const DeclContext *DC) {
62  if (!DC)
63    DC = D->getDeclContext();
64
65  const Decl *OrigD = D;
66  if (isa<ObjCPropertyImplDecl>(D)) {
67    D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
68  }
69  return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
70                              Roles, Relations,
71                              nullptr, OrigD, DC);
72}
73
74bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
75                                      const NamedDecl *Parent,
76                                      const DeclContext *DC,
77                                      SymbolRoleSet Roles,
78                                      ArrayRef<SymbolRelation> Relations,
79                                      const Expr *RefE,
80                                      const Decl *RefD) {
81  if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
82    return true;
83
84  if (!shouldIndexTemplateParameters() &&
85      (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
86       isa<TemplateTemplateParmDecl>(D))) {
87    return true;
88  }
89
90  return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
91                              RefE, RefD, DC);
92}
93
94static void reportModuleReferences(const Module *Mod,
95                                   ArrayRef<SourceLocation> IdLocs,
96                                   const ImportDecl *ImportD,
97                                   IndexDataConsumer &DataConsumer) {
98  if (!Mod)
99    return;
100  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
101                         DataConsumer);
102  DataConsumer.handleModuleOccurrence(
103      ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, 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.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
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      // Instantiation maybe not happen yet when we see a SpecializationDecl,
173      // e.g. when the type doesn't need to be complete, we still treat it as an
174      // instantiation as we'd like to keep the canonicalized result consistent.
175      return isa<ClassTemplateSpecializationDecl>(D);
176    case TSK_ExplicitSpecialization:
177      return false;
178    case TSK_ImplicitInstantiation:
179    case TSK_ExplicitInstantiationDeclaration:
180    case TSK_ExplicitInstantiationDefinition:
181      return true;
182  }
183  llvm_unreachable("invalid TemplateSpecializationKind");
184}
185
186bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
187  if (isa<ObjCInterfaceDecl>(D))
188    return false;
189  if (isa<ObjCCategoryDecl>(D))
190    return false;
191  if (isa<ObjCIvarDecl>(D))
192    return false;
193  if (isa<ObjCMethodDecl>(D))
194    return false;
195  if (isa<ImportDecl>(D))
196    return false;
197  return true;
198}
199
200static const CXXRecordDecl *
201getDeclContextForTemplateInstationPattern(const Decl *D) {
202  if (const auto *CTSD =
203          dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
204    return CTSD->getTemplateInstantiationPattern();
205  else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
206    return RD->getInstantiatedFromMemberClass();
207  return nullptr;
208}
209
210static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
211  if (const ClassTemplateSpecializationDecl *
212      SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
213    const auto *Template = SD->getTemplateInstantiationPattern();
214    if (Template)
215      return Template;
216    // Fallback to primary template if no instantiation is available yet (e.g.
217    // the type doesn't need to be complete).
218    return SD->getSpecializedTemplate()->getTemplatedDecl();
219  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
220    return FD->getTemplateInstantiationPattern();
221  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
222    return VD->getTemplateInstantiationPattern();
223  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
224    return RD->getInstantiatedFromMemberClass();
225  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
226    return ED->getInstantiatedFromMemberEnum();
227  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
228    const auto *ND = cast<NamedDecl>(D);
229    if (const CXXRecordDecl *Pattern =
230            getDeclContextForTemplateInstationPattern(ND)) {
231      for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
232        if (BaseND->isImplicit())
233          continue;
234        if (BaseND->getKind() == ND->getKind())
235          return BaseND;
236      }
237    }
238  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
239    if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
240      if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
241        for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
242          return BaseECD;
243      }
244    }
245  }
246  return nullptr;
247}
248
249static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
250  if (auto VD = dyn_cast<VarDecl>(D))
251    return VD->isThisDeclarationADefinition(Ctx);
252
253  if (auto FD = dyn_cast<FunctionDecl>(D))
254    return FD->isThisDeclarationADefinition();
255
256  if (auto TD = dyn_cast<TagDecl>(D))
257    return TD->isThisDeclarationADefinition();
258
259  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
260    return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
261
262  if (isa<TypedefNameDecl>(D) ||
263      isa<EnumConstantDecl>(D) ||
264      isa<FieldDecl>(D) ||
265      isa<MSPropertyDecl>(D) ||
266      isa<ObjCImplDecl>(D) ||
267      isa<ObjCPropertyImplDecl>(D))
268    return true;
269
270  return false;
271}
272
273/// Whether the given NamedDecl should be skipped because it has no name.
274static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
275  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
276          !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
277}
278
279static const Decl *adjustParent(const Decl *Parent) {
280  if (!Parent)
281    return nullptr;
282  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
283    if (isa<TranslationUnitDecl>(Parent))
284      return nullptr;
285    if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
286      continue;
287    if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
288      if (NS->isAnonymousNamespace())
289        continue;
290    } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
291      if (RD->isAnonymousStructOrUnion())
292        continue;
293    } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
294      if (shouldSkipNamelessDecl(ND))
295        continue;
296    }
297    return Parent;
298  }
299}
300
301static const Decl *getCanonicalDecl(const Decl *D) {
302  D = D->getCanonicalDecl();
303  if (auto TD = dyn_cast<TemplateDecl>(D)) {
304    if (auto TTD = TD->getTemplatedDecl()) {
305      D = TTD;
306      assert(D->isCanonicalDecl());
307    }
308  }
309
310  return D;
311}
312
313static bool shouldReportOccurrenceForSystemDeclOnlyMode(
314    bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
315  if (!IsRef)
316    return true;
317
318  auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
319    bool accept = false;
320    applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
321      switch (r) {
322      case SymbolRole::RelationChildOf:
323      case SymbolRole::RelationBaseOf:
324      case SymbolRole::RelationOverrideOf:
325      case SymbolRole::RelationExtendedBy:
326      case SymbolRole::RelationAccessorOf:
327      case SymbolRole::RelationIBTypeOf:
328        accept = true;
329        return false;
330      case SymbolRole::Declaration:
331      case SymbolRole::Definition:
332      case SymbolRole::Reference:
333      case SymbolRole::Read:
334      case SymbolRole::Write:
335      case SymbolRole::Call:
336      case SymbolRole::Dynamic:
337      case SymbolRole::AddressOf:
338      case SymbolRole::Implicit:
339      case SymbolRole::Undefinition:
340      case SymbolRole::RelationReceivedBy:
341      case SymbolRole::RelationCalledBy:
342      case SymbolRole::RelationContainedBy:
343      case SymbolRole::RelationSpecializationOf:
344      case SymbolRole::NameReference:
345        return true;
346      }
347      llvm_unreachable("Unsupported SymbolRole value!");
348    });
349    return accept;
350  };
351
352  for (auto &Rel : Relations) {
353    if (acceptForRelation(Rel.Roles))
354      return true;
355  }
356
357  return false;
358}
359
360bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
361                                           bool IsRef, const Decl *Parent,
362                                           SymbolRoleSet Roles,
363                                           ArrayRef<SymbolRelation> Relations,
364                                           const Expr *OrigE,
365                                           const Decl *OrigD,
366                                           const DeclContext *ContainerDC) {
367  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
368    return true;
369  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
370    return true;
371
372  SourceManager &SM = Ctx->getSourceManager();
373  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
374  if (FID.isInvalid())
375    return true;
376
377  bool Invalid = false;
378  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
379  if (Invalid || !SEntry.isFile())
380    return true;
381
382  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
383    switch (IndexOpts.SystemSymbolFilter) {
384    case IndexingOptions::SystemSymbolFilterKind::None:
385      return true;
386    case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
387      if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
388        return true;
389      break;
390    case IndexingOptions::SystemSymbolFilterKind::All:
391      break;
392    }
393  }
394
395  if (!OrigD)
396    OrigD = D;
397
398  if (isTemplateImplicitInstantiation(D)) {
399    if (!IsRef)
400      return true;
401    D = adjustTemplateImplicitInstantiation(D);
402    if (!D)
403      return true;
404    assert(!isTemplateImplicitInstantiation(D));
405  }
406
407  if (IsRef)
408    Roles |= (unsigned)SymbolRole::Reference;
409  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
410    Roles |= (unsigned)SymbolRole::Definition;
411  else
412    Roles |= (unsigned)SymbolRole::Declaration;
413
414  D = getCanonicalDecl(D);
415  Parent = adjustParent(Parent);
416  if (Parent)
417    Parent = getCanonicalDecl(Parent);
418
419  SmallVector<SymbolRelation, 6> FinalRelations;
420  FinalRelations.reserve(Relations.size()+1);
421
422  auto addRelation = [&](SymbolRelation Rel) {
423    auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
424      return Elem.RelatedSymbol == Rel.RelatedSymbol;
425    });
426    if (It != FinalRelations.end()) {
427      It->Roles |= Rel.Roles;
428    } else {
429      FinalRelations.push_back(Rel);
430    }
431    Roles |= Rel.Roles;
432  };
433
434  if (Parent) {
435    if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
436      addRelation(SymbolRelation{
437        (unsigned)SymbolRole::RelationContainedBy,
438        Parent
439      });
440    } else {
441      addRelation(SymbolRelation{
442        (unsigned)SymbolRole::RelationChildOf,
443        Parent
444      });
445    }
446  }
447
448  for (auto &Rel : Relations) {
449    addRelation(SymbolRelation(Rel.Roles,
450                               Rel.RelatedSymbol->getCanonicalDecl()));
451  }
452
453  IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
454  return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
455}
456
457void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
458                                         SourceLocation Loc,
459                                         const MacroInfo &MI) {
460  if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
461    return;
462  SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
463  DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
464}
465
466void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
467                                           SourceLocation Loc,
468                                           const MacroInfo &MI) {
469  if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
470    return;
471  SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
472  DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
473}
474
475void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
476                                           SourceLocation Loc,
477                                           const MacroInfo &MI) {
478  if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
479    return;
480  SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
481  DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
482}
483
484bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
485                                                 SourceLocation Loc) {
486  if (!IndexOpts.IndexMacros)
487    return false;
488
489  switch (IndexOpts.SystemSymbolFilter) {
490  case IndexingOptions::SystemSymbolFilterKind::None:
491    break;
492  case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
493    if (!IsRef)
494      return true;
495    break;
496  case IndexingOptions::SystemSymbolFilterKind::All:
497    return true;
498  }
499
500  SourceManager &SM = Ctx->getSourceManager();
501  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
502  if (FID.isInvalid())
503    return false;
504
505  bool Invalid = false;
506  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
507  if (Invalid || !SEntry.isFile())
508    return false;
509
510  return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;
511}
512