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(); }
331 using NS::foo;using NS::unrelated;
335 // If all other using are fully qualified, add ::
339 using ::one::two::cc;
340 using ::one::two::ee;
348 using ::one::two::cc;
349 using ::one::two::ff;using ::one::two::ee;
354 // Make sure we don't add :: if it's already there
358 using ::one::two::cc;
359 using ::one::two::ee;
367 using ::one::two::cc;
368 using ::one::two::ff;using ::one::two::ee;
373 // If even one using doesn't start with ::, do not add it
377 using ::one::two::cc;
386 using ::one::two::cc;
387 using one::two::ff;using one::two::ee;
392 // using alias; insert using for the spelled name.
417 namespace {using two::cc;
421 // Type defined in main file, make sure using is after that.
438 // Type defined in main file via "using", insert after that.
443 using yy = one::two::cc;
452 using yy = one::two::cc;
459 // Using must come after function definition.
480 // Existing using with non-namespace part.
483 using one::two::ee::ee_one;
488 using one::two::cc;using one::two::ee::ee_one;
491 // Template (like std::vector).
519 switch(one::two::ee{}) { case two::ee_^one:break; }
525 using one::two::ee_one;
528 switch(one::two::ee{}) { case ee_one:break; }
534 one::f^unc_temp<int>();
538 using one::func_temp;
556 llvm::StringMap
<std::string
> EditedFiles
;
557 for (const auto &Case
: Cases
) {
558 ExtraFiles
["test.hpp"] = R
"cpp(
566 struct st { struct nested {}; };
571 template<typename T> struct vec {};
572 template <typename T> void func_temp();
573 template <typename T> T var_temp();
575 // Typo correction is disabled in msvc-compatibility mode.
576 ExtraArgs
.push_back("-fno-ms-compatibility");
577 EXPECT_EQ(apply(Case
.TestSource
, &EditedFiles
), Case
.ExpectedSource
);
582 } // namespace clangd