blob: 04252d57fdd3637f40981b1587336ecae11ef5c4 [file] [log] [blame]
Eric Liu495b2112016-09-19 17:40:32 +00001//===-- ChangeNamespaceTests.cpp - Change namespace unit tests ---*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ChangeNamespace.h"
11#include "unittests/Tooling/RewriterTestContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Basic/FileManager.h"
14#include "clang/Basic/FileSystemOptions.h"
15#include "clang/Basic/VirtualFileSystem.h"
16#include "clang/Format/Format.h"
17#include "clang/Frontend/CompilerInstance.h"
18#include "clang/Frontend/PCHContainerOperations.h"
19#include "clang/Tooling/Refactoring.h"
20#include "clang/Tooling/Tooling.h"
21#include "llvm/ADT/IntrusiveRefCntPtr.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "gtest/gtest.h"
25#include <memory>
26#include <string>
27#include <vector>
28
29namespace clang {
30namespace change_namespace {
31namespace {
32
33class ChangeNamespaceTest : public ::testing::Test {
34public:
35 std::string runChangeNamespaceOnCode(llvm::StringRef Code) {
36 clang::RewriterTestContext Context;
37 clang::FileID ID = Context.createInMemoryFile(FileName, Code);
38
39 std::map<std::string, tooling::Replacements> FileToReplacements;
40 change_namespace::ChangeNamespaceTool NamespaceTool(
41 OldNamespace, NewNamespace, FilePattern, &FileToReplacements);
42 ast_matchers::MatchFinder Finder;
43 NamespaceTool.registerMatchers(&Finder);
44 std::unique_ptr<tooling::FrontendActionFactory> Factory =
45 tooling::newFrontendActionFactory(&Finder);
46 tooling::runToolOnCodeWithArgs(Factory->create(), Code, {"-std=c++11"},
47 FileName);
48 formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite);
49 return format(Context.getRewrittenText(ID));
50 }
51
52 std::string format(llvm::StringRef Code) {
53 tooling::Replacements Replaces = format::reformat(
54 format::getLLVMStyle(), Code, {tooling::Range(0, Code.size())});
55 auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
56 EXPECT_TRUE(static_cast<bool>(ChangedCode));
57 if (!ChangedCode) {
58 llvm::errs() << llvm::toString(ChangedCode.takeError());
59 return "";
60 }
61 return *ChangedCode;
62 }
63
64protected:
65 std::string FileName = "input.cc";
66 std::string OldNamespace = "na::nb";
67 std::string NewNamespace = "x::y";
68 std::string FilePattern = "input.cc";
69};
70
71TEST_F(ChangeNamespaceTest, NoMatchingNamespace) {
72 std::string Code = "namespace na {\n"
73 "namespace nx {\n"
74 "class A {};\n"
75 "} // namespace nx\n"
76 "} // namespace na\n";
77 std::string Expected = "namespace na {\n"
78 "namespace nx {\n"
79 "class A {};\n"
80 "} // namespace nx\n"
81 "} // namespace na\n";
82 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
83}
84
85TEST_F(ChangeNamespaceTest, SimpleMoveWithoutTypeRefs) {
86 std::string Code = "namespace na {\n"
87 "namespace nb {\n"
88 "class A {};\n"
89 "} // namespace nb\n"
90 "} // namespace na\n";
91 std::string Expected = "\n\n"
92 "namespace x {\n"
93 "namespace y {\n"
94 "class A {};\n"
95 "} // namespace y\n"
96 "} // namespace x\n";
97 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
98}
99
100TEST_F(ChangeNamespaceTest, SimpleMoveIntoAnotherNestedNamespace) {
101 NewNamespace = "na::nc";
102 std::string Code = "namespace na {\n"
103 "namespace nb {\n"
104 "class A {};\n"
105 "} // namespace nb\n"
106 "} // namespace na\n";
107 std::string Expected = "namespace na {\n"
108 "\n"
109 "namespace nc {\n"
110 "class A {};\n"
111 "} // namespace nc\n"
112 "} // namespace na\n";
113 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
114}
115
116TEST_F(ChangeNamespaceTest, SimpleMoveNestedNamespace) {
117 NewNamespace = "na::x::y";
118 std::string Code = "namespace na {\n"
119 "class A {};\n"
120 "namespace nb {\n"
121 "class B {};\n"
122 "} // namespace nb\n"
123 "} // namespace na\n";
124 std::string Expected = "namespace na {\n"
125 "class A {};\n"
126 "\n"
127 "namespace x {\n"
128 "namespace y {\n"
129 "class B {};\n"
130 "} // namespace y\n"
131 "} // namespace x\n"
132 "} // namespace na\n";
133 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
134}
135
136TEST_F(ChangeNamespaceTest, SimpleMoveWithTypeRefs) {
137 std::string Code = "namespace na {\n"
138 "class C_A {};\n"
139 "namespace nc {\n"
140 "class C_C {};"
141 "} // namespace nc\n"
142 "namespace nb {\n"
143 "class C_X {\n"
144 "public:\n"
145 " C_A a;\n"
146 " nc::C_C c;\n"
147 "};\n"
148 "class C_Y {\n"
149 " C_X x;\n"
150 "};\n"
151 "} // namespace nb\n"
152 "} // namespace na\n";
153 std::string Expected = "namespace na {\n"
154 "class C_A {};\n"
155 "namespace nc {\n"
156 "class C_C {};"
157 "} // namespace nc\n"
158 "\n"
159 "} // namespace na\n"
160 "namespace x {\n"
161 "namespace y {\n"
162 "class C_X {\n"
163 "public:\n"
164 " na::C_A a;\n"
165 " na::nc::C_C c;\n"
166 "};\n"
167 "class C_Y {\n"
168 " C_X x;\n"
169 "};\n"
170 "} // namespace y\n"
171 "} // namespace x\n";
172 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
173}
174
175TEST_F(ChangeNamespaceTest, LeaveForwardDeclarationBehind) {
176 std::string Code = "namespace na {\n"
177 "namespace nb {\n"
178 "class FWD;\n"
179 "class A {\n"
180 " FWD *fwd;\n"
181 "};\n"
182 "} // namespace nb\n"
183 "} // namespace na\n";
184 std::string Expected = "namespace na {\n"
185 "namespace nb {\n"
186 "class FWD;\n"
187 "} // namespace nb\n"
188 "} // namespace na\n"
189 "namespace x {\n"
190 "namespace y {\n"
191 "\n"
192 "class A {\n"
193 " na::nb::FWD *fwd;\n"
194 "};\n"
195 "} // namespace y\n"
196 "} // namespace x\n";
197 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
198}
199
200TEST_F(ChangeNamespaceTest, MoveFunctions) {
201 std::string Code = "namespace na {\n"
202 "class C_A {};\n"
203 "namespace nc {\n"
204 "class C_C {};"
205 "} // namespace nc\n"
206 "namespace nb {\n"
207 "void fwd();\n"
208 "void f(C_A ca, nc::C_C cc) {\n"
209 " C_A ca_1 = ca;\n"
210 "}\n"
211 "} // namespace nb\n"
212 "} // namespace na\n";
213
214 std::string Expected = "namespace na {\n"
215 "class C_A {};\n"
216 "namespace nc {\n"
217 "class C_C {};"
218 "} // namespace nc\n"
219 "\n"
220 "} // namespace na\n"
221 "namespace x {\n"
222 "namespace y {\n"
223 "void fwd();\n"
224 "void f(na::C_A ca, na::nc::C_C cc) {\n"
225 " na::C_A ca_1 = ca;\n"
226 "}\n"
227 "} // namespace y\n"
228 "} // namespace x\n";
229 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
230}
231
Eric Liu912d0392016-09-27 12:54:48 +0000232TEST_F(ChangeNamespaceTest, DoNotCrashWithLambdaAsParameter) {
233 std::string Code =
234 "#include <functional>\n"
235 "void f(std::function<void(int)> func, int param) { func(param); } "
236 "void g() { f([](int x) {}, 1); }";
237
238 std::string Expected =
239 "#include <functional>\n"
240 "void f(std::function<void(int)> func, int param) { func(param); } "
241 "void g() { f([](int x) {}, 1); }";
242 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
243}
244
Eric Liu68765a82016-09-21 15:06:12 +0000245TEST_F(ChangeNamespaceTest, FixUsingShadowDecl) {
Eric Liu912d0392016-09-27 12:54:48 +0000246 std::string Code = "class GLOB {};\n"
247 "using BLOG = GLOB;\n"
248 "namespace na {\n"
Eric Liu68765a82016-09-21 15:06:12 +0000249 "namespace nc {\n"
250 "class SAME {};\n"
251 "}\n"
252 "namespace nd {\n"
253 "class SAME {};\n"
254 "}\n"
255 "namespace nb {\n"
256 "using nc::SAME;\n"
257 "using YO = nc::SAME;\n"
258 "typedef nc::SAME IDENTICAL;\n"
259 "void f(nd::SAME Same) {}\n"
260 "} // namespace nb\n"
261 "} // namespace na\n";
262
Eric Liu912d0392016-09-27 12:54:48 +0000263 std::string Expected = "class GLOB {};\n"
264 "using BLOG = GLOB;\n"
265 "namespace na {\n"
Eric Liu68765a82016-09-21 15:06:12 +0000266 "namespace nc {\n"
267 "class SAME {};\n"
268 "}\n"
269 "namespace nd {\n"
270 "class SAME {};\n"
271 "}\n"
272 "\n"
273 "} // namespace na\n"
274 "namespace x {\n"
275 "namespace y {\n"
276 "using ::na::nc::SAME;\n"
277 "using YO = na::nc::SAME;\n"
278 "typedef na::nc::SAME IDENTICAL;\n"
279 "void f(na::nd::SAME Same) {}\n"
280 "} // namespace y\n"
281 "} // namespace x\n";
282 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
283}
284
Eric Liu912d0392016-09-27 12:54:48 +0000285TEST_F(ChangeNamespaceTest, UsingShadowDeclInFunction) {
286 std::string Code = "namespace glob {\n"
287 "class Glob {};\n"
288 "}\n"
289 "namespace na {\n"
290 "namespace nb {\n"
291 "void f() {\n"
292 " using glob::Glob;\n"
293 " Glob g;\n"
294 "}\n"
295 "} // namespace nb\n"
296 "} // namespace na\n";
297
298 // FIXME: don't add namespace qualifier when there is UsingShadowDecl.
299 std::string Expected = "namespace glob {\n"
300 "class Glob {};\n"
301 "}\n"
302 "\n"
303 "namespace x {\n"
304 "namespace y {\n"
305 "void f() {\n"
306 " using ::glob::Glob;\n"
307 " glob::Glob g;\n"
308 "}\n"
309 "} // namespace y\n"
310 "} // namespace x\n";
311 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
312}
313
314TEST_F(ChangeNamespaceTest, UsingShadowDeclInGlobal) {
315 std::string Code = "namespace glob {\n"
316 "class Glob {};\n"
317 "}\n"
318 "using glob::Glob;\n"
319 "namespace na {\n"
320 "namespace nb {\n"
321 "void f() { Glob g; }\n"
322 "} // namespace nb\n"
323 "} // namespace na\n";
324
325 // FIXME: don't add namespace qualifier when there is UsingShadowDecl.
326 std::string Expected = "namespace glob {\n"
327 "class Glob {};\n"
328 "}\n"
329 "using glob::Glob;\n"
330 "\n"
331 "namespace x {\n"
332 "namespace y {\n"
333 "void f() { glob::Glob g; }\n"
334 "} // namespace y\n"
335 "} // namespace x\n";
336 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
337}
338
339TEST_F(ChangeNamespaceTest, UsingNamespace) {
340 std::string Code = "namespace glob {\n"
341 "class Glob {};\n"
342 "}\n"
343 "using namespace glob;\n"
344 "namespace na {\n"
345 "namespace nb {\n"
346 "void f() { Glob g; }\n"
347 "} // namespace nb\n"
348 "} // namespace na\n";
349
350 // FIXME: don't add namespace qualifier when there is "using namespace" decl.
351 std::string Expected = "namespace glob {\n"
352 "class Glob {};\n"
353 "}\n"
354 "using namespace glob;\n"
355 "\n"
356 "namespace x {\n"
357 "namespace y {\n"
358 "void f() { glob::Glob g; }\n"
359 "} // namespace y\n"
360 "} // namespace x\n";
361 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
362}
363
Eric Liu68765a82016-09-21 15:06:12 +0000364TEST_F(ChangeNamespaceTest, TypeInNestedNameSpecifier) {
365 std::string Code =
366 "namespace na {\n"
367 "class C_A {\n"
368 "public:\n"
369 " class Nested {\n"
370 " public:\n"
371 " static int NestedX;\n"
372 " static void nestedFunc() {}\n"
373 " };\n"
374 "};\n"
375 "namespace nb {\n"
376 "class C_X {\n"
377 " C_A na;\n"
378 " C_A::Nested nested;\n"
379 " void f() {\n"
380 " C_A::Nested::nestedFunc();\n"
381 " int X = C_A::Nested::NestedX;\n"
382 " }\n"
383 "};\n"
384 "} // namespace nb\n"
385 "} // namespace na\n";
386 std::string Expected =
387 "namespace na {\n"
388 "class C_A {\n"
389 "public:\n"
390 " class Nested {\n"
391 " public:\n"
392 " static int NestedX;\n"
393 " static void nestedFunc() {}\n"
394 " };\n"
395 "};\n"
396 "\n"
397 "} // namespace na\n"
398 "namespace x {\n"
399 "namespace y {\n"
400 "class C_X {\n"
401 " na::C_A na;\n"
402 " na::C_A::Nested nested;\n"
403 " void f() {\n"
404 " na::C_A::Nested::nestedFunc();\n"
405 " int X = na::C_A::Nested::NestedX;\n"
406 " }\n"
407 "};\n"
408 "} // namespace y\n"
409 "} // namespace x\n";
410 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
411}
412
Eric Liu12068d82016-09-22 11:54:00 +0000413TEST_F(ChangeNamespaceTest, FixFunctionNameSpecifiers) {
414 std::string Code =
415 "namespace na {\n"
416 "class A {\n"
417 "public:\n"
418 " static void f() {}\n"
419 " static void g();\n"
420 "};\n"
421 "void A::g() {}"
422 "void a_f() {}\n"
423 "static void static_f() {}\n"
424 "namespace nb {\n"
425 "void f() { a_f(); static_f(); A::f(); }\n"
426 "void g() { f(); A::g(); }\n"
427 "} // namespace nb\n"
428 "} // namespace na\n";
429 std::string Expected =
430 "namespace na {\n"
431 "class A {\n"
432 "public:\n"
433 " static void f() {}\n"
434 " static void g();\n"
435 "};\n"
436 "void A::g() {}"
437 "void a_f() {}\n"
438 "static void static_f() {}\n"
439 "\n"
440 "} // namespace na\n"
441 "namespace x {\n"
442 "namespace y {\n"
443 "void f() { na::a_f(); na::static_f(); na::A::f(); }\n"
444 "void g() { f(); na::A::g(); }\n"
445 "} // namespace y\n"
446 "} // namespace x\n";
447 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
448}
449
Eric Liu159f0132016-09-30 04:32:39 +0000450TEST_F(ChangeNamespaceTest, MoveAndFixGlobalVariables) {
451 std::string Code = "namespace na {\n"
452 "int GlobA;\n"
453 "static int GlobAStatic = 0;\n"
454 "namespace nc { int GlobC; }\n"
455 "namespace nb {\n"
456 "int GlobB;\n"
457 "void f() {\n"
458 " int a = GlobA;\n"
459 " int b = GlobAStatic;\n"
460 " int c = nc::GlobC;\n"
461 "}\n"
462 "} // namespace nb\n"
463 "} // namespace na\n";
464
465 std::string Expected = "namespace na {\n"
466 "int GlobA;\n"
467 "static int GlobAStatic = 0;\n"
468 "namespace nc { int GlobC; }\n"
469 "\n"
470 "} // namespace na\n"
471 "namespace x {\n"
472 "namespace y {\n"
473 "int GlobB;\n"
474 "void f() {\n"
475 " int a = na::GlobA;\n"
476 " int b = na::GlobAStatic;\n"
477 " int c = na::nc::GlobC;\n"
478 "}\n"
479 "} // namespace y\n"
480 "} // namespace x\n";
481
482 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
483}
484
485TEST_F(ChangeNamespaceTest, DoNotFixStaticVariableOfClass) {
486 std::string Code = "namespace na {\n"
487 "class A {\n"
488 "public:\n"
489 "static int A1;\n"
490 "static int A2;\n"
491 "}\n"
492 "static int A::A1 = 0;\n"
493 "namespace nb {\n"
494 "void f() { int a = A::A1; int b = A::A2; }"
495 "} // namespace nb\n"
496 "} // namespace na\n";
497
498 std::string Expected = "namespace na {\n"
499 "class A {\n"
500 "public:\n"
501 "static int A1;\n"
502 "static int A2;\n"
503 "}\n"
504 "static int A::A1 = 0;\n"
505 "\n"
506 "} // namespace na\n"
507 "namespace x {\n"
508 "namespace y {\n"
509 "void f() { int a = na::A::A1; int b = na::A::A2; }"
510 "} // namespace y\n"
511 "} // namespace x\n";
512
513 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
514}
515
Haojian Wuef8a6dc2016-10-04 10:35:53 +0000516TEST_F(ChangeNamespaceTest, NoMisplaceAtEOF) {
517 std::string Code = "namespace na {\n"
518 "namespace nb {\n"
519 "class A;\n"
520 "class B {};\n"
521 "}"
522 "}";
523 std::string Expected = "namespace na {\n"
524 "namespace nb {\n"
525 "class A;\n"
526 "}\n"
527 "}\n"
528 "namespace x {\n"
529 "namespace y {\n"
530 "\n"
531 "class B {};\n"
532 "} // namespace y\n"
533 "} // namespace x\n";
534 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
535}
536
Eric Liu495b2112016-09-19 17:40:32 +0000537} // anonymous namespace
538} // namespace change_namespace
539} // namespace clang