1 | //===-- RenameAliasTest.cpp - unit tests for renaming alias ---------------===// |
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 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ClangRenameTest.h" |
10 | |
11 | namespace clang { |
12 | namespace clang_rename { |
13 | namespace test { |
14 | namespace { |
15 | |
16 | class RenameAliasTest : public ClangRenameTest { |
17 | public: |
18 | RenameAliasTest() { |
19 | AppendToHeader(Code: R"( |
20 | #define MACRO(x) x |
21 | namespace some_ns { |
22 | class A { |
23 | public: |
24 | void foo() {} |
25 | struct Nested { |
26 | enum NestedEnum { |
27 | E1, E2, |
28 | }; |
29 | }; |
30 | }; |
31 | } // namespace some_ns |
32 | namespace a { |
33 | typedef some_ns::A TA; |
34 | using UA = some_ns::A; |
35 | } // namespace a |
36 | namespace b { |
37 | typedef some_ns::A TA; |
38 | using UA = some_ns::A; |
39 | } |
40 | template <typename T> class ptr {}; |
41 | template <typename T> |
42 | |
43 | using TPtr = ptr<int>; |
44 | )" ); |
45 | } |
46 | }; |
47 | |
48 | INSTANTIATE_TEST_SUITE_P( |
49 | RenameAliasTests, RenameAliasTest, |
50 | testing::ValuesIn(std::vector<Case>({ |
51 | // basic functions |
52 | {"void f(a::TA a1) {}" , "void f(b::TB a1) {}" , "a::TA" , "b::TB" }, |
53 | {"void f(a::UA a1) {}" , "void f(b::UB a1) {}" , "a::UA" , "b::UB" }, |
54 | {"void f(a::TA* a1) {}" , "void f(b::TB* a1) {}" , "a::TA" , "b::TB" }, |
55 | {"void f(a::TA** a1) {}" , "void f(b::TB** a1) {}" , "a::TA" , "b::TB" }, |
56 | {"a::TA f() { return a::TA(); }" , "b::TB f() { return b::TB(); }" , |
57 | "a::TA" , "b::TB" }, |
58 | {"a::TA f() { return a::UA(); }" , "b::TB f() { return a::UA(); }" , |
59 | "a::TA" , "b::TB" }, |
60 | {"a::TA f() { return a::UA(); }" , "a::TA f() { return b::UB(); }" , |
61 | "a::UA" , "b::UB" }, |
62 | {"void f() { a::TA a; }" , "void f() { b::TB a; }" , "a::TA" , "b::TB" }, |
63 | {"void f(const a::TA& a1) {}" , "void f(const b::TB& a1) {}" , "a::TA" , |
64 | "b::TB" }, |
65 | {"void f(const a::UA& a1) {}" , "void f(const b::UB& a1) {}" , "a::UA" , |
66 | "b::UB" }, |
67 | {"void f(const a::TA* a1) {}" , "void f(const b::TB* a1) {}" , "a::TA" , |
68 | "b::TB" }, |
69 | {"namespace a { void f(TA a1) {} }" , |
70 | "namespace a { void f(b::TB a1) {} }" , "a::TA" , "b::TB" }, |
71 | {"void f(MACRO(a::TA) a1) {}" , "void f(MACRO(b::TB) a1) {}" , "a::TA" , |
72 | "b::TB" }, |
73 | {"void f(MACRO(a::TA a1)) {}" , "void f(MACRO(b::TB a1)) {}" , "a::TA" , |
74 | "b::TB" }, |
75 | |
76 | // shorten/add namespace. |
77 | {"namespace b { void f(a::UA a1) {} }" , |
78 | "namespace b {void f(UB a1) {} }" , "a::UA" , "b::UB" }, |
79 | {"namespace a { void f(UA a1) {} }" , |
80 | "namespace a {void f(b::UB a1) {} }" , "a::UA" , "b::UB" }, |
81 | |
82 | // use namespace and typedefs |
83 | {"struct S { using T = a::TA; T a_; };" , |
84 | "struct S { using T = b::TB; T a_; };" , "a::TA" , "b::TB" }, |
85 | {"using T = a::TA; T gA;" , "using T = b::TB; T gA;" , "a::TA" , "b::TB" }, |
86 | {"using T = a::UA; T gA;" , "using T = b::UB; T gA;" , "a::UA" , "b::UB" }, |
87 | {"typedef a::TA T; T gA;" , "typedef b::TB T; T gA;" , "a::TA" , "b::TB" }, |
88 | {"typedef a::UA T; T gA;" , "typedef b::UB T; T gA;" , "a::UA" , "b::UB" }, |
89 | {"typedef MACRO(a::TA) T; T gA;" , "typedef MACRO(b::TB) T; T gA;" , |
90 | "a::TA" , "b::TB" }, |
91 | |
92 | // types in using shadows. |
93 | {"using a::TA; TA gA;" , "using b::TB; b::TB gA;" , "a::TA" , "b::TB" }, |
94 | {"using a::UA; UA gA;" , "using b::UB; b::UB gA;" , "a::UA" , "b::UB" }, |
95 | |
96 | // struct members and other oddities |
97 | {"struct S : public a::TA {};" , "struct S : public b::TB {};" , "a::TA" , |
98 | "b::TB" }, |
99 | {"struct S : public a::UA {};" , "struct S : public b::UB {};" , "a::UA" , |
100 | "b::UB" }, |
101 | {"struct F { void f(a::TA a1) {} };" , |
102 | "struct F { void f(b::TB a1) {} };" , "a::TA" , "b::TB" }, |
103 | {"struct F { a::TA a_; };" , "struct F { b::TB a_; };" , "a::TA" , |
104 | "b::TB" }, |
105 | {"struct F { ptr<a::TA> a_; };" , "struct F { ptr<b::TB> a_; };" , |
106 | "a::TA" , "b::TB" }, |
107 | {"struct F { ptr<a::UA> a_; };" , "struct F { ptr<b::UB> a_; };" , |
108 | "a::UA" , "b::UB" }, |
109 | |
110 | // types in nested name specifiers |
111 | {"void f() { a::TA::Nested ne; }" , "void f() { b::TB::Nested ne; }" , |
112 | "a::TA" , "b::TB" }, |
113 | {"void f() { a::UA::Nested ne; }" , "void f() { b::UB::Nested ne; }" , |
114 | "a::UA" , "b::UB" }, |
115 | {"void f() { a::TA::Nested::NestedEnum e; }" , |
116 | "void f() { b::TB::Nested::NestedEnum e; }" , "a::TA" , "b::TB" }, |
117 | {"void f() { auto e = a::TA::Nested::NestedEnum::E1; }" , |
118 | "void f() { auto e = b::TB::Nested::NestedEnum::E1; }" , "a::TA" , |
119 | "b::TB" }, |
120 | {"void f() { auto e = a::TA::Nested::E1; }" , |
121 | "void f() { auto e = b::TB::Nested::E1; }" , "a::TA" , "b::TB" }, |
122 | |
123 | // templates |
124 | {"template <typename T> struct Foo { T t; }; void f() { Foo<a::TA> " |
125 | "foo; }" , |
126 | "template <typename T> struct Foo { T t; }; void f() { Foo<b::TB> " |
127 | "foo; }" , |
128 | "a::TA" , "b::TB" }, |
129 | {"template <typename T> struct Foo { a::TA a; };" , |
130 | "template <typename T> struct Foo { b::TB a; };" , "a::TA" , "b::TB" }, |
131 | {"template <typename T> void f(T t) {} void g() { f<a::TA>(a::TA()); }" , |
132 | "template <typename T> void f(T t) {} void g() { f<b::TB>(b::TB()); }" , |
133 | "a::TA" , "b::TB" }, |
134 | {"template <typename T> void f(T t) {} void g() { f<a::UA>(a::UA()); }" , |
135 | "template <typename T> void f(T t) {} void g() { f<b::UB>(b::UB()); }" , |
136 | "a::UA" , "b::UB" }, |
137 | {"template <typename T> int f() { return 1; } template <> int " |
138 | "f<a::TA>() { return 2; } int g() { return f<a::TA>(); }" , |
139 | "template <typename T> int f() { return 1; } template <> int " |
140 | "f<b::TB>() { return 2; } int g() { return f<b::TB>(); }" , |
141 | "a::TA" , "b::TB" }, |
142 | {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " |
143 | "auto a = f.template foo<a::TA>(); }" , |
144 | "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " |
145 | "auto a = f.template foo<b::TB>(); }" , |
146 | "a::TA" , "b::TB" }, |
147 | {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " |
148 | "auto a = f.template foo<a::UA>(); }" , |
149 | "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " |
150 | "auto a = f.template foo<b::UB>(); }" , |
151 | "a::UA" , "b::UB" }, |
152 | |
153 | // The following two templates are distilled from regressions found in |
154 | // unique_ptr<> and type_traits.h |
155 | {"template <typename T> struct outer { typedef T type; type Baz(); }; " |
156 | "outer<a::TA> g_A;" , |
157 | "template <typename T> struct outer { typedef T type; type Baz(); }; " |
158 | "outer<b::TB> g_A;" , |
159 | "a::TA" , "b::TB" }, |
160 | {"template <typename T> struct nested { typedef T type; }; template " |
161 | "<typename T> struct outer { typename nested<T>::type Foo(); }; " |
162 | "outer<a::TA> g_A;" , |
163 | "template <typename T> struct nested { typedef T type; }; template " |
164 | "<typename T> struct outer { typename nested<T>::type Foo(); }; " |
165 | "outer<b::TB> g_A;" , |
166 | "a::TA" , "b::TB" }, |
167 | |
168 | // macros |
169 | {"#define FOO(T, t) T t\nvoid f() { FOO(a::TA, a1); FOO(a::TA, a2); }" , |
170 | "#define FOO(T, t) T t\nvoid f() { FOO(b::TB, a1); FOO(b::TB, a2); }" , |
171 | "a::TA" , "b::TB" }, |
172 | {"#define FOO(n) a::TA n\nvoid f() { FOO(a1); FOO(a2); }" , |
173 | "#define FOO(n) b::TB n\nvoid f() { FOO(a1); FOO(a2); }" , "a::TA" , |
174 | "b::TB" }, |
175 | {"#define FOO(n) a::UA n\nvoid f() { FOO(a1); FOO(a2); }" , |
176 | "#define FOO(n) b::UB n\nvoid f() { FOO(a1); FOO(a2); }" , "a::UA" , |
177 | "b::UB" }, |
178 | |
179 | // Pointer to member functions |
180 | {"auto gA = &a::TA::foo;" , "auto gA = &b::TB::foo;" , "a::TA" , "b::TB" }, |
181 | {"using a::TA; auto gA = &TA::foo;" , |
182 | "using b::TB; auto gA = &b::TB::foo;" , "a::TA" , "b::TB" }, |
183 | {"typedef a::TA T; auto gA = &T::foo;" , |
184 | "typedef b::TB T; auto gA = &T::foo;" , "a::TA" , "b::TB" }, |
185 | {"auto gA = &MACRO(a::TA)::foo;" , "auto gA = &MACRO(b::TB)::foo;" , |
186 | "a::TA" , "b::TB" }, |
187 | |
188 | // templated using alias. |
189 | {"void f(TPtr<int> p) {}" , "void f(NewTPtr<int> p) {}" , "TPtr" , |
190 | "NewTPtr" }, |
191 | {"void f(::TPtr<int> p) {}" , "void f(::NewTPtr<int> p) {}" , "TPtr" , |
192 | "NewTPtr" }, |
193 | }))); |
194 | |
195 | TEST_P(RenameAliasTest, RenameAlias) { |
196 | auto Param = GetParam(); |
197 | assert(!Param.OldName.empty()); |
198 | assert(!Param.NewName.empty()); |
199 | std::string Actual = |
200 | runClangRenameOnCode(Code: Param.Before, OldName: Param.OldName, NewName: Param.NewName); |
201 | CompareSnippets(Expected: Param.After, Actual); |
202 | } |
203 | |
204 | TEST_F(RenameAliasTest, RenameTypedefDefinitions) { |
205 | std::string Before = R"( |
206 | class X {}; |
207 | typedef X TOld; |
208 | )" ; |
209 | std::string Expected = R"( |
210 | class X {}; |
211 | typedef X TNew; |
212 | )" ; |
213 | std::string After = runClangRenameOnCode(Code: Before, OldName: "TOld" , NewName: "TNew" ); |
214 | CompareSnippets(Expected, Actual: After); |
215 | } |
216 | |
217 | TEST_F(RenameAliasTest, RenameUsingAliasDefinitions) { |
218 | std::string Before = R"( |
219 | class X {}; |
220 | using UOld = X; |
221 | )" ; |
222 | std::string Expected = R"( |
223 | class X {}; |
224 | using UNew = X; |
225 | )" ; |
226 | std::string After = runClangRenameOnCode(Code: Before, OldName: "UOld" , NewName: "UNew" ); |
227 | CompareSnippets(Expected, Actual: After); |
228 | } |
229 | |
230 | TEST_F(RenameAliasTest, RenameTemplatedAliasDefinitions) { |
231 | std::string Before = R"( |
232 | template <typename T> |
233 | class X { T t; }; |
234 | |
235 | template <typename T> |
236 | using Old = X<T>; |
237 | )" ; |
238 | std::string Expected = R"( |
239 | template <typename T> |
240 | class X { T t; }; |
241 | |
242 | template <typename T> |
243 | using New = X<T>; |
244 | )" ; |
245 | std::string After = runClangRenameOnCode(Code: Before, OldName: "Old" , NewName: "New" ); |
246 | CompareSnippets(Expected, Actual: After); |
247 | } |
248 | |
249 | TEST_F(RenameAliasTest, RenameAliasesInNamespaces) { |
250 | std::string Before = R"( |
251 | namespace x { class X {}; } |
252 | namespace ns { |
253 | using UOld = x::X; |
254 | } |
255 | )" ; |
256 | std::string Expected = R"( |
257 | namespace x { class X {}; } |
258 | namespace ns { |
259 | using UNew = x::X; |
260 | } |
261 | )" ; |
262 | std::string After = runClangRenameOnCode(Code: Before, OldName: "ns::UOld" , NewName: "ns::UNew" ); |
263 | CompareSnippets(Expected, Actual: After); |
264 | } |
265 | |
266 | TEST_F(RenameAliasTest, AliasesInMacros) { |
267 | std::string Before = R"( |
268 | namespace x { class Old {}; } |
269 | namespace ns { |
270 | #define REF(alias) alias alias_var; |
271 | |
272 | #define ALIAS(old) \ |
273 | using old##Alias = x::old; \ |
274 | REF(old##Alias); |
275 | |
276 | ALIAS(Old); |
277 | |
278 | OldAlias old_alias; |
279 | } |
280 | )" ; |
281 | std::string Expected = R"( |
282 | namespace x { class Old {}; } |
283 | namespace ns { |
284 | #define REF(alias) alias alias_var; |
285 | |
286 | #define ALIAS(old) \ |
287 | using old##Alias = x::old; \ |
288 | REF(old##Alias); |
289 | |
290 | ALIAS(Old); |
291 | |
292 | NewAlias old_alias; |
293 | } |
294 | )" ; |
295 | std::string After = |
296 | runClangRenameOnCode(Code: Before, OldName: "ns::OldAlias" , NewName: "ns::NewAlias" ); |
297 | CompareSnippets(Expected, Actual: After); |
298 | } |
299 | |
300 | } // anonymous namespace |
301 | } // namespace test |
302 | } // namespace clang_rename |
303 | } // namesdpace clang |
304 | |