brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.7 KiB · c592e74 Raw
1023 lines · cpp
1//===-- HeuristicResolverTests.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#include "clang/Sema/HeuristicResolver.h"9#include "clang/ASTMatchers/ASTMatchFinder.h"10#include "clang/ASTMatchers/ASTMatchers.h"11#include "clang/Basic/Diagnostic.h"12#include "clang/Tooling/Tooling.h"13#include "gmock/gmock-matchers.h"14#include "gtest/gtest.h"15 16using namespace clang::ast_matchers;17using testing::ElementsAre;18 19namespace clang {20namespace {21 22// Helper for matching a sequence of elements with a variadic list of matchers.23// Usage: `ElementsAre(matchAdapter(Vs, MatchFunction)...)`, where `Vs...` is24//        a variadic list of matchers.25// For each `V` in `Vs`, this will match the corresponding element `E` if26// `MatchFunction(V, E)` is true.27MATCHER_P2(matchAdapter, MatcherForElement, MatchFunction, "matchAdapter") {28  return MatchFunction(MatcherForElement, arg);29}30 31template <typename InputNode>32using ResolveFnT = std::function<std::vector<const NamedDecl *>(33    const HeuristicResolver *, InputNode)>;34 35// Test heuristic resolution on `Code` using the resolution procedure36// `ResolveFn`, which takes a `HeuristicResolver` and an input AST node of type37// `InputNode` and returns a `std::vector<const NamedDecl *>`.38// `InputMatcher` should be an AST matcher that matches a single node to pass as39// input to `ResolveFn`, bound to the ID "input". `OutputMatchers` should be AST40// matchers that each match a single node, bound to the ID "output".41template <typename InputNode, typename ParamT, typename InputMatcher,42          typename... OutputMatchers>43void expectResolution(llvm::StringRef Code, ResolveFnT<ParamT> ResolveFn,44                      const InputMatcher &IM, const OutputMatchers &...OMS) {45  auto TU = tooling::buildASTFromCodeWithArgs(46      Code, {"-std=c++23"}, "input.cc", "clang-tool",47      std::make_shared<PCHContainerOperations>(),48      tooling::getClangStripDependencyFileAdjuster(),49      tooling::FileContentMappings(), nullptr, llvm::vfs::getRealFileSystem(),50      CaptureDiagsKind::All);51 52  for (const auto &D : TU->storedDiagnostics()) {53    EXPECT_TRUE(D.getLevel() < DiagnosticsEngine::Error)54        << "Unexpected error diagnostic while building AST for test code: "55        << D.getMessage();56  }57 58  auto &Ctx = TU->getASTContext();59  auto InputMatches = match(IM, Ctx);60  ASSERT_EQ(1u, InputMatches.size());61  const auto *Input = InputMatches[0].template getNodeAs<InputNode>("input");62  ASSERT_TRUE(Input);63 64  auto OutputNodeMatches = [&](auto &OutputMatcher, auto &Actual) {65    auto OutputMatches = match(OutputMatcher, Ctx);66    if (OutputMatches.size() != 1u)67      return false;68    const auto *ExpectedOutput =69        OutputMatches[0].template getNodeAs<NamedDecl>("output");70    if (!ExpectedOutput)71      return false;72    return ExpectedOutput == Actual;73  };74 75  HeuristicResolver H(Ctx);76  std::vector<const NamedDecl *> Results;77  if constexpr (std::is_pointer_v<ParamT>)78    Results = ResolveFn(&H, Input);79  else80    Results = ResolveFn(&H, *Input);81  EXPECT_THAT(Results, ElementsAre(matchAdapter(OMS, OutputNodeMatches)...));82}83 84// Wrapper for the above that accepts a HeuristicResolver member function85// pointer directly.86template <typename InputNode, typename InputMatcher, typename... OutputMatchers>87void expectResolution(llvm::StringRef Code,88                      std::vector<const NamedDecl *> (89                          HeuristicResolver::*ResolveFn)(const InputNode *)90                          const,91                      const InputMatcher &IM, const OutputMatchers &...OMS) {92  expectResolution<InputNode>(93      Code, ResolveFnT<const InputNode *>(std::mem_fn(ResolveFn)), IM, OMS...);94}95 96TEST(HeuristicResolver, MemberExpr) {97  std::string Code = R"cpp(98    template <typename T>99    struct S {100      void bar() {}101    };102 103    template <typename T>104    void foo(S<T> arg) {105      arg.bar();106    }107  )cpp";108  // Test resolution of "bar" in "arg.bar()".109  expectResolution(110      Code, &HeuristicResolver::resolveMemberExpr,111      cxxDependentScopeMemberExpr(hasMemberName("bar")).bind("input"),112      cxxMethodDecl(hasName("bar")).bind("output"));113}114 115TEST(HeuristicResolver, MemberExpr_Overloads) {116  std::string Code = R"cpp(117    template <typename T>118    struct S {119      void bar(int);120      void bar(float);121    };122 123    template <typename T, typename U>124    void foo(S<T> arg, U u) {125      arg.bar(u);126    }127  )cpp";128  // Test resolution of "bar" in "arg.bar(u)". Both overloads should be found.129  expectResolution(130      Code, &HeuristicResolver::resolveMemberExpr,131      cxxDependentScopeMemberExpr(hasMemberName("bar")).bind("input"),132      cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("int"))))133          .bind("output"),134      cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("float"))))135          .bind("output"));136}137 138TEST(HeuristicResolver, MemberExpr_SmartPointer) {139  std::string Code = R"cpp(140    template <typename> struct S { void foo() {} };141    template <typename T> struct unique_ptr {142      T* operator->();143    };144    template <typename T>145    void test(unique_ptr<S<T>>& v) {146      v->foo();147    }148  )cpp";149  // Test resolution of "foo" in "v->foo()".150  expectResolution(151      Code, &HeuristicResolver::resolveMemberExpr,152      cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),153      cxxMethodDecl(hasName("foo")).bind("output"));154}155 156TEST(HeuristicResolver, MemberExpr_SmartPointer_Qualified) {157  std::string Code = R"cpp(158    template <typename> struct Waldo {159      void find();160      void find() const;161    };162    template <typename T> struct unique_ptr {163      T* operator->();164    };165    template <typename T>166    void test(unique_ptr<const Waldo<T>>& w) {167      w->find();168    }169  )cpp";170  expectResolution(171      Code, &HeuristicResolver::resolveMemberExpr,172      cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),173      cxxMethodDecl(hasName("find"), isConst()).bind("output"));174}175 176TEST(HeuristicResolver, MemberExpr_Static_Qualified) {177  std::string Code = R"cpp(178    template <typename T>179    struct Waldo {180      static void find();181    };182    template <typename T>183    void foo(const Waldo<T>& t) {184      t.find();185    }186  )cpp";187  // Test resolution of "find" in "t.find()".188  // The object being `const` should have no bearing on a call to a static189  // method.190  expectResolution(191      Code, &HeuristicResolver::resolveMemberExpr,192      cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),193      cxxMethodDecl(hasName("find")).bind("output"));194}195 196TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction1) {197  std::string Code = R"cpp(198    template <typename T>199    struct A {200      int waldo;201    };202    template <typename T>203    void foo(A<T> a) {204      auto copy = a;205      copy.waldo;206    }207  )cpp";208  expectResolution(209      Code, &HeuristicResolver::resolveMemberExpr,210      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),211      fieldDecl(hasName("waldo")).bind("output"));212}213 214TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction2) {215  std::string Code = R"cpp(216    struct B {217      int waldo;218    };219    template <typename T>220    struct A {221      B b;222    };223    template <typename T>224    void foo(A<T> a) {225      auto b = a.b;226      b.waldo;227    }228  )cpp";229  expectResolution(230      Code, &HeuristicResolver::resolveMemberExpr,231      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),232      fieldDecl(hasName("waldo")).bind("output"));233}234 235TEST(HeuristicResolver, MemberExpr_Chained) {236  std::string Code = R"cpp(237    struct A { void foo() {} };238    template <typename T>239    struct B {240      A func(int);241      void bar() {242        func(1).foo();243      }244    };245  )cpp";246  // Test resolution of "foo" in "func(1).foo()".247  expectResolution(248      Code, &HeuristicResolver::resolveMemberExpr,249      cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),250      cxxMethodDecl(hasName("foo")).bind("output"));251}252 253TEST(HeuristicResolver, MemberExpr_Chained_ReferenceType) {254  std::string Code = R"cpp(255    struct B {256      int waldo;257    };258    template <typename T>259    struct A {260      B &foo();261    };262    template <typename T>263    void bar(A<T> a) {264      a.foo().waldo;265    }266  )cpp";267  // Test resolution of "waldo" in "a.foo().waldo"268  expectResolution(269      Code, &HeuristicResolver::resolveMemberExpr,270      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),271      fieldDecl(hasName("waldo")).bind("output"));272}273 274TEST(HeuristicResolver, MemberExpr_Chained_PointerArrow) {275  std::string Code = R"cpp(276    struct B {277      int waldo;278    };279    template <typename T>280    B* foo(T);281    template <class T>282    void bar(T t) {283      foo(t)->waldo;284    }285  )cpp";286  // Test resolution of "waldo" in "foo(t)->waldo"287  expectResolution(288      Code, &HeuristicResolver::resolveMemberExpr,289      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),290      fieldDecl(hasName("waldo")).bind("output"));291}292 293TEST(HeuristicResolver, MemberExpr_Chained_PointerDeref) {294  std::string Code = R"cpp(295    struct B {296      int waldo;297    };298    template <typename T>299    B* foo(T);300    template <class T>301    void bar(T t) {302      (*foo(t)).waldo;303    }304  )cpp";305  // Test resolution of "waldo" in "foo(t)->waldo"306  expectResolution(307      Code, &HeuristicResolver::resolveMemberExpr,308      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),309      fieldDecl(hasName("waldo")).bind("output"));310}311 312TEST(HeuristicResolver, MemberExpr_Chained_Overload) {313  std::string Code = R"cpp(314    struct B {315      int waldo;316    };317    B overloaded(int);318    B overloaded(double);319    template <typename T>320    void foo(T t) {321      overloaded(t).waldo;322    }323  )cpp";324  // Test resolution of "waldo" in "overloaded(t).waldo"325  expectResolution(326      Code, &HeuristicResolver::resolveMemberExpr,327      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),328      fieldDecl(hasName("waldo")).bind("output"));329}330 331TEST(HeuristicResolver, MemberExpr_CallToFunctionTemplate) {332  std::string Code = R"cpp(333    struct B {334      int waldo;335    };336    template <typename T>337    B bar(T);338    template <typename T>339    void foo(T t) {340      bar(t).waldo;341    }342  )cpp";343  // Test resolution of "waldo" in "bar(t).waldo"344  expectResolution(345      Code, &HeuristicResolver::resolveMemberExpr,346      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),347      fieldDecl(hasName("waldo")).bind("output"));348}349 350TEST(HeuristicResolver, MemberExpr_ReferenceType) {351  std::string Code = R"cpp(352    struct B {353      int waldo;354    };355    template <typename T>356    struct A {357      B &b;358    };359    template <typename T>360    void foo(A<T> &a) {361      a.b.waldo;362    }363  )cpp";364  // Test resolution of "waldo" in "a.b.waldo".365  expectResolution(366      Code, &HeuristicResolver::resolveMemberExpr,367      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),368      fieldDecl(hasName("waldo")).bind("output"));369}370 371TEST(HeuristicResolver, MemberExpr_PointerType) {372  std::string Code = R"cpp(373    struct B {374      int waldo;375    };376    template <typename T>377    struct A {378      B *b;379    };380    template <typename T>381    void foo(A<T> &a) {382      a.b->waldo;383    }384  )cpp";385  // Test resolution of "waldo" in "a.b->waldo".386  expectResolution(387      Code, &HeuristicResolver::resolveMemberExpr,388      cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),389      fieldDecl(hasName("waldo")).bind("output"));390}391 392TEST(HeuristicResolver, MemberExpr_TemplateArgs) {393  std::string Code = R"cpp(394    struct Foo {395      static Foo k(int);396      template <typename T> T convert();397    };398    template <typename T>399    void test() {400      Foo::k(T()).template convert<T>();401    }402  )cpp";403  // Test resolution of "convert" in "Foo::k(T()).template convert<T>()".404  expectResolution(405      Code, &HeuristicResolver::resolveMemberExpr,406      cxxDependentScopeMemberExpr(hasMemberName("convert")).bind("input"),407      functionTemplateDecl(hasName("convert")).bind("output"));408}409 410TEST(HeuristicResolver, MemberExpr_TypeAlias) {411  std::string Code = R"cpp(412    template <typename T>413    struct Waldo {414      void find();415    };416    template <typename T>417    using Wally = Waldo<T>;418    template <typename T>419    void foo(Wally<T> w) {420      w.find();421    }422  )cpp";423  // Test resolution of "find" in "w.find()".424  expectResolution(425      Code, &HeuristicResolver::resolveMemberExpr,426      cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),427      cxxMethodDecl(hasName("find")).bind("output"));428}429 430TEST(HeuristicResolver, MemberExpr_BaseClass_TypeAlias) {431  std::string Code = R"cpp(432    template <typename T>433    struct Waldo {434      void find();435    };436    template <typename T>437    using Wally = Waldo<T>;438    template <typename T>439    struct S : Wally<T> {440      void foo() {441        this->find();442      }443    };444  )cpp";445  // Test resolution of "find" in "this->find()".446  expectResolution(447      Code, &HeuristicResolver::resolveMemberExpr,448      cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),449      cxxMethodDecl(hasName("find")).bind("output"));450}451 452TEST(HeuristicResolver, MemberExpr_Metafunction) {453  std::string Code = R"cpp(454    template <typename T>455    struct Waldo {456      void find();457    };458    template <typename T>459    struct MetaWaldo {460      using Type = Waldo<T>;461    };462    template <typename T>463    void foo(typename MetaWaldo<T>::Type w) {464      w.find();465    }466  )cpp";467  // Test resolution of "find" in "w.find()".468  expectResolution(469      Code, &HeuristicResolver::resolveMemberExpr,470      cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),471      cxxMethodDecl(hasName("find")).bind("output"));472}473 474TEST(HeuristicResolver, MemberExpr_Metafunction_Enumerator) {475  std::string Code = R"cpp(476    enum class State { Hidden };477    template <typename T>478    struct Meta {479      using Type = State;480    };481    template <typename T>482    void foo(typename Meta<T>::Type t) {483      t.Hidden;484    }485  )cpp";486  // Test resolution of "Hidden" in "t.Hidden".487  expectResolution(488      Code, &HeuristicResolver::resolveMemberExpr,489      cxxDependentScopeMemberExpr(hasMemberName("Hidden")).bind("input"),490      enumConstantDecl(hasName("Hidden")).bind("output"));491}492 493TEST(HeuristicResolver, MemberExpr_DeducedNonTypeTemplateParameter) {494  std::string Code = R"cpp(495    template <int N>496    struct Waldo {497      const int found = N;498    };499    template <Waldo W>500    int foo() {501      return W.found;502    }503  )cpp";504  // Test resolution of "found" in "W.found".505  expectResolution(506      Code, &HeuristicResolver::resolveMemberExpr,507      cxxDependentScopeMemberExpr(hasMemberName("found")).bind("input"),508      fieldDecl(hasName("found")).bind("output"));509}510 511TEST(HeuristicResolver, MemberExpr_HangIssue126536) {512  std::string Code = R"cpp(513    template <class T>514    void foo() {515      T bar;516      auto baz = (bar, bar);517      baz.foo();518    }519  )cpp";520  // Test resolution of "foo" in "baz.foo()".521  // Here, we are testing that we do not get into an infinite loop.522  expectResolution(523      Code, &HeuristicResolver::resolveMemberExpr,524      cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"));525}526 527TEST(HeuristicResolver, MemberExpr_HangOnLongCallChain) {528  const size_t CallChainLength = 50;529  std::string Code = R"cpp(530    template <typename T>531    void foo(T t) {532      t533    )cpp";534  for (size_t I = 0; I < CallChainLength; ++I)535    Code.append(".method()\n");536  Code.append(R"cpp(537      .lastMethod();538    }539  )cpp");540  // Test that resolution of a name whose base is a long call chain541  // does not hang. Note that the hang for which this is a regression542  // test is finite (exponential runtime in the length of the chain),543  // so a "failure" here manifests as abnormally long runtime.544  expectResolution(545      Code, &HeuristicResolver::resolveMemberExpr,546      cxxDependentScopeMemberExpr(hasMemberName("lastMethod")).bind("input"));547}548 549TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument) {550  std::string Code = R"cpp(551    struct Default {552      void foo();553    };554    template <typename T = Default>555    void bar(T t) {556      t.foo();557    }558  )cpp";559  // Test resolution of "foo" in "t.foo()".560  expectResolution(561      Code, &HeuristicResolver::resolveMemberExpr,562      cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),563      cxxMethodDecl(hasName("foo")).bind("output"));564}565 566TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument_Recursive) {567  std::string Code = R"cpp(568    struct Default {569      void foo();570    };571    template <typename D = Default, typename T = D>572    void bar(T t) {573      t.foo();574    }575  )cpp";576  // Test resolution of "foo" in "t.foo()".577  expectResolution(578      Code, &HeuristicResolver::resolveMemberExpr,579      cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),580      cxxMethodDecl(hasName("foo")).bind("output"));581}582 583TEST(HeuristicResolver, MemberExpr_DefaultTemplateTemplateArgument) {584  std::string Code = R"cpp(585    template <typename T>586    struct vector {587      void push_back(T);588    };589    template <typename Element, template <typename> class Container = vector>590    void foo(Container<Element> c, Element e) {591      c.push_back(e);592    }593  )cpp";594  // Test resolution of "push_back" in "c.push_back(e)".595  expectResolution(596      Code, &HeuristicResolver::resolveMemberExpr,597      cxxDependentScopeMemberExpr(hasMemberName("push_back")).bind("input"),598      cxxMethodDecl(hasName("push_back")).bind("output"));599}600 601TEST(HeuristicResolver, MemberExpr_ExplicitObjectParameter) {602  std::string Code = R"cpp(603    struct Foo {604      int m_int;605 606      int bar(this auto&& self) {607        return self.m_int;608      }609    };610  )cpp";611  // Test resolution of "m_int" in "self.m_int()".612  expectResolution(613      Code, &HeuristicResolver::resolveMemberExpr,614      cxxDependentScopeMemberExpr(hasMemberName("m_int")).bind("input"),615      fieldDecl(hasName("m_int")).bind("output"));616}617 618TEST(HeuristicResolver, DeclRefExpr_StaticMethod) {619  std::string Code = R"cpp(620    template <typename T>621    struct S {622      static void bar() {}623    };624 625    template <typename T>626    void foo() {627      S<T>::bar();628    }629  )cpp";630  // Test resolution of "bar" in "S<T>::bar()".631  expectResolution(632      Code, &HeuristicResolver::resolveDeclRefExpr,633      dependentScopeDeclRefExpr(hasDependentName("bar")).bind("input"),634      cxxMethodDecl(hasName("bar")).bind("output"));635}636 637TEST(HeuristicResolver, DeclRefExpr_DefaultTemplateArgument) {638  std::string Code = R"cpp(639    struct Default {640      static void foo();641    };642    template <typename T = Default>643    void bar() {644      T::foo();645    }646  )cpp";647  // Test resolution of "foo" in "T::foo()".648  expectResolution(649      Code, &HeuristicResolver::resolveDeclRefExpr,650      dependentScopeDeclRefExpr(hasDependentName("foo")).bind("input"),651      cxxMethodDecl(hasName("foo")).bind("output"));652}653 654TEST(HeuristicResolver, DeclRefExpr_StaticOverloads) {655  std::string Code = R"cpp(656    template <typename T>657    struct S {658      static void bar(int);659      static void bar(float);660    };661 662    template <typename T, typename U>663    void foo(U u) {664      S<T>::bar(u);665    }666  )cpp";667  // Test resolution of "bar" in "S<T>::bar(u)". Both overloads should be found.668  expectResolution(669      Code, &HeuristicResolver::resolveDeclRefExpr,670      dependentScopeDeclRefExpr(hasDependentName("bar")).bind("input"),671      cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("int"))))672          .bind("output"),673      cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("float"))))674          .bind("output"));675}676 677TEST(HeuristicResolver, DeclRefExpr_Enumerator) {678  std::string Code = R"cpp(679    template <typename T>680    struct Foo {681      enum class E { A, B };682      E e = E::A;683    };684  )cpp";685  // Test resolution of "A" in "E::A".686  expectResolution(687      Code, &HeuristicResolver::resolveDeclRefExpr,688      dependentScopeDeclRefExpr(hasDependentName("A")).bind("input"),689      enumConstantDecl(hasName("A")).bind("output"));690}691 692TEST(HeuristicResolver, DeclRefExpr_RespectScope) {693  std::string Code = R"cpp(694    template <typename Info>695    struct PointerIntPair {696      void *getPointer() const { return Info::getPointer(); }697    };698  )cpp";699  // Test resolution of "getPointer" in "Info::getPointer()".700  // Here, we are testing that we do not incorrectly get the enclosing701  // getPointer() function as a result.702  expectResolution(703      Code, &HeuristicResolver::resolveDeclRefExpr,704      dependentScopeDeclRefExpr(hasDependentName("getPointer")).bind("input"));705}706 707TEST(HeuristicResolver, DeclRefExpr_Nested) {708  std::string Code = R"cpp(709    struct S {710      static int Waldo;711    };712    template <typename T>713    struct Meta {714      using Type = S;715    };716    template <typename T>717    void foo() {718      Meta<T>::Type::Waldo;719    }720  )cpp";721  // Test resolution of "Waldo" in "Meta<T>::Type::Waldo".722  expectResolution(723      Code, &HeuristicResolver::resolveDeclRefExpr,724      dependentScopeDeclRefExpr(hasDependentName("Waldo")).bind("input"),725      varDecl(hasName("Waldo")).bind("output"));726}727 728TEST(HeuristicResolver, DependentNameType) {729  std::string Code = R"cpp(730    template <typename>731    struct A {732      struct B {};733    };734    template <typename T>735    void foo(typename A<T>::B);736  )cpp";737  // Tests resolution of "B" in "A<T>::B".738  expectResolution(739      Code, &HeuristicResolver::resolveDependentNameType,740      functionDecl(hasParameter(0, hasType(dependentNameType().bind("input")))),741      classTemplateDecl(742          has(cxxRecordDecl(has(cxxRecordDecl(hasName("B")).bind("output"))))));743}744 745TEST(HeuristicResolver, DependentNameType_Nested) {746  std::string Code = R"cpp(747    template <typename>748    struct A {749      struct B {750        struct C {};751      };752    };753    template <typename T>754    void foo(typename A<T>::B::C);755  )cpp";756  // Tests resolution of "C" in "A<T>::B::C".757  expectResolution(758      Code, &HeuristicResolver::resolveDependentNameType,759      functionDecl(hasParameter(0, hasType(dependentNameType().bind("input")))),760      classTemplateDecl(has(cxxRecordDecl(has(761          cxxRecordDecl(has(cxxRecordDecl(hasName("C")).bind("output"))))))));762}763 764TEST(HeuristicResolver, DependentNameType_Recursion) {765  std::string Code = R"cpp(766    template <int N>767    struct Waldo {768      using Type = typename Waldo<N - 1>::Type::Next;769    };770  )cpp";771  // Test resolution of "Next" in "typename Waldo<N - 1>::Type::Next".772  // Here, we are testing that we do not get into an infinite recursion.773  expectResolution(Code, &HeuristicResolver::resolveDependentNameType,774                   typeAliasDecl(hasType(dependentNameType().bind("input"))));775}776 777TEST(HeuristicResolver, DependentNameType_MutualRecursion) {778  std::string Code = R"cpp(779    template <int N>780    struct Odd;781    template <int N>782    struct Even {783      using Type = typename Odd<N - 1>::Type::Next;784    };785    template <int N>786    struct Odd {787      using Type = typename Even<N - 1>::Type::Next;788    };789  )cpp";790  // Test resolution of "Next" in "typename Even<N - 1>::Type::Next".791  // Similar to the above but we have two mutually recursive templates.792  expectResolution(793      Code, &HeuristicResolver::resolveDependentNameType,794      classTemplateDecl(hasName("Odd"),795                        has(cxxRecordDecl(has(typeAliasDecl(796                            hasType(dependentNameType().bind("input"))))))));797}798 799TEST(HeuristicResolver, NestedNameSpecifier) {800  // Test resolution of "B" in "A<T>::B::C".801  // Unlike the "C", the "B" does not get its own DependentNameTypeLoc node,802  // so the resolution uses the NestedNameSpecifier as input.803  std::string Code = R"cpp(804    template <typename>805    struct A {806      struct B {807        struct C {};808      };809    };810    template <typename T>811    void foo(typename A<T>::B::C);812  )cpp";813  // Adapt the call to resolveNestedNameSpecifierToType() to the interface814  // expected by expectResolution() (returning a vector of decls).815  ResolveFnT<NestedNameSpecifier> ResolveFn =816      [](const HeuristicResolver *H,817         NestedNameSpecifier NNS) -> std::vector<const NamedDecl *> {818    return {H->resolveNestedNameSpecifierToType(NNS)->getAsCXXRecordDecl()};819  };820  expectResolution<NestedNameSpecifier>(821      Code, ResolveFn,822      nestedNameSpecifier(hasPrefix(specifiesType(823                              hasDeclaration(classTemplateDecl(hasName("A"))))))824          .bind("input"),825      classTemplateDecl(826          has(cxxRecordDecl(has(cxxRecordDecl(hasName("B")).bind("output"))))));827}828 829TEST(HeuristicResolver, TemplateSpecializationType) {830  std::string Code = R"cpp(831    template <typename>832    struct A {833      template <typename>834      struct B {};835    };836    template <typename T>837    void foo(typename A<T>::template B<int>);838  )cpp";839  // Test resolution of "B" in "A<T>::template B<int>".840  expectResolution(Code, &HeuristicResolver::resolveTemplateSpecializationType,841                   functionDecl(hasParameter(0, hasType(type().bind("input")))),842                   classTemplateDecl(has(cxxRecordDecl(843                       has(classTemplateDecl(hasName("B")).bind("output"))))));844}845 846TEST(HeuristicResolver, DependentCall_NonMember) {847  std::string Code = R"cpp(848    template <typename T>849    void nonmember(T);850    template <typename T>851    void bar(T t) {852      nonmember(t);853    }854  )cpp";855  // Test resolution of "nonmember" in "nonmember(t)".856  expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr,857                   callExpr(callee(unresolvedLookupExpr(hasAnyDeclaration(858                                functionTemplateDecl(hasName("nonmember"))))))859                       .bind("input"),860                   functionTemplateDecl(hasName("nonmember")).bind("output"));861}862 863TEST(HeuristicResolver, DependentCall_Member) {864  std::string Code = R"cpp(865    template <typename T>866    struct A {867      void member(T);868    };869    template <typename T>870    void bar(A<T> a, T t) {871      a.member(t);872    }873  )cpp";874  // Test resolution of "member" in "a.member(t)".875  expectResolution(876      Code, &HeuristicResolver::resolveCalleeOfCallExpr,877      callExpr(callee(cxxDependentScopeMemberExpr(hasMemberName("member"))))878          .bind("input"),879      cxxMethodDecl(hasName("member")).bind("output"));880}881 882TEST(HeuristicResolver, DependentCall_StaticMember) {883  std::string Code = R"cpp(884    template <typename T>885    struct A {886      static void static_member(T);887    };888    template <typename T>889    void bar(T t) {890      A<T>::static_member(t);891    }892  )cpp";893  // Test resolution of "static_member" in "A<T>::static_member(t)".894  expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr,895                   callExpr(callee(dependentScopeDeclRefExpr(896                                hasDependentName("static_member"))))897                       .bind("input"),898                   cxxMethodDecl(hasName("static_member")).bind("output"));899}900 901TEST(HeuristicResolver, DependentCall_Overload) {902  std::string Code = R"cpp(903    void overload(int);904    void overload(double);905    template <typename T>906    void bar(T t) {907      overload(t);908    }909  )cpp";910  // Test resolution of "overload" in "overload(t)". Both overload should be911  // found.912  expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr,913                   callExpr(callee(unresolvedLookupExpr(hasAnyDeclaration(914                                functionDecl(hasName("overload"))))))915                       .bind("input"),916                   functionDecl(hasName("overload"),917                                hasParameter(0, hasType(asString("double"))))918                       .bind("output"),919                   functionDecl(hasName("overload"),920                                hasParameter(0, hasType(asString("int"))))921                       .bind("output"));922}923 924TEST(HeuristicResolver, UsingValueDecl) {925  std::string Code = R"cpp(926    template <typename T>927    struct Base {928      void waldo();929    };930    template <typename T>931    struct Derived : Base<T> {932      using Base<T>::waldo;933    };934  )cpp";935  // Test resolution of "waldo" in "Base<T>::waldo".936  expectResolution(Code, &HeuristicResolver::resolveUsingValueDecl,937                   unresolvedUsingValueDecl(hasName("waldo")).bind("input"),938                   cxxMethodDecl(hasName("waldo")).bind("output"));939}940 941// `arg` is a ParamVarDecl*, `Expected` is a string942MATCHER_P(ParamNameMatcher, Expected, "paramNameMatcher") {943  EXPECT_TRUE(arg);944  if (IdentifierInfo *Ident = arg->getDeclName().getAsIdentifierInfo()) {945    return Ident->getName() == Expected;946  }947  return false;948}949 950// Helper function for testing HeuristicResolver::getProtoTypeLoc.951// Takes a matcher that selects a callee expression bound to the ID "input",952// calls getProtoTypeLoc() on it, and checks that the call found a953// FunctionProtoTypeLoc encoding the given parameter names.954template <typename InputMatcher, typename... ParameterNames>955void expectParameterNames(ASTContext &Ctx, const InputMatcher &IM,956                          ParameterNames... ExpectedParameterNames) {957  auto InputMatches = match(IM, Ctx);958  ASSERT_EQ(1u, InputMatches.size());959  const auto *Input = InputMatches[0].template getNodeAs<Expr>("input");960  ASSERT_TRUE(Input);961 962  HeuristicResolver H(Ctx);963  auto Loc = H.getFunctionProtoTypeLoc(Input);964  ASSERT_TRUE(Loc);965  EXPECT_THAT(Loc.getParams(),966              ElementsAre(ParamNameMatcher(ExpectedParameterNames)...));967}968 969TEST(HeuristicResolver, ProtoTypeLoc) {970  std::string Code = R"cpp(971    void (*f1)(int param1);972    void (__stdcall *f2)(int param2);973    using f3_t = void(*)(int param3);974    f3_t f3;975    using f4_t = void(__stdcall *)(int param4);976    f4_t f4;977    struct S {978      void (*f5)(int param5);979      using f6_t = void(*)(int param6);980      f6_t f6;981    };982    void bar() {983      f1(42);984      f2(42);985      f3(42);986      f4(42);987      S s;988      s.f5(42);989      s.f6(42);990    }991  )cpp";992  auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"});993  auto &Ctx = TU->getASTContext();994  auto checkFreeFunction = [&](llvm::StringRef FunctionName,995                               llvm::StringRef ParamName) {996    expectParameterNames(997        Ctx,998        callExpr(999            callee(implicitCastExpr(hasSourceExpression(declRefExpr(1000                                        to(namedDecl(hasName(FunctionName))))))1001                       .bind("input"))),1002        ParamName);1003  };1004  checkFreeFunction("f1", "param1");1005  checkFreeFunction("f2", "param2");1006  checkFreeFunction("f3", "param3");1007  checkFreeFunction("f4", "param4");1008  auto checkMemberFunction = [&](llvm::StringRef MemberName,1009                                 llvm::StringRef ParamName) {1010    expectParameterNames(1011        Ctx,1012        callExpr(callee(implicitCastExpr(hasSourceExpression(memberExpr(1013                                             member(hasName(MemberName)))))1014                            .bind("input"))),1015        ParamName);1016  };1017  checkMemberFunction("f5", "param5");1018  checkMemberFunction("f6", "param6");1019}1020 1021} // namespace1022} // namespace clang1023