blob: 2514327ec0d1f2c99ce357bf3dc5bb0892938e0c [file] [log] [blame]
Haojian Wu357ef992016-09-21 13:18:19 +00001//===-- ClangMoveTest.cpp - clang-move unit tests -------------------------===//
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 "ClangMove.h"
11#include "unittests/Tooling/RewriterTestContext.h"
12#include "clang/Format/Format.h"
13#include "clang/Frontend/FrontendActions.h"
14#include "clang/Frontend/TextDiagnosticPrinter.h"
15#include "clang/Rewrite/Core/Rewriter.h"
16#include "clang/Tooling/Refactoring.h"
17#include "clang/Tooling/Tooling.h"
18#include "llvm/ADT/StringRef.h"
19#include "gtest/gtest.h"
20#include <string>
21#include <vector>
22
23namespace clang {
24namespace move {
25namespace {
26
27const char TestHeaderName[] = "foo.h";
28
29const char TestCCName[] = "foo.cc";
30
31const char TestHeader[] = "namespace a {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000032 "class C1; // test\n"
Haojian Wu29c38f72016-10-21 19:26:43 +000033 "template <typename T> class C2;\n"
Haojian Wu357ef992016-09-21 13:18:19 +000034 "namespace b {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000035 "// This is a Foo class\n"
36 "// which is used in\n"
37 "// test.\n"
Haojian Wu357ef992016-09-21 13:18:19 +000038 "class Foo {\n"
39 "public:\n"
40 " void f();\n"
41 "\n"
42 "private:\n"
43 " C1 *c1;\n"
44 " static int b;\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000045 "}; // abc\n"
Haojian Wu357ef992016-09-21 13:18:19 +000046 "\n"
47 "class Foo2 {\n"
48 "public:\n"
49 " int f();\n"
50 "};\n"
51 "} // namespace b\n"
52 "} // namespace a\n";
53
54const char TestCC[] = "#include \"foo.h\"\n"
55 "namespace a {\n"
56 "namespace b {\n"
57 "namespace {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000058 "// comment1.\n"
Haojian Wu357ef992016-09-21 13:18:19 +000059 "void f1() {}\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000060 "/// comment2.\n"
Haojian Wu357ef992016-09-21 13:18:19 +000061 "int kConstInt1 = 0;\n"
62 "} // namespace\n"
63 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000064 "/* comment 3*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +000065 "static int kConstInt2 = 1;\n"
66 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000067 "/** comment4\n"
68 "*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +000069 "static int help() {\n"
70 " int a = 0;\n"
71 " return a;\n"
72 "}\n"
73 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000074 "// comment5\n"
75 "// comment5\n"
Haojian Wu36265162017-01-03 09:00:51 +000076 "void Foo::f() {\n"
77 " f1();\n"
78 " kConstInt1;\n"
79 " kConstInt2;\n"
80 " help();\n"
81 "}\n"
Haojian Wu357ef992016-09-21 13:18:19 +000082 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000083 "/////////////\n"
84 "// comment //\n"
85 "/////////////\n"
Haojian Wu357ef992016-09-21 13:18:19 +000086 "int Foo::b = 2;\n"
87 "int Foo2::f() {\n"
Haojian Wu36265162017-01-03 09:00:51 +000088 " kConstInt1;\n"
89 " kConstInt2;\n"
90 " help();\n"
Haojian Wu357ef992016-09-21 13:18:19 +000091 " f1();\n"
92 " return 1;\n"
93 "}\n"
94 "} // namespace b\n"
95 "} // namespace a\n";
96
97const char ExpectedTestHeader[] = "namespace a {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000098 "class C1; // test\n"
Haojian Wu29c38f72016-10-21 19:26:43 +000099 "template <typename T> class C2;\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000100 "namespace b {\n"
101 "\n"
102 "class Foo2 {\n"
103 "public:\n"
104 " int f();\n"
105 "};\n"
106 "} // namespace b\n"
107 "} // namespace a\n";
108
109const char ExpectedTestCC[] = "#include \"foo.h\"\n"
110 "namespace a {\n"
111 "namespace b {\n"
112 "namespace {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000113 "// comment1.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000114 "void f1() {}\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000115 "/// comment2.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000116 "int kConstInt1 = 0;\n"
117 "} // namespace\n"
118 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000119 "/* comment 3*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000120 "static int kConstInt2 = 1;\n"
121 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000122 "/** comment4\n"
123 "*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000124 "static int help() {\n"
125 " int a = 0;\n"
126 " return a;\n"
127 "}\n"
128 "\n"
129 "int Foo2::f() {\n"
Haojian Wu36265162017-01-03 09:00:51 +0000130 " kConstInt1;\n"
131 " kConstInt2;\n"
132 " help();\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000133 " f1();\n"
134 " return 1;\n"
135 "}\n"
136 "} // namespace b\n"
137 "} // namespace a\n";
138
Haojian Wu220c7552016-10-14 13:01:36 +0000139const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
140 "#define NEW_FOO_H\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000141 "\n"
Haojian Wu220c7552016-10-14 13:01:36 +0000142 "namespace a {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000143 "class C1; // test\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000144 "\n"
Haojian Wu29c38f72016-10-21 19:26:43 +0000145 "template <typename T> class C2;\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000146 "namespace b {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000147 "// This is a Foo class\n"
148 "// which is used in\n"
149 "// test.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000150 "class Foo {\n"
151 "public:\n"
152 " void f();\n"
153 "\n"
154 "private:\n"
155 " C1 *c1;\n"
156 " static int b;\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000157 "}; // abc\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000158 "} // namespace b\n"
Haojian Wu220c7552016-10-14 13:01:36 +0000159 "} // namespace a\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000160 "\n"
Haojian Wu220c7552016-10-14 13:01:36 +0000161 "#endif // NEW_FOO_H\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000162
Haojian Wudaf4cb82016-09-23 13:28:38 +0000163const char ExpectedNewCC[] = "namespace a {\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000164 "namespace b {\n"
165 "namespace {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000166 "// comment1.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000167 "void f1() {}\n"
Haojian Wu36265162017-01-03 09:00:51 +0000168 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000169 "/// comment2.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000170 "int kConstInt1 = 0;\n"
171 "} // namespace\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000172 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000173 "/* comment 3*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000174 "static int kConstInt2 = 1;\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000175 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000176 "/** comment4\n"
177 "*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000178 "static int help() {\n"
179 " int a = 0;\n"
180 " return a;\n"
181 "}\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000182 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000183 "// comment5\n"
184 "// comment5\n"
Haojian Wu36265162017-01-03 09:00:51 +0000185 "void Foo::f() {\n"
186 " f1();\n"
187 " kConstInt1;\n"
188 " kConstInt2;\n"
189 " help();\n"
190 "}\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000191 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000192 "/////////////\n"
193 "// comment //\n"
194 "/////////////\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000195 "int Foo::b = 2;\n"
196 "} // namespace b\n"
197 "} // namespace a\n";
198
199std::map<std::string, std::string>
Haojian Wub15c8da2016-11-24 10:17:17 +0000200runClangMoveOnCode(const move::MoveDefinitionSpec &Spec,
Haojian Wu2930be12016-11-08 19:55:13 +0000201 const char *const Header = TestHeader,
Haojian Wub15c8da2016-11-24 10:17:17 +0000202 const char *const CC = TestCC,
203 DeclarationReporter *const Reporter = nullptr) {
Haojian Wu357ef992016-09-21 13:18:19 +0000204 clang::RewriterTestContext Context;
205
206 std::map<llvm::StringRef, clang::FileID> FileToFileID;
207 std::vector<std::pair<std::string, std::string>> FileToSourceText = {
Haojian Wu2930be12016-11-08 19:55:13 +0000208 {TestHeaderName, Header}, {TestCCName, CC}};
Haojian Wu357ef992016-09-21 13:18:19 +0000209
Malcolm Parsonse65b1022017-01-13 19:02:50 +0000210 auto CreateFiles = [&Context, &FileToFileID](llvm::StringRef Name,
211 llvm::StringRef Code) {
Haojian Wu357ef992016-09-21 13:18:19 +0000212 if (!Name.empty()) {
Haojian Wu357ef992016-09-21 13:18:19 +0000213 FileToFileID[Name] = Context.createInMemoryFile(Name, Code);
214 }
215 };
216 CreateFiles(Spec.NewCC, "");
217 CreateFiles(Spec.NewHeader, "");
Haojian Wu2930be12016-11-08 19:55:13 +0000218 CreateFiles(Spec.OldHeader, Header);
219 CreateFiles(Spec.OldCC, CC);
Haojian Wu357ef992016-09-21 13:18:19 +0000220
221 std::map<std::string, tooling::Replacements> FileToReplacements;
Haojian Wud2a6d7b2016-10-04 09:05:31 +0000222 llvm::SmallString<128> InitialDirectory;
223 std::error_code EC = llvm::sys::fs::current_path(InitialDirectory);
224 assert(!EC);
225 (void)EC;
Haojian Wub15c8da2016-11-24 10:17:17 +0000226 ClangMoveContext MoveContext = {Spec, FileToReplacements,
227 InitialDirectory.str(), "LLVM",
228 Reporter != nullptr};
229
Haojian Wu357ef992016-09-21 13:18:19 +0000230 auto Factory = llvm::make_unique<clang::move::ClangMoveActionFactory>(
Haojian Wub15c8da2016-11-24 10:17:17 +0000231 &MoveContext, Reporter);
Haojian Wu357ef992016-09-21 13:18:19 +0000232
233 tooling::runToolOnCodeWithArgs(
Haojian Wu2930be12016-11-08 19:55:13 +0000234 Factory->create(), CC, {"-std=c++11", "-fparse-all-comments"},
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000235 TestCCName, "clang-move", std::make_shared<PCHContainerOperations>(),
236 FileToSourceText);
Haojian Wu357ef992016-09-21 13:18:19 +0000237 formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
238 // The Key is file name, value is the new code after moving the class.
239 std::map<std::string, std::string> Results;
240 for (const auto &It : FileToReplacements) {
241 StringRef FilePath = It.first;
242 Results[FilePath] = Context.getRewrittenText(FileToFileID[FilePath]);
243 }
244 return Results;
245}
246
247TEST(ClangMove, MoveHeaderAndCC) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000248 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000249 Spec.Names = {std::string("a::b::Foo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000250 Spec.OldHeader = "foo.h";
251 Spec.OldCC = "foo.cc";
252 Spec.NewHeader = "new_foo.h";
253 Spec.NewCC = "new_foo.cc";
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000254 std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000255 auto Results = runClangMoveOnCode(Spec);
256 EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
257 EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
258 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
Haojian Wudaf4cb82016-09-23 13:28:38 +0000259 EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
Haojian Wu357ef992016-09-21 13:18:19 +0000260}
261
262TEST(ClangMove, MoveHeaderOnly) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000263 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000264 Spec.Names = {std::string("a::b::Foo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000265 Spec.OldHeader = "foo.h";
266 Spec.NewHeader = "new_foo.h";
267 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000268 EXPECT_EQ(2u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000269 EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
270 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
271}
272
273TEST(ClangMove, MoveCCOnly) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000274 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000275 Spec.Names = {std::string("a::b::Foo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000276 Spec.OldCC = "foo.cc";
277 Spec.NewCC = "new_foo.cc";
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000278 std::string ExpectedHeader = "#include \"foo.h\"\n\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000279 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000280 EXPECT_EQ(2u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000281 EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
Haojian Wudaf4cb82016-09-23 13:28:38 +0000282 EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
Haojian Wu357ef992016-09-21 13:18:19 +0000283}
284
285TEST(ClangMove, MoveNonExistClass) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000286 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000287 Spec.Names = {std::string("NonExistFoo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000288 Spec.OldHeader = "foo.h";
289 Spec.OldCC = "foo.cc";
290 Spec.NewHeader = "new_foo.h";
291 Spec.NewCC = "new_foo.cc";
292 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000293 EXPECT_EQ(0u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000294}
295
Haojian Wu2930be12016-11-08 19:55:13 +0000296TEST(ClangMove, MoveAll) {
297 std::vector<std::string> TestHeaders = {
298 "class A {\npublic:\n int f();\n};",
299 // forward declaration.
300 "class B;\nclass A {\npublic:\n int f();\n};",
301 // template forward declaration.
302 "template <typename T> class B;\nclass A {\npublic:\n int f();\n};",
303 "namespace a {}\nclass A {\npublic:\n int f();\n};",
304 "namespace a {}\nusing namespace a;\nclass A {\npublic:\n int f();\n};",
305 };
306 const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
Haojian Wub15c8da2016-11-24 10:17:17 +0000307 move::MoveDefinitionSpec Spec;
Haojian Wu2930be12016-11-08 19:55:13 +0000308 Spec.Names.push_back("A");
309 Spec.OldHeader = "foo.h";
310 Spec.OldCC = "foo.cc";
311 Spec.NewHeader = "new_foo.h";
312 Spec.NewCC = "new_foo.cc";
313 for (const auto& Header : TestHeaders) {
314 auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
315 EXPECT_EQ(Header, Results[Spec.NewHeader]);
316 EXPECT_EQ("", Results[Spec.OldHeader]);
317 EXPECT_EQ("", Results[Spec.OldCC]);
318 }
319}
320
321TEST(ClangMove, MoveAllMultipleClasses) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000322 move::MoveDefinitionSpec Spec;
Haojian Wu2930be12016-11-08 19:55:13 +0000323 std::vector<std::string> TestHeaders = {
324 "class C;\nclass A {\npublic:\n int f();\n};\nclass B {};",
325 "class C;\nclass B;\nclass A {\npublic:\n int f();\n};\nclass B {};",
326 };
327 const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
328 Spec.Names = {std::string("A"), std::string("B")};
329 Spec.OldHeader = "foo.h";
330 Spec.OldCC = "foo.cc";
331 Spec.NewHeader = "new_foo.h";
332 Spec.NewCC = "new_foo.cc";
333 for (const auto& Header : TestHeaders) {
334 auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
335 EXPECT_EQ(Header, Results[Spec.NewHeader]);
336 EXPECT_EQ("", Results[Spec.OldHeader]);
337 EXPECT_EQ("", Results[Spec.OldCC]);
338 }
339}
340
341TEST(ClangMove, DontMoveAll) {
342 const char ExpectedHeader[] = "#ifndef NEW_FOO_H\n"
343 "#define NEW_FOO_H\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000344 "\n"
Haojian Wu2930be12016-11-08 19:55:13 +0000345 "class A {\npublic:\n int f();\n};\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000346 "\n"
Haojian Wu2930be12016-11-08 19:55:13 +0000347 "#endif // NEW_FOO_H\n";
348 const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
349 std::vector<std::string> TestHeaders = {
Haojian Wu53315a72016-11-15 09:06:59 +0000350 "class B {};\nclass A {\npublic:\n int f();\n};\n",
351 "void f() {};\nclass A {\npublic:\n int f();\n};\n",
Haojian Wu2930be12016-11-08 19:55:13 +0000352 };
Haojian Wub15c8da2016-11-24 10:17:17 +0000353 move::MoveDefinitionSpec Spec;
Haojian Wu2930be12016-11-08 19:55:13 +0000354 Spec.Names.push_back("A");
355 Spec.OldHeader = "foo.h";
356 Spec.OldCC = "foo.cc";
357 Spec.NewHeader = "new_foo.h";
358 Spec.NewCC = "new_foo.cc";
359 for (const auto& Header : TestHeaders) {
360 auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
361 EXPECT_EQ(ExpectedHeader, Results[Spec.NewHeader]);
362 // The expected old header should not contain class A definition.
Haojian Wu53315a72016-11-15 09:06:59 +0000363 std::string ExpectedOldHeader = Header.substr(0, Header.size() - 32);
Haojian Wu2930be12016-11-08 19:55:13 +0000364 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
365 }
366}
367
Haojian Wu24675392016-11-14 14:46:48 +0000368TEST(ClangMove, MacroInFunction) {
369 const char TestHeader[] = "#define INT int\n"
370 "class A {\npublic:\n int f();\n};\n"
371 "class B {};\n";
372 const char TestCode[] = "#include \"foo.h\"\n"
373 "INT A::f() { return 0; }\n";
374 const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
375 "INT A::f() { return 0; }\n";
Haojian Wub15c8da2016-11-24 10:17:17 +0000376 move::MoveDefinitionSpec Spec;
Haojian Wu24675392016-11-14 14:46:48 +0000377 Spec.Names.push_back("A");
378 Spec.OldHeader = "foo.h";
379 Spec.OldCC = "foo.cc";
380 Spec.NewHeader = "new_foo.h";
381 Spec.NewCC = "new_foo.cc";
382 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
383 EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
384}
385
Haojian Wudc4edba2016-12-13 15:35:47 +0000386TEST(ClangMove, DefinitionInMacro) {
387 const char TestHeader[] = "#define DEF(CLASS) void CLASS##_::f() {}\n"
388 "class A_ {\nvoid f();\n};\n"
389 "class B {};\n";
390 const char TestCode[] = "#include \"foo.h\"\n"
391 "DEF(A)\n";
392 const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
393 "DEF(A)\n";
394 move::MoveDefinitionSpec Spec;
395 Spec.Names.push_back("A_");
396 Spec.OldHeader = "foo.h";
397 Spec.OldCC = "foo.cc";
398 Spec.NewHeader = "new_foo.h";
399 Spec.NewCC = "new_foo.cc";
400 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
401 EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
402}
403
Haojian Wu53315a72016-11-15 09:06:59 +0000404TEST(ClangMove, WellFormattedCode) {
405 const std::string CommonHeader =
406 "namespace a {\n"
407 "namespace b {\n"
408 "namespace c {\n"
409 "class C;\n"
410 "\n"
411 "class A {\npublic:\n void f();\n void f2();\n};\n"
412 "} // namespace c\n"
413 "} // namespace b\n"
414 "\n"
415 "namespace d {\n"
416 "namespace e {\n"
417 "class B {\npublic:\n void f();\n};\n"
418 "} // namespace e\n"
419 "} // namespace d\n"
420 "} // namespace a\n";
421 const std::string CommonCode = "\n"
422 "namespace a {\n"
423 "namespace b {\n"
424 "namespace c {\n"
425 "void A::f() {}\n"
426 "\n"
427 "void A::f2() {}\n"
428 "} // namespace c\n"
429 "} // namespace b\n"
430 "\n"
431 "namespace d {\n"
432 "namespace e {\n"
433 "void B::f() {}\n"
434 "} // namespace e\n"
435 "} // namespace d\n"
436 "} // namespace a\n";
437 // Add dummy class to prevent behavior of moving all declarations from header.
438 const std::string TestHeader = CommonHeader + "class D {};\n";
439 const std::string TestCode = "#include \"foo.h\"\n" + CommonCode;
440 const std::string ExpectedNewHeader = "#ifndef NEW_FOO_H\n"
441 "#define NEW_FOO_H\n"
442 "\n" +
443 CommonHeader +
444 "\n"
445 "#endif // NEW_FOO_H\n";
446 const std::string ExpectedNewCC = "#include \"new_foo.h\"\n" + CommonCode;
Haojian Wub15c8da2016-11-24 10:17:17 +0000447 move::MoveDefinitionSpec Spec;
Haojian Wu53315a72016-11-15 09:06:59 +0000448 Spec.Names.push_back("a::b::c::A");
449 Spec.Names.push_back("a::d::e::B");
450 Spec.OldHeader = "foo.h";
451 Spec.OldCC = "foo.cc";
452 Spec.NewHeader = "new_foo.h";
453 Spec.NewCC = "new_foo.cc";
454 auto Results = runClangMoveOnCode(Spec, TestHeader.c_str(), TestCode.c_str());
455 EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
456 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
457}
458
Haojian Wu48ac3042016-11-23 10:04:19 +0000459TEST(ClangMove, AddDependentNewHeader) {
460 const char TestHeader[] = "class A {};\n"
461 "class B {};\n";
462 const char TestCode[] = "#include \"foo.h\"\n";
463 const char ExpectedOldHeader[] = "#include \"new_foo.h\"\nclass B {};\n";
464 const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
465 "#define NEW_FOO_H\n"
466 "\n"
467 "class A {};\n"
468 "\n"
469 "#endif // NEW_FOO_H\n";
Haojian Wub15c8da2016-11-24 10:17:17 +0000470 move::MoveDefinitionSpec Spec;
Haojian Wu48ac3042016-11-23 10:04:19 +0000471 Spec.Names.push_back("A");
472 Spec.OldHeader = "foo.h";
473 Spec.OldCC = "foo.cc";
474 Spec.NewHeader = "new_foo.h";
475 Spec.NewCC = "new_foo.cc";
476 Spec.OldDependOnNew = true;
477 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
478 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
479 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
480}
481
482TEST(ClangMove, AddDependentOldHeader) {
483 const char TestHeader[] = "class A {};\n"
484 "class B {};\n";
485 const char TestCode[] = "#include \"foo.h\"\n";
486 const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
487 "#define NEW_FOO_H\n"
488 "\n"
489 "#include \"foo.h\"\n"
490 "\n"
491 "class B {};\n"
492 "\n"
493 "#endif // NEW_FOO_H\n";
494 const char ExpectedOldHeader[] = "class A {};\n";
Haojian Wub15c8da2016-11-24 10:17:17 +0000495 move::MoveDefinitionSpec Spec;
Haojian Wu48ac3042016-11-23 10:04:19 +0000496 Spec.Names.push_back("B");
497 Spec.OldHeader = "foo.h";
498 Spec.OldCC = "foo.cc";
499 Spec.NewHeader = "new_foo.h";
500 Spec.NewCC = "new_foo.cc";
501 Spec.NewDependOnOld = true;
502 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
503 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
504 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
505}
506
Haojian Wub15c8da2016-11-24 10:17:17 +0000507TEST(ClangMove, DumpDecls) {
508 const char TestHeader[] = "template <typename T>\n"
509 "class A {\n"
510 " public:\n"
511 " void f();\n"
512 " template <typename U> void h();\n"
513 " static int b;\n"
514 "};\n"
515 "\n"
516 "template <typename T> void A<T>::f() {}\n"
517 "\n"
518 "template <typename T>\n"
519 "template <typename U>\n"
520 "void A<T>::h() {}\n"
521 "\n"
522 "template <typename T> int A<T>::b = 2;\n"
523 "\n"
524 "template <> class A<int> {};\n"
525 "\n"
526 "class B {};\n"
527 "\n"
528 "namespace a {\n"
529 "class Move1 {};\n"
530 "void f1() {}\n"
531 "void f2();\n"
532 "} // namespace a\n"
533 "\n"
534 "namespace a {\n"
535 "namespace b {\n"
536 "class Move1 { public : void f(); };\n"
537 "void f() {}\n"
Haojian Wu85867722017-01-16 09:34:07 +0000538 "enum E1 { Green };\n"
539 "enum class E2 { Red };\n"
540 "typedef int Int2;\n"
541 "using Int = int;\n"
Haojian Wub15c8da2016-11-24 10:17:17 +0000542 "} // namespace b\n"
543 "} // namespace a\n";
544 const char TestCode[] = "#include \"foo.h\"\n";
545 move::MoveDefinitionSpec Spec;
546 Spec.Names.push_back("B");
547 Spec.OldHeader = "foo.h";
548 Spec.OldCC = "foo.cc";
549 Spec.NewHeader = "new_foo.h";
550 Spec.NewCC = "new_foo.cc";
551 DeclarationReporter Reporter;
Haojian Wu85867722017-01-16 09:34:07 +0000552 std::set<DeclarationReporter::DeclarationPair> ExpectedDeclarations = {
Haojian Wub15c8da2016-11-24 10:17:17 +0000553 {"A", "Class"}, {"B", "Class"}, {"a::Move1", "Class"},
554 {"a::f1", "Function"}, {"a::f2", "Function"}, {"a::b::Move1", "Class"},
Haojian Wu85867722017-01-16 09:34:07 +0000555 {"a::b::f", "Function"}, {"a::b::E1", "Enum"}, {"a::b::E2", "Enum"},
556 {"a::b::Int2", "TypeAlias"}, {"a::b::Int", "TypeAlias"} };
Haojian Wub15c8da2016-11-24 10:17:17 +0000557 runClangMoveOnCode(Spec, TestHeader, TestCode, &Reporter);
Haojian Wu85867722017-01-16 09:34:07 +0000558 std::set<DeclarationReporter::DeclarationPair> Results;
559 for (const auto& DelPair : Reporter.getDeclarationList())
560 Results.insert(DelPair);
561 EXPECT_EQ(ExpectedDeclarations, Results);
Haojian Wub15c8da2016-11-24 10:17:17 +0000562}
563
Haojian Wu357ef992016-09-21 13:18:19 +0000564} // namespace
565} // namespce move
566} // namespace clang