brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.6 KiB · 056e133 Raw
692 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Sema/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/TemplateBase.h"15#include "clang/AST/Type.h"16 17namespace clang {18 19namespace {20 21// Helper class for implementing HeuristicResolver.22// Unlike HeuristicResolver which is a long-lived class,23// a new instance of this class is created for every external24// call into a HeuristicResolver operation. That allows this25// class to store state that's local to such a top-level call,26// particularly "recursion protection sets" that keep track of27// nodes that have already been seen to avoid infinite recursion.28class HeuristicResolverImpl {29public:30  HeuristicResolverImpl(ASTContext &Ctx) : Ctx(Ctx) {}31 32  // These functions match the public interface of HeuristicResolver33  // (but aren't const since they may modify the recursion protection sets).34  std::vector<const NamedDecl *>35  resolveMemberExpr(const CXXDependentScopeMemberExpr *ME);36  std::vector<const NamedDecl *>37  resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE);38  std::vector<const NamedDecl *> resolveCalleeOfCallExpr(const CallExpr *CE);39  std::vector<const NamedDecl *>40  resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD);41  std::vector<const NamedDecl *>42  resolveDependentNameType(const DependentNameType *DNT);43  std::vector<const NamedDecl *>44  resolveTemplateSpecializationType(const TemplateSpecializationType *TST);45  QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS);46  QualType getPointeeType(QualType T);47  std::vector<const NamedDecl *>48  lookupDependentName(CXXRecordDecl *RD, DeclarationName Name,49                      llvm::function_ref<bool(const NamedDecl *ND)> Filter);50  TagDecl *resolveTypeToTagDecl(QualType T);51  QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);52  QualType resolveExprToType(const Expr *E);53  FunctionProtoTypeLoc getFunctionProtoTypeLoc(const Expr *Fn);54 55private:56  ASTContext &Ctx;57 58  // Recursion protection sets59  llvm::SmallPtrSet<const DependentNameType *, 4> SeenDependentNameTypes;60 61  // Given a tag-decl type and a member name, heuristically resolve the62  // name to one or more declarations.63  // The current heuristic is simply to look up the name in the primary64  // template. This is a heuristic because the template could potentially65  // have specializations that declare different members.66  // Multiple declarations could be returned if the name is overloaded67  // (e.g. an overloaded method in the primary template).68  // This heuristic will give the desired answer in many cases, e.g.69  // for a call to vector<T>::size().70  std::vector<const NamedDecl *>71  resolveDependentMember(QualType T, DeclarationName Name,72                         llvm::function_ref<bool(const NamedDecl *ND)> Filter);73 74  std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E);75  QualType resolveTypeOfCallExpr(const CallExpr *CE);76 77  bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,78                                            CXXBasePath &Path,79                                            DeclarationName Name);80};81 82// Convenience lambdas for use as the 'Filter' parameter of83// HeuristicResolver::resolveDependentMember().84const auto NoFilter = [](const NamedDecl *D) { return true; };85const auto NonStaticFilter = [](const NamedDecl *D) {86  return D->isCXXInstanceMember();87};88const auto StaticFilter = [](const NamedDecl *D) {89  return !D->isCXXInstanceMember();90};91const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };92const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };93const auto TemplateFilter = [](const NamedDecl *D) {94  return isa<TemplateDecl>(D);95};96 97QualType resolveDeclToType(const NamedDecl *D, ASTContext &Ctx) {98  if (const auto *TempD = dyn_cast<TemplateDecl>(D)) {99    D = TempD->getTemplatedDecl();100  }101  if (const auto *TD = dyn_cast<TypeDecl>(D))102    return Ctx.getCanonicalTypeDeclType(TD);103  if (const auto *VD = dyn_cast<ValueDecl>(D)) {104    return VD->getType();105  }106  return QualType();107}108 109QualType resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,110                            ASTContext &Ctx) {111  if (Decls.size() != 1) // Names an overload set -- just bail.112    return QualType();113  return resolveDeclToType(Decls[0], Ctx);114}115 116TemplateName getReferencedTemplateName(const Type *T) {117  if (const auto *TST = T->getAs<TemplateSpecializationType>()) {118    return TST->getTemplateName();119  }120  if (const auto *DTST = T->getAs<DeducedTemplateSpecializationType>()) {121    return DTST->getTemplateName();122  }123  return TemplateName();124}125 126// Helper function for HeuristicResolver::resolveDependentMember()127// which takes a possibly-dependent type `T` and heuristically128// resolves it to a CXXRecordDecl in which we can try name lookup.129TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(QualType QT) {130  const Type *T = QT.getTypePtrOrNull();131  if (!T)132    return nullptr;133 134  // Unwrap type sugar such as type aliases.135  T = T->getCanonicalTypeInternal().getTypePtr();136 137  if (const auto *DNT = T->getAs<DependentNameType>()) {138    T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx)139            .getTypePtrOrNull();140    if (!T)141      return nullptr;142    T = T->getCanonicalTypeInternal().getTypePtr();143  }144 145  if (auto *TD = T->getAsTagDecl()) {146    // Template might not be instantiated yet, fall back to primary template147    // in such cases.148    if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) {149      if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) {150        return CTSD->getSpecializedTemplate()->getTemplatedDecl();151      }152    }153    return TD;154  }155 156  TemplateName TN = getReferencedTemplateName(T);157  if (TN.isNull())158    return nullptr;159 160  const ClassTemplateDecl *TD =161      dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());162  if (!TD)163    return nullptr;164 165  return TD->getTemplatedDecl();166}167 168QualType HeuristicResolverImpl::getPointeeType(QualType T) {169  if (T.isNull())170    return QualType();171 172  if (T->isPointerType())173    return T->castAs<PointerType>()->getPointeeType();174 175  // Try to handle smart pointer types.176 177  // Look up operator-> in the primary template. If we find one, it's probably a178  // smart pointer type.179  auto ArrowOps = resolveDependentMember(180      T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter);181  if (ArrowOps.empty())182    return QualType();183 184  // Getting the return type of the found operator-> method decl isn't useful,185  // because we discarded template arguments to perform lookup in the primary186  // template scope, so the return type would just have the form U* where U is a187  // template parameter type.188  // Instead, just handle the common case where the smart pointer type has the189  // form of SmartPtr<X, ...>, and assume X is the pointee type.190  auto *TST = T->getAs<TemplateSpecializationType>();191  if (!TST)192    return QualType();193  if (TST->template_arguments().size() == 0)194    return QualType();195  const TemplateArgument &FirstArg = TST->template_arguments()[0];196  if (FirstArg.getKind() != TemplateArgument::Type)197    return QualType();198  return FirstArg.getAsType();199}200 201QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,202                                             bool UnwrapPointer) {203  bool DidUnwrapPointer = false;204  // A type, together with an optional expression whose type it represents205  // which may have additional information about the expression's type206  // not stored in the QualType itself.207  struct TypeExprPair {208    QualType Type;209    const Expr *E = nullptr;210  };211  TypeExprPair Current{Type, E};212  auto SimplifyOneStep = [UnwrapPointer, &DidUnwrapPointer,213                          this](TypeExprPair T) -> TypeExprPair {214    if (UnwrapPointer) {215      if (QualType Pointee = getPointeeType(T.Type); !Pointee.isNull()) {216        DidUnwrapPointer = true;217        return {Pointee};218      }219    }220    if (const auto *RT = T.Type->getAs<ReferenceType>()) {221      // Does not count as "unwrap pointer".222      return {RT->getPointeeType()};223    }224    if (const auto *BT = T.Type->getAs<BuiltinType>()) {225      // If BaseType is the type of a dependent expression, it's just226      // represented as BuiltinType::Dependent which gives us no information. We227      // can get further by analyzing the dependent expression.228      if (T.E && BT->getKind() == BuiltinType::Dependent) {229        return {resolveExprToType(T.E), T.E};230      }231    }232    if (const auto *AT = T.Type->getContainedAutoType()) {233      // If T contains a dependent `auto` type, deduction will not have234      // been performed on it yet. In simple cases (e.g. `auto` variable with235      // initializer), get the approximate type that would result from236      // deduction.237      // FIXME: A more accurate implementation would propagate things like the238      // `const` in `const auto`.239      if (T.E && AT->isUndeducedAutoType()) {240        if (const auto *DRE = dyn_cast<DeclRefExpr>(T.E)) {241          if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {242            if (auto *Init = VD->getInit())243              return {resolveExprToType(Init), Init};244          }245        }246      }247    }248    if (const auto *TTPT = dyn_cast_if_present<TemplateTypeParmType>(T.Type)) {249      // We can't do much useful with a template parameter (e.g. we cannot look250      // up member names inside it). However, if the template parameter has a251      // default argument, as a heuristic we can replace T with the default252      // argument type.253      if (const auto *TTPD = TTPT->getDecl()) {254        if (TTPD->hasDefaultArgument()) {255          const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();256          if (DefaultArg.getKind() == TemplateArgument::Type) {257            return {DefaultArg.getAsType()};258          }259        }260      }261    }262 263    // Similarly, heuristically replace a template template parameter with its264    // default argument if it has one.265    if (const auto *TST =266            dyn_cast_if_present<TemplateSpecializationType>(T.Type)) {267      if (const auto *TTPD = dyn_cast_if_present<TemplateTemplateParmDecl>(268              TST->getTemplateName().getAsTemplateDecl())) {269        if (TTPD->hasDefaultArgument()) {270          const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();271          if (DefaultArg.getKind() == TemplateArgument::Template) {272            if (const auto *CTD = dyn_cast_if_present<ClassTemplateDecl>(273                    DefaultArg.getAsTemplate().getAsTemplateDecl())) {274              return {Ctx.getCanonicalTagType(CTD->getTemplatedDecl())};275            }276          }277        }278      }279    }280 281    // Check if the expression refers to an explicit object parameter of282    // templated type. If so, heuristically treat it as having the type of the283    // enclosing class.284    if (!T.Type.isNull() &&285        (T.Type->isUndeducedAutoType() || T.Type->isTemplateTypeParmType())) {286      if (auto *DRE = dyn_cast_if_present<DeclRefExpr>(T.E)) {287        auto *PrDecl = dyn_cast<ParmVarDecl>(DRE->getDecl());288        if (PrDecl && PrDecl->isExplicitObjectParameter()) {289          const auto *Parent =290              dyn_cast<TagDecl>(PrDecl->getDeclContext()->getParent());291          return {Ctx.getCanonicalTagType(Parent)};292        }293      }294    }295 296    return T;297  };298  // As an additional protection against infinite loops, bound the number of299  // simplification steps.300  size_t StepCount = 0;301  const size_t MaxSteps = 64;302  while (!Current.Type.isNull() && StepCount++ < MaxSteps) {303    TypeExprPair New = SimplifyOneStep(Current);304    if (New.Type == Current.Type)305      break;306    Current = New;307  }308  if (UnwrapPointer && !DidUnwrapPointer)309    return QualType();310  return Current.Type;311}312 313std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(314    const CXXDependentScopeMemberExpr *ME) {315  // If the expression has a qualifier, try resolving the member inside the316  // qualifier's type.317  // Note that we cannot use a NonStaticFilter in either case, for a couple318  // of reasons:319  //   1. It's valid to access a static member using instance member syntax,320  //      e.g. `instance.static_member`.321  //   2. We can sometimes get a CXXDependentScopeMemberExpr for static322  //      member syntax too, e.g. if `X::static_member` occurs inside323  //      an instance method, it's represented as a CXXDependentScopeMemberExpr324  //      with `this` as the base expression as `X` as the qualifier325  //      (which could be valid if `X` names a base class after instantiation).326  if (NestedNameSpecifier NNS = ME->getQualifier()) {327    if (QualType QualifierType = resolveNestedNameSpecifierToType(NNS);328        !QualifierType.isNull()) {329      auto Decls =330          resolveDependentMember(QualifierType, ME->getMember(), NoFilter);331      if (!Decls.empty())332        return Decls;333    }334 335    // Do not proceed to try resolving the member in the expression's base type336    // without regard to the qualifier, as that could produce incorrect results.337    // For example, `void foo() { this->Base::foo(); }` shouldn't resolve to338    // foo() itself!339    return {};340  }341 342  // Try resolving the member inside the expression's base type.343  Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();344  QualType BaseType = ME->getBaseType();345  BaseType = simplifyType(BaseType, Base, ME->isArrow());346  return resolveDependentMember(BaseType, ME->getMember(), NoFilter);347}348 349std::vector<const NamedDecl *>350HeuristicResolverImpl::resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) {351  QualType Qualifier = resolveNestedNameSpecifierToType(RE->getQualifier());352  Qualifier = simplifyType(Qualifier, nullptr, /*UnwrapPointer=*/false);353  return resolveDependentMember(Qualifier, RE->getDeclName(), StaticFilter);354}355 356QualType HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) {357  // resolveExprToType(CE->getCallee()) would bail in the case of multiple358  // overloads, as it can't produce a single type for them. We can be more359  // permissive here, and allow multiple overloads with a common return type.360  std::vector<const NamedDecl *> CalleeDecls =361      resolveExprToDecls(CE->getCallee());362  QualType CommonReturnType;363  for (const NamedDecl *CalleeDecl : CalleeDecls) {364    QualType CalleeType = resolveDeclToType(CalleeDecl, Ctx);365    if (CalleeType.isNull())366      continue;367    if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())368      CalleeType = FnTypePtr->getPointeeType();369    if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {370      QualType ReturnType =371          simplifyType(FnType->getReturnType(), nullptr, false);372      if (!CommonReturnType.isNull() && CommonReturnType != ReturnType) {373        return {}; // conflicting return types374      }375      CommonReturnType = ReturnType;376    }377  }378  return CommonReturnType;379}380 381std::vector<const NamedDecl *>382HeuristicResolverImpl::resolveCalleeOfCallExpr(const CallExpr *CE) {383  if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {384    return {ND};385  }386 387  return resolveExprToDecls(CE->getCallee());388}389 390std::vector<const NamedDecl *> HeuristicResolverImpl::resolveUsingValueDecl(391    const UnresolvedUsingValueDecl *UUVD) {392  NestedNameSpecifier Qualifier = UUVD->getQualifier();393  if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type)394    return {};395  return resolveDependentMember(QualType(Qualifier.getAsType(), 0),396                                UUVD->getNameInfo().getName(), ValueFilter);397}398 399std::vector<const NamedDecl *>400HeuristicResolverImpl::resolveDependentNameType(const DependentNameType *DNT) {401  if (auto [_, inserted] = SeenDependentNameTypes.insert(DNT); !inserted)402    return {};403  return resolveDependentMember(404      resolveNestedNameSpecifierToType(DNT->getQualifier()),405      DNT->getIdentifier(), TypeFilter);406}407 408std::vector<const NamedDecl *>409HeuristicResolverImpl::resolveTemplateSpecializationType(410    const TemplateSpecializationType *TST) {411  const DependentTemplateStorage &DTN =412      *TST->getTemplateName().getAsDependentTemplateName();413  return resolveDependentMember(414      resolveNestedNameSpecifierToType(DTN.getQualifier()),415      DTN.getName().getIdentifier(), TemplateFilter);416}417 418std::vector<const NamedDecl *>419HeuristicResolverImpl::resolveExprToDecls(const Expr *E) {420  if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {421    return resolveMemberExpr(ME);422  }423  if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {424    return resolveDeclRefExpr(RE);425  }426  if (const auto *OE = dyn_cast<OverloadExpr>(E)) {427    return {OE->decls_begin(), OE->decls_end()};428  }429  if (const auto *CE = dyn_cast<CallExpr>(E)) {430    QualType T = resolveTypeOfCallExpr(CE);431    if (const auto *D = resolveTypeToTagDecl(T)) {432      return {D};433    }434    return {};435  }436  if (const auto *ME = dyn_cast<MemberExpr>(E))437    return {ME->getMemberDecl()};438  if (const auto *DRE = dyn_cast<DeclRefExpr>(E))439    return {DRE->getDecl()};440 441  return {};442}443 444QualType HeuristicResolverImpl::resolveExprToType(const Expr *E) {445  // resolveExprToDecls on a CallExpr only succeeds if the return type is446  // a TagDecl, but we may want the type of a call in other cases as well.447  // (FIXME: There are probably other cases where we can do something more448  // flexible than resoveExprToDecls + resolveDeclsToType, e.g. in the case449  // of OverloadExpr we can probably accept overloads with a common type).450  if (const auto *CE = dyn_cast<CallExpr>(E)) {451    if (QualType Resolved = resolveTypeOfCallExpr(CE); !Resolved.isNull())452      return Resolved;453 454    // Don't proceed to try resolveExprToDecls(), it would just call455    // resolveTypeOfCallExpr() again.456    return E->getType();457  }458 459  // Similarly, unwrapping a unary dereference operation does not work via460  // resolveExprToDecls.461  if (const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) {462    if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) {463      if (auto Pointee = getPointeeType(resolveExprToType(UO->getSubExpr()));464          !Pointee.isNull()) {465        return Pointee;466      }467    }468  }469 470  std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);471  if (!Decls.empty())472    return resolveDeclsToType(Decls, Ctx);473 474  return E->getType();475}476 477QualType HeuristicResolverImpl::resolveNestedNameSpecifierToType(478    NestedNameSpecifier NNS) {479  // The purpose of this function is to handle the dependent (Kind ==480  // Identifier) case, but we need to recurse on the prefix because481  // that may be dependent as well, so for convenience handle482  // the TypeSpec cases too.483  switch (NNS.getKind()) {484  case NestedNameSpecifier::Kind::Type: {485    const auto *T = NNS.getAsType();486    // FIXME: Should this handle the DependentTemplateSpecializationType as487    // well?488    if (const auto *DTN = dyn_cast<DependentNameType>(T))489      return resolveDeclsToType(490          resolveDependentMember(491              resolveNestedNameSpecifierToType(DTN->getQualifier()),492              DTN->getIdentifier(), TypeFilter),493          Ctx);494    return QualType(T, 0);495  }496  default:497    break;498  }499  return QualType();500}501 502bool isOrdinaryMember(const NamedDecl *ND) {503  return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |504                                     Decl::IDNS_Member);505}506 507bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,508                        DeclarationName Name) {509  Path.Decls = RD->lookup(Name).begin();510  for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)511    if (isOrdinaryMember(*I))512      return true;513 514  return false;515}516 517bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses(518    const CXXBaseSpecifier *Specifier, CXXBasePath &Path,519    DeclarationName Name) {520  TagDecl *TD = resolveTypeToTagDecl(Specifier->getType());521  if (const auto *RD = dyn_cast_if_present<CXXRecordDecl>(TD)) {522    return findOrdinaryMember(RD, Path, Name);523  }524  return false;525}526 527std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName(528    CXXRecordDecl *RD, DeclarationName Name,529    llvm::function_ref<bool(const NamedDecl *ND)> Filter) {530  std::vector<const NamedDecl *> Results;531 532  // Lookup in the class.533  bool AnyOrdinaryMembers = false;534  for (const NamedDecl *ND : RD->lookup(Name)) {535    if (isOrdinaryMember(ND))536      AnyOrdinaryMembers = true;537    if (Filter(ND))538      Results.push_back(ND);539  }540  if (AnyOrdinaryMembers)541    return Results;542 543  // Perform lookup into our base classes.544  CXXBasePaths Paths;545  Paths.setOrigin(RD);546  if (!RD->lookupInBases(547          [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {548            return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);549          },550          Paths, /*LookupInDependent=*/true))551    return Results;552  for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();553       I != E; ++I) {554    if (isOrdinaryMember(*I) && Filter(*I))555      Results.push_back(*I);556  }557  return Results;558}559 560std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(561    QualType QT, DeclarationName Name,562    llvm::function_ref<bool(const NamedDecl *ND)> Filter) {563  TagDecl *TD = resolveTypeToTagDecl(QT);564  if (!TD)565    return {};566  if (auto *ED = dyn_cast<EnumDecl>(TD)) {567    auto Result = ED->lookup(Name);568    return {Result.begin(), Result.end()};569  }570  if (auto *RD = dyn_cast<CXXRecordDecl>(TD)) {571    if (!RD->hasDefinition())572      return {};573    RD = RD->getDefinition();574    return lookupDependentName(RD, Name, [&](const NamedDecl *ND) {575      if (!Filter(ND))576        return false;577      if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) {578        return !MD->isInstance() ||579               MD->getMethodQualifiers().compatiblyIncludes(QT.getQualifiers(),580                                                            Ctx);581      }582      return true;583    });584  }585  return {};586}587 588FunctionProtoTypeLoc589HeuristicResolverImpl::getFunctionProtoTypeLoc(const Expr *Fn) {590  TypeLoc Target;591  const Expr *NakedFn = Fn->IgnoreParenCasts();592  if (const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {593    Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();594  } else if (const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {595    const auto *D = DR->getDecl();596    if (const auto *const VD = dyn_cast<VarDecl>(D)) {597      Target = VD->getTypeSourceInfo()->getTypeLoc();598    }599  } else if (const auto *ME = dyn_cast<MemberExpr>(NakedFn)) {600    const auto *MD = ME->getMemberDecl();601    if (const auto *FD = dyn_cast<FieldDecl>(MD)) {602      Target = FD->getTypeSourceInfo()->getTypeLoc();603    }604  }605 606  if (!Target)607    return {};608 609  // Unwrap types that may be wrapping the function type610  while (true) {611    if (auto P = Target.getAs<PointerTypeLoc>()) {612      Target = P.getPointeeLoc();613      continue;614    }615    if (auto A = Target.getAs<AttributedTypeLoc>()) {616      Target = A.getModifiedLoc();617      continue;618    }619    if (auto P = Target.getAs<ParenTypeLoc>()) {620      Target = P.getInnerLoc();621      continue;622    }623    break;624  }625 626  if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {627    // In some edge cases the AST can contain a "trivial" FunctionProtoTypeLoc628    // which has null parameters. Avoid these as they don't contain useful629    // information.630    if (!llvm::is_contained(F.getParams(), nullptr))631      return F;632  }633 634  return {};635}636 637} // namespace638 639std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(640    const CXXDependentScopeMemberExpr *ME) const {641  return HeuristicResolverImpl(Ctx).resolveMemberExpr(ME);642}643std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(644    const DependentScopeDeclRefExpr *RE) const {645  return HeuristicResolverImpl(Ctx).resolveDeclRefExpr(RE);646}647std::vector<const NamedDecl *>648HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {649  return HeuristicResolverImpl(Ctx).resolveCalleeOfCallExpr(CE);650}651std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(652    const UnresolvedUsingValueDecl *UUVD) const {653  return HeuristicResolverImpl(Ctx).resolveUsingValueDecl(UUVD);654}655std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(656    const DependentNameType *DNT) const {657  return HeuristicResolverImpl(Ctx).resolveDependentNameType(DNT);658}659std::vector<const NamedDecl *>660HeuristicResolver::resolveTemplateSpecializationType(661    const TemplateSpecializationType *TST) const {662  return HeuristicResolverImpl(Ctx).resolveTemplateSpecializationType(TST);663}664QualType HeuristicResolver::resolveNestedNameSpecifierToType(665    NestedNameSpecifier NNS) const {666  return HeuristicResolverImpl(Ctx).resolveNestedNameSpecifierToType(NNS);667}668std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(669    CXXRecordDecl *RD, DeclarationName Name,670    llvm::function_ref<bool(const NamedDecl *ND)> Filter) {671  return HeuristicResolverImpl(Ctx).lookupDependentName(RD, Name, Filter);672}673const QualType HeuristicResolver::getPointeeType(QualType T) const {674  return HeuristicResolverImpl(Ctx).getPointeeType(T);675}676TagDecl *HeuristicResolver::resolveTypeToTagDecl(QualType T) const {677  return HeuristicResolverImpl(Ctx).resolveTypeToTagDecl(T);678}679QualType HeuristicResolver::simplifyType(QualType Type, const Expr *E,680                                         bool UnwrapPointer) {681  return HeuristicResolverImpl(Ctx).simplifyType(Type, E, UnwrapPointer);682}683QualType HeuristicResolver::resolveExprToType(const Expr *E) const {684  return HeuristicResolverImpl(Ctx).resolveExprToType(E);685}686FunctionProtoTypeLoc687HeuristicResolver::getFunctionProtoTypeLoc(const Expr *Fn) const {688  return HeuristicResolverImpl(Ctx).getFunctionProtoTypeLoc(Fn);689}690 691} // namespace clang692