[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clangd / unittests / tweaks / AddUsingTests.cpp
blob1fd2487378d7055fa07729934d7f1c193fa43df6
1 //===-- AddUsingTests.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 "Config.h"
10 #include "TweakTesting.h"
11 #include "support/Context.h"
12 #include "llvm/ADT/StringMap.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "gtest/gtest.h"
15 #include <string>
16 #include <utility>
18 namespace clang {
19 namespace clangd {
20 namespace {
22 TWEAK_TEST(AddUsing);
24 TEST_F(AddUsingTest, Prepare) {
25 Config Cfg;
26 Cfg.Style.FullyQualifiedNamespaces.push_back("ban");
27 WithContextValue WithConfig(Config::Key, std::move(Cfg));
29 const std::string Header = R"cpp(
30 #define NS(name) one::two::name
31 namespace ban { void foo() {} }
32 namespace banana { void foo() {} }
33 namespace one {
34 void oo() {}
35 template<typename TT> class tt {};
36 namespace two {
37 enum ee { ee_enum_value };
38 void ff() {}
39 class cc {
40 public:
41 struct st {};
42 static void mm() {}
43 cc operator|(const cc& x) const { return x; }
46 })cpp";
48 EXPECT_AVAILABLE(Header + "void fun() { o^n^e^:^:^t^w^o^:^:^f^f(); }");
49 EXPECT_AVAILABLE(Header + "void fun() { o^n^e^::^o^o(); }");
50 EXPECT_AVAILABLE(Header + "void fun() { o^n^e^:^:^t^w^o^:^:^e^e E; }");
51 EXPECT_AVAILABLE(Header + "void fun() { o^n^e^:^:^t^w^o:^:^c^c C; }");
52 EXPECT_UNAVAILABLE(Header +
53 "void fun() { o^n^e^:^:^t^w^o^:^:^c^c^:^:^m^m(); }");
54 EXPECT_UNAVAILABLE(Header +
55 "void fun() { o^n^e^:^:^t^w^o^:^:^c^c^:^:^s^t inst; }");
56 EXPECT_UNAVAILABLE(Header +
57 "void fun() { o^n^e^:^:^t^w^o^:^:^c^c^:^:^s^t inst; }");
58 EXPECT_UNAVAILABLE(Header + "void fun() { N^S(c^c) inst; }");
59 // This used to crash. Ideally we would support this case, but for now we just
60 // test that we don't crash.
61 EXPECT_UNAVAILABLE(Header +
62 "template<typename TT> using foo = one::tt<T^T>;");
63 // Test that we don't crash or misbehave on unnamed DeclRefExpr.
64 EXPECT_UNAVAILABLE(Header +
65 "void fun() { one::two::cc() ^| one::two::cc(); }");
66 // Do not offer code action when operating on a banned namespace.
67 EXPECT_UNAVAILABLE(Header + "void fun() { ban::fo^o(); }");
68 EXPECT_UNAVAILABLE(Header + "void fun() { ::ban::fo^o(); }");
69 EXPECT_AVAILABLE(Header + "void fun() { banana::fo^o(); }");
71 // NestedNameSpecifier, but no namespace.
72 EXPECT_UNAVAILABLE(Header + "class Foo {}; class F^oo foo;");
74 // Nested macro case.
75 EXPECT_AVAILABLE(R"cpp(
76 #define ID2(X) X
77 #define ID(Y, X) Y;ID2(X)
78 namespace ns { struct Foo{}; }
79 ID(int xyz, ns::F^oo) f;)cpp");
81 // Check that we do not trigger in header files.
82 FileName = "test.h";
83 ExtraArgs.push_back("-xc++-header"); // .h file is treated a C by default.
84 EXPECT_UNAVAILABLE(Header + "void fun() { one::two::f^f(); }");
85 FileName = "test.hpp";
86 EXPECT_UNAVAILABLE(Header + "void fun() { one::two::f^f(); }");
89 TEST_F(AddUsingTest, Crash1072) {
90 // Used to crash when traversing catch(...)
91 // https://github.com/clangd/clangd/issues/1072
92 const char *Code = R"cpp(
93 namespace ns { class A; }
94 ns::^A *err;
95 void catchall() {
96 try {} catch(...) {}
98 )cpp";
99 EXPECT_AVAILABLE(Code);
102 TEST_F(AddUsingTest, Apply) {
103 FileName = "test.cpp";
104 struct {
105 llvm::StringRef TestSource;
106 llvm::StringRef ExpectedSource;
107 } Cases[]{
109 // Function, no other using, namespace.
110 R"cpp(
111 #include "test.hpp"
112 namespace {
113 void fun() {
114 ^one::two::ff();
116 })cpp",
117 R"cpp(
118 #include "test.hpp"
119 namespace {using one::two::ff;
121 void fun() {
122 ff();
124 })cpp",
126 // Type, no other using, namespace.
128 R"cpp(
129 #include "test.hpp"
130 namespace {
131 void fun() {
132 ::one::t^wo::cc inst;
134 })cpp",
135 R"cpp(
136 #include "test.hpp"
137 namespace {using ::one::two::cc;
139 void fun() {
140 cc inst;
142 })cpp",
144 // Type, no other using, no namespace.
146 R"cpp(
147 #include "test.hpp"
149 void fun() {
150 one::two::e^e inst;
151 })cpp",
152 R"cpp(
153 #include "test.hpp"
155 using one::two::ee;
157 void fun() {
158 ee inst;
159 })cpp"},
160 // Function, other usings.
162 R"cpp(
163 #include "test.hpp"
165 using one::two::cc;
166 using one::two::ee;
168 namespace {
169 void fun() {
170 one::two::f^f();
172 })cpp",
173 R"cpp(
174 #include "test.hpp"
176 using one::two::cc;
177 using one::two::ff;using one::two::ee;
179 namespace {
180 void fun() {
181 ff();
183 })cpp",
185 // Function, other usings inside namespace.
187 R"cpp(
188 #include "test.hpp"
190 using one::two::cc;
192 namespace {
194 using one::two::ff;
196 void fun() {
197 o^ne::oo();
199 })cpp",
200 R"cpp(
201 #include "test.hpp"
203 using one::two::cc;
205 namespace {
207 using one::oo;using one::two::ff;
209 void fun() {
210 oo();
212 })cpp"},
213 // Using comes after cursor.
215 R"cpp(
216 #include "test.hpp"
218 namespace {
220 void fun() {
221 one::t^wo::ff();
224 using one::two::cc;
226 })cpp",
227 R"cpp(
228 #include "test.hpp"
230 namespace {using one::two::ff;
233 void fun() {
234 ff();
237 using one::two::cc;
239 })cpp"},
240 // Pointer type.
241 {R"cpp(
242 #include "test.hpp"
244 void fun() {
245 one::two::c^c *p;
246 })cpp",
247 R"cpp(
248 #include "test.hpp"
250 using one::two::cc;
252 void fun() {
253 cc *p;
254 })cpp"},
255 // Namespace declared via macro.
256 {R"cpp(
257 #include "test.hpp"
258 #define NS_BEGIN(name) namespace name {
260 NS_BEGIN(foo)
262 void fun() {
263 one::two::f^f();
265 })cpp",
266 R"cpp(
267 #include "test.hpp"
268 #define NS_BEGIN(name) namespace name {
270 using one::two::ff;
272 NS_BEGIN(foo)
274 void fun() {
275 ff();
277 })cpp"},
278 // Inside macro argument.
279 {R"cpp(
280 #include "test.hpp"
281 #define CALL(name) name()
283 void fun() {
284 CALL(one::t^wo::ff);
285 })cpp",
286 R"cpp(
287 #include "test.hpp"
288 #define CALL(name) name()
290 using one::two::ff;
292 void fun() {
293 CALL(ff);
294 })cpp"},
295 // Parent namespace != lexical parent namespace
296 {R"cpp(
297 #include "test.hpp"
298 namespace foo { void fun(); }
300 void foo::fun() {
301 one::two::f^f();
302 })cpp",
303 R"cpp(
304 #include "test.hpp"
305 using one::two::ff;
307 namespace foo { void fun(); }
309 void foo::fun() {
310 ff();
311 })cpp"},
312 // If all other using are fully qualified, add ::
313 {R"cpp(
314 #include "test.hpp"
316 using ::one::two::cc;
317 using ::one::two::ee;
319 void fun() {
320 one::two::f^f();
321 })cpp",
322 R"cpp(
323 #include "test.hpp"
325 using ::one::two::cc;
326 using ::one::two::ff;using ::one::two::ee;
328 void fun() {
329 ff();
330 })cpp"},
331 // Make sure we don't add :: if it's already there
332 {R"cpp(
333 #include "test.hpp"
335 using ::one::two::cc;
336 using ::one::two::ee;
338 void fun() {
339 ::one::two::f^f();
340 })cpp",
341 R"cpp(
342 #include "test.hpp"
344 using ::one::two::cc;
345 using ::one::two::ff;using ::one::two::ee;
347 void fun() {
348 ff();
349 })cpp"},
350 // If even one using doesn't start with ::, do not add it
351 {R"cpp(
352 #include "test.hpp"
354 using ::one::two::cc;
355 using one::two::ee;
357 void fun() {
358 one::two::f^f();
359 })cpp",
360 R"cpp(
361 #include "test.hpp"
363 using ::one::two::cc;
364 using one::two::ff;using one::two::ee;
366 void fun() {
367 ff();
368 })cpp"},
369 // using alias; insert using for the spelled name.
370 {R"cpp(
371 #include "test.hpp"
373 void fun() {
374 one::u^u u;
375 })cpp",
376 R"cpp(
377 #include "test.hpp"
379 using one::uu;
381 void fun() {
382 uu u;
383 })cpp"},
384 // using namespace.
385 {R"cpp(
386 #include "test.hpp"
387 using namespace one;
388 namespace {
389 two::c^c C;
390 })cpp",
391 R"cpp(
392 #include "test.hpp"
393 using namespace one;
394 namespace {using two::cc;
396 cc C;
397 })cpp"},
398 // Type defined in main file, make sure using is after that.
399 {R"cpp(
400 namespace xx {
401 struct yy {};
404 x^x::yy X;
405 )cpp",
406 R"cpp(
407 namespace xx {
408 struct yy {};
411 using xx::yy;
413 yy X;
414 )cpp"},
415 // Type defined in main file via "using", insert after that.
416 {R"cpp(
417 #include "test.hpp"
419 namespace xx {
420 using yy = one::two::cc;
423 x^x::yy X;
424 )cpp",
425 R"cpp(
426 #include "test.hpp"
428 namespace xx {
429 using yy = one::two::cc;
432 using xx::yy;
434 yy X;
435 )cpp"},
436 // Using must come after function definition.
437 {R"cpp(
438 namespace xx {
439 void yy();
442 void fun() {
443 x^x::yy();
445 )cpp",
446 R"cpp(
447 namespace xx {
448 void yy();
451 using xx::yy;
453 void fun() {
454 yy();
456 )cpp"},
457 // Existing using with non-namespace part.
458 {R"cpp(
459 #include "test.hpp"
460 using one::two::ee::ee_one;
461 one::t^wo::cc c;
462 )cpp",
463 R"cpp(
464 #include "test.hpp"
465 using one::two::cc;using one::two::ee::ee_one;
466 cc c;
467 )cpp"},
468 // Template (like std::vector).
469 {R"cpp(
470 #include "test.hpp"
471 one::v^ec<int> foo;
472 )cpp",
473 R"cpp(
474 #include "test.hpp"
475 using one::vec;
477 vec<int> foo;
478 )cpp"},
479 // Typo correction.
480 {R"cpp(
481 // error-ok
482 #include "test.hpp"
483 c^c C;
484 )cpp",
485 R"cpp(
486 // error-ok
487 #include "test.hpp"
488 using one::two::cc;
490 cc C;
491 )cpp"},
492 {R"cpp(
493 // error-ok
494 #include "test.hpp"
495 void foo() {
496 switch(one::two::ee{}) { case two::ee_^one:break; }
498 )cpp",
499 R"cpp(
500 // error-ok
501 #include "test.hpp"
502 using one::two::ee_one;
504 void foo() {
505 switch(one::two::ee{}) { case ee_one:break; }
507 )cpp"},
508 {R"cpp(
509 #include "test.hpp"
510 void foo() {
511 one::f^unc_temp<int>();
512 })cpp",
513 R"cpp(
514 #include "test.hpp"
515 using one::func_temp;
517 void foo() {
518 func_temp<int>();
519 })cpp"},
520 {R"cpp(
521 #include "test.hpp"
522 void foo() {
523 one::va^r_temp<int>;
524 })cpp",
525 R"cpp(
526 #include "test.hpp"
527 using one::var_temp;
529 void foo() {
530 var_temp<int>;
531 })cpp"},
533 llvm::StringMap<std::string> EditedFiles;
534 for (const auto &Case : Cases) {
535 ExtraFiles["test.hpp"] = R"cpp(
536 namespace one {
537 void oo() {}
538 namespace two {
539 enum ee {ee_one};
540 void ff() {}
541 class cc {
542 public:
543 struct st { struct nested {}; };
544 static void mm() {}
547 using uu = two::cc;
548 template<typename T> struct vec {};
549 template <typename T> void func_temp();
550 template <typename T> T var_temp();
551 })cpp";
552 // Typo correction is disabled in msvc-compatibility mode.
553 ExtraArgs.push_back("-fno-ms-compatibility");
554 EXPECT_EQ(apply(Case.TestSource, &EditedFiles), Case.ExpectedSource);
558 } // namespace
559 } // namespace clangd
560 } // namespace clang