[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clangd / unittests / tweaks / DefineOutlineTests.cpp
blob576377a658678ccdf2fb5497eaa0aa6e1f28a349
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 using ::testing::ElementsAre;
16 namespace clang {
17 namespace clangd {
18 namespace {
20 TWEAK_TEST(DefineOutline);
22 TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) {
23 FileName = "Test.cpp";
24 // Not available unless in a header file.
25 EXPECT_UNAVAILABLE(R"cpp(
26 [[void [[f^o^o]]() [[{
27 return;
28 }]]]])cpp");
30 FileName = "Test.hpp";
31 // Not available unless function name or fully body is selected.
32 EXPECT_UNAVAILABLE(R"cpp(
33 // Not a definition
34 vo^i[[d^ ^f]]^oo();
36 [[vo^id ]]foo[[()]] {[[
37 [[(void)(5+3);
38 return;]]
39 }]])cpp");
41 // Available even if there are no implementation files.
42 EXPECT_AVAILABLE(R"cpp(
43 [[void [[f^o^o]]() [[{
44 return;
45 }]]]])cpp");
47 // Not available for out-of-line methods.
48 EXPECT_UNAVAILABLE(R"cpp(
49 class Bar {
50 void baz();
53 [[void [[Bar::[[b^a^z]]]]() [[{
54 return;
55 }]]]])cpp");
57 // Basic check for function body and signature.
58 EXPECT_AVAILABLE(R"cpp(
59 class Bar {
60 [[void [[f^o^o^]]() [[{ return; }]]]]
63 void foo();
64 [[void [[f^o^o]]() [[{
65 return;
66 }]]]])cpp");
68 // Not available on defaulted/deleted members.
69 EXPECT_UNAVAILABLE(R"cpp(
70 class Foo {
71 Fo^o() = default;
72 F^oo(const Foo&) = delete;
73 };)cpp");
75 // Not available within templated classes, as it is hard to spell class name
76 // out-of-line in such cases.
77 EXPECT_UNAVAILABLE(R"cpp(
78 template <typename> struct Foo { void fo^o(){} };
79 )cpp");
81 // Not available on function templates and specializations, as definition must
82 // be visible to all translation units.
83 EXPECT_UNAVAILABLE(R"cpp(
84 template <typename> void fo^o() {};
85 template <> void fo^o<int>() {};
86 )cpp");
88 // Not available on methods of unnamed classes.
89 EXPECT_UNAVAILABLE(R"cpp(
90 struct Foo {
91 struct { void b^ar() {} } Bar;
93 )cpp");
95 // Not available on methods of named classes with unnamed parent in parents
96 // nesting.
97 EXPECT_UNAVAILABLE(R"cpp(
98 struct Foo {
99 struct {
100 struct Bar { void b^ar() {} };
101 } Baz;
103 )cpp");
105 // Not available on definitions within unnamed namespaces
106 EXPECT_UNAVAILABLE(R"cpp(
107 namespace {
108 struct Foo {
109 void f^oo() {}
111 } // namespace
112 )cpp");
115 TEST_F(DefineOutlineTest, FailsWithoutSource) {
116 FileName = "Test.hpp";
117 llvm::StringRef Test = "void fo^o() { return; }";
118 llvm::StringRef Expected =
119 "fail: Couldn't find a suitable implementation file.";
120 EXPECT_EQ(apply(Test), Expected);
123 TEST_F(DefineOutlineTest, ApplyTest) {
124 llvm::StringMap<std::string> EditedFiles;
125 ExtraFiles["Test.cpp"] = "";
126 FileName = "Test.hpp";
128 struct {
129 llvm::StringRef Test;
130 llvm::StringRef ExpectedHeader;
131 llvm::StringRef ExpectedSource;
132 } Cases[] = {
133 // Simple check
135 "void fo^o() { return; }",
136 "void foo() ;",
137 "void foo() { return; }",
139 // Inline specifier.
141 "inline void fo^o() { return; }",
142 " void foo() ;",
143 " void foo() { return; }",
145 // Default args.
147 "void fo^o(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) {}",
148 "void foo(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) ;",
149 "void foo(int x, int y , int , int (*foo)(int) ) {}",
152 "struct Bar{Bar();}; void fo^o(Bar x = {}) {}",
153 "struct Bar{Bar();}; void foo(Bar x = {}) ;",
154 "void foo(Bar x ) {}",
156 // Constructors
158 R"cpp(
159 class Foo {public: Foo(); Foo(int);};
160 class Bar {
161 Ba^r() {}
162 Bar(int x) : f1(x) {}
163 Foo f1;
164 Foo f2 = 2;
165 };)cpp",
166 R"cpp(
167 class Foo {public: Foo(); Foo(int);};
168 class Bar {
169 Bar() ;
170 Bar(int x) : f1(x) {}
171 Foo f1;
172 Foo f2 = 2;
173 };)cpp",
174 "Bar::Bar() {}\n",
176 // Ctor with initializer.
178 R"cpp(
179 class Foo {public: Foo(); Foo(int);};
180 class Bar {
181 Bar() {}
182 B^ar(int x) : f1(x), f2(3) {}
183 Foo f1;
184 Foo f2 = 2;
185 };)cpp",
186 R"cpp(
187 class Foo {public: Foo(); Foo(int);};
188 class Bar {
189 Bar() {}
190 Bar(int x) ;
191 Foo f1;
192 Foo f2 = 2;
193 };)cpp",
194 "Bar::Bar(int x) : f1(x), f2(3) {}\n",
196 // Ctor initializer with attribute.
198 R"cpp(
199 class Foo {
200 F^oo(int z) __attribute__((weak)) : bar(2){}
201 int bar;
202 };)cpp",
203 R"cpp(
204 class Foo {
205 Foo(int z) __attribute__((weak)) ;
206 int bar;
207 };)cpp",
208 "Foo::Foo(int z) __attribute__((weak)) : bar(2){}\n",
210 // Virt specifiers.
212 R"cpp(
213 struct A {
214 virtual void f^oo() {}
215 };)cpp",
216 R"cpp(
217 struct A {
218 virtual void foo() ;
219 };)cpp",
220 " void A::foo() {}\n",
223 R"cpp(
224 struct A {
225 virtual virtual void virtual f^oo() {}
226 };)cpp",
227 R"cpp(
228 struct A {
229 virtual virtual void virtual foo() ;
230 };)cpp",
231 " void A::foo() {}\n",
234 R"cpp(
235 struct A {
236 virtual void foo() = 0;
238 struct B : A {
239 void fo^o() override {}
240 };)cpp",
241 R"cpp(
242 struct A {
243 virtual void foo() = 0;
245 struct B : A {
246 void foo() override ;
247 };)cpp",
248 "void B::foo() {}\n",
251 R"cpp(
252 struct A {
253 virtual void foo() = 0;
255 struct B : A {
256 void fo^o() final {}
257 };)cpp",
258 R"cpp(
259 struct A {
260 virtual void foo() = 0;
262 struct B : A {
263 void foo() final ;
264 };)cpp",
265 "void B::foo() {}\n",
268 R"cpp(
269 struct A {
270 virtual void foo() = 0;
272 struct B : A {
273 void fo^o() final override {}
274 };)cpp",
275 R"cpp(
276 struct A {
277 virtual void foo() = 0;
279 struct B : A {
280 void foo() final override ;
281 };)cpp",
282 "void B::foo() {}\n",
285 R"cpp(
286 struct A {
287 static void fo^o() {}
288 };)cpp",
289 R"cpp(
290 struct A {
291 static void foo() ;
292 };)cpp",
293 " void A::foo() {}\n",
296 R"cpp(
297 struct A {
298 static static void fo^o() {}
299 };)cpp",
300 R"cpp(
301 struct A {
302 static static void foo() ;
303 };)cpp",
304 " void A::foo() {}\n",
307 R"cpp(
308 struct Foo {
309 explicit Fo^o(int) {}
310 };)cpp",
311 R"cpp(
312 struct Foo {
313 explicit Foo(int) ;
314 };)cpp",
315 " Foo::Foo(int) {}\n",
318 R"cpp(
319 struct Foo {
320 explicit explicit Fo^o(int) {}
321 };)cpp",
322 R"cpp(
323 struct Foo {
324 explicit explicit Foo(int) ;
325 };)cpp",
326 " Foo::Foo(int) {}\n",
329 R"cpp(
330 struct A {
331 inline void f^oo(int) {}
332 };)cpp",
333 R"cpp(
334 struct A {
335 void foo(int) ;
336 };)cpp",
337 " void A::foo(int) {}\n",
339 // Destrctors
341 "class A { ~A^(){} };",
342 "class A { ~A(); };",
343 "A::~A(){} ",
346 for (const auto &Case : Cases) {
347 SCOPED_TRACE(Case.Test);
348 EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader);
349 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
350 testPath("Test.cpp"), Case.ExpectedSource)));
354 TEST_F(DefineOutlineTest, HandleMacros) {
355 llvm::StringMap<std::string> EditedFiles;
356 ExtraFiles["Test.cpp"] = "";
357 FileName = "Test.hpp";
358 ExtraArgs.push_back("-DVIRTUAL=virtual");
359 ExtraArgs.push_back("-DOVER=override");
361 struct {
362 llvm::StringRef Test;
363 llvm::StringRef ExpectedHeader;
364 llvm::StringRef ExpectedSource;
365 } Cases[] = {
366 {R"cpp(
367 #define BODY { return; }
368 void f^oo()BODY)cpp",
369 R"cpp(
370 #define BODY { return; }
371 void foo();)cpp",
372 "void foo()BODY"},
374 {R"cpp(
375 #define BODY return;
376 void f^oo(){BODY})cpp",
377 R"cpp(
378 #define BODY return;
379 void foo();)cpp",
380 "void foo(){BODY}"},
382 {R"cpp(
383 #define TARGET void foo()
384 [[TARGET]]{ return; })cpp",
385 R"cpp(
386 #define TARGET void foo()
387 TARGET;)cpp",
388 "TARGET{ return; }"},
390 {R"cpp(
391 #define TARGET foo
392 void [[TARGET]](){ return; })cpp",
393 R"cpp(
394 #define TARGET foo
395 void TARGET();)cpp",
396 "void TARGET(){ return; }"},
397 {R"cpp(#define VIRT virtual
398 struct A {
399 VIRT void f^oo() {}
400 };)cpp",
401 R"cpp(#define VIRT virtual
402 struct A {
403 VIRT void foo() ;
404 };)cpp",
405 " void A::foo() {}\n"},
406 {R"cpp(
407 struct A {
408 VIRTUAL void f^oo() {}
409 };)cpp",
410 R"cpp(
411 struct A {
412 VIRTUAL void foo() ;
413 };)cpp",
414 " void A::foo() {}\n"},
415 {R"cpp(
416 struct A {
417 virtual void foo() = 0;
419 struct B : A {
420 void fo^o() OVER {}
421 };)cpp",
422 R"cpp(
423 struct A {
424 virtual void foo() = 0;
426 struct B : A {
427 void foo() OVER ;
428 };)cpp",
429 "void B::foo() {}\n"},
430 {R"cpp(#define STUPID_MACRO(X) virtual
431 struct A {
432 STUPID_MACRO(sizeof sizeof int) void f^oo() {}
433 };)cpp",
434 R"cpp(#define STUPID_MACRO(X) virtual
435 struct A {
436 STUPID_MACRO(sizeof sizeof int) void foo() ;
437 };)cpp",
438 " void A::foo() {}\n"},
439 {R"cpp(#define STAT static
440 struct A {
441 STAT void f^oo() {}
442 };)cpp",
443 R"cpp(#define STAT static
444 struct A {
445 STAT void foo() ;
446 };)cpp",
447 " void A::foo() {}\n"},
448 {R"cpp(#define STUPID_MACRO(X) static
449 struct A {
450 STUPID_MACRO(sizeof sizeof int) void f^oo() {}
451 };)cpp",
452 R"cpp(#define STUPID_MACRO(X) static
453 struct A {
454 STUPID_MACRO(sizeof sizeof int) void foo() ;
455 };)cpp",
456 " void A::foo() {}\n"},
458 for (const auto &Case : Cases) {
459 SCOPED_TRACE(Case.Test);
460 EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader);
461 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
462 testPath("Test.cpp"), Case.ExpectedSource)));
466 TEST_F(DefineOutlineTest, QualifyReturnValue) {
467 FileName = "Test.hpp";
468 ExtraFiles["Test.cpp"] = "";
470 struct {
471 llvm::StringRef Test;
472 llvm::StringRef ExpectedHeader;
473 llvm::StringRef ExpectedSource;
474 } Cases[] = {
475 {R"cpp(
476 namespace a { class Foo{}; }
477 using namespace a;
478 Foo fo^o() { return {}; })cpp",
479 R"cpp(
480 namespace a { class Foo{}; }
481 using namespace a;
482 Foo foo() ;)cpp",
483 "a::Foo foo() { return {}; }"},
484 {R"cpp(
485 namespace a {
486 class Foo {
487 class Bar {};
488 Bar fo^o() { return {}; }
490 })cpp",
491 R"cpp(
492 namespace a {
493 class Foo {
494 class Bar {};
495 Bar foo() ;
497 })cpp",
498 "a::Foo::Bar a::Foo::foo() { return {}; }\n"},
499 {R"cpp(
500 class Foo {};
501 Foo fo^o() { return {}; })cpp",
502 R"cpp(
503 class Foo {};
504 Foo foo() ;)cpp",
505 "Foo foo() { return {}; }"},
507 llvm::StringMap<std::string> EditedFiles;
508 for (auto &Case : Cases) {
509 apply(Case.Test, &EditedFiles);
510 EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader);
511 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
512 testPath("Test.cpp"), Case.ExpectedSource)));
516 TEST_F(DefineOutlineTest, QualifyFunctionName) {
517 FileName = "Test.hpp";
518 struct {
519 llvm::StringRef TestHeader;
520 llvm::StringRef TestSource;
521 llvm::StringRef ExpectedHeader;
522 llvm::StringRef ExpectedSource;
523 } Cases[] = {
525 R"cpp(
526 namespace a {
527 namespace b {
528 class Foo {
529 void fo^o() {}
532 })cpp",
534 R"cpp(
535 namespace a {
536 namespace b {
537 class Foo {
538 void foo() ;
541 })cpp",
542 "void a::b::Foo::foo() {}\n",
545 "namespace a { namespace b { void f^oo() {} } }",
546 "namespace a{}",
547 "namespace a { namespace b { void foo() ; } }",
548 "namespace a{void b::foo() {} }",
551 "namespace a { namespace b { void f^oo() {} } }",
552 "using namespace a;",
553 "namespace a { namespace b { void foo() ; } }",
554 // FIXME: Take using namespace directives in the source file into
555 // account. This can be spelled as b::foo instead.
556 "using namespace a;void a::b::foo() {} ",
559 "namespace a { class A { ~A^(){} }; }",
561 "namespace a { class A { ~A(); }; }",
562 "a::A::~A(){} ",
565 "namespace a { class A { ~A^(){} }; }",
566 "namespace a{}",
567 "namespace a { class A { ~A(); }; }",
568 "namespace a{A::~A(){} }",
571 llvm::StringMap<std::string> EditedFiles;
572 for (auto &Case : Cases) {
573 ExtraFiles["Test.cpp"] = std::string(Case.TestSource);
574 EXPECT_EQ(apply(Case.TestHeader, &EditedFiles), Case.ExpectedHeader);
575 EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
576 testPath("Test.cpp"), Case.ExpectedSource)))
577 << Case.TestHeader;
581 TEST_F(DefineOutlineTest, FailsMacroSpecifier) {
582 FileName = "Test.hpp";
583 ExtraFiles["Test.cpp"] = "";
584 ExtraArgs.push_back("-DFINALOVER=final override");
586 std::pair<StringRef, StringRef> Cases[] = {
588 R"cpp(
589 #define VIRT virtual void
590 struct A {
591 VIRT fo^o() {}
592 };)cpp",
593 "fail: define outline: couldn't remove `virtual` keyword."},
595 R"cpp(
596 #define OVERFINAL final override
597 struct A {
598 virtual void foo() {}
600 struct B : A {
601 void fo^o() OVERFINAL {}
602 };)cpp",
603 "fail: define outline: Can't move out of line as function has a "
604 "macro `override` specifier.\ndefine outline: Can't move out of line "
605 "as function has a macro `final` specifier."},
607 R"cpp(
608 struct A {
609 virtual void foo() {}
611 struct B : A {
612 void fo^o() FINALOVER {}
613 };)cpp",
614 "fail: define outline: Can't move out of line as function has a "
615 "macro `override` specifier.\ndefine outline: Can't move out of line "
616 "as function has a macro `final` specifier."},
618 for (const auto &Case : Cases) {
619 EXPECT_EQ(apply(Case.first), Case.second);
623 } // namespace
624 } // namespace clangd
625 } // namespace clang