xref: /llvm-project/clang/unittests/Sema/HeuristicResolverTest.cpp (revision a4d17c44f14984f8f031d0715ea4d1387e96b741)
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