[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clangd / unittests / tweaks / DefineOutlineTests.cpp
blobd2d2ae9e7bb6103fb6eda9e099d644be60466a24
1 //===-- DefineOutline.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 //===----------------------------------------------------------------------===//
9 #include "TestFS.h"
10 #include "TweakTesting.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
14 namespace clang {
15 namespace clangd {
16 namespace {
18 TWEAK_TEST(DefineOutline);
20 TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) {
21 FileName = "Test.cpp";
22 // Not available for free function unless in a header file.
23 EXPECT_UNAVAILABLE(R"cpp(
24 [[void [[f^o^o]]() [[{
25 return;
26 }]]]])cpp");
28 // Available in soure file.
29 EXPECT_AVAILABLE(R"cpp(
30 struct Foo {
31 void f^oo() {}
33 )cpp");
35 // Available within named namespace in source file.
36 EXPECT_AVAILABLE(R"cpp(
37 namespace N {
38 struct Foo {
39 void f^oo() {}
41 } // namespace N
42 )cpp");
44 // Available within anonymous namespace in source file.
45 EXPECT_AVAILABLE(R"cpp(
46 namespace {
47 struct Foo {
48 void f^oo() {}
50 } // namespace
51 )cpp");
53 // Not available for out-of-line method.
54 EXPECT_UNAVAILABLE(R"cpp(
55 class Bar {
56 void baz();
59 [[void [[Bar::[[b^a^z]]]]() [[{
60 return;
61 }]]]])cpp");
63 FileName = "Test.hpp";
64 // Not available unless function name or fully body is selected.
65 EXPECT_UNAVAILABLE(R"cpp(
66 // Not a definition
67 vo^i[[d^ ^f]]^oo();
69 [[vo^id ]]foo[[()]] {[[
70 [[(void)(5+3);
71 return;]]
72 }]])cpp");
74 // Available even if there are no implementation files.
75 EXPECT_AVAILABLE(R"cpp(
76 [[void [[f^o^o]]() [[{
77 return;
78 }]]]])cpp");
80 // Not available for out-of-line methods.
81 EXPECT_UNAVAILABLE(R"cpp(
82 class Bar {
83 void baz();
86 [[void [[Bar::[[b^a^z]]]]() [[{
87 return;
88 }]]]])cpp");
90 // Basic check for function body and signature.
91 EXPECT_AVAILABLE(R"cpp(
92 class Bar {
93 [[void [[f^o^o^]]() [[{ return; }]]]]
96 void foo();
97 [[void [[f^o^o]]() [[{
98 return;
99 }]]]])cpp");
101 // Not available on defaulted/deleted members.
102 EXPECT_UNAVAILABLE(R"cpp(
103 class Foo {
104 Fo^o() = default;
105 F^oo(const Foo&) = delete;
106 };)cpp");
108 // Not available within templated classes with unnamed parameters, as it is
109 // hard to spell class name out-of-line in such cases.
110 EXPECT_UNAVAILABLE(R"cpp(
111 template <typename> struct Foo { void fo^o(){} };
112 )cpp");
114 // Not available on function template specializations and free function
115 // templates.
116 EXPECT_UNAVAILABLE(R"cpp(
117 template <typename T> void fo^o() {}
118 template <> void fo^o<int>() {}
119 )cpp");
121 // Not available on member function templates with unnamed template
122 // parameters.
123 EXPECT_UNAVAILABLE(R"cpp(
124 struct Foo { template <typename> void ba^r() {} };
125 )cpp");
127 // Not available on methods of unnamed classes.
128 EXPECT_UNAVAILABLE(R"cpp(
129 struct Foo {
130 struct { void b^ar() {} } Bar;
132 )cpp");
134 // Not available on methods of named classes with unnamed parent in parents
135 // nesting.
136 EXPECT_UNAVAILABLE(R"cpp(
137 struct Foo {
138 struct {
139 struct Bar { void b^ar() {} };
140 } Baz;
142 )cpp");
144 // Not available on definitions in header file within unnamed namespaces
145 EXPECT_UNAVAILABLE(R"cpp(
146 namespace {
147 struct Foo {
148 void f^oo() {}
150 } // namespace
151 )cpp");
154 TEST_F(DefineOutlineTest, FailsWithoutSource) {
155 FileName = "Test.hpp";
156 llvm::StringRef Test = "void fo^o() { return; }";
157 llvm::StringRef Expected =
158 "fail: Couldn't find a suitable implementation file.";
159 EXPECT_EQ(apply(Test), Expected);
162 TEST_F(DefineOutlineTest, ApplyTest) {
163 ExtraFiles["Test.cpp"] = "";
164 FileName = "Test.hpp";
166 struct {
167 llvm::StringRef Test;
168 llvm::StringRef ExpectedHeader;
169 llvm::StringRef ExpectedSource;
170 } Cases[] = {
171 // Simple check
173 "void fo^o() { return; }",
174 "void foo() ;",
175 "void foo() { return; }",
177 // Inline specifier.
179 "inline void fo^o() { return; }",
180 " void foo() ;",
181 " void foo() { return; }",
183 // Default args.
185 "void fo^o(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) {}",
186 "void foo(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) ;",
187 "void foo(int x, int y , int , int (*foo)(int) ) {}",
190 "struct Bar{Bar();}; void fo^o(Bar x = {}) {}",
191 "struct Bar{Bar();}; void foo(Bar x = {}) ;",
192 "void foo(Bar x ) {}",
194 // Constructors
196 R"cpp(
197 class Foo {public: Foo(); Foo(int);};
198 class Bar {
199 Ba^r() {}
200 Bar(int x) : f1(x) {}
201 Foo f1;
202 Foo f2 = 2;
203 };)cpp",
204 R"cpp(
205 class Foo {public: Foo(); Foo(int);};
206 class Bar {
207 Bar() ;
208 Bar(int x) : f1(x) {}
209 Foo f1;
210 Foo f2 = 2;
211 };)cpp",
212 "Bar::Bar() {}\n",
214 // Ctor with initializer.
216 R"cpp(
217 class Foo {public: Foo(); Foo(int);};
218 class Bar {
219 Bar() {}
220 B^ar(int x) : f1(x), f2(3) {}
221 Foo f1;
222 Foo f2 = 2;
223 };)cpp",
224 R"cpp(
225 class Foo {public: Foo(); Foo(int);};
226 class Bar {
227 Bar() {}
228 Bar(int x) ;
229 Foo f1;
230 Foo f2 = 2;
231 };)cpp",
232 "Bar::Bar(int x) : f1(x), f2(3) {}\n",
234 // Ctor initializer with attribute.
236 R"cpp(
237 template <typename T> class Foo {
238 F^oo(T z) __attribute__((weak)) : bar(2){}
239 int bar;
240 };)cpp",
241 R"cpp(
242 template <typename T> class Foo {
243 Foo(T z) __attribute__((weak)) ;
244 int bar;
245 };template <typename T>
246 inline Foo<T>::Foo(T z) __attribute__((weak)) : bar(2){}
247 )cpp",
248 ""},
249 // Virt specifiers.
251 R"cpp(
252 struct A {
253 virtual void f^oo() {}
254 };)cpp",
255 R"cpp(
256 struct A {
257 virtual void foo() ;
258 };)cpp",
259 " void A::foo() {}\n",
262 R"cpp(
263 struct A {
264 virtual virtual void virtual f^oo() {}
265 };)cpp",
266 R"cpp(
267 struct A {
268 virtual virtual void virtual foo() ;
269 };)cpp",
270 " void A::foo() {}\n",
273 R"cpp(
274 struct A {
275 virtual void foo() = 0;
277 struct B : A {
278 void fo^o() override {}
279 };)cpp",
280 R"cpp(
281 struct A {
282 virtual void foo() = 0;
284 struct B : A {
285 void foo() override ;
286 };)cpp",
287 "void B::foo() {}\n",
290 R"cpp(
291 struct A {
292 virtual void foo() = 0;
294 struct B : A {
295 void fo^o() final {}
296 };)cpp",
297 R"cpp(
298 struct A {
299 virtual void foo() = 0;
301 struct B : A {
302 void foo() final ;
303 };)cpp",
304 "void B::foo() {}\n",
307 R"cpp(
308 struct A {
309 virtual void foo() = 0;
311 struct B : A {
312 void fo^o() final override {}
313 };)cpp",
314 R"cpp(
315 struct A {
316 virtual void foo() = 0;
318 struct B : A {
319 void foo() final override ;
320 };)cpp",
321 "void B::foo() {}\n",
324 R"cpp(
325 struct A {
326 static void fo^o() {}
327 };)cpp",
328 R"cpp(
329 struct A {
330 static void foo() ;
331 };)cpp",
332 " void A::foo() {}\n",
335 R"cpp(
336 struct A {
337 static static void fo^o() {}
338 };)cpp",
339 R"cpp(
340 struct A {
341 static static void foo() ;
342 };)cpp",
343 " void A::foo() {}\n",
346 R"cpp(
347 struct Foo {
348 explicit Fo^o(int) {}
349 };)cpp",
350 R"cpp(
351 struct Foo {
352 explicit Foo(int) ;
353 };)cpp",
354 " Foo::Foo(int) {}\n",
357 R"cpp(
358 struct Foo {
359 explicit explicit Fo^o(int) {}
360 };)cpp",
361 R"cpp(
362 struct Foo {
363 explicit explicit Foo(int) ;
364 };)cpp",
365 " Foo::Foo(int) {}\n",
368 R"cpp(
369 struct A {
370 inline void f^oo(int) {}
371 };)cpp",
372 R"cpp(
373 struct A {
374 void foo(int) ;
375 };)cpp",
376 " void A::foo(int) {}\n",
378 // Complex class template
380 R"cpp(
381 template <typename T, typename ...U> struct O1 {
382 template <class V, int A> struct O2 {
383 enum E { E1, E2 };
384 struct I {
385 E f^oo(T, U..., V, E) { return E1; }
388 };)cpp",
389 R"cpp(
390 template <typename T, typename ...U> struct O1 {
391 template <class V, int A> struct O2 {
392 enum E { E1, E2 };
393 struct I {
394 E foo(T, U..., V, E) ;
397 };template <typename T, typename ...U>
398 template <class V, int A>
399 inline typename O1<T, U...>::template O2<V, A>::E O1<T, U...>::template O2<V, A>::I::foo(T, U..., V, E) { return E1; }
400 )cpp",
401 ""},
402 // Destructors
404 "class A { ~A^(){} };",
405 "class A { ~A(); };",
406 "A::~A(){} ",
409 // Member template
411 R"cpp(
412 struct Foo {
413 template <typename T, bool B = true>
414 T ^bar() { return {}; }
415 };)cpp",
416 R"cpp(
417 struct Foo {
418 template <typename T, bool B = true>
419 T bar() ;
420 };template <typename T, bool B>
421 inline T Foo::bar() { return {}; }
422 )cpp",
423 ""},
425 // Class template with member template
427 R"cpp(
428 template <typename T> struct Foo {
429 template <typename U> T ^bar(const T& t, const U& u) { return {}; }
430 };)cpp",
431 R"cpp(
432 template <typename T> struct Foo {
433 template <typename U> T bar(const T& t, const U& u) ;
434 };template <typename T>
435 template <typename U>
436 inline T Foo<T>::bar(const T& t, const U& u) { return {}; }
437 )cpp",
438 ""},
440 for (const auto &Case : Cases) {
441 SCOPED_TRACE(Case.Test);
442 llvm::StringMap<std::string> EditedFiles;
443 EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader);
444 if (Case.ExpectedSource.empty()) {
445 EXPECT_TRUE(EditedFiles.empty());
446 } else {
447 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
448 testPath("Test.cpp"), Case.ExpectedSource)));
453 TEST_F(DefineOutlineTest, InCppFile) {
454 FileName = "Test.cpp";
456 struct {
457 llvm::StringRef Test;
458 llvm::StringRef ExpectedSource;
459 } Cases[] = {
461 R"cpp(
462 namespace foo {
463 namespace {
464 struct Foo { void ba^r() {} };
465 struct Bar { void foo(); };
466 void Bar::foo() {}
469 )cpp",
470 R"cpp(
471 namespace foo {
472 namespace {
473 struct Foo { void bar() ; };void Foo::bar() {}
474 struct Bar { void foo(); };
475 void Bar::foo() {}
478 )cpp"},
481 for (const auto &Case : Cases) {
482 SCOPED_TRACE(Case.Test);
483 EXPECT_EQ(apply(Case.Test, nullptr), Case.ExpectedSource);
487 TEST_F(DefineOutlineTest, HandleMacros) {
488 llvm::StringMap<std::string> EditedFiles;
489 ExtraFiles["Test.cpp"] = "";
490 FileName = "Test.hpp";
491 ExtraArgs.push_back("-DVIRTUAL=virtual");
492 ExtraArgs.push_back("-DOVER=override");
494 struct {
495 llvm::StringRef Test;
496 llvm::StringRef ExpectedHeader;
497 llvm::StringRef ExpectedSource;
498 } Cases[] = {
499 {R"cpp(
500 #define BODY { return; }
501 void f^oo()BODY)cpp",
502 R"cpp(
503 #define BODY { return; }
504 void foo();)cpp",
505 "void foo()BODY"},
507 {R"cpp(
508 #define BODY return;
509 void f^oo(){BODY})cpp",
510 R"cpp(
511 #define BODY return;
512 void foo();)cpp",
513 "void foo(){BODY}"},
515 {R"cpp(
516 #define TARGET void foo()
517 [[TARGET]]{ return; })cpp",
518 R"cpp(
519 #define TARGET void foo()
520 TARGET;)cpp",
521 "TARGET{ return; }"},
523 {R"cpp(
524 #define TARGET foo
525 void [[TARGET]](){ return; })cpp",
526 R"cpp(
527 #define TARGET foo
528 void TARGET();)cpp",
529 "void TARGET(){ return; }"},
530 {R"cpp(#define VIRT virtual
531 struct A {
532 VIRT void f^oo() {}
533 };)cpp",
534 R"cpp(#define VIRT virtual
535 struct A {
536 VIRT void foo() ;
537 };)cpp",
538 " void A::foo() {}\n"},
539 {R"cpp(
540 struct A {
541 VIRTUAL void f^oo() {}
542 };)cpp",
543 R"cpp(
544 struct A {
545 VIRTUAL void foo() ;
546 };)cpp",
547 " void A::foo() {}\n"},
548 {R"cpp(
549 struct A {
550 virtual void foo() = 0;
552 struct B : A {
553 void fo^o() OVER {}
554 };)cpp",
555 R"cpp(
556 struct A {
557 virtual void foo() = 0;
559 struct B : A {
560 void foo() OVER ;
561 };)cpp",
562 "void B::foo() {}\n"},
563 {R"cpp(#define STUPID_MACRO(X) virtual
564 struct A {
565 STUPID_MACRO(sizeof sizeof int) void f^oo() {}
566 };)cpp",
567 R"cpp(#define STUPID_MACRO(X) virtual
568 struct A {
569 STUPID_MACRO(sizeof sizeof int) void foo() ;
570 };)cpp",
571 " void A::foo() {}\n"},
572 {R"cpp(#define STAT static
573 struct A {
574 STAT void f^oo() {}
575 };)cpp",
576 R"cpp(#define STAT static
577 struct A {
578 STAT void foo() ;
579 };)cpp",
580 " void A::foo() {}\n"},
581 {R"cpp(#define STUPID_MACRO(X) static
582 struct A {
583 STUPID_MACRO(sizeof sizeof int) void f^oo() {}
584 };)cpp",
585 R"cpp(#define STUPID_MACRO(X) static
586 struct A {
587 STUPID_MACRO(sizeof sizeof int) void foo() ;
588 };)cpp",
589 " void A::foo() {}\n"},
591 for (const auto &Case : Cases) {
592 SCOPED_TRACE(Case.Test);
593 EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader);
594 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
595 testPath("Test.cpp"), Case.ExpectedSource)));
599 TEST_F(DefineOutlineTest, QualifyReturnValue) {
600 FileName = "Test.hpp";
601 ExtraFiles["Test.cpp"] = "";
603 struct {
604 llvm::StringRef Test;
605 llvm::StringRef ExpectedHeader;
606 llvm::StringRef ExpectedSource;
607 } Cases[] = {
608 {R"cpp(
609 namespace a { class Foo{}; }
610 using namespace a;
611 Foo fo^o() { return {}; })cpp",
612 R"cpp(
613 namespace a { class Foo{}; }
614 using namespace a;
615 Foo foo() ;)cpp",
616 "a::Foo foo() { return {}; }"},
617 {R"cpp(
618 namespace a {
619 class Foo {
620 class Bar {};
621 Bar fo^o() { return {}; }
623 })cpp",
624 R"cpp(
625 namespace a {
626 class Foo {
627 class Bar {};
628 Bar foo() ;
630 })cpp",
631 "a::Foo::Bar a::Foo::foo() { return {}; }\n"},
632 {R"cpp(
633 class Foo {};
634 Foo fo^o() { return {}; })cpp",
635 R"cpp(
636 class Foo {};
637 Foo foo() ;)cpp",
638 "Foo foo() { return {}; }"},
640 llvm::StringMap<std::string> EditedFiles;
641 for (auto &Case : Cases) {
642 apply(Case.Test, &EditedFiles);
643 EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader);
644 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
645 testPath("Test.cpp"), Case.ExpectedSource)));
649 TEST_F(DefineOutlineTest, QualifyFunctionName) {
650 FileName = "Test.hpp";
651 struct {
652 llvm::StringRef TestHeader;
653 llvm::StringRef TestSource;
654 llvm::StringRef ExpectedHeader;
655 llvm::StringRef ExpectedSource;
656 } Cases[] = {
658 R"cpp(
659 namespace a {
660 namespace b {
661 class Foo {
662 void fo^o() {}
665 })cpp",
667 R"cpp(
668 namespace a {
669 namespace b {
670 class Foo {
671 void foo() ;
674 })cpp",
675 "void a::b::Foo::foo() {}\n",
678 "namespace a { namespace b { void f^oo() {} } }",
679 "namespace a{}",
680 "namespace a { namespace b { void foo() ; } }",
681 "namespace a{void b::foo() {} }",
684 "namespace a { namespace b { void f^oo() {} } }",
685 "using namespace a;",
686 "namespace a { namespace b { void foo() ; } }",
687 // FIXME: Take using namespace directives in the source file into
688 // account. This can be spelled as b::foo instead.
689 "using namespace a;void a::b::foo() {} ",
692 "namespace a { class A { ~A^(){} }; }",
694 "namespace a { class A { ~A(); }; }",
695 "a::A::~A(){} ",
698 "namespace a { class A { ~A^(){} }; }",
699 "namespace a{}",
700 "namespace a { class A { ~A(); }; }",
701 "namespace a{A::~A(){} }",
704 llvm::StringMap<std::string> EditedFiles;
705 for (auto &Case : Cases) {
706 ExtraFiles["Test.cpp"] = std::string(Case.TestSource);
707 EXPECT_EQ(apply(Case.TestHeader, &EditedFiles), Case.ExpectedHeader);
708 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
709 testPath("Test.cpp"), Case.ExpectedSource)))
710 << Case.TestHeader;
714 TEST_F(DefineOutlineTest, FailsMacroSpecifier) {
715 FileName = "Test.hpp";
716 ExtraFiles["Test.cpp"] = "";
717 ExtraArgs.push_back("-DFINALOVER=final override");
719 std::pair<StringRef, StringRef> Cases[] = {
721 R"cpp(
722 #define VIRT virtual void
723 struct A {
724 VIRT fo^o() {}
725 };)cpp",
726 "fail: define outline: couldn't remove `virtual` keyword."},
728 R"cpp(
729 #define OVERFINAL final override
730 struct A {
731 virtual void foo() {}
733 struct B : A {
734 void fo^o() OVERFINAL {}
735 };)cpp",
736 "fail: define outline: Can't move out of line as function has a "
737 "macro `override` specifier.\ndefine outline: Can't move out of line "
738 "as function has a macro `final` specifier."},
740 R"cpp(
741 struct A {
742 virtual void foo() {}
744 struct B : A {
745 void fo^o() FINALOVER {}
746 };)cpp",
747 "fail: define outline: Can't move out of line as function has a "
748 "macro `override` specifier.\ndefine outline: Can't move out of line "
749 "as function has a macro `final` specifier."},
751 for (const auto &Case : Cases) {
752 EXPECT_EQ(apply(Case.first), Case.second);
756 } // namespace
757 } // namespace clangd
758 } // namespace clang