1 //===-- DefineInlineTests.cpp -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "TweakTesting.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
14 using ::testing::ElementsAre
;
20 TWEAK_TEST(DefineInline
);
22 TEST_F(DefineInlineTest
, TriggersOnFunctionDecl
) {
23 // Basic check for function body and signature.
24 EXPECT_AVAILABLE(R
"cpp(
29 [[void [[Bar::[[b^a^z]]]]() [[{
34 [[void [[f^o^o]]() [[{
39 EXPECT_UNAVAILABLE(R
"cpp(
43 [[vo^id ]]foo[[()]] {[[
48 // Definition with no body.
49 class Bar { Bar() = def^ault; };
53 TEST_F(DefineInlineTest
, NoForwardDecl
) {
54 Header
= "void bar();";
55 EXPECT_UNAVAILABLE(R
"cpp(
59 // FIXME: Generate a decl in the header.
65 TEST_F(DefineInlineTest
, ReferencedDecls
) {
66 EXPECT_AVAILABLE(R
"cpp(
75 // Internal symbol usage.
76 Header
= "void foo(int test);";
77 EXPECT_UNAVAILABLE(R
"cpp(
84 // Becomes available after making symbol visible.
85 Header
= "void bar();" + Header
;
86 EXPECT_AVAILABLE(R
"cpp(
92 // FIXME: Move declaration below bar to make it visible.
94 EXPECT_UNAVAILABLE(R
"cpp(
102 // Order doesn't matter within a class.
103 EXPECT_AVAILABLE(R
"cpp(
113 // FIXME: Perform include insertion to make symbol visible.
114 ExtraFiles
["a.h"] = "void bar();";
115 Header
= "void foo(int test);";
116 EXPECT_UNAVAILABLE(R
"cpp(
124 TEST_F(DefineInlineTest
, TemplateSpec
) {
125 EXPECT_UNAVAILABLE(R
"cpp(
126 template <typename T> void foo();
127 template<> void foo<char>();
129 template<> void f^oo<int>() {
131 EXPECT_UNAVAILABLE(R
"cpp(
132 template <typename T> void foo();
134 template<> void f^oo<int>() {
136 EXPECT_UNAVAILABLE(R
"cpp(
137 template <typename T> struct Foo { void foo(); };
139 template <typename T> void Foo<T>::f^oo() {
141 EXPECT_AVAILABLE(R
"cpp(
142 template <typename T> void foo();
144 template <> void foo<int>();
146 template<> void f^oo<int>() {
149 EXPECT_UNAVAILABLE(R
"cpp(
151 template <typename T> void f^oo() {}
152 template void foo<int>();
156 TEST_F(DefineInlineTest
, CheckForCanonDecl
) {
157 EXPECT_UNAVAILABLE(R
"cpp(
162 // This bar normally refers to the definition just above, but it is not
163 // visible from the forward declaration of foo.
166 // Make it available with a forward decl.
167 EXPECT_AVAILABLE(R
"cpp(
177 TEST_F(DefineInlineTest
, UsingShadowDecls
) {
178 EXPECT_UNAVAILABLE(R
"cpp(
179 namespace ns1 { void foo(int); }
180 namespace ns2 { void foo(int*); }
181 template <typename T>
187 template <typename T>
193 TEST_F(DefineInlineTest
, TransformNestedNamespaces
) {
222 auto *Expected
= R
"cpp(
250 EXPECT_EQ(apply(Test
), Expected
);
253 TEST_F(DefineInlineTest
, TransformUsings
) {
255 namespace a { namespace b { namespace c { void aux(); } } }
265 auto *Expected
= R
"cpp(
266 namespace a { namespace b { namespace c { void aux(); } } }
270 using namespace a::b;
271 using namespace a::b::c;
273 namespace d = a::b::c;
276 EXPECT_EQ(apply(Test
), Expected
);
279 TEST_F(DefineInlineTest
, TransformDecls
) {
289 enum En { Zero, One };
292 enum class EnClass { Zero, One };
293 EnClass y = EnClass::Zero;
295 auto *Expected
= R
"cpp(
303 enum En { Zero, One };
306 enum class EnClass { Zero, One };
307 EnClass y = EnClass::Zero;
310 EXPECT_EQ(apply(Test
), Expected
);
313 TEST_F(DefineInlineTest
, TransformTemplDecls
) {
316 template <typename T> class Bar {
320 template <typename T> T bar;
321 template <typename T> void aux() {}
331 auto *Expected
= R
"cpp(
333 template <typename T> class Bar {
337 template <typename T> T bar;
338 template <typename T> void aux() {}
342 a::bar<a::Bar<int>>.bar();
343 a::aux<a::Bar<int>>();
348 EXPECT_EQ(apply(Test
), Expected
);
351 TEST_F(DefineInlineTest
, TransformMembers
) {
360 auto *Expected
= R
"cpp(
368 EXPECT_EQ(apply(Test
), Expected
);
370 ExtraFiles
["a.h"] = R
"cpp(
375 llvm::StringMap
<std::string
> EditedFiles
;
384 EXPECT_EQ(apply(Test
, &EditedFiles
), Expected
);
392 EXPECT_THAT(EditedFiles
,
393 ElementsAre(FileWithContents(testPath("a.h"), Expected
)));
396 TEST_F(DefineInlineTest
, TransformDependentTypes
) {
399 template <typename T> class Bar {};
402 template <typename T>
406 template <typename T>
411 auto *Expected
= R
"cpp(
413 template <typename T> class Bar {};
416 template <typename T>
425 EXPECT_EQ(apply(Test
), Expected
);
428 TEST_F(DefineInlineTest
, TransformFunctionTempls
) {
429 // Check we select correct specialization decl.
430 std::pair
<llvm::StringRef
, llvm::StringRef
> Cases
[] = {
432 template <typename T>
436 void foo<int>(int p);
439 void foo<char>(char p);
442 void fo^o<int>(int p) {
446 template <typename T>
450 void foo<int>(int p){
455 void foo<char>(char p);
458 {// Make sure we are not selecting the first specialization all the time.
460 template <typename T>
464 void foo<int>(int p);
467 void foo<char>(char p);
470 void fo^o<char>(char p) {
474 template <typename T>
478 void foo<int>(int p);
481 void foo<char>(char p){
487 template <typename T>
491 void foo<int>(int p);
493 template <typename T>
498 template <typename T>
504 void foo<int>(int p);
508 for (const auto &Case
: Cases
)
509 EXPECT_EQ(apply(Case
.first
), Case
.second
) << Case
.first
;
512 TEST_F(DefineInlineTest
, TransformTypeLocs
) {
515 template <typename T> class Bar {
517 template <typename Q> class Baz {};
528 a::Bar<Bar<int>>::Baz<Bar<int>> q;
530 auto *Expected
= R
"cpp(
532 template <typename T> class Bar {
534 template <typename Q> class Baz {};
542 a::Bar<a::Bar<int>>::Baz<a::Bar<int>> q;
547 EXPECT_EQ(apply(Test
), Expected
);
550 TEST_F(DefineInlineTest
, TransformDeclRefs
) {
553 template <typename T> class Bar {
570 Bar<Bar<int>>::bar();
577 auto *Expected
= R
"cpp(
579 template <typename T> class Bar {
594 a::Bar<a::Bar<int>>::bar();
596 B.x = a::Bar<int>::y;
603 EXPECT_EQ(apply(Test
), Expected
);
606 TEST_F(DefineInlineTest
, StaticMembers
) {
608 namespace ns { class X { static void foo(); void bar(); }; }
612 auto *Expected
= R
"cpp(
613 namespace ns { class X { static void foo(); void bar(){
617 EXPECT_EQ(apply(Test
), Expected
);
620 TEST_F(DefineInlineTest
, TransformParamNames
) {
621 std::pair
<llvm::StringRef
, llvm::StringRef
> Cases
[] = {
623 void foo(int, bool b, int T\
625 void ^foo(int f, bool x, int z) {})cpp",
627 void foo(int f, bool x, int z){}
633 void ^foo(int X) {})cpp",
634 "fail: Cant rename parameter inside macro body."},
638 #define BODY(x) 5 * (x) + 2
640 void foo(PARAM, TYPE Q, TYPE, TYPE W = BODY(P));
642 void ^foo(int Z, int b, int c, int d) {})cpp",
646 #define BODY(x) 5 * (x) + 2
648 void foo(PARAM, TYPE b, TYPE c, TYPE d = BODY(x)){}
651 for (const auto &Case
: Cases
)
652 EXPECT_EQ(apply(Case
.first
), Case
.second
) << Case
.first
;
655 TEST_F(DefineInlineTest
, TransformTemplParamNames
) {
659 template <class, class X,
660 template<typename> class, template<typename> class Y,
662 void foo(X, Y<X>, int W = 5 * Z + 2);
666 template <class T, class U,
667 template<typename> class V, template<typename> class W,
669 void Foo::Bar::f^oo(U, W<U>, int Q) {})cpp";
670 auto *Expected
= R
"cpp(
673 template <class T, class U,
674 template<typename> class V, template<typename> class W,
676 void foo(U, W<U>, int Q = 5 * Y + 2){}
681 EXPECT_EQ(apply(Test
), Expected
);
684 TEST_F(DefineInlineTest
, TransformInlineNamespaces
) {
686 namespace a { inline namespace b { namespace { struct Foo{}; } } }
690 void ^foo() {Foo foo;})cpp";
691 auto *Expected
= R
"cpp(
692 namespace a { inline namespace b { namespace { struct Foo{}; } } }
693 void foo(){a::Foo foo;}
697 EXPECT_EQ(apply(Test
), Expected
);
700 TEST_F(DefineInlineTest
, TokensBeforeSemicolon
) {
701 std::pair
<llvm::StringRef
, llvm::StringRef
> Cases
[] = {
703 void foo() /*Comment -_-*/ /*Com 2*/ ;
704 void fo^o() { return ; })cpp",
706 void foo() /*Comment -_-*/ /*Com 2*/ { return ; }
711 void fo^o() { return ; })cpp",
713 void foo(){ return ; }
719 void fo^o() { return ; })cpp",
720 "fail: Couldn't find semicolon for target declaration."},
722 for (const auto &Case
: Cases
)
723 EXPECT_EQ(apply(Case
.first
), Case
.second
) << Case
.first
;
726 TEST_F(DefineInlineTest
, HandleMacros
) {
727 EXPECT_UNAVAILABLE(R
"cpp(
728 #define BODY { return; }
730 void f^oo()BODY)cpp");
732 EXPECT_UNAVAILABLE(R
"cpp(
733 #define BODY void foo(){ return; }
737 std::pair
<llvm::StringRef
, llvm::StringRef
> Cases
[] = {
738 // We don't qualify declarations coming from macros.
741 namespace a { class Foo{}; }
744 void f^oo(){BODY();})cpp",
747 namespace a { class Foo{}; }
752 // Macro is not visible at declaration location, but we proceed.
756 void f^oo(){BODY})cpp",
763 #define TARGET void foo()
765 void f^oo(){ return; })cpp",
767 #define TARGET void foo()
774 void f^oo(){ return; })cpp",
777 void TARGET(){ return; }
780 for (const auto &Case
: Cases
)
781 EXPECT_EQ(apply(Case
.first
), Case
.second
) << Case
.first
;
784 TEST_F(DefineInlineTest
, DropCommonNameSpecifiers
) {
786 llvm::StringRef Test
;
787 llvm::StringRef Expected
;
790 namespace a { namespace b { void aux(); } }
793 namespace qq { void test(); }
796 namespace ns3 { void baz(); }
801 using namespace a::b;
802 using namespace ns1::qq;
803 void ns1::ns2::ns3::b^az() {
807 ns1::ns2::ns3::baz();
812 namespace a { namespace b { void aux(); } }
815 namespace qq { void test(); }
818 namespace ns3 { void baz(){
822 ns1::ns2::ns3::baz();
830 using namespace a::b;
831 using namespace ns1::qq;
835 namespace qq { struct Foo { struct Bar {}; }; using B = Foo::Bar; }
836 namespace ns2 { void baz(); }
839 using namespace ns1::qq;
840 void ns1::ns2::b^az() { Foo f; B b; })cpp",
843 namespace qq { struct Foo { struct Bar {}; }; using B = Foo::Bar; }
844 namespace ns2 { void baz(){ qq::Foo f; qq::B b; } }
847 using namespace ns1::qq;
852 template<class T> struct Foo { template <class U> struct Bar {}; };
853 template<class T, class U>
854 using B = typename Foo<T>::template Bar<U>;
856 namespace ns2 { void baz(); }
859 using namespace ns1::qq;
860 void ns1::ns2::b^az() { B<int, bool> b; })cpp",
864 template<class T> struct Foo { template <class U> struct Bar {}; };
865 template<class T, class U>
866 using B = typename Foo<T>::template Bar<U>;
868 namespace ns2 { void baz(){ qq::B<int, bool> b; } }
871 using namespace ns1::qq;
874 for (const auto &Case
: Cases
)
875 EXPECT_EQ(apply(Case
.Test
), Case
.Expected
) << Case
.Test
;
878 TEST_F(DefineInlineTest
, QualifyWithUsingDirectives
) {
879 llvm::StringRef Test
= R
"cpp(
882 namespace b { struct Foo{}; void aux(); }
883 namespace c { void cux(); }
897 // FIXME: The last reference to cux() in body of foo should not be
898 // qualified, since there is a using directive inside the function body.
901 llvm::StringRef Expected
= R
"cpp(
904 namespace b { struct Foo{}; void aux(); }
905 namespace c { void cux(); }
915 // FIXME: The last reference to cux() in body of foo should not be
916 // qualified, since there is a using directive inside the function body.
923 EXPECT_EQ(apply(Test
), Expected
) << Test
;
926 TEST_F(DefineInlineTest
, AddInline
) {
927 llvm::StringMap
<std::string
> EditedFiles
;
928 ExtraFiles
["a.h"] = "void foo();";
929 apply(R
"cpp(#include "a
.h
"
932 EXPECT_THAT(EditedFiles
, testing::ElementsAre(FileWithContents(
933 testPath("a.h"), "inline void foo(){}")));
935 // Check we put inline before cv-qualifiers.
936 ExtraFiles
["a.h"] = "const int foo();";
937 apply(R
"cpp(#include "a
.h
"
938 const int fo^o() {})cpp",
940 EXPECT_THAT(EditedFiles
, testing::ElementsAre(FileWithContents(
941 testPath("a.h"), "inline const int foo(){}")));
944 ExtraFiles
["a.h"] = "inline void foo();";
945 apply(R
"cpp(#include "a
.h
"
946 inline void fo^o() {})cpp",
948 EXPECT_THAT(EditedFiles
, testing::ElementsAre(FileWithContents(
949 testPath("a.h"), "inline void foo(){}")));
951 // Constexprs don't need "inline".
952 ExtraFiles
["a.h"] = "constexpr void foo();";
953 apply(R
"cpp(#include "a
.h
"
954 constexpr void fo^o() {})cpp",
956 EXPECT_THAT(EditedFiles
, testing::ElementsAre(FileWithContents(
957 testPath("a.h"), "constexpr void foo(){}")));
959 // Class members don't need "inline".
960 ExtraFiles
["a.h"] = "struct Foo { void foo(); };";
961 apply(R
"cpp(#include "a
.h
"
962 void Foo::fo^o() {})cpp",
964 EXPECT_THAT(EditedFiles
,
965 testing::ElementsAre(FileWithContents(
966 testPath("a.h"), "struct Foo { void foo(){} };")));
968 // Function template doesn't need to be "inline"d.
969 ExtraFiles
["a.h"] = "template <typename T> void foo();";
970 apply(R
"cpp(#include "a
.h
"
971 template <typename T>
974 EXPECT_THAT(EditedFiles
,
975 testing::ElementsAre(FileWithContents(
976 testPath("a.h"), "template <typename T> void foo(){}")));
978 // Specializations needs to be marked "inline".
979 ExtraFiles
["a.h"] = R
"cpp(
980 template <typename T> void foo();
981 template <> void foo<int>();)cpp";
982 apply(R
"cpp(#include "a
.h
"
984 void fo^o<int>() {})cpp",
986 EXPECT_THAT(EditedFiles
,
987 testing::ElementsAre(FileWithContents(testPath("a.h"),
989 template <typename T> void foo();
990 template <> inline void foo<int>(){})cpp")));
994 } // namespace clangd