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 | |
14 | using ::testing::ElementsAre; |
15 | |
16 | namespace clang { |
17 | namespace clangd { |
18 | namespace { |
19 | |
20 | TWEAK_TEST(DefineInline); |
21 | |
22 | TEST_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 | |
53 | TEST_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 | |
65 | TEST_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 | |
124 | TEST_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 | |
156 | TEST_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 | |
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> |
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 | |
193 | TEST_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 | |
253 | TEST_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 | |
279 | TEST_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 | |
313 | TEST_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 | |
351 | TEST_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 | |
396 | TEST_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 | |
428 | TEST_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 | |
512 | TEST_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 | |
550 | TEST_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 | |
606 | TEST_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 | |
620 | TEST_F(DefineInlineTest, TransformParamNames) { |
621 | std::pair<llvm::StringRef, llvm::StringRef> Cases[] = { |
622 | {R"cpp( |
623 | void foo(int, bool b, int T\ |
624 | est); |
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 | |
655 | TEST_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 | |
684 | TEST_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 | |
700 | TEST_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 | |
726 | TEST_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 | |
784 | TEST_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 | |
878 | TEST_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 | |
926 | TEST_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 | |