brintos

brintos / llvm-project-archived public Read only

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