[M68k] always use movem for register spills (#106715)
[llvm-project.git] / clang / unittests / Sema / HeuristicResolverTest.cpp
blob5c3459dbeb1018bbe9c7e3a3cb43ee1242e829b8
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "clang/Sema/HeuristicResolver.h"
9 #include "clang/ASTMatchers/ASTMatchFinder.h"
10 #include "clang/ASTMatchers/ASTMatchers.h"
11 #include "clang/Tooling/Tooling.h"
12 #include "gmock/gmock-matchers.h"
13 #include "gtest/gtest.h"
15 using namespace clang::ast_matchers;
16 using testing::ElementsAre;
18 namespace clang {
19 namespace {
21 // Helper for matching a sequence of elements with a variadic list of matchers.
22 // Usage: `ElementsAre(matchAdapter(Vs, MatchFunction)...)`, where `Vs...` is
23 // a variadic list of matchers.
24 // For each `V` in `Vs`, this will match the corresponding element `E` if
25 // `MatchFunction(V, E)` is true.
26 MATCHER_P2(matchAdapter, MatcherForElement, MatchFunction, "matchAdapter") {
27 return MatchFunction(MatcherForElement, arg);
30 template <typename InputNode>
31 using ResolveFnT = std::function<std::vector<const NamedDecl *>(
32 const HeuristicResolver *, const InputNode *)>;
34 // Test heuristic resolution on `Code` using the resolution procedure
35 // `ResolveFn`, which takes a `HeuristicResolver` and an input AST node of type
36 // `InputNode` and returns a `std::vector<const NamedDecl *>`.
37 // `InputMatcher` should be an AST matcher that matches a single node to pass as
38 // input to `ResolveFn`, bound to the ID "input". `OutputMatchers` should be AST
39 // matchers that each match a single node, bound to the ID "output".
40 template <typename InputNode, typename InputMatcher, typename... OutputMatchers>
41 void expectResolution(llvm::StringRef Code, ResolveFnT<InputNode> ResolveFn,
42 const InputMatcher &IM, const OutputMatchers &...OMS) {
43 auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"});
44 auto &Ctx = TU->getASTContext();
45 auto InputMatches = match(IM, Ctx);
46 ASSERT_EQ(1u, InputMatches.size());
47 const auto *Input = InputMatches[0].template getNodeAs<InputNode>("input");
48 ASSERT_TRUE(Input);
50 auto OutputNodeMatches = [&](auto &OutputMatcher, auto &Actual) {
51 auto OutputMatches = match(OutputMatcher, Ctx);
52 if (OutputMatches.size() != 1u)
53 return false;
54 const auto *ExpectedOutput =
55 OutputMatches[0].template getNodeAs<NamedDecl>("output");
56 if (!ExpectedOutput)
57 return false;
58 return ExpectedOutput == Actual;
61 HeuristicResolver H(Ctx);
62 auto Results = ResolveFn(&H, Input);
63 EXPECT_THAT(Results, ElementsAre(matchAdapter(OMS, OutputNodeMatches)...));
66 // Wrapper for the above that accepts a HeuristicResolver member function
67 // pointer directly.
68 template <typename InputNode, typename InputMatcher, typename... OutputMatchers>
69 void expectResolution(llvm::StringRef Code,
70 std::vector<const NamedDecl *> (
71 HeuristicResolver::*ResolveFn)(const InputNode *)
72 const,
73 const InputMatcher &IM, const OutputMatchers &...OMS) {
74 expectResolution(Code, ResolveFnT<InputNode>(std::mem_fn(ResolveFn)), IM,
75 OMS...);
78 TEST(HeuristicResolver, MemberExpr) {
79 std::string Code = R"cpp(
80 template <typename T>
81 struct S {
82 void bar() {}
85 template <typename T>
86 void foo(S<T> arg) {
87 arg.bar();
89 )cpp";
90 // Test resolution of "bar" in "arg.bar()".
91 expectResolution(
92 Code, &HeuristicResolver::resolveMemberExpr,
93 cxxDependentScopeMemberExpr(hasMemberName("bar")).bind("input"),
94 cxxMethodDecl(hasName("bar")).bind("output"));
97 TEST(HeuristicResolver, MemberExpr_Overloads) {
98 std::string Code = R"cpp(
99 template <typename T>
100 struct S {
101 void bar(int);
102 void bar(float);
105 template <typename T, typename U>
106 void foo(S<T> arg, U u) {
107 arg.bar(u);
109 )cpp";
110 // Test resolution of "bar" in "arg.bar(u)". Both overloads should be found.
111 expectResolution(
112 Code, &HeuristicResolver::resolveMemberExpr,
113 cxxDependentScopeMemberExpr(hasMemberName("bar")).bind("input"),
114 cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("int"))))
115 .bind("output"),
116 cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("float"))))
117 .bind("output"));
120 TEST(HeuristicResolver, MemberExpr_SmartPointer) {
121 std::string Code = R"cpp(
122 template <typename> struct S { void foo() {} };
123 template <typename T> struct unique_ptr {
124 T* operator->();
126 template <typename T>
127 void test(unique_ptr<S<T>>& v) {
128 v->foo();
130 )cpp";
131 // Test resolution of "foo" in "v->foo()".
132 expectResolution(
133 Code, &HeuristicResolver::resolveMemberExpr,
134 cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),
135 cxxMethodDecl(hasName("foo")).bind("output"));
138 TEST(HeuristicResolver, MemberExpr_SmartPointer_Qualified) {
139 std::string Code = R"cpp(
140 template <typename> struct Waldo {
141 void find();
142 void find() const;
144 template <typename T> struct unique_ptr {
145 T* operator->();
147 template <typename T>
148 void test(unique_ptr<const Waldo<T>>& w) {
149 w->find();
151 )cpp";
152 expectResolution(
153 Code, &HeuristicResolver::resolveMemberExpr,
154 cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),
155 cxxMethodDecl(hasName("find"), isConst()).bind("output"));
158 TEST(HeuristicResolver, MemberExpr_Static_Qualified) {
159 std::string Code = R"cpp(
160 template <typename T>
161 struct Waldo {
162 static void find();
164 template <typename T>
165 void foo(const Waldo<T>& t) {
166 t.find();
168 )cpp";
169 // Test resolution of "find" in "t.find()".
170 // The object being `const` should have no bearing on a call to a static
171 // method.
172 expectResolution(
173 Code, &HeuristicResolver::resolveMemberExpr,
174 cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),
175 cxxMethodDecl(hasName("find")).bind("output"));
178 TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction1) {
179 std::string Code = R"cpp(
180 template <typename T>
181 struct A {
182 int waldo;
184 template <typename T>
185 void foo(A<T> a) {
186 auto copy = a;
187 copy.waldo;
189 )cpp";
190 expectResolution(
191 Code, &HeuristicResolver::resolveMemberExpr,
192 cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),
193 fieldDecl(hasName("waldo")).bind("output"));
196 TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction2) {
197 std::string Code = R"cpp(
198 struct B {
199 int waldo;
202 template <typename T>
203 struct A {
204 B b;
206 template <typename T>
207 void foo(A<T> a) {
208 auto b = a.b;
209 b.waldo;
211 )cpp";
212 expectResolution(
213 Code, &HeuristicResolver::resolveMemberExpr,
214 cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),
215 fieldDecl(hasName("waldo")).bind("output"));
218 TEST(HeuristicResolver, MemberExpr_Chained) {
219 std::string Code = R"cpp(
220 struct A { void foo() {} };
221 template <typename T>
222 struct B {
223 A func(int);
224 void bar() {
225 func(1).foo();
228 )cpp";
229 // Test resolution of "foo" in "func(1).foo()".
230 expectResolution(
231 Code, &HeuristicResolver::resolveMemberExpr,
232 cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),
233 cxxMethodDecl(hasName("foo")).bind("output"));
236 TEST(HeuristicResolver, MemberExpr_ReferenceType) {
237 std::string Code = R"cpp(
238 struct B {
239 int waldo;
241 template <typename T>
242 struct A {
243 B &b;
245 template <typename T>
246 void foo(A<T> &a) {
247 a.b.waldo;
249 )cpp";
250 // Test resolution of "waldo" in "a.b.waldo".
251 expectResolution(
252 Code, &HeuristicResolver::resolveMemberExpr,
253 cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),
254 fieldDecl(hasName("waldo")).bind("output"));
257 TEST(HeuristicResolver, MemberExpr_PointerType) {
258 std::string Code = R"cpp(
259 struct B {
260 int waldo;
262 template <typename T>
263 struct A {
264 B *b;
266 template <typename T>
267 void foo(A<T> &a) {
268 a.b->waldo;
270 )cpp";
271 // Test resolution of "waldo" in "a.b->waldo".
272 expectResolution(
273 Code, &HeuristicResolver::resolveMemberExpr,
274 cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),
275 fieldDecl(hasName("waldo")).bind("output"));
278 TEST(HeuristicResolver, MemberExpr_TemplateArgs) {
279 std::string Code = R"cpp(
280 struct Foo {
281 static Foo k(int);
282 template <typename T> T convert();
284 template <typename T>
285 void test() {
286 Foo::k(T()).template convert<T>();
288 )cpp";
289 // Test resolution of "convert" in "Foo::k(T()).template convert<T>()".
290 expectResolution(
291 Code, &HeuristicResolver::resolveMemberExpr,
292 cxxDependentScopeMemberExpr(hasMemberName("convert")).bind("input"),
293 functionTemplateDecl(hasName("convert")).bind("output"));
296 TEST(HeuristicResolver, MemberExpr_TypeAlias) {
297 std::string Code = R"cpp(
298 template <typename T>
299 struct Waldo {
300 void find();
302 template <typename T>
303 using Wally = Waldo<T>;
304 template <typename T>
305 void foo(Wally<T> w) {
306 w.find();
308 )cpp";
309 // Test resolution of "find" in "w.find()".
310 expectResolution(
311 Code, &HeuristicResolver::resolveMemberExpr,
312 cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),
313 cxxMethodDecl(hasName("find")).bind("output"));
316 TEST(HeuristicResolver, MemberExpr_BaseClass_TypeAlias) {
317 std::string Code = R"cpp(
318 template <typename T>
319 struct Waldo {
320 void find();
322 template <typename T>
323 using Wally = Waldo<T>;
324 template <typename T>
325 struct S : Wally<T> {
326 void foo() {
327 this->find();
330 )cpp";
331 // Test resolution of "find" in "this->find()".
332 expectResolution(
333 Code, &HeuristicResolver::resolveMemberExpr,
334 cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),
335 cxxMethodDecl(hasName("find")).bind("output"));
338 TEST(HeuristicResolver, MemberExpr_Metafunction) {
339 std::string Code = R"cpp(
340 template <typename T>
341 struct Waldo {
342 void find();
344 template <typename T>
345 struct MetaWaldo {
346 using Type = Waldo<T>;
348 template <typename T>
349 void foo(typename MetaWaldo<T>::Type w) {
350 w.find();
352 )cpp";
353 // Test resolution of "find" in "w.find()".
354 expectResolution(
355 Code, &HeuristicResolver::resolveMemberExpr,
356 cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"),
357 cxxMethodDecl(hasName("find")).bind("output"));
360 TEST(HeuristicResolver, MemberExpr_Metafunction_Enumerator) {
361 std::string Code = R"cpp(
362 enum class State { Hidden };
363 template <typename T>
364 struct Meta {
365 using Type = State;
367 template <typename T>
368 void foo(typename Meta<T>::Type t) {
369 t.Hidden;
371 )cpp";
372 // Test resolution of "Hidden" in "t.Hidden".
373 expectResolution(
374 Code, &HeuristicResolver::resolveMemberExpr,
375 cxxDependentScopeMemberExpr(hasMemberName("Hidden")).bind("input"),
376 enumConstantDecl(hasName("Hidden")).bind("output"));
379 TEST(HeuristicResolver, MemberExpr_DeducedNonTypeTemplateParameter) {
380 std::string Code = R"cpp(
381 template <int N>
382 struct Waldo {
383 const int found = N;
385 template <Waldo W>
386 int foo() {
387 return W.found;
389 )cpp";
390 // Test resolution of "found" in "W.found".
391 expectResolution(
392 Code, &HeuristicResolver::resolveMemberExpr,
393 cxxDependentScopeMemberExpr(hasMemberName("found")).bind("input"),
394 fieldDecl(hasName("found")).bind("output"));
397 TEST(HeuristicResolver, DeclRefExpr_StaticMethod) {
398 std::string Code = R"cpp(
399 template <typename T>
400 struct S {
401 static void bar() {}
404 template <typename T>
405 void foo() {
406 S<T>::bar();
408 )cpp";
409 // Test resolution of "bar" in "S<T>::bar()".
410 expectResolution(
411 Code, &HeuristicResolver::resolveDeclRefExpr,
412 dependentScopeDeclRefExpr(hasDependentName("bar")).bind("input"),
413 cxxMethodDecl(hasName("bar")).bind("output"));
416 TEST(HeuristicResolver, DeclRefExpr_StaticOverloads) {
417 std::string Code = R"cpp(
418 template <typename T>
419 struct S {
420 static void bar(int);
421 static void bar(float);
424 template <typename T, typename U>
425 void foo(U u) {
426 S<T>::bar(u);
428 )cpp";
429 // Test resolution of "bar" in "S<T>::bar(u)". Both overloads should be found.
430 expectResolution(
431 Code, &HeuristicResolver::resolveDeclRefExpr,
432 dependentScopeDeclRefExpr(hasDependentName("bar")).bind("input"),
433 cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("int"))))
434 .bind("output"),
435 cxxMethodDecl(hasName("bar"), hasParameter(0, hasType(asString("float"))))
436 .bind("output"));
439 TEST(HeuristicResolver, DeclRefExpr_Enumerator) {
440 std::string Code = R"cpp(
441 template <typename T>
442 struct Foo {
443 enum class E { A, B };
444 E e = E::A;
446 )cpp";
447 // Test resolution of "A" in "E::A".
448 expectResolution(
449 Code, &HeuristicResolver::resolveDeclRefExpr,
450 dependentScopeDeclRefExpr(hasDependentName("A")).bind("input"),
451 enumConstantDecl(hasName("A")).bind("output"));
454 TEST(HeuristicResolver, DeclRefExpr_RespectScope) {
455 std::string Code = R"cpp(
456 template <typename Info>
457 struct PointerIntPair {
458 void *getPointer() const { return Info::getPointer(); }
460 )cpp";
461 // Test resolution of "getPointer" in "Info::getPointer()".
462 // Here, we are testing that we do not incorrectly get the enclosing
463 // getPointer() function as a result.
464 expectResolution(
465 Code, &HeuristicResolver::resolveDeclRefExpr,
466 dependentScopeDeclRefExpr(hasDependentName("getPointer")).bind("input"));
469 TEST(HeuristicResolver, DeclRefExpr_Nested) {
470 std::string Code = R"cpp(
471 struct S {
472 static int Waldo;
474 template <typename T>
475 struct Meta {
476 using Type = S;
478 template <typename T>
479 void foo() {
480 Meta<T>::Type::Waldo;
482 )cpp";
483 // Test resolution of "Waldo" in "Meta<T>::Type::Waldo".
484 expectResolution(
485 Code, &HeuristicResolver::resolveDeclRefExpr,
486 dependentScopeDeclRefExpr(hasDependentName("Waldo")).bind("input"),
487 varDecl(hasName("Waldo")).bind("output"));
490 TEST(HeuristicResolver, DependentNameType) {
491 std::string Code = R"cpp(
492 template <typename>
493 struct A {
494 struct B {};
496 template <typename T>
497 void foo(typename A<T>::B);
498 )cpp";
499 // Tests resolution of "B" in "A<T>::B".
500 expectResolution(
501 Code, &HeuristicResolver::resolveDependentNameType,
502 functionDecl(hasParameter(0, hasType(dependentNameType().bind("input")))),
503 classTemplateDecl(
504 has(cxxRecordDecl(has(cxxRecordDecl(hasName("B")).bind("output"))))));
507 TEST(HeuristicResolver, DependentNameType_Nested) {
508 std::string Code = R"cpp(
509 template <typename>
510 struct A {
511 struct B {
512 struct C {};
515 template <typename T>
516 void foo(typename A<T>::B::C);
517 )cpp";
518 // Tests resolution of "C" in "A<T>::B::C".
519 expectResolution(
520 Code, &HeuristicResolver::resolveDependentNameType,
521 functionDecl(hasParameter(0, hasType(dependentNameType().bind("input")))),
522 classTemplateDecl(has(cxxRecordDecl(has(
523 cxxRecordDecl(has(cxxRecordDecl(hasName("C")).bind("output"))))))));
526 TEST(HeuristicResolver, DependentNameType_Recursion) {
527 std::string Code = R"cpp(
528 template <int N>
529 struct Waldo {
530 using Type = typename Waldo<N - 1>::Type::Next;
532 )cpp";
533 // Test resolution of "Next" in "typename Waldo<N - 1>::Type::Next".
534 // Here, we are testing that we do not get into an infinite recursion.
535 expectResolution(Code, &HeuristicResolver::resolveDependentNameType,
536 typeAliasDecl(hasType(dependentNameType().bind("input"))));
539 TEST(HeuristicResolver, DependentNameType_MutualRecursion) {
540 std::string Code = R"cpp(
541 template <int N>
542 struct Odd;
543 template <int N>
544 struct Even {
545 using Type = typename Odd<N - 1>::Type::Next;
547 template <int N>
548 struct Odd {
549 using Type = typename Even<N - 1>::Type::Next;
551 )cpp";
552 // Test resolution of "Next" in "typename Even<N - 1>::Type::Next".
553 // Similar to the above but we have two mutually recursive templates.
554 expectResolution(
555 Code, &HeuristicResolver::resolveDependentNameType,
556 classTemplateDecl(hasName("Odd"),
557 has(cxxRecordDecl(has(typeAliasDecl(
558 hasType(dependentNameType().bind("input"))))))));
561 TEST(HeuristicResolver, NestedNameSpecifier) {
562 // Test resolution of "B" in "A<T>::B::C".
563 // Unlike the "C", the "B" does not get its own DependentNameTypeLoc node,
564 // so the resolution uses the NestedNameSpecifier as input.
565 std::string Code = R"cpp(
566 template <typename>
567 struct A {
568 struct B {
569 struct C {};
572 template <typename T>
573 void foo(typename A<T>::B::C);
574 )cpp";
575 // Adapt the call to resolveNestedNameSpecifierToType() to the interface
576 // expected by expectResolution() (returning a vector of decls).
577 ResolveFnT<NestedNameSpecifier> ResolveFn =
578 [](const HeuristicResolver *H,
579 const NestedNameSpecifier *NNS) -> std::vector<const NamedDecl *> {
580 return {H->resolveNestedNameSpecifierToType(NNS)->getAsCXXRecordDecl()};
582 expectResolution(Code, ResolveFn,
583 nestedNameSpecifier(hasPrefix(specifiesType(hasDeclaration(
584 classTemplateDecl(hasName("A"))))))
585 .bind("input"),
586 classTemplateDecl(has(cxxRecordDecl(
587 has(cxxRecordDecl(hasName("B")).bind("output"))))));
590 TEST(HeuristicResolver, TemplateSpecializationType) {
591 std::string Code = R"cpp(
592 template <typename>
593 struct A {
594 template <typename>
595 struct B {};
597 template <typename T>
598 void foo(typename A<T>::template B<int>);
599 )cpp";
600 // Test resolution of "B" in "A<T>::template B<int>".
601 expectResolution(Code, &HeuristicResolver::resolveTemplateSpecializationType,
602 functionDecl(hasParameter(0, hasType(type().bind("input")))),
603 classTemplateDecl(has(cxxRecordDecl(
604 has(classTemplateDecl(hasName("B")).bind("output"))))));
607 TEST(HeuristicResolver, DependentCall_NonMember) {
608 std::string Code = R"cpp(
609 template <typename T>
610 void nonmember(T);
611 template <typename T>
612 void bar(T t) {
613 nonmember(t);
615 )cpp";
616 // Test resolution of "nonmember" in "nonmember(t)".
617 expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr,
618 callExpr(callee(unresolvedLookupExpr(hasAnyDeclaration(
619 functionTemplateDecl(hasName("nonmember"))))))
620 .bind("input"),
621 functionTemplateDecl(hasName("nonmember")).bind("output"));
624 TEST(HeuristicResolver, DependentCall_Member) {
625 std::string Code = R"cpp(
626 template <typename T>
627 struct A {
628 void member(T);
630 template <typename T>
631 void bar(A<T> a, T t) {
632 a.member(t);
634 )cpp";
635 // Test resolution of "member" in "a.member(t)".
636 expectResolution(
637 Code, &HeuristicResolver::resolveCalleeOfCallExpr,
638 callExpr(callee(cxxDependentScopeMemberExpr(hasMemberName("member"))))
639 .bind("input"),
640 cxxMethodDecl(hasName("member")).bind("output"));
643 TEST(HeuristicResolver, DependentCall_StaticMember) {
644 std::string Code = R"cpp(
645 template <typename T>
646 struct A {
647 static void static_member(T);
649 template <typename T>
650 void bar(T t) {
651 A<T>::static_member(t);
653 )cpp";
654 // Test resolution of "static_member" in "A<T>::static_member(t)".
655 expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr,
656 callExpr(callee(dependentScopeDeclRefExpr(
657 hasDependentName("static_member"))))
658 .bind("input"),
659 cxxMethodDecl(hasName("static_member")).bind("output"));
662 TEST(HeuristicResolver, DependentCall_Overload) {
663 std::string Code = R"cpp(
664 void overload(int);
665 void overload(double);
666 template <typename T>
667 void bar(T t) {
668 overload(t);
670 )cpp";
671 // Test resolution of "overload" in "overload(t)". Both overload should be
672 // found.
673 expectResolution(Code, &HeuristicResolver::resolveCalleeOfCallExpr,
674 callExpr(callee(unresolvedLookupExpr(hasAnyDeclaration(
675 functionDecl(hasName("overload"))))))
676 .bind("input"),
677 functionDecl(hasName("overload"),
678 hasParameter(0, hasType(asString("double"))))
679 .bind("output"),
680 functionDecl(hasName("overload"),
681 hasParameter(0, hasType(asString("int"))))
682 .bind("output"));
685 TEST(HeuristicResolver, UsingValueDecl) {
686 std::string Code = R"cpp(
687 template <typename T>
688 struct Base {
689 void waldo();
691 template <typename T>
692 struct Derived : Base<T> {
693 using Base<T>::waldo;
695 )cpp";
696 // Test resolution of "waldo" in "Base<T>::waldo".
697 expectResolution(Code, &HeuristicResolver::resolveUsingValueDecl,
698 unresolvedUsingValueDecl(hasName("waldo")).bind("input"),
699 cxxMethodDecl(hasName("waldo")).bind("output"));
702 } // namespace
703 } // namespace clang