1 //===-- AddUsingTests.cpp ---------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
24 TEST_F(AddUsingTest
, Prepare
) {
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() {} }
35 template<typename TT> class tt {};
37 enum ee { ee_enum_value };
43 cc operator|(const cc& x) const { return x; }
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;");
75 EXPECT_AVAILABLE(R
"cpp(
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.
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; }
99 EXPECT_AVAILABLE(Code
);
102 TEST_F(AddUsingTest
, Apply
) {
103 FileName
= "test.cpp";
105 llvm::StringRef TestSource
;
106 llvm::StringRef ExpectedSource
;
109 // Function, no other using, namespace.
119 namespace {using one::two::ff;
126 // Type, no other using, namespace.
132 ::one::t^wo::cc inst;
137 namespace {using ::one::two::cc;
144 // Type, no other using, no namespace.
160 // Function, other usings.
177 using one::two::ff;using one::two::ee;
185 // Function, other usings inside namespace.
207 using one::oo;using one::two::ff;
213 // Using comes after cursor.
230 namespace {using one::two::ff;
255 // Namespace declared via macro.
258 #define NS_BEGIN(name) namespace name {
268 #define NS_BEGIN(name) namespace name {
278 // Inside macro argument.
281 #define CALL(name) name()
288 #define CALL(name) name()
295 // Parent namespace != lexical parent namespace
298 namespace foo { void fun(); }
307 namespace foo { void fun(); }
312 // If all other using are fully qualified, add ::
316 using ::one::two::cc;
317 using ::one::two::ee;
325 using ::one::two::cc;
326 using ::one::two::ff;using ::one::two::ee;
331 // Make sure we don't add :: if it's already there
335 using ::one::two::cc;
336 using ::one::two::ee;
344 using ::one::two::cc;
345 using ::one::two::ff;using ::one::two::ee;
350 // If even one using doesn't start with ::, do not add it
354 using ::one::two::cc;
363 using ::one::two::cc;
364 using one::two::ff;using one::two::ee;
369 // using alias; insert using for the spelled name.
394 namespace {using two::cc;
398 // Type defined in main file, make sure using is after that.
415 // Type defined in main file via "using", insert after that.
420 using yy = one::two::cc;
429 using yy = one::two::cc;
436 // Using must come after function definition.
457 // Existing using with non-namespace part.
460 using one::two::ee::ee_one;
465 using one::two::cc;using one::two::ee::ee_one;
468 // Template (like std::vector).
496 switch(one::two::ee{}) { case two::ee_^one:break; }
502 using one::two::ee_one;
505 switch(one::two::ee{}) { case ee_one:break; }
511 one::f^unc_temp<int>();
515 using one::func_temp;
533 llvm::StringMap
<std::string
> EditedFiles
;
534 for (const auto &Case
: Cases
) {
535 ExtraFiles
["test.hpp"] = R
"cpp(
543 struct st { struct nested {}; };
548 template<typename T> struct vec {};
549 template <typename T> void func_temp();
550 template <typename T> T var_temp();
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
);
559 } // namespace clangd