blob: e8fdfaf1145db8cad411b8cb365ed0eed9292ce0 [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
Eric Liu447164d2016-10-05 15:52:39 +0000116TEST_F(ChangeNamespaceTest, MoveIntoAnotherNestedNamespaceWithRef) {
117 NewNamespace = "na::nc";
118 std::string Code = "namespace na {\n"
119 "class A {};\n"
120 "namespace nb {\n"
121 "class X { A a; };\n"
122 "} // namespace nb\n"
123 "} // namespace na\n";
124 std::string Expected = "namespace na {\n"
125 "class A {};\n"
126 "\n"
127 "namespace nc {\n"
128 "class X { A a; };\n"
129 "} // namespace nc\n"
130 "} // namespace na\n";
131 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
132}
133
Eric Liu495b2112016-09-19 17:40:32 +0000134TEST_F(ChangeNamespaceTest, SimpleMoveNestedNamespace) {
135 NewNamespace = "na::x::y";
136 std::string Code = "namespace na {\n"
137 "class A {};\n"
138 "namespace nb {\n"
139 "class B {};\n"
140 "} // namespace nb\n"
141 "} // namespace na\n";
142 std::string Expected = "namespace na {\n"
143 "class A {};\n"
144 "\n"
145 "namespace x {\n"
146 "namespace y {\n"
147 "class B {};\n"
148 "} // namespace y\n"
149 "} // namespace x\n"
150 "} // namespace na\n";
151 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
152}
153
154TEST_F(ChangeNamespaceTest, SimpleMoveWithTypeRefs) {
155 std::string Code = "namespace na {\n"
156 "class C_A {};\n"
157 "namespace nc {\n"
158 "class C_C {};"
159 "} // namespace nc\n"
160 "namespace nb {\n"
161 "class C_X {\n"
162 "public:\n"
163 " C_A a;\n"
164 " nc::C_C c;\n"
165 "};\n"
166 "class C_Y {\n"
167 " C_X x;\n"
168 "};\n"
169 "} // namespace nb\n"
170 "} // namespace na\n";
171 std::string Expected = "namespace na {\n"
172 "class C_A {};\n"
173 "namespace nc {\n"
174 "class C_C {};"
175 "} // namespace nc\n"
176 "\n"
177 "} // namespace na\n"
178 "namespace x {\n"
179 "namespace y {\n"
180 "class C_X {\n"
181 "public:\n"
182 " na::C_A a;\n"
183 " na::nc::C_C c;\n"
184 "};\n"
185 "class C_Y {\n"
186 " C_X x;\n"
187 "};\n"
188 "} // namespace y\n"
189 "} // namespace x\n";
190 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
191}
192
193TEST_F(ChangeNamespaceTest, LeaveForwardDeclarationBehind) {
194 std::string Code = "namespace na {\n"
195 "namespace nb {\n"
196 "class FWD;\n"
197 "class A {\n"
198 " FWD *fwd;\n"
199 "};\n"
200 "} // namespace nb\n"
201 "} // namespace na\n";
202 std::string Expected = "namespace na {\n"
203 "namespace nb {\n"
204 "class FWD;\n"
205 "} // namespace nb\n"
206 "} // namespace na\n"
207 "namespace x {\n"
208 "namespace y {\n"
209 "\n"
210 "class A {\n"
211 " na::nb::FWD *fwd;\n"
212 "};\n"
213 "} // namespace y\n"
214 "} // namespace x\n";
215 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
216}
217
218TEST_F(ChangeNamespaceTest, MoveFunctions) {
219 std::string Code = "namespace na {\n"
220 "class C_A {};\n"
221 "namespace nc {\n"
222 "class C_C {};"
223 "} // namespace nc\n"
224 "namespace nb {\n"
225 "void fwd();\n"
226 "void f(C_A ca, nc::C_C cc) {\n"
227 " C_A ca_1 = ca;\n"
228 "}\n"
229 "} // namespace nb\n"
230 "} // namespace na\n";
231
232 std::string Expected = "namespace na {\n"
233 "class C_A {};\n"
234 "namespace nc {\n"
235 "class C_C {};"
236 "} // namespace nc\n"
237 "\n"
238 "} // namespace na\n"
239 "namespace x {\n"
240 "namespace y {\n"
241 "void fwd();\n"
242 "void f(na::C_A ca, na::nc::C_C cc) {\n"
243 " na::C_A ca_1 = ca;\n"
244 "}\n"
245 "} // namespace y\n"
246 "} // namespace x\n";
247 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
248}
249
Eric Liu912d0392016-09-27 12:54:48 +0000250TEST_F(ChangeNamespaceTest, DoNotCrashWithLambdaAsParameter) {
251 std::string Code =
252 "#include <functional>\n"
253 "void f(std::function<void(int)> func, int param) { func(param); } "
254 "void g() { f([](int x) {}, 1); }";
255
256 std::string Expected =
257 "#include <functional>\n"
258 "void f(std::function<void(int)> func, int param) { func(param); } "
259 "void g() { f([](int x) {}, 1); }";
260 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
261}
262
Eric Liu68765a82016-09-21 15:06:12 +0000263TEST_F(ChangeNamespaceTest, FixUsingShadowDecl) {
Eric Liu912d0392016-09-27 12:54:48 +0000264 std::string Code = "class GLOB {};\n"
265 "using BLOG = GLOB;\n"
266 "namespace na {\n"
Eric Liu68765a82016-09-21 15:06:12 +0000267 "namespace nc {\n"
268 "class SAME {};\n"
269 "}\n"
270 "namespace nd {\n"
271 "class SAME {};\n"
272 "}\n"
273 "namespace nb {\n"
274 "using nc::SAME;\n"
275 "using YO = nc::SAME;\n"
276 "typedef nc::SAME IDENTICAL;\n"
277 "void f(nd::SAME Same) {}\n"
278 "} // namespace nb\n"
279 "} // namespace na\n";
280
Eric Liu912d0392016-09-27 12:54:48 +0000281 std::string Expected = "class GLOB {};\n"
282 "using BLOG = GLOB;\n"
283 "namespace na {\n"
Eric Liu68765a82016-09-21 15:06:12 +0000284 "namespace nc {\n"
285 "class SAME {};\n"
286 "}\n"
287 "namespace nd {\n"
288 "class SAME {};\n"
289 "}\n"
290 "\n"
291 "} // namespace na\n"
292 "namespace x {\n"
293 "namespace y {\n"
294 "using ::na::nc::SAME;\n"
295 "using YO = na::nc::SAME;\n"
296 "typedef na::nc::SAME IDENTICAL;\n"
297 "void f(na::nd::SAME Same) {}\n"
298 "} // namespace y\n"
299 "} // namespace x\n";
300 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
301}
302
Eric Liu912d0392016-09-27 12:54:48 +0000303TEST_F(ChangeNamespaceTest, UsingShadowDeclInFunction) {
304 std::string Code = "namespace glob {\n"
305 "class Glob {};\n"
306 "}\n"
307 "namespace na {\n"
308 "namespace nb {\n"
309 "void f() {\n"
310 " using glob::Glob;\n"
311 " Glob g;\n"
312 "}\n"
313 "} // namespace nb\n"
314 "} // namespace na\n";
315
316 // FIXME: don't add namespace qualifier when there is UsingShadowDecl.
317 std::string Expected = "namespace glob {\n"
318 "class Glob {};\n"
319 "}\n"
320 "\n"
321 "namespace x {\n"
322 "namespace y {\n"
323 "void f() {\n"
324 " using ::glob::Glob;\n"
325 " glob::Glob g;\n"
326 "}\n"
327 "} // namespace y\n"
328 "} // namespace x\n";
329 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
330}
331
332TEST_F(ChangeNamespaceTest, UsingShadowDeclInGlobal) {
333 std::string Code = "namespace glob {\n"
334 "class Glob {};\n"
335 "}\n"
336 "using glob::Glob;\n"
337 "namespace na {\n"
338 "namespace nb {\n"
339 "void f() { Glob g; }\n"
340 "} // namespace nb\n"
341 "} // namespace na\n";
342
343 // FIXME: don't add namespace qualifier when there is UsingShadowDecl.
344 std::string Expected = "namespace glob {\n"
345 "class Glob {};\n"
346 "}\n"
347 "using glob::Glob;\n"
348 "\n"
349 "namespace x {\n"
350 "namespace y {\n"
351 "void f() { glob::Glob g; }\n"
352 "} // namespace y\n"
353 "} // namespace x\n";
354 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
355}
356
357TEST_F(ChangeNamespaceTest, UsingNamespace) {
358 std::string Code = "namespace glob {\n"
359 "class Glob {};\n"
360 "}\n"
361 "using namespace glob;\n"
362 "namespace na {\n"
363 "namespace nb {\n"
364 "void f() { Glob g; }\n"
365 "} // namespace nb\n"
366 "} // namespace na\n";
367
368 // FIXME: don't add namespace qualifier when there is "using namespace" decl.
369 std::string Expected = "namespace glob {\n"
370 "class Glob {};\n"
371 "}\n"
372 "using namespace glob;\n"
373 "\n"
374 "namespace x {\n"
375 "namespace y {\n"
376 "void f() { glob::Glob g; }\n"
377 "} // namespace y\n"
378 "} // namespace x\n";
379 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
380}
381
Eric Liu68765a82016-09-21 15:06:12 +0000382TEST_F(ChangeNamespaceTest, TypeInNestedNameSpecifier) {
383 std::string Code =
384 "namespace na {\n"
385 "class C_A {\n"
386 "public:\n"
387 " class Nested {\n"
388 " public:\n"
389 " static int NestedX;\n"
390 " static void nestedFunc() {}\n"
391 " };\n"
392 "};\n"
393 "namespace nb {\n"
394 "class C_X {\n"
395 " C_A na;\n"
396 " C_A::Nested nested;\n"
397 " void f() {\n"
398 " C_A::Nested::nestedFunc();\n"
399 " int X = C_A::Nested::NestedX;\n"
400 " }\n"
401 "};\n"
402 "} // namespace nb\n"
403 "} // namespace na\n";
404 std::string Expected =
405 "namespace na {\n"
406 "class C_A {\n"
407 "public:\n"
408 " class Nested {\n"
409 " public:\n"
410 " static int NestedX;\n"
411 " static void nestedFunc() {}\n"
412 " };\n"
413 "};\n"
414 "\n"
415 "} // namespace na\n"
416 "namespace x {\n"
417 "namespace y {\n"
418 "class C_X {\n"
419 " na::C_A na;\n"
420 " na::C_A::Nested nested;\n"
421 " void f() {\n"
422 " na::C_A::Nested::nestedFunc();\n"
423 " int X = na::C_A::Nested::NestedX;\n"
424 " }\n"
425 "};\n"
426 "} // namespace y\n"
427 "} // namespace x\n";
428 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
429}
430
Eric Liu12068d82016-09-22 11:54:00 +0000431TEST_F(ChangeNamespaceTest, FixFunctionNameSpecifiers) {
432 std::string Code =
433 "namespace na {\n"
434 "class A {\n"
435 "public:\n"
436 " static void f() {}\n"
437 " static void g();\n"
438 "};\n"
439 "void A::g() {}"
440 "void a_f() {}\n"
441 "static void static_f() {}\n"
442 "namespace nb {\n"
443 "void f() { a_f(); static_f(); A::f(); }\n"
444 "void g() { f(); A::g(); }\n"
445 "} // namespace nb\n"
446 "} // namespace na\n";
447 std::string Expected =
448 "namespace na {\n"
449 "class A {\n"
450 "public:\n"
451 " static void f() {}\n"
452 " static void g();\n"
453 "};\n"
454 "void A::g() {}"
455 "void a_f() {}\n"
456 "static void static_f() {}\n"
457 "\n"
458 "} // namespace na\n"
459 "namespace x {\n"
460 "namespace y {\n"
461 "void f() { na::a_f(); na::static_f(); na::A::f(); }\n"
462 "void g() { f(); na::A::g(); }\n"
463 "} // namespace y\n"
464 "} // namespace x\n";
465 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
466}
467
Eric Liu159f0132016-09-30 04:32:39 +0000468TEST_F(ChangeNamespaceTest, MoveAndFixGlobalVariables) {
469 std::string Code = "namespace na {\n"
470 "int GlobA;\n"
471 "static int GlobAStatic = 0;\n"
472 "namespace nc { int GlobC; }\n"
473 "namespace nb {\n"
474 "int GlobB;\n"
475 "void f() {\n"
476 " int a = GlobA;\n"
477 " int b = GlobAStatic;\n"
478 " int c = nc::GlobC;\n"
479 "}\n"
480 "} // namespace nb\n"
481 "} // namespace na\n";
482
483 std::string Expected = "namespace na {\n"
484 "int GlobA;\n"
485 "static int GlobAStatic = 0;\n"
486 "namespace nc { int GlobC; }\n"
487 "\n"
488 "} // namespace na\n"
489 "namespace x {\n"
490 "namespace y {\n"
491 "int GlobB;\n"
492 "void f() {\n"
493 " int a = na::GlobA;\n"
494 " int b = na::GlobAStatic;\n"
495 " int c = na::nc::GlobC;\n"
496 "}\n"
497 "} // namespace y\n"
498 "} // namespace x\n";
499
500 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
501}
502
503TEST_F(ChangeNamespaceTest, DoNotFixStaticVariableOfClass) {
504 std::string Code = "namespace na {\n"
505 "class A {\n"
506 "public:\n"
507 "static int A1;\n"
508 "static int A2;\n"
509 "}\n"
510 "static int A::A1 = 0;\n"
511 "namespace nb {\n"
512 "void f() { int a = A::A1; int b = A::A2; }"
513 "} // namespace nb\n"
514 "} // namespace na\n";
515
516 std::string Expected = "namespace na {\n"
517 "class A {\n"
518 "public:\n"
519 "static int A1;\n"
520 "static int A2;\n"
521 "}\n"
522 "static int A::A1 = 0;\n"
523 "\n"
524 "} // namespace na\n"
525 "namespace x {\n"
526 "namespace y {\n"
527 "void f() { int a = na::A::A1; int b = na::A::A2; }"
528 "} // namespace y\n"
529 "} // namespace x\n";
530
531 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
532}
533
Haojian Wuef8a6dc2016-10-04 10:35:53 +0000534TEST_F(ChangeNamespaceTest, NoMisplaceAtEOF) {
535 std::string Code = "namespace na {\n"
536 "namespace nb {\n"
537 "class A;\n"
538 "class B {};\n"
539 "}"
540 "}";
541 std::string Expected = "namespace na {\n"
542 "namespace nb {\n"
543 "class A;\n"
544 "}\n"
545 "}\n"
546 "namespace x {\n"
547 "namespace y {\n"
548 "\n"
549 "class B {};\n"
550 "} // namespace y\n"
551 "} // namespace x\n";
552 EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
553}
554
Eric Liu495b2112016-09-19 17:40:32 +0000555} // anonymous namespace
556} // namespace change_namespace
557} // namespace clang