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