1//===-- DefineInlineTests.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
9#include "TweakTesting.h"
10#include "TestFS.h"
11#include "gmock/gmock.h"
12#include "gtest/gtest.h"
13
14using ::testing::ElementsAre;
15
16namespace clang {
17namespace clangd {
18namespace {
19
20TWEAK_TEST(DefineInline);
21
22TEST_F(DefineInlineTest, TriggersOnFunctionDecl) {
23 // Basic check for function body and signature.
24 EXPECT_AVAILABLE(R"cpp(
25 class Bar {
26 void baz();
27 };
28
29 [[void [[Bar::[[b^a^z]]]]() [[{
30 return;
31 }]]]]
32
33 void foo();
34 [[void [[f^o^o]]() [[{
35 return;
36 }]]]]
37 )cpp");
38
39 EXPECT_UNAVAILABLE(R"cpp(
40 // Not a definition
41 vo^i[[d^ ^f]]^oo();
42
43 [[vo^id ]]foo[[()]] {[[
44 [[(void)(5+3);
45 return;]]
46 }]]
47
48 // Definition with no body.
49 class Bar { Bar() = def^ault; };
50 )cpp");
51}
52
53TEST_F(DefineInlineTest, NoForwardDecl) {
54 Header = "void bar();";
55 EXPECT_UNAVAILABLE(R"cpp(
56 void bar() {
57 return;
58 }
59 // FIXME: Generate a decl in the header.
60 void fo^o() {
61 return;
62 })cpp");
63}
64
65TEST_F(DefineInlineTest, ReferencedDecls) {
66 EXPECT_AVAILABLE(R"cpp(
67 void bar();
68 void foo(int test);
69
70 void fo^o(int baz) {
71 int x = 10;
72 bar();
73 })cpp");
74
75 // Internal symbol usage.
76 Header = "void foo(int test);";
77 EXPECT_UNAVAILABLE(R"cpp(
78 void bar();
79 void fo^o(int baz) {
80 int x = 10;
81 bar();
82 })cpp");
83
84 // Becomes available after making symbol visible.
85 Header = "void bar();" + Header;
86 EXPECT_AVAILABLE(R"cpp(
87 void fo^o(int baz) {
88 int x = 10;
89 bar();
90 })cpp");
91
92 // FIXME: Move declaration below bar to make it visible.
93 Header.clear();
94 EXPECT_UNAVAILABLE(R"cpp(
95 void foo();
96 void bar();
97
98 void fo^o() {
99 bar();
100 })cpp");
101
102 // Order doesn't matter within a class.
103 EXPECT_AVAILABLE(R"cpp(
104 class Bar {
105 void foo();
106 void bar();
107 };
108
109 void Bar::fo^o() {
110 bar();
111 })cpp");
112
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(
117 #include "a.h"
118 void fo^o(int baz) {
119 int x = 10;
120 bar();
121 })cpp");
122}
123
124TEST_F(DefineInlineTest, TemplateSpec) {
125 EXPECT_UNAVAILABLE(R"cpp(
126 template <typename T> void foo();
127 template<> void foo<char>();
128
129 template<> void f^oo<int>() {
130 })cpp");
131 EXPECT_UNAVAILABLE(R"cpp(
132 template <typename T> void foo();
133
134 template<> void f^oo<int>() {
135 })cpp");
136 EXPECT_UNAVAILABLE(R"cpp(
137 template <typename T> struct Foo { void foo(); };
138
139 template <typename T> void Foo<T>::f^oo() {
140 })cpp");
141 EXPECT_AVAILABLE(R"cpp(
142 template <typename T> void foo();
143 void bar();
144 template <> void foo<int>();
145
146 template<> void f^oo<int>() {
147 bar();
148 })cpp");
149 EXPECT_UNAVAILABLE(R"cpp(
150 namespace bar {
151 template <typename T> void f^oo() {}
152 template void foo<int>();
153 })cpp");
154}
155
156TEST_F(DefineInlineTest, CheckForCanonDecl) {
157 EXPECT_UNAVAILABLE(R"cpp(
158 void foo();
159
160 void bar() {}
161 void f^oo() {
162 // This bar normally refers to the definition just above, but it is not
163 // visible from the forward declaration of foo.
164 bar();
165 })cpp");
166 // Make it available with a forward decl.
167 EXPECT_AVAILABLE(R"cpp(
168 void bar();
169 void foo();
170
171 void bar() {}
172 void f^oo() {
173 bar();
174 })cpp");
175}
176
177TEST_F(DefineInlineTest, UsingShadowDecls) {
178 EXPECT_UNAVAILABLE(R"cpp(
179 namespace ns1 { void foo(int); }
180 namespace ns2 { void foo(int*); }
181 template <typename T>
182 void bar();
183
184 using ns1::foo;
185 using ns2::foo;
186
187 template <typename T>
188 void b^ar() {
189 foo(T());
190 })cpp");
191}
192
193TEST_F(DefineInlineTest, TransformNestedNamespaces) {
194 auto *Test = R"cpp(
195 namespace a {
196 void bar();
197 namespace b {
198 void baz();
199 namespace c {
200 void aux();
201 }
202 }
203 }
204
205 void foo();
206 using namespace a;
207 using namespace b;
208 using namespace c;
209 void f^oo() {
210 bar();
211 a::bar();
212
213 baz();
214 b::baz();
215 a::b::baz();
216
217 aux();
218 c::aux();
219 b::c::aux();
220 a::b::c::aux();
221 })cpp";
222 auto *Expected = R"cpp(
223 namespace a {
224 void bar();
225 namespace b {
226 void baz();
227 namespace c {
228 void aux();
229 }
230 }
231 }
232
233 void foo(){
234 a::bar();
235 a::bar();
236
237 a::b::baz();
238 a::b::baz();
239 a::b::baz();
240
241 a::b::c::aux();
242 a::b::c::aux();
243 a::b::c::aux();
244 a::b::c::aux();
245 }
246 using namespace a;
247 using namespace b;
248 using namespace c;
249 )cpp";
250 EXPECT_EQ(apply(Test), Expected);
251}
252
253TEST_F(DefineInlineTest, TransformUsings) {
254 auto *Test = R"cpp(
255 namespace a { namespace b { namespace c { void aux(); } } }
256
257 void foo();
258 void f^oo() {
259 using namespace a;
260 using namespace b;
261 using namespace c;
262 using c::aux;
263 namespace d = c;
264 })cpp";
265 auto *Expected = R"cpp(
266 namespace a { namespace b { namespace c { void aux(); } } }
267
268 void foo(){
269 using namespace a;
270 using namespace a::b;
271 using namespace a::b::c;
272 using a::b::c::aux;
273 namespace d = a::b::c;
274 }
275 )cpp";
276 EXPECT_EQ(apply(Test), Expected);
277}
278
279TEST_F(DefineInlineTest, TransformDecls) {
280 auto *Test = R"cpp(
281 void foo();
282 void f^oo() {
283 class Foo {
284 public:
285 void foo();
286 int x;
287 };
288
289 enum En { Zero, One };
290 En x = Zero;
291
292 enum class EnClass { Zero, One };
293 EnClass y = EnClass::Zero;
294 })cpp";
295 auto *Expected = R"cpp(
296 void foo(){
297 class Foo {
298 public:
299 void foo();
300 int x;
301 };
302
303 enum En { Zero, One };
304 En x = Zero;
305
306 enum class EnClass { Zero, One };
307 EnClass y = EnClass::Zero;
308 }
309 )cpp";
310 EXPECT_EQ(apply(Test), Expected);
311}
312
313TEST_F(DefineInlineTest, TransformTemplDecls) {
314 auto *Test = R"cpp(
315 namespace a {
316 template <typename T> class Bar {
317 public:
318 void bar();
319 };
320 template <typename T> T bar;
321 template <typename T> void aux() {}
322 }
323
324 void foo();
325
326 using namespace a;
327 void f^oo() {
328 bar<Bar<int>>.bar();
329 aux<Bar<int>>();
330 })cpp";
331 auto *Expected = R"cpp(
332 namespace a {
333 template <typename T> class Bar {
334 public:
335 void bar();
336 };
337 template <typename T> T bar;
338 template <typename T> void aux() {}
339 }
340
341 void foo(){
342 a::bar<a::Bar<int>>.bar();
343 a::aux<a::Bar<int>>();
344 }
345
346 using namespace a;
347 )cpp";
348 EXPECT_EQ(apply(Test), Expected);
349}
350
351TEST_F(DefineInlineTest, TransformMembers) {
352 auto *Test = R"cpp(
353 class Foo {
354 void foo();
355 };
356
357 void Foo::f^oo() {
358 return;
359 })cpp";
360 auto *Expected = R"cpp(
361 class Foo {
362 void foo(){
363 return;
364 }
365 };
366
367 )cpp";
368 EXPECT_EQ(apply(Test), Expected);
369
370 ExtraFiles["a.h"] = R"cpp(
371 class Foo {
372 void foo();
373 };)cpp";
374
375 llvm::StringMap<std::string> EditedFiles;
376 Test = R"cpp(
377 #include "a.h"
378 void Foo::f^oo() {
379 return;
380 })cpp";
381 Expected = R"cpp(
382 #include "a.h"
383 )cpp";
384 EXPECT_EQ(apply(Test, &EditedFiles), Expected);
385
386 Expected = R"cpp(
387 class Foo {
388 void foo(){
389 return;
390 }
391 };)cpp";
392 EXPECT_THAT(EditedFiles,
393 ElementsAre(FileWithContents(testPath("a.h"), Expected)));
394}
395
396TEST_F(DefineInlineTest, TransformDependentTypes) {
397 auto *Test = R"cpp(
398 namespace a {
399 template <typename T> class Bar {};
400 }
401
402 template <typename T>
403 void foo();
404
405 using namespace a;
406 template <typename T>
407 void f^oo() {
408 Bar<T> B;
409 Bar<Bar<T>> q;
410 })cpp";
411 auto *Expected = R"cpp(
412 namespace a {
413 template <typename T> class Bar {};
414 }
415
416 template <typename T>
417 void foo(){
418 a::Bar<T> B;
419 a::Bar<a::Bar<T>> q;
420 }
421
422 using namespace a;
423 )cpp";
424
425 EXPECT_EQ(apply(Test), Expected);
426}
427
428TEST_F(DefineInlineTest, TransformFunctionTempls) {
429 // Check we select correct specialization decl.
430 std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {
431 {R"cpp(
432 template <typename T>
433 void foo(T p);
434
435 template <>
436 void foo<int>(int p);
437
438 template <>
439 void foo<char>(char p);
440
441 template <>
442 void fo^o<int>(int p) {
443 return;
444 })cpp",
445 R"cpp(
446 template <typename T>
447 void foo(T p);
448
449 template <>
450 void foo<int>(int p){
451 return;
452 }
453
454 template <>
455 void foo<char>(char p);
456
457 )cpp"},
458 {// Make sure we are not selecting the first specialization all the time.
459 R"cpp(
460 template <typename T>
461 void foo(T p);
462
463 template <>
464 void foo<int>(int p);
465
466 template <>
467 void foo<char>(char p);
468
469 template <>
470 void fo^o<char>(char p) {
471 return;
472 })cpp",
473 R"cpp(
474 template <typename T>
475 void foo(T p);
476
477 template <>
478 void foo<int>(int p);
479
480 template <>
481 void foo<char>(char p){
482 return;
483 }
484
485 )cpp"},
486 {R"cpp(
487 template <typename T>
488 void foo(T p);
489
490 template <>
491 void foo<int>(int p);
492
493 template <typename T>
494 void fo^o(T p) {
495 return;
496 })cpp",
497 R"cpp(
498 template <typename T>
499 void foo(T p){
500 return;
501 }
502
503 template <>
504 void foo<int>(int p);
505
506 )cpp"},
507 };
508 for (const auto &Case : Cases)
509 EXPECT_EQ(apply(Case.first), Case.second) << Case.first;
510}
511
512TEST_F(DefineInlineTest, TransformTypeLocs) {
513 auto *Test = R"cpp(
514 namespace a {
515 template <typename T> class Bar {
516 public:
517 template <typename Q> class Baz {};
518 };
519 class Foo{};
520 }
521
522 void foo();
523
524 using namespace a;
525 void f^oo() {
526 Bar<int> B;
527 Foo foo;
528 a::Bar<Bar<int>>::Baz<Bar<int>> q;
529 })cpp";
530 auto *Expected = R"cpp(
531 namespace a {
532 template <typename T> class Bar {
533 public:
534 template <typename Q> class Baz {};
535 };
536 class Foo{};
537 }
538
539 void foo(){
540 a::Bar<int> B;
541 a::Foo foo;
542 a::Bar<a::Bar<int>>::Baz<a::Bar<int>> q;
543 }
544
545 using namespace a;
546 )cpp";
547 EXPECT_EQ(apply(Test), Expected);
548}
549
550TEST_F(DefineInlineTest, TransformDeclRefs) {
551 auto *Test = R"cpp(
552 namespace a {
553 template <typename T> class Bar {
554 public:
555 void foo();
556 static void bar();
557 int x;
558 static int y;
559 };
560 void bar();
561 void test();
562 }
563
564 void foo();
565 using namespace a;
566 void f^oo() {
567 a::Bar<int> B;
568 B.foo();
569 a::bar();
570 Bar<Bar<int>>::bar();
571 a::Bar<int>::bar();
572 B.x = Bar<int>::y;
573 Bar<int>::y = 3;
574 bar();
575 a::test();
576 })cpp";
577 auto *Expected = R"cpp(
578 namespace a {
579 template <typename T> class Bar {
580 public:
581 void foo();
582 static void bar();
583 int x;
584 static int y;
585 };
586 void bar();
587 void test();
588 }
589
590 void foo(){
591 a::Bar<int> B;
592 B.foo();
593 a::bar();
594 a::Bar<a::Bar<int>>::bar();
595 a::Bar<int>::bar();
596 B.x = a::Bar<int>::y;
597 a::Bar<int>::y = 3;
598 a::bar();
599 a::test();
600 }
601 using namespace a;
602 )cpp";
603 EXPECT_EQ(apply(Test), Expected);
604}
605
606TEST_F(DefineInlineTest, StaticMembers) {
607 auto *Test = R"cpp(
608 namespace ns { class X { static void foo(); void bar(); }; }
609 void ns::X::b^ar() {
610 foo();
611 })cpp";
612 auto *Expected = R"cpp(
613 namespace ns { class X { static void foo(); void bar(){
614 foo();
615 } }; }
616 )cpp";
617 EXPECT_EQ(apply(Test), Expected);
618}
619
620TEST_F(DefineInlineTest, TransformParamNames) {
621 std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {
622 {R"cpp(
623 void foo(int, bool b, int T\
624est);
625 void ^foo(int f, bool x, int z) {})cpp",
626 R"cpp(
627 void foo(int f, bool x, int z){}
628 )cpp"},
629 {R"cpp(
630 #define PARAM int Z
631 void foo(PARAM);
632
633 void ^foo(int X) {})cpp",
634 "fail: Cant rename parameter inside macro body."},
635 {R"cpp(
636 #define TYPE int
637 #define PARAM TYPE Z
638 #define BODY(x) 5 * (x) + 2
639 template <int P>
640 void foo(PARAM, TYPE Q, TYPE, TYPE W = BODY(P));
641 template <int x>
642 void ^foo(int Z, int b, int c, int d) {})cpp",
643 R"cpp(
644 #define TYPE int
645 #define PARAM TYPE Z
646 #define BODY(x) 5 * (x) + 2
647 template <int x>
648 void foo(PARAM, TYPE b, TYPE c, TYPE d = BODY(x)){}
649 )cpp"},
650 };
651 for (const auto &Case : Cases)
652 EXPECT_EQ(apply(Case.first), Case.second) << Case.first;
653}
654
655TEST_F(DefineInlineTest, TransformTemplParamNames) {
656 auto *Test = R"cpp(
657 struct Foo {
658 struct Bar {
659 template <class, class X,
660 template<typename> class, template<typename> class Y,
661 int, int Z>
662 void foo(X, Y<X>, int W = 5 * Z + 2);
663 };
664 };
665
666 template <class T, class U,
667 template<typename> class V, template<typename> class W,
668 int X, int Y>
669 void Foo::Bar::f^oo(U, W<U>, int Q) {})cpp";
670 auto *Expected = R"cpp(
671 struct Foo {
672 struct Bar {
673 template <class T, class U,
674 template<typename> class V, template<typename> class W,
675 int X, int Y>
676 void foo(U, W<U>, int Q = 5 * Y + 2){}
677 };
678 };
679
680 )cpp";
681 EXPECT_EQ(apply(Test), Expected);
682}
683
684TEST_F(DefineInlineTest, TransformInlineNamespaces) {
685 auto *Test = R"cpp(
686 namespace a { inline namespace b { namespace { struct Foo{}; } } }
687 void foo();
688
689 using namespace a;
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;}
694
695 using namespace a;
696 )cpp";
697 EXPECT_EQ(apply(Test), Expected);
698}
699
700TEST_F(DefineInlineTest, TokensBeforeSemicolon) {
701 std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {
702 {R"cpp(
703 void foo() /*Comment -_-*/ /*Com 2*/ ;
704 void fo^o() { return ; })cpp",
705 R"cpp(
706 void foo() /*Comment -_-*/ /*Com 2*/ { return ; }
707 )cpp"},
708
709 {R"cpp(
710 void foo();
711 void fo^o() { return ; })cpp",
712 R"cpp(
713 void foo(){ return ; }
714 )cpp"},
715
716 {R"cpp(
717 #define SEMI ;
718 void foo() SEMI
719 void fo^o() { return ; })cpp",
720 "fail: Couldn't find semicolon for target declaration."},
721 };
722 for (const auto &Case : Cases)
723 EXPECT_EQ(apply(Case.first), Case.second) << Case.first;
724}
725
726TEST_F(DefineInlineTest, HandleMacros) {
727 EXPECT_UNAVAILABLE(R"cpp(
728 #define BODY { return; }
729 void foo();
730 void f^oo()BODY)cpp");
731
732 EXPECT_UNAVAILABLE(R"cpp(
733 #define BODY void foo(){ return; }
734 void foo();
735 [[BODY]])cpp");
736
737 std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {
738 // We don't qualify declarations coming from macros.
739 {R"cpp(
740 #define BODY Foo
741 namespace a { class Foo{}; }
742 void foo();
743 using namespace a;
744 void f^oo(){BODY();})cpp",
745 R"cpp(
746 #define BODY Foo
747 namespace a { class Foo{}; }
748 void foo(){BODY();}
749 using namespace a;
750 )cpp"},
751
752 // Macro is not visible at declaration location, but we proceed.
753 {R"cpp(
754 void foo();
755 #define BODY return;
756 void f^oo(){BODY})cpp",
757 R"cpp(
758 void foo(){BODY}
759 #define BODY return;
760 )cpp"},
761
762 {R"cpp(
763 #define TARGET void foo()
764 TARGET;
765 void f^oo(){ return; })cpp",
766 R"cpp(
767 #define TARGET void foo()
768 TARGET{ return; }
769 )cpp"},
770
771 {R"cpp(
772 #define TARGET foo
773 void TARGET();
774 void f^oo(){ return; })cpp",
775 R"cpp(
776 #define TARGET foo
777 void TARGET(){ return; }
778 )cpp"},
779 };
780 for (const auto &Case : Cases)
781 EXPECT_EQ(apply(Case.first), Case.second) << Case.first;
782}
783
784TEST_F(DefineInlineTest, DropCommonNameSpecifiers) {
785 struct {
786 llvm::StringRef Test;
787 llvm::StringRef Expected;
788 } Cases[] = {
789 {.Test: R"cpp(
790 namespace a { namespace b { void aux(); } }
791 namespace ns1 {
792 void foo();
793 namespace qq { void test(); }
794 namespace ns2 {
795 void bar();
796 namespace ns3 { void baz(); }
797 }
798 }
799
800 using namespace a;
801 using namespace a::b;
802 using namespace ns1::qq;
803 void ns1::ns2::ns3::b^az() {
804 foo();
805 bar();
806 baz();
807 ns1::ns2::ns3::baz();
808 aux();
809 test();
810 })cpp",
811 .Expected: R"cpp(
812 namespace a { namespace b { void aux(); } }
813 namespace ns1 {
814 void foo();
815 namespace qq { void test(); }
816 namespace ns2 {
817 void bar();
818 namespace ns3 { void baz(){
819 foo();
820 bar();
821 baz();
822 ns1::ns2::ns3::baz();
823 a::b::aux();
824 qq::test();
825 } }
826 }
827 }
828
829 using namespace a;
830 using namespace a::b;
831 using namespace ns1::qq;
832 )cpp"},
833 {.Test: R"cpp(
834 namespace ns1 {
835 namespace qq { struct Foo { struct Bar {}; }; using B = Foo::Bar; }
836 namespace ns2 { void baz(); }
837 }
838
839 using namespace ns1::qq;
840 void ns1::ns2::b^az() { Foo f; B b; })cpp",
841 .Expected: R"cpp(
842 namespace ns1 {
843 namespace qq { struct Foo { struct Bar {}; }; using B = Foo::Bar; }
844 namespace ns2 { void baz(){ qq::Foo f; qq::B b; } }
845 }
846
847 using namespace ns1::qq;
848 )cpp"},
849 {.Test: R"cpp(
850 namespace ns1 {
851 namespace 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>;
855 }
856 namespace ns2 { void baz(); }
857 }
858
859 using namespace ns1::qq;
860 void ns1::ns2::b^az() { B<int, bool> b; })cpp",
861 .Expected: R"cpp(
862 namespace ns1 {
863 namespace qq {
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>;
867 }
868 namespace ns2 { void baz(){ qq::B<int, bool> b; } }
869 }
870
871 using namespace ns1::qq;
872 )cpp"},
873 };
874 for (const auto &Case : Cases)
875 EXPECT_EQ(apply(Case.Test), Case.Expected) << Case.Test;
876}
877
878TEST_F(DefineInlineTest, QualifyWithUsingDirectives) {
879 llvm::StringRef Test = R"cpp(
880 namespace a {
881 void bar();
882 namespace b { struct Foo{}; void aux(); }
883 namespace c { void cux(); }
884 }
885 using namespace a;
886 using X = b::Foo;
887 void foo();
888
889 using namespace b;
890 using namespace c;
891 void ^foo() {
892 cux();
893 bar();
894 X x;
895 aux();
896 using namespace c;
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.
899 cux();
900 })cpp";
901 llvm::StringRef Expected = R"cpp(
902 namespace a {
903 void bar();
904 namespace b { struct Foo{}; void aux(); }
905 namespace c { void cux(); }
906 }
907 using namespace a;
908 using X = b::Foo;
909 void foo(){
910 c::cux();
911 bar();
912 X x;
913 b::aux();
914 using namespace c;
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.
917 c::cux();
918 }
919
920 using namespace b;
921 using namespace c;
922 )cpp";
923 EXPECT_EQ(apply(Test), Expected) << Test;
924}
925
926TEST_F(DefineInlineTest, AddInline) {
927 llvm::StringMap<std::string> EditedFiles;
928 ExtraFiles["a.h"] = "void foo();";
929 apply(MarkedCode: R"cpp(#include "a.h"
930 void fo^o() {})cpp",
931 EditedFiles: &EditedFiles);
932 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
933 testPath("a.h"), "inline void foo(){}")));
934
935 // Check we put inline before cv-qualifiers.
936 ExtraFiles["a.h"] = "const int foo();";
937 apply(MarkedCode: R"cpp(#include "a.h"
938 const int fo^o() {})cpp",
939 EditedFiles: &EditedFiles);
940 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
941 testPath("a.h"), "inline const int foo(){}")));
942
943 // No double inline.
944 ExtraFiles["a.h"] = "inline void foo();";
945 apply(MarkedCode: R"cpp(#include "a.h"
946 inline void fo^o() {})cpp",
947 EditedFiles: &EditedFiles);
948 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
949 testPath("a.h"), "inline void foo(){}")));
950
951 // Constexprs don't need "inline".
952 ExtraFiles["a.h"] = "constexpr void foo();";
953 apply(MarkedCode: R"cpp(#include "a.h"
954 constexpr void fo^o() {})cpp",
955 EditedFiles: &EditedFiles);
956 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
957 testPath("a.h"), "constexpr void foo(){}")));
958
959 // Class members don't need "inline".
960 ExtraFiles["a.h"] = "struct Foo { void foo(); };";
961 apply(MarkedCode: R"cpp(#include "a.h"
962 void Foo::fo^o() {})cpp",
963 EditedFiles: &EditedFiles);
964 EXPECT_THAT(EditedFiles,
965 testing::ElementsAre(FileWithContents(
966 testPath("a.h"), "struct Foo { void foo(){} };")));
967
968 // Function template doesn't need to be "inline"d.
969 ExtraFiles["a.h"] = "template <typename T> void foo();";
970 apply(MarkedCode: R"cpp(#include "a.h"
971 template <typename T>
972 void fo^o() {})cpp",
973 EditedFiles: &EditedFiles);
974 EXPECT_THAT(EditedFiles,
975 testing::ElementsAre(FileWithContents(
976 testPath("a.h"), "template <typename T> void foo(){}")));
977
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(MarkedCode: R"cpp(#include "a.h"
983 template <>
984 void fo^o<int>() {})cpp",
985 EditedFiles: &EditedFiles);
986 EXPECT_THAT(EditedFiles,
987 testing::ElementsAre(FileWithContents(testPath("a.h"),
988 R"cpp(
989 template <typename T> void foo();
990 template <> inline void foo<int>(){})cpp")));
991}
992
993} // namespace
994} // namespace clangd
995} // namespace clang
996

source code of clang-tools-extra/clangd/unittests/tweaks/DefineInlineTests.cpp