tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HeuristicResolver.cpp (11886B)


      1 //===--- HeuristicResolver.cpp ---------------------------*- C++-*-===//
      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 "HeuristicResolver.h"
     10 #include "clang/AST/ASTContext.h"
     11 #include "clang/AST/CXXInheritance.h"
     12 #include "clang/AST/DeclTemplate.h"
     13 #include "clang/AST/ExprCXX.h"
     14 #include "clang/AST/Type.h"
     15 
     16 namespace clang {
     17 namespace clangd {
     18 
     19 // Convenience lambdas for use as the 'Filter' parameter of
     20 // HeuristicResolver::resolveDependentMember().
     21 const auto NoFilter = [](const NamedDecl *D) { return true; };
     22 const auto NonStaticFilter = [](const NamedDecl *D) {
     23  return D->isCXXInstanceMember();
     24 };
     25 const auto StaticFilter = [](const NamedDecl *D) {
     26  return !D->isCXXInstanceMember();
     27 };
     28 const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
     29 const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };
     30 const auto TemplateFilter = [](const NamedDecl *D) {
     31  return isa<TemplateDecl>(D);
     32 };
     33 
     34 namespace {
     35 
     36 const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
     37                               ASTContext &Ctx) {
     38  if (Decls.size() != 1) // Names an overload set -- just bail.
     39    return nullptr;
     40  if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
     41    return Ctx.getTypeDeclType(TD).getTypePtr();
     42  }
     43  if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
     44    return VD->getType().getTypePtrOrNull();
     45  }
     46  return nullptr;
     47 }
     48 
     49 } // namespace
     50 
     51 // Helper function for HeuristicResolver::resolveDependentMember()
     52 // which takes a possibly-dependent type `T` and heuristically
     53 // resolves it to a CXXRecordDecl in which we can try name lookup.
     54 CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const {
     55  assert(T);
     56 
     57  // Unwrap type sugar such as type aliases.
     58  T = T->getCanonicalTypeInternal().getTypePtr();
     59 
     60  if (const auto *DNT = T->getAs<DependentNameType>()) {
     61    T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx);
     62    if (!T)
     63      return nullptr;
     64    T = T->getCanonicalTypeInternal().getTypePtr();
     65  }
     66 
     67  if (const auto *RT = T->getAs<RecordType>())
     68    return dyn_cast<CXXRecordDecl>(RT->getDecl());
     69 
     70  if (const auto *ICNT = T->getAs<InjectedClassNameType>())
     71    T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
     72  if (!T)
     73    return nullptr;
     74 
     75  const auto *TST = T->getAs<TemplateSpecializationType>();
     76  if (!TST)
     77    return nullptr;
     78 
     79  const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
     80      TST->getTemplateName().getAsTemplateDecl());
     81  if (!TD)
     82    return nullptr;
     83 
     84  return TD->getTemplatedDecl();
     85 }
     86 
     87 const Type *HeuristicResolver::getPointeeType(const Type *T) const {
     88  if (!T)
     89    return nullptr;
     90 
     91  if (T->isPointerType())
     92    return T->castAs<PointerType>()->getPointeeType().getTypePtrOrNull();
     93 
     94  // Try to handle smart pointer types.
     95 
     96  // Look up operator-> in the primary template. If we find one, it's probably a
     97  // smart pointer type.
     98  auto ArrowOps = resolveDependentMember(
     99      T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter);
    100  if (ArrowOps.empty())
    101    return nullptr;
    102 
    103  // Getting the return type of the found operator-> method decl isn't useful,
    104  // because we discarded template arguments to perform lookup in the primary
    105  // template scope, so the return type would just have the form U* where U is a
    106  // template parameter type.
    107  // Instead, just handle the common case where the smart pointer type has the
    108  // form of SmartPtr<X, ...>, and assume X is the pointee type.
    109  auto *TST = T->getAs<TemplateSpecializationType>();
    110  if (!TST)
    111    return nullptr;
    112  if (TST->template_arguments().size() == 0)
    113    return nullptr;
    114  const TemplateArgument &FirstArg = TST->template_arguments()[0];
    115  if (FirstArg.getKind() != TemplateArgument::Type)
    116    return nullptr;
    117  return FirstArg.getAsType().getTypePtrOrNull();
    118 }
    119 
    120 std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
    121    const CXXDependentScopeMemberExpr *ME) const {
    122  // If the expression has a qualifier, first try resolving the member
    123  // inside the qualifier's type.
    124  // Note that we cannot use a NonStaticFilter in either case, for a couple
    125  // of reasons:
    126  //   1. It's valid to access a static member using instance member syntax,
    127  //      e.g. `instance.static_member`.
    128  //   2. We can sometimes get a CXXDependentScopeMemberExpr for static
    129  //      member syntax too, e.g. if `X::static_member` occurs inside
    130  //      an instance method, it's represented as a CXXDependentScopeMemberExpr
    131  //      with `this` as the base expression as `X` as the qualifier
    132  //      (which could be valid if `X` names a base class after instantiation).
    133  if (NestedNameSpecifier *NNS = ME->getQualifier()) {
    134    if (const Type *QualifierType = resolveNestedNameSpecifierToType(NNS)) {
    135      auto Decls =
    136          resolveDependentMember(QualifierType, ME->getMember(), NoFilter);
    137      if (!Decls.empty())
    138        return Decls;
    139    }
    140  }
    141 
    142  // If that didn't yield any results, try resolving the member inside
    143  // the expression's base type.
    144  const Type *BaseType = ME->getBaseType().getTypePtrOrNull();
    145  if (ME->isArrow()) {
    146    BaseType = getPointeeType(BaseType);
    147  }
    148  if (!BaseType)
    149    return {};
    150  if (const auto *BT = BaseType->getAs<BuiltinType>()) {
    151    // If BaseType is the type of a dependent expression, it's just
    152    // represented as BuiltinType::Dependent which gives us no information. We
    153    // can get further by analyzing the dependent expression.
    154    Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
    155    if (Base && BT->getKind() == BuiltinType::Dependent) {
    156      BaseType = resolveExprToType(Base);
    157    }
    158  }
    159  return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
    160 }
    161 
    162 std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
    163    const DependentScopeDeclRefExpr *RE) const {
    164  return resolveDependentMember(RE->getQualifier()->getAsType(),
    165                                RE->getDeclName(), StaticFilter);
    166 }
    167 
    168 std::vector<const NamedDecl *>
    169 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
    170  const auto *CalleeType = resolveExprToType(CE->getCallee());
    171  if (!CalleeType)
    172    return {};
    173  if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
    174    CalleeType = FnTypePtr->getPointeeType().getTypePtr();
    175  if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
    176    if (const auto *D =
    177            resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) {
    178      return {D};
    179    }
    180  }
    181  return {};
    182 }
    183 
    184 std::vector<const NamedDecl *>
    185 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
    186  if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
    187    return {ND};
    188  }
    189 
    190  return resolveExprToDecls(CE->getCallee());
    191 }
    192 
    193 std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
    194    const UnresolvedUsingValueDecl *UUVD) const {
    195  return resolveDependentMember(UUVD->getQualifier()->getAsType(),
    196                                UUVD->getNameInfo().getName(), ValueFilter);
    197 }
    198 
    199 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
    200    const DependentNameType *DNT) const {
    201  return resolveDependentMember(
    202      resolveNestedNameSpecifierToType(DNT->getQualifier()),
    203      DNT->getIdentifier(), TypeFilter);
    204 }
    205 
    206 std::vector<const NamedDecl *>
    207 HeuristicResolver::resolveTemplateSpecializationType(
    208    const DependentTemplateSpecializationType *DTST) const {
    209  return resolveDependentMember(
    210      resolveNestedNameSpecifierToType(DTST->getQualifier()),
    211      DTST->getIdentifier(), TemplateFilter);
    212 }
    213 
    214 std::vector<const NamedDecl *>
    215 HeuristicResolver::resolveExprToDecls(const Expr *E) const {
    216  if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
    217    return resolveMemberExpr(ME);
    218  }
    219  if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
    220    return resolveDeclRefExpr(RE);
    221  }
    222  if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
    223    return {OE->decls_begin(), OE->decls_end()};
    224  }
    225  if (const auto *CE = dyn_cast<CallExpr>(E)) {
    226    return resolveTypeOfCallExpr(CE);
    227  }
    228  if (const auto *ME = dyn_cast<MemberExpr>(E))
    229    return {ME->getMemberDecl()};
    230 
    231  return {};
    232 }
    233 
    234 const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
    235  std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
    236  if (!Decls.empty())
    237    return resolveDeclsToType(Decls, Ctx);
    238 
    239  return E->getType().getTypePtr();
    240 }
    241 
    242 const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
    243    const NestedNameSpecifier *NNS) const {
    244  if (!NNS)
    245    return nullptr;
    246 
    247  // The purpose of this function is to handle the dependent (Kind ==
    248  // Identifier) case, but we need to recurse on the prefix because
    249  // that may be dependent as well, so for convenience handle
    250  // the TypeSpec cases too.
    251  switch (NNS->getKind()) {
    252  case NestedNameSpecifier::TypeSpec:
    253  case NestedNameSpecifier::TypeSpecWithTemplate:
    254    return NNS->getAsType();
    255  case NestedNameSpecifier::Identifier: {
    256    return resolveDeclsToType(
    257        resolveDependentMember(
    258            resolveNestedNameSpecifierToType(NNS->getPrefix()),
    259            NNS->getAsIdentifier(), TypeFilter),
    260        Ctx);
    261  }
    262  default:
    263    break;
    264  }
    265  return nullptr;
    266 }
    267 
    268 namespace {
    269 
    270 bool isOrdinaryMember(const NamedDecl *ND) {
    271  return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
    272                                     Decl::IDNS_Member);
    273 }
    274 
    275 bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
    276                        DeclarationName Name) {
    277  Path.Decls = RD->lookup(Name).begin();
    278  for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)
    279    if (isOrdinaryMember(*I))
    280      return true;
    281 
    282  return false;
    283 }
    284 
    285 } // namespace
    286 
    287 bool HeuristicResolver::findOrdinaryMemberInDependentClasses(
    288    const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
    289    DeclarationName Name) const {
    290  CXXRecordDecl *RD =
    291      resolveTypeToRecordDecl(Specifier->getType().getTypePtr());
    292  if (!RD)
    293    return false;
    294  return findOrdinaryMember(RD, Path, Name);
    295 }
    296 
    297 std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
    298    CXXRecordDecl *RD, DeclarationName Name,
    299    llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
    300  std::vector<const NamedDecl *> Results;
    301 
    302  // Lookup in the class.
    303  bool AnyOrdinaryMembers = false;
    304  for (const NamedDecl *ND : RD->lookup(Name)) {
    305    if (isOrdinaryMember(ND))
    306      AnyOrdinaryMembers = true;
    307    if (Filter(ND))
    308      Results.push_back(ND);
    309  }
    310  if (AnyOrdinaryMembers)
    311    return Results;
    312 
    313  // Perform lookup into our base classes.
    314  CXXBasePaths Paths;
    315  Paths.setOrigin(RD);
    316  if (!RD->lookupInBases(
    317          [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
    318            return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);
    319          },
    320          Paths, /*LookupInDependent=*/true))
    321    return Results;
    322  for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();
    323       I != E; ++I) {
    324    if (isOrdinaryMember(*I) && Filter(*I))
    325      Results.push_back(*I);
    326  }
    327  return Results;
    328 }
    329 
    330 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
    331    const Type *T, DeclarationName Name,
    332    llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
    333  if (!T)
    334    return {};
    335  if (auto *ET = T->getAs<EnumType>()) {
    336    auto Result = ET->getDecl()->lookup(Name);
    337    return {Result.begin(), Result.end()};
    338  }
    339  if (auto *RD = resolveTypeToRecordDecl(T)) {
    340    if (!RD->hasDefinition())
    341      return {};
    342    RD = RD->getDefinition();
    343    return lookupDependentName(RD, Name, Filter);
    344  }
    345  return {};
    346 }
    347 
    348 } // namespace clangd
    349 } // namespace clang