1ae932becSNathan Ridge //===-- HeuristicResolverTests.cpp --------------------------*- C++ -*-----===// 2ae932becSNathan Ridge // 3ae932becSNathan Ridge // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ae932becSNathan Ridge // See https://llvm.org/LICENSE.txt for license information. 5ae932becSNathan Ridge // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ae932becSNathan Ridge // 7ae932becSNathan Ridge //===----------------------------------------------------------------------===// 8ae932becSNathan Ridge #include "clang/Sema/HeuristicResolver.h" 9ae932becSNathan Ridge #include "clang/ASTMatchers/ASTMatchFinder.h" 10ae932becSNathan Ridge #include "clang/ASTMatchers/ASTMatchers.h" 11ae932becSNathan Ridge #include "clang/Tooling/Tooling.h" 12ae932becSNathan Ridge #include "gmock/gmock-matchers.h" 13ae932becSNathan Ridge #include "gtest/gtest.h" 14ae932becSNathan Ridge 15ae932becSNathan Ridge using namespace clang::ast_matchers; 16ae932becSNathan Ridge using testing::ElementsAre; 17ae932becSNathan Ridge 18ae932becSNathan Ridge namespace clang { 19ae932becSNathan Ridge namespace { 20ae932becSNathan Ridge 21ae932becSNathan Ridge // Helper for matching a sequence of elements with a variadic list of matchers. 22ae932becSNathan Ridge // Usage: `ElementsAre(matchAdapter(Vs, MatchFunction)...)`, where `Vs...` is 23ae932becSNathan Ridge // a variadic list of matchers. 24ae932becSNathan Ridge // For each `V` in `Vs`, this will match the corresponding element `E` if 25ae932becSNathan Ridge // `MatchFunction(V, E)` is true. 26ae932becSNathan Ridge MATCHER_P2(matchAdapter, MatcherForElement, MatchFunction, "matchAdapter") { 27ae932becSNathan Ridge return MatchFunction(MatcherForElement, arg); 28ae932becSNathan Ridge } 29ae932becSNathan Ridge 30ae932becSNathan Ridge template <typename InputNode> 31ae932becSNathan Ridge using ResolveFnT = std::function<std::vector<const NamedDecl *>( 32ae932becSNathan Ridge const HeuristicResolver *, const InputNode *)>; 33ae932becSNathan Ridge 34ae932becSNathan Ridge // Test heuristic resolution on `Code` using the resolution procedure 35ae932becSNathan Ridge // `ResolveFn`, which takes a `HeuristicResolver` and an input AST node of type 36ae932becSNathan Ridge // `InputNode` and returns a `std::vector<const NamedDecl *>`. 37ae932becSNathan Ridge // `InputMatcher` should be an AST matcher that matches a single node to pass as 38ae932becSNathan Ridge // input to `ResolveFn`, bound to the ID "input". `OutputMatchers` should be AST 39ae932becSNathan Ridge // matchers that each match a single node, bound to the ID "output". 40ae932becSNathan Ridge template <typename InputNode, typename InputMatcher, typename... OutputMatchers> 41ae932becSNathan Ridge void expectResolution(llvm::StringRef Code, ResolveFnT<InputNode> ResolveFn, 42ae932becSNathan Ridge const InputMatcher &IM, const OutputMatchers &...OMS) { 43ae932becSNathan Ridge auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"}); 44ae932becSNathan Ridge auto &Ctx = TU->getASTContext(); 45ae932becSNathan Ridge auto InputMatches = match(IM, Ctx); 46ae932becSNathan Ridge ASSERT_EQ(1u, InputMatches.size()); 47ae932becSNathan Ridge const auto *Input = InputMatches[0].template getNodeAs<InputNode>("input"); 48ae932becSNathan Ridge ASSERT_TRUE(Input); 49ae932becSNathan Ridge 50ae932becSNathan Ridge auto OutputNodeMatches = [&](auto &OutputMatcher, auto &Actual) { 51ae932becSNathan Ridge auto OutputMatches = match(OutputMatcher, Ctx); 52ae932becSNathan Ridge if (OutputMatches.size() != 1u) 53ae932becSNathan Ridge return false; 54ae932becSNathan Ridge const auto *ExpectedOutput = 55ae932becSNathan Ridge OutputMatches[0].template getNodeAs<NamedDecl>("output"); 56ae932becSNathan Ridge if (!ExpectedOutput) 57ae932becSNathan Ridge return false; 58ae932becSNathan Ridge return ExpectedOutput == Actual; 59ae932becSNathan Ridge }; 60ae932becSNathan Ridge 61ae932becSNathan Ridge HeuristicResolver H(Ctx); 62ae932becSNathan Ridge auto Results = ResolveFn(&H, Input); 63ae932becSNathan Ridge EXPECT_THAT(Results, ElementsAre(matchAdapter(OMS, OutputNodeMatches)...)); 64ae932becSNathan Ridge } 65ae932becSNathan Ridge 66ae932becSNathan Ridge // Wrapper for the above that accepts a HeuristicResolver member function 67ae932becSNathan Ridge // pointer directly. 68ae932becSNathan Ridge template <typename InputNode, typename InputMatcher, typename... OutputMatchers> 69ae932becSNathan Ridge void expectResolution(llvm::StringRef Code, 70ae932becSNathan Ridge std::vector<const NamedDecl *> ( 71ae932becSNathan Ridge HeuristicResolver::*ResolveFn)(const InputNode *) 72ae932becSNathan Ridge const, 73ae932becSNathan Ridge const InputMatcher &IM, const OutputMatchers &...OMS) { 74ae932becSNathan Ridge expectResolution(Code, ResolveFnT<InputNode>(std::mem_fn(ResolveFn)), IM, 75ae932becSNathan Ridge OMS...); 76ae932becSNathan Ridge } 77ae932becSNathan Ridge 78ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr) { 79ae932becSNathan Ridge std::string Code = R"cpp( 80ae932becSNathan Ridge template <typename T> 81ae932becSNathan Ridge struct S { 82ae932becSNathan Ridge void bar() {} 83ae932becSNathan Ridge }; 84ae932becSNathan Ridge 85ae932becSNathan Ridge template <typename T> 86ae932becSNathan Ridge void foo(S<T> arg) { 87ae932becSNathan Ridge arg.bar(); 88ae932becSNathan Ridge } 89ae932becSNathan Ridge )cpp"; 90ae932becSNathan Ridge // Test resolution of "bar" in "arg.bar()". 91ae932becSNathan Ridge expectResolution( 92ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 93ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("bar")).bind("input"), 94ae932becSNathan Ridge cxxMethodDecl(hasName("bar")).bind("output")); 95ae932becSNathan Ridge } 96ae932becSNathan Ridge 97ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_Overloads) { 98ae932becSNathan Ridge std::string Code = R"cpp( 99ae932becSNathan Ridge template <typename T> 100ae932becSNathan Ridge struct S { 101ae932becSNathan Ridge void bar(int); 102ae932becSNathan Ridge void bar(float); 103ae932becSNathan Ridge }; 104ae932becSNathan Ridge 105ae932becSNathan Ridge template <typename T, typename U> 106ae932becSNathan Ridge void foo(S<T> arg, U u) { 107ae932becSNathan Ridge arg.bar(u); 108ae932becSNathan Ridge } 109ae932becSNathan Ridge )cpp"; 110ae932becSNathan Ridge // Test resolution of "bar" in "arg.bar(u)". Both overloads should be found. 111ae932becSNathan Ridge expectResolution( 112ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 113ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("bar")).bind("input"), 114ae932becSNathan Ridge cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("int")))) 115ae932becSNathan Ridge .bind("output"), 116ae932becSNathan Ridge cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("float")))) 117ae932becSNathan Ridge .bind("output")); 118ae932becSNathan Ridge } 119ae932becSNathan Ridge 120ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_SmartPointer) { 121ae932becSNathan Ridge std::string Code = R"cpp( 122ae932becSNathan Ridge template <typename> struct S { void foo() {} }; 123ae932becSNathan Ridge template <typename T> struct unique_ptr { 124ae932becSNathan Ridge T* operator->(); 125ae932becSNathan Ridge }; 126ae932becSNathan Ridge template <typename T> 127ae932becSNathan Ridge void test(unique_ptr<S<T>>& v) { 128ae932becSNathan Ridge v->foo(); 129ae932becSNathan Ridge } 130ae932becSNathan Ridge )cpp"; 131ae932becSNathan Ridge // Test resolution of "foo" in "v->foo()". 132ae932becSNathan Ridge expectResolution( 133ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 134ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"), 135ae932becSNathan Ridge cxxMethodDecl(hasName("foo")).bind("output")); 136ae932becSNathan Ridge } 137ae932becSNathan Ridge 1384740e097SNathan Ridge TEST(HeuristicResolver, MemberExpr_SmartPointer_Qualified) { 1394740e097SNathan Ridge std::string Code = R"cpp( 1404740e097SNathan Ridge template <typename> struct Waldo { 1414740e097SNathan Ridge void find(); 1424740e097SNathan Ridge void find() const; 1434740e097SNathan Ridge }; 1444740e097SNathan Ridge template <typename T> struct unique_ptr { 1454740e097SNathan Ridge T* operator->(); 1464740e097SNathan Ridge }; 1474740e097SNathan Ridge template <typename T> 1484740e097SNathan Ridge void test(unique_ptr<const Waldo<T>>& w) { 1494740e097SNathan Ridge w->find(); 1504740e097SNathan Ridge } 1514740e097SNathan Ridge )cpp"; 1524740e097SNathan Ridge expectResolution( 1534740e097SNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 1544740e097SNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"), 1554740e097SNathan Ridge cxxMethodDecl(hasName("find"), isConst()).bind("output")); 1564740e097SNathan Ridge } 1574740e097SNathan Ridge 158df9b31f1SNathan Ridge TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction1) { 159df9b31f1SNathan Ridge std::string Code = R"cpp( 160df9b31f1SNathan Ridge template <typename T> 161df9b31f1SNathan Ridge struct A { 162df9b31f1SNathan Ridge int waldo; 163df9b31f1SNathan Ridge }; 164df9b31f1SNathan Ridge template <typename T> 165df9b31f1SNathan Ridge void foo(A<T> a) { 166df9b31f1SNathan Ridge auto copy = a; 167df9b31f1SNathan Ridge copy.waldo; 168df9b31f1SNathan Ridge } 169df9b31f1SNathan Ridge )cpp"; 170df9b31f1SNathan Ridge expectResolution( 171df9b31f1SNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 172df9b31f1SNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"), 173df9b31f1SNathan Ridge fieldDecl(hasName("waldo")).bind("output")); 174df9b31f1SNathan Ridge } 175df9b31f1SNathan Ridge 176df9b31f1SNathan Ridge TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction2) { 177df9b31f1SNathan Ridge std::string Code = R"cpp( 178df9b31f1SNathan Ridge struct B { 179df9b31f1SNathan Ridge int waldo; 180df9b31f1SNathan Ridge }; 181df9b31f1SNathan Ridge 182df9b31f1SNathan Ridge template <typename T> 183df9b31f1SNathan Ridge struct A { 184df9b31f1SNathan Ridge B b; 185df9b31f1SNathan Ridge }; 186df9b31f1SNathan Ridge template <typename T> 187df9b31f1SNathan Ridge void foo(A<T> a) { 188df9b31f1SNathan Ridge auto b = a.b; 189df9b31f1SNathan Ridge b.waldo; 190df9b31f1SNathan Ridge } 191df9b31f1SNathan Ridge )cpp"; 192df9b31f1SNathan Ridge expectResolution( 193df9b31f1SNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 194df9b31f1SNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"), 195df9b31f1SNathan Ridge fieldDecl(hasName("waldo")).bind("output")); 196df9b31f1SNathan Ridge } 197df9b31f1SNathan Ridge 198ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_Chained) { 199ae932becSNathan Ridge std::string Code = R"cpp( 200ae932becSNathan Ridge struct A { void foo() {} }; 201ae932becSNathan Ridge template <typename T> 202ae932becSNathan Ridge struct B { 203ae932becSNathan Ridge A func(int); 204ae932becSNathan Ridge void bar() { 205ae932becSNathan Ridge func(1).foo(); 206ae932becSNathan Ridge } 207ae932becSNathan Ridge }; 208ae932becSNathan Ridge )cpp"; 209ae932becSNathan Ridge // Test resolution of "foo" in "func(1).foo()". 210ae932becSNathan Ridge expectResolution( 211ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 212ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"), 213ae932becSNathan Ridge cxxMethodDecl(hasName("foo")).bind("output")); 214ae932becSNathan Ridge } 215ae932becSNathan Ridge 216ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_TemplateArgs) { 217ae932becSNathan Ridge std::string Code = R"cpp( 218ae932becSNathan Ridge struct Foo { 219ae932becSNathan Ridge static Foo k(int); 220ae932becSNathan Ridge template <typename T> T convert(); 221ae932becSNathan Ridge }; 222ae932becSNathan Ridge template <typename T> 223ae932becSNathan Ridge void test() { 224ae932becSNathan Ridge Foo::k(T()).template convert<T>(); 225ae932becSNathan Ridge } 226ae932becSNathan Ridge )cpp"; 227ae932becSNathan Ridge // Test resolution of "convert" in "Foo::k(T()).template convert<T>()". 228ae932becSNathan Ridge expectResolution( 229ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 230ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("convert")).bind("input"), 231ae932becSNathan Ridge functionTemplateDecl(hasName("convert")).bind("output")); 232ae932becSNathan Ridge } 233ae932becSNathan Ridge 234ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_TypeAlias) { 235ae932becSNathan Ridge std::string Code = R"cpp( 236ae932becSNathan Ridge template <typename T> 237ae932becSNathan Ridge struct Waldo { 238ae932becSNathan Ridge void find(); 239ae932becSNathan Ridge }; 240ae932becSNathan Ridge template <typename T> 241ae932becSNathan Ridge using Wally = Waldo<T>; 242ae932becSNathan Ridge template <typename T> 243ae932becSNathan Ridge void foo(Wally<T> w) { 244ae932becSNathan Ridge w.find(); 245ae932becSNathan Ridge } 246ae932becSNathan Ridge )cpp"; 247ae932becSNathan Ridge // Test resolution of "find" in "w.find()". 248ae932becSNathan Ridge expectResolution( 249ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 250ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"), 251ae932becSNathan Ridge cxxMethodDecl(hasName("find")).bind("output")); 252ae932becSNathan Ridge } 253ae932becSNathan Ridge 254ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_BaseClass_TypeAlias) { 255ae932becSNathan Ridge std::string Code = R"cpp( 256ae932becSNathan Ridge template <typename T> 257ae932becSNathan Ridge struct Waldo { 258ae932becSNathan Ridge void find(); 259ae932becSNathan Ridge }; 260ae932becSNathan Ridge template <typename T> 261ae932becSNathan Ridge using Wally = Waldo<T>; 262ae932becSNathan Ridge template <typename T> 263ae932becSNathan Ridge struct S : Wally<T> { 264ae932becSNathan Ridge void foo() { 265ae932becSNathan Ridge this->find(); 266ae932becSNathan Ridge } 267ae932becSNathan Ridge }; 268ae932becSNathan Ridge )cpp"; 269ae932becSNathan Ridge // Test resolution of "find" in "this->find()". 270ae932becSNathan Ridge expectResolution( 271ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 272ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"), 273ae932becSNathan Ridge cxxMethodDecl(hasName("find")).bind("output")); 274ae932becSNathan Ridge } 275ae932becSNathan Ridge 276ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_Metafunction) { 277ae932becSNathan Ridge std::string Code = R"cpp( 278ae932becSNathan Ridge template <typename T> 279ae932becSNathan Ridge struct Waldo { 280ae932becSNathan Ridge void find(); 281ae932becSNathan Ridge }; 282ae932becSNathan Ridge template <typename T> 283ae932becSNathan Ridge struct MetaWaldo { 284ae932becSNathan Ridge using Type = Waldo<T>; 285ae932becSNathan Ridge }; 286ae932becSNathan Ridge template <typename T> 287ae932becSNathan Ridge void foo(typename MetaWaldo<T>::Type w) { 288ae932becSNathan Ridge w.find(); 289ae932becSNathan Ridge } 290ae932becSNathan Ridge )cpp"; 291ae932becSNathan Ridge // Test resolution of "find" in "w.find()". 292ae932becSNathan Ridge expectResolution( 293ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 294ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"), 295ae932becSNathan Ridge cxxMethodDecl(hasName("find")).bind("output")); 296ae932becSNathan Ridge } 297ae932becSNathan Ridge 298*a4d17c44SNathan Ridge TEST(HeuristicResolver, MemberExpr_Metafunction_Enumerator) { 299*a4d17c44SNathan Ridge std::string Code = R"cpp( 300*a4d17c44SNathan Ridge enum class State { Hidden }; 301*a4d17c44SNathan Ridge template <typename T> 302*a4d17c44SNathan Ridge struct Meta { 303*a4d17c44SNathan Ridge using Type = State; 304*a4d17c44SNathan Ridge }; 305*a4d17c44SNathan Ridge template <typename T> 306*a4d17c44SNathan Ridge void foo(typename Meta<T>::Type t) { 307*a4d17c44SNathan Ridge t.Hidden; 308*a4d17c44SNathan Ridge } 309*a4d17c44SNathan Ridge )cpp"; 310*a4d17c44SNathan Ridge // Test resolution of "Hidden" in "t.Hidden". 311*a4d17c44SNathan Ridge expectResolution( 312*a4d17c44SNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 313*a4d17c44SNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("Hidden")).bind("input"), 314*a4d17c44SNathan Ridge enumConstantDecl(hasName("Hidden")).bind("output")); 315*a4d17c44SNathan Ridge } 316*a4d17c44SNathan Ridge 317ae932becSNathan Ridge TEST(HeuristicResolver, MemberExpr_DeducedNonTypeTemplateParameter) { 318ae932becSNathan Ridge std::string Code = R"cpp( 319ae932becSNathan Ridge template <int N> 320ae932becSNathan Ridge struct Waldo { 321ae932becSNathan Ridge const int found = N; 322ae932becSNathan Ridge }; 323ae932becSNathan Ridge template <Waldo W> 324ae932becSNathan Ridge int foo() { 325ae932becSNathan Ridge return W.found; 326ae932becSNathan Ridge } 327ae932becSNathan Ridge )cpp"; 328ae932becSNathan Ridge // Test resolution of "found" in "W.found". 329ae932becSNathan Ridge expectResolution( 330ae932becSNathan Ridge Code, &HeuristicResolver::resolveMemberExpr, 331ae932becSNathan Ridge cxxDependentScopeMemberExpr(hasMemberName("found")).bind("input"), 332ae932becSNathan Ridge fieldDecl(hasName("found")).bind("output")); 333ae932becSNathan Ridge } 334ae932becSNathan Ridge 335ae932becSNathan Ridge TEST(HeuristicResolver, DeclRefExpr_StaticMethod) { 336ae932becSNathan Ridge std::string Code = R"cpp( 337ae932becSNathan Ridge template <typename T> 338ae932becSNathan Ridge struct S { 339ae932becSNathan Ridge static void bar() {} 340ae932becSNathan Ridge }; 341ae932becSNathan Ridge 342ae932becSNathan Ridge template <typename T> 343ae932becSNathan Ridge void foo() { 344ae932becSNathan Ridge S<T>::bar(); 345ae932becSNathan Ridge } 346ae932becSNathan Ridge )cpp"; 347ae932becSNathan Ridge // Test resolution of "bar" in "S<T>::bar()". 348ae932becSNathan Ridge expectResolution( 349ae932becSNathan Ridge Code, &HeuristicResolver::resolveDeclRefExpr, 350ae932becSNathan Ridge dependentScopeDeclRefExpr(hasDependentName("bar")).bind("input"), 351ae932becSNathan Ridge cxxMethodDecl(hasName("bar")).bind("output")); 352ae932becSNathan Ridge } 353ae932becSNathan Ridge 354ae932becSNathan Ridge TEST(HeuristicResolver, DeclRefExpr_StaticOverloads) { 355ae932becSNathan Ridge std::string Code = R"cpp( 356ae932becSNathan Ridge template <typename T> 357ae932becSNathan Ridge struct S { 358ae932becSNathan Ridge static void bar(int); 359ae932becSNathan Ridge static void bar(float); 360ae932becSNathan Ridge }; 361ae932becSNathan Ridge 362ae932becSNathan Ridge template <typename T, typename U> 363ae932becSNathan Ridge void foo(U u) { 364ae932becSNathan Ridge S<T>::bar(u); 365ae932becSNathan Ridge } 366ae932becSNathan Ridge )cpp"; 367ae932becSNathan Ridge // Test resolution of "bar" in "S<T>::bar(u)". Both overloads should be found. 368ae932becSNathan Ridge expectResolution( 369ae932becSNathan Ridge Code, &HeuristicResolver::resolveDeclRefExpr, 370ae932becSNathan Ridge dependentScopeDeclRefExpr(hasDependentName("bar")).bind("input"), 371ae932becSNathan Ridge cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("int")))) 372ae932becSNathan Ridge .bind("output"), 373ae932becSNathan Ridge cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("float")))) 374ae932becSNathan Ridge .bind("output")); 375ae932becSNathan Ridge } 376ae932becSNathan Ridge 377ae932becSNathan Ridge TEST(HeuristicResolver, DeclRefExpr_Enumerator) { 378ae932becSNathan Ridge std::string Code = R"cpp( 379ae932becSNathan Ridge template <typename T> 380ae932becSNathan Ridge struct Foo { 381ae932becSNathan Ridge enum class E { A, B }; 382ae932becSNathan Ridge E e = E::A; 383ae932becSNathan Ridge }; 384ae932becSNathan Ridge )cpp"; 385ae932becSNathan Ridge // Test resolution of "A" in "E::A". 386ae932becSNathan Ridge expectResolution( 387ae932becSNathan Ridge Code, &HeuristicResolver::resolveDeclRefExpr, 388ae932becSNathan Ridge dependentScopeDeclRefExpr(hasDependentName("A")).bind("input"), 389ae932becSNathan Ridge enumConstantDecl(hasName("A")).bind("output")); 390ae932becSNathan Ridge } 391ae932becSNathan Ridge 392ae932becSNathan Ridge TEST(HeuristicResolver, DeclRefExpr_RespectScope) { 393ae932becSNathan Ridge std::string Code = R"cpp( 394ae932becSNathan Ridge template <typename Info> 395ae932becSNathan Ridge struct PointerIntPair { 396ae932becSNathan Ridge void *getPointer() const { return Info::getPointer(); } 397ae932becSNathan Ridge }; 398ae932becSNathan Ridge )cpp"; 399ae932becSNathan Ridge // Test resolution of "getPointer" in "Info::getPointer()". 400ae932becSNathan Ridge // Here, we are testing that we do not incorrectly get the enclosing 401ae932becSNathan Ridge // getPointer() function as a result. 402ae932becSNathan Ridge expectResolution( 403ae932becSNathan Ridge Code, &HeuristicResolver::resolveDeclRefExpr, 404ae932becSNathan Ridge dependentScopeDeclRefExpr(hasDependentName("getPointer")).bind("input")); 405ae932becSNathan Ridge } 406ae932becSNathan Ridge 407a01e1d4eSNathan Ridge TEST(HeuristicResolver, DeclRefExpr_Nested) { 408a01e1d4eSNathan Ridge std::string Code = R"cpp( 409a01e1d4eSNathan Ridge struct S { 410a01e1d4eSNathan Ridge static int Waldo; 411a01e1d4eSNathan Ridge }; 412a01e1d4eSNathan Ridge template <typename T> 413a01e1d4eSNathan Ridge struct Meta { 414a01e1d4eSNathan Ridge using Type = S; 415a01e1d4eSNathan Ridge }; 416a01e1d4eSNathan Ridge template <typename T> 417a01e1d4eSNathan Ridge void foo() { 418a01e1d4eSNathan Ridge Meta<T>::Type::Waldo; 419a01e1d4eSNathan Ridge } 420a01e1d4eSNathan Ridge )cpp"; 421a01e1d4eSNathan Ridge // Test resolution of "Waldo" in "Meta<T>::Type::Waldo". 422a01e1d4eSNathan Ridge expectResolution( 423a01e1d4eSNathan Ridge Code, &HeuristicResolver::resolveDeclRefExpr, 424a01e1d4eSNathan Ridge dependentScopeDeclRefExpr(hasDependentName("Waldo")).bind("input"), 425a01e1d4eSNathan Ridge varDecl(hasName("Waldo")).bind("output")); 426a01e1d4eSNathan Ridge } 427a01e1d4eSNathan Ridge 428ae932becSNathan Ridge TEST(HeuristicResolver, DependentNameType) { 429ae932becSNathan Ridge std::string Code = R"cpp( 430ae932becSNathan Ridge template <typename> 431ae932becSNathan Ridge struct A { 432ae932becSNathan Ridge struct B {}; 433ae932becSNathan Ridge }; 434ae932becSNathan Ridge template <typename T> 435ae932becSNathan Ridge void foo(typename A<T>::B); 436ae932becSNathan Ridge )cpp"; 437ae932becSNathan Ridge // Tests resolution of "B" in "A<T>::B". 438ae932becSNathan Ridge expectResolution( 439ae932becSNathan Ridge Code, &HeuristicResolver::resolveDependentNameType, 440ae932becSNathan Ridge functionDecl(hasParameter(0, hasType(dependentNameType().bind("input")))), 441ae932becSNathan Ridge classTemplateDecl( 442ae932becSNathan Ridge has(cxxRecordDecl(has(cxxRecordDecl(hasName("B")).bind("output")))))); 443ae932becSNathan Ridge } 444ae932becSNathan Ridge 445ae932becSNathan Ridge TEST(HeuristicResolver, DependentNameType_Nested) { 446ae932becSNathan Ridge std::string Code = R"cpp( 447ae932becSNathan Ridge template <typename> 448ae932becSNathan Ridge struct A { 449ae932becSNathan Ridge struct B { 450ae932becSNathan Ridge struct C {}; 451ae932becSNathan Ridge }; 452ae932becSNathan Ridge }; 453ae932becSNathan Ridge template <typename T> 454ae932becSNathan Ridge void foo(typename A<T>::B::C); 455ae932becSNathan Ridge )cpp"; 456ae932becSNathan Ridge // Tests resolution of "C" in "A<T>::B::C". 457ae932becSNathan Ridge expectResolution( 458ae932becSNathan Ridge Code, &HeuristicResolver::resolveDependentNameType, 459ae932becSNathan Ridge functionDecl(hasParameter(0, hasType(dependentNameType().bind("input")))), 460ae932becSNathan Ridge classTemplateDecl(has(cxxRecordDecl(has( 461ae932becSNathan Ridge cxxRecordDecl(has(cxxRecordDecl(hasName("C")).bind("output")))))))); 462ae932becSNathan Ridge } 463ae932becSNathan Ridge 464ae932becSNathan Ridge TEST(HeuristicResolver, DependentNameType_Recursion) { 465ae932becSNathan Ridge std::string Code = R"cpp( 466ae932becSNathan Ridge template <int N> 467ae932becSNathan Ridge struct Waldo { 468ae932becSNathan Ridge using Type = typename Waldo<N - 1>::Type::Next; 469ae932becSNathan Ridge }; 470ae932becSNathan Ridge )cpp"; 471ae932becSNathan Ridge // Test resolution of "Next" in "typename Waldo<N - 1>::Type::Next". 472ae932becSNathan Ridge // Here, we are testing that we do not get into an infinite recursion. 473ae932becSNathan Ridge expectResolution(Code, &HeuristicResolver::resolveDependentNameType, 474ae932becSNathan Ridge typeAliasDecl(hasType(dependentNameType().bind("input")))); 475ae932becSNathan Ridge } 476ae932becSNathan Ridge 477ae932becSNathan Ridge TEST(HeuristicResolver, DependentNameType_MutualRecursion) { 478ae932becSNathan Ridge std::string Code = R"cpp( 479ae932becSNathan Ridge template <int N> 480ae932becSNathan Ridge struct Odd; 481ae932becSNathan Ridge template <int N> 482ae932becSNathan Ridge struct Even { 483ae932becSNathan Ridge using Type = typename Odd<N - 1>::Type::Next; 484ae932becSNathan Ridge }; 485ae932becSNathan Ridge template <int N> 486ae932becSNathan Ridge struct Odd { 487ae932becSNathan Ridge using Type = typename Even<N - 1>::Type::Next; 488ae932becSNathan Ridge }; 489ae932becSNathan Ridge )cpp"; 490ae932becSNathan Ridge // Test resolution of "Next" in "typename Even<N - 1>::Type::Next". 491ae932becSNathan Ridge // Similar to the above but we have two mutually recursive templates. 492ae932becSNathan Ridge expectResolution( 493ae932becSNathan Ridge Code, &HeuristicResolver::resolveDependentNameType, 494ae932becSNathan Ridge classTemplateDecl(hasName("Odd"), 495ae932becSNathan Ridge has(cxxRecordDecl(has(typeAliasDecl( 496ae932becSNathan Ridge hasType(dependentNameType().bind("input")))))))); 497ae932becSNathan Ridge } 498ae932becSNathan Ridge 499ae932becSNathan Ridge TEST(HeuristicResolver, NestedNameSpecifier) { 500ae932becSNathan Ridge // Test resolution of "B" in "A<T>::B::C". 501ae932becSNathan Ridge // Unlike the "C", the "B" does not get its own DependentNameTypeLoc node, 502ae932becSNathan Ridge // so the resolution uses the NestedNameSpecifier as input. 503ae932becSNathan Ridge std::string Code = R"cpp( 504ae932becSNathan Ridge template <typename> 505ae932becSNathan Ridge struct A { 506ae932becSNathan Ridge struct B { 507ae932becSNathan Ridge struct C {}; 508ae932becSNathan Ridge }; 509ae932becSNathan Ridge }; 510ae932becSNathan Ridge template <typename T> 511ae932becSNathan Ridge void foo(typename A<T>::B::C); 512ae932becSNathan Ridge )cpp"; 513ae932becSNathan Ridge // Adapt the call to resolveNestedNameSpecifierToType() to the interface 514ae932becSNathan Ridge // expected by expectResolution() (returning a vector of decls). 515ae932becSNathan Ridge ResolveFnT<NestedNameSpecifier> ResolveFn = 516ae932becSNathan Ridge [](const HeuristicResolver *H, 517ae932becSNathan Ridge const NestedNameSpecifier *NNS) -> std::vector<const NamedDecl *> { 518ae932becSNathan Ridge return {H->resolveNestedNameSpecifierToType(NNS)->getAsCXXRecordDecl()}; 519ae932becSNathan Ridge }; 520ae932becSNathan Ridge expectResolution(Code, ResolveFn, 521ae932becSNathan Ridge nestedNameSpecifier(hasPrefix(specifiesType(hasDeclaration( 522ae932becSNathan Ridge classTemplateDecl(hasName("A")))))) 523ae932becSNathan Ridge .bind("input"), 524ae932becSNathan Ridge classTemplateDecl(has(cxxRecordDecl( 525ae932becSNathan Ridge has(cxxRecordDecl(hasName("B")).bind("output")))))); 526ae932becSNathan Ridge } 527ae932becSNathan Ridge 528ae932becSNathan Ridge TEST(HeuristicResolver, TemplateSpecializationType) { 529ae932becSNathan Ridge std::string Code = R"cpp( 530ae932becSNathan Ridge template <typename> 531ae932becSNathan Ridge struct A { 532ae932becSNathan Ridge template <typename> 533ae932becSNathan Ridge struct B {}; 534ae932becSNathan Ridge }; 535ae932becSNathan Ridge template <typename T> 536ae932becSNathan Ridge void foo(typename A<T>::template B<int>); 537ae932becSNathan Ridge )cpp"; 538ae932becSNathan Ridge // Test resolution of "B" in "A<T>::template B<int>". 539ae932becSNathan Ridge expectResolution(Code, &HeuristicResolver::resolveTemplateSpecializationType, 540ae932becSNathan Ridge functionDecl(hasParameter(0, hasType(type().bind("input")))), 541ae932becSNathan Ridge classTemplateDecl(has(cxxRecordDecl( 542ae932becSNathan Ridge has(classTemplateDecl(hasName("B")).bind("output")))))); 543ae932becSNathan Ridge } 544ae932becSNathan Ridge 545ae932becSNathan Ridge TEST(HeuristicResolver, DependentCall_NonMember) { 546ae932becSNathan Ridge std::string Code = R"cpp( 547ae932becSNathan Ridge template <typename T> 548ae932becSNathan Ridge void nonmember(T); 549ae932becSNathan Ridge template <typename T> 550ae932becSNathan Ridge void bar(T t) { 551ae932becSNathan Ridge nonmember(t); 552ae932becSNathan Ridge } 553ae932becSNathan Ridge )cpp"; 554ae932becSNathan Ridge // Test resolution of "nonmember" in "nonmember(t)". 555ae932becSNathan Ridge expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr, 556ae932becSNathan Ridge callExpr(callee(unresolvedLookupExpr(hasAnyDeclaration( 557ae932becSNathan Ridge functionTemplateDecl(hasName("nonmember")))))) 558ae932becSNathan Ridge .bind("input"), 559ae932becSNathan Ridge functionTemplateDecl(hasName("nonmember")).bind("output")); 560ae932becSNathan Ridge } 561ae932becSNathan Ridge 562ae932becSNathan Ridge TEST(HeuristicResolver, DependentCall_Member) { 563ae932becSNathan Ridge std::string Code = R"cpp( 564ae932becSNathan Ridge template <typename T> 565ae932becSNathan Ridge struct A { 566ae932becSNathan Ridge void member(T); 567ae932becSNathan Ridge }; 568ae932becSNathan Ridge template <typename T> 569ae932becSNathan Ridge void bar(A<T> a, T t) { 570ae932becSNathan Ridge a.member(t); 571ae932becSNathan Ridge } 572ae932becSNathan Ridge )cpp"; 573ae932becSNathan Ridge // Test resolution of "member" in "a.member(t)". 574ae932becSNathan Ridge expectResolution( 575ae932becSNathan Ridge Code, &HeuristicResolver::resolveCalleeOfCallExpr, 576ae932becSNathan Ridge callExpr(callee(cxxDependentScopeMemberExpr(hasMemberName("member")))) 577ae932becSNathan Ridge .bind("input"), 578ae932becSNathan Ridge cxxMethodDecl(hasName("member")).bind("output")); 579ae932becSNathan Ridge } 580ae932becSNathan Ridge 581ae932becSNathan Ridge TEST(HeuristicResolver, DependentCall_StaticMember) { 582ae932becSNathan Ridge std::string Code = R"cpp( 583ae932becSNathan Ridge template <typename T> 584ae932becSNathan Ridge struct A { 585ae932becSNathan Ridge static void static_member(T); 586ae932becSNathan Ridge }; 587ae932becSNathan Ridge template <typename T> 588ae932becSNathan Ridge void bar(T t) { 589ae932becSNathan Ridge A<T>::static_member(t); 590ae932becSNathan Ridge } 591ae932becSNathan Ridge )cpp"; 592ae932becSNathan Ridge // Test resolution of "static_member" in "A<T>::static_member(t)". 593ae932becSNathan Ridge expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr, 594ae932becSNathan Ridge callExpr(callee(dependentScopeDeclRefExpr( 595ae932becSNathan Ridge hasDependentName("static_member")))) 596ae932becSNathan Ridge .bind("input"), 597ae932becSNathan Ridge cxxMethodDecl(hasName("static_member")).bind("output")); 598ae932becSNathan Ridge } 599ae932becSNathan Ridge 600ae932becSNathan Ridge TEST(HeuristicResolver, DependentCall_Overload) { 601ae932becSNathan Ridge std::string Code = R"cpp( 602ae932becSNathan Ridge void overload(int); 603ae932becSNathan Ridge void overload(double); 604ae932becSNathan Ridge template <typename T> 605ae932becSNathan Ridge void bar(T t) { 606ae932becSNathan Ridge overload(t); 607ae932becSNathan Ridge } 608ae932becSNathan Ridge )cpp"; 609ae932becSNathan Ridge // Test resolution of "overload" in "overload(t)". Both overload should be 610ae932becSNathan Ridge // found. 611ae932becSNathan Ridge expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr, 612ae932becSNathan Ridge callExpr(callee(unresolvedLookupExpr(hasAnyDeclaration( 613ae932becSNathan Ridge functionDecl(hasName("overload")))))) 614ae932becSNathan Ridge .bind("input"), 615ae932becSNathan Ridge functionDecl(hasName("overload"), 616ae932becSNathan Ridge hasParameter(0, hasType(asString("double")))) 617ae932becSNathan Ridge .bind("output"), 618ae932becSNathan Ridge functionDecl(hasName("overload"), 619ae932becSNathan Ridge hasParameter(0, hasType(asString("int")))) 620ae932becSNathan Ridge .bind("output")); 621ae932becSNathan Ridge } 622ae932becSNathan Ridge 623ae932becSNathan Ridge TEST(HeuristicResolver, UsingValueDecl) { 624ae932becSNathan Ridge std::string Code = R"cpp( 625ae932becSNathan Ridge template <typename T> 626ae932becSNathan Ridge struct Base { 627ae932becSNathan Ridge void waldo(); 628ae932becSNathan Ridge }; 629ae932becSNathan Ridge template <typename T> 630ae932becSNathan Ridge struct Derived : Base<T> { 631ae932becSNathan Ridge using Base<T>::waldo; 632ae932becSNathan Ridge }; 633ae932becSNathan Ridge )cpp"; 634ae932becSNathan Ridge // Test resolution of "waldo" in "Base<T>::waldo". 635ae932becSNathan Ridge expectResolution(Code, &HeuristicResolver::resolveUsingValueDecl, 636ae932becSNathan Ridge unresolvedUsingValueDecl(hasName("waldo")).bind("input"), 637ae932becSNathan Ridge cxxMethodDecl(hasName("waldo")).bind("output")); 638ae932becSNathan Ridge } 639ae932becSNathan Ridge 640ae932becSNathan Ridge } // namespace 641ae932becSNathan Ridge } // namespace clang 642