blob: 11d14eca1de52187e325e812dae12d084819ca8b [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 Wu357ef992016-09-21 13:18:19 +000076 "void Foo::f() { f1(); }\n"
77 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000078 "/////////////\n"
79 "// comment //\n"
80 "/////////////\n"
Haojian Wu357ef992016-09-21 13:18:19 +000081 "int Foo::b = 2;\n"
82 "int Foo2::f() {\n"
83 " f1();\n"
84 " return 1;\n"
85 "}\n"
86 "} // namespace b\n"
87 "} // namespace a\n";
88
89const char ExpectedTestHeader[] = "namespace a {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +000090 "class C1; // test\n"
Haojian Wu29c38f72016-10-21 19:26:43 +000091 "template <typename T> class C2;\n"
Haojian Wu357ef992016-09-21 13:18:19 +000092 "namespace b {\n"
93 "\n"
94 "class Foo2 {\n"
95 "public:\n"
96 " int f();\n"
97 "};\n"
98 "} // namespace b\n"
99 "} // namespace a\n";
100
101const char ExpectedTestCC[] = "#include \"foo.h\"\n"
102 "namespace a {\n"
103 "namespace b {\n"
104 "namespace {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000105 "// comment1.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000106 "void f1() {}\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000107 "/// comment2.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000108 "int kConstInt1 = 0;\n"
109 "} // namespace\n"
110 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000111 "/* comment 3*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000112 "static int kConstInt2 = 1;\n"
113 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000114 "/** comment4\n"
115 "*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000116 "static int help() {\n"
117 " int a = 0;\n"
118 " return a;\n"
119 "}\n"
120 "\n"
121 "int Foo2::f() {\n"
122 " f1();\n"
123 " return 1;\n"
124 "}\n"
125 "} // namespace b\n"
126 "} // namespace a\n";
127
Haojian Wu220c7552016-10-14 13:01:36 +0000128const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
129 "#define NEW_FOO_H\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000130 "\n"
Haojian Wu220c7552016-10-14 13:01:36 +0000131 "namespace a {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000132 "class C1; // test\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000133 "\n"
Haojian Wu29c38f72016-10-21 19:26:43 +0000134 "template <typename T> class C2;\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000135 "namespace b {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000136 "// This is a Foo class\n"
137 "// which is used in\n"
138 "// test.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000139 "class Foo {\n"
140 "public:\n"
141 " void f();\n"
142 "\n"
143 "private:\n"
144 " C1 *c1;\n"
145 " static int b;\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000146 "}; // abc\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000147 "} // namespace b\n"
Haojian Wu220c7552016-10-14 13:01:36 +0000148 "} // namespace a\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000149 "\n"
Haojian Wu220c7552016-10-14 13:01:36 +0000150 "#endif // NEW_FOO_H\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000151
Haojian Wudaf4cb82016-09-23 13:28:38 +0000152const char ExpectedNewCC[] = "namespace a {\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000153 "namespace b {\n"
154 "namespace {\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000155 "// comment1.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000156 "void f1() {}\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000157 "/// comment2.\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000158 "int kConstInt1 = 0;\n"
159 "} // namespace\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000160 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000161 "/* comment 3*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000162 "static int kConstInt2 = 1;\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000163 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000164 "/** comment4\n"
165 "*/\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000166 "static int help() {\n"
167 " int a = 0;\n"
168 " return a;\n"
169 "}\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000170 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000171 "// comment5\n"
172 "// comment5\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000173 "void Foo::f() { f1(); }\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000174 "\n"
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000175 "/////////////\n"
176 "// comment //\n"
177 "/////////////\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000178 "int Foo::b = 2;\n"
179 "} // namespace b\n"
180 "} // namespace a\n";
181
182std::map<std::string, std::string>
Haojian Wub15c8da2016-11-24 10:17:17 +0000183runClangMoveOnCode(const move::MoveDefinitionSpec &Spec,
Haojian Wu2930be12016-11-08 19:55:13 +0000184 const char *const Header = TestHeader,
Haojian Wub15c8da2016-11-24 10:17:17 +0000185 const char *const CC = TestCC,
186 DeclarationReporter *const Reporter = nullptr) {
Haojian Wu357ef992016-09-21 13:18:19 +0000187 clang::RewriterTestContext Context;
188
189 std::map<llvm::StringRef, clang::FileID> FileToFileID;
190 std::vector<std::pair<std::string, std::string>> FileToSourceText = {
Haojian Wu2930be12016-11-08 19:55:13 +0000191 {TestHeaderName, Header}, {TestCCName, CC}};
Haojian Wu357ef992016-09-21 13:18:19 +0000192
193 auto CreateFiles = [&FileToSourceText, &Context, &FileToFileID](
194 llvm::StringRef Name, llvm::StringRef Code) {
195 if (!Name.empty()) {
Haojian Wu357ef992016-09-21 13:18:19 +0000196 FileToFileID[Name] = Context.createInMemoryFile(Name, Code);
197 }
198 };
199 CreateFiles(Spec.NewCC, "");
200 CreateFiles(Spec.NewHeader, "");
Haojian Wu2930be12016-11-08 19:55:13 +0000201 CreateFiles(Spec.OldHeader, Header);
202 CreateFiles(Spec.OldCC, CC);
Haojian Wu357ef992016-09-21 13:18:19 +0000203
204 std::map<std::string, tooling::Replacements> FileToReplacements;
Haojian Wud2a6d7b2016-10-04 09:05:31 +0000205 llvm::SmallString<128> InitialDirectory;
206 std::error_code EC = llvm::sys::fs::current_path(InitialDirectory);
207 assert(!EC);
208 (void)EC;
Haojian Wub15c8da2016-11-24 10:17:17 +0000209 ClangMoveContext MoveContext = {Spec, FileToReplacements,
210 InitialDirectory.str(), "LLVM",
211 Reporter != nullptr};
212
Haojian Wu357ef992016-09-21 13:18:19 +0000213 auto Factory = llvm::make_unique<clang::move::ClangMoveActionFactory>(
Haojian Wub15c8da2016-11-24 10:17:17 +0000214 &MoveContext, Reporter);
Haojian Wu357ef992016-09-21 13:18:19 +0000215
216 tooling::runToolOnCodeWithArgs(
Haojian Wu2930be12016-11-08 19:55:13 +0000217 Factory->create(), CC, {"-std=c++11", "-fparse-all-comments"},
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000218 TestCCName, "clang-move", std::make_shared<PCHContainerOperations>(),
219 FileToSourceText);
Haojian Wu357ef992016-09-21 13:18:19 +0000220 formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
221 // The Key is file name, value is the new code after moving the class.
222 std::map<std::string, std::string> Results;
223 for (const auto &It : FileToReplacements) {
224 StringRef FilePath = It.first;
225 Results[FilePath] = Context.getRewrittenText(FileToFileID[FilePath]);
226 }
227 return Results;
228}
229
230TEST(ClangMove, MoveHeaderAndCC) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000231 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000232 Spec.Names = {std::string("a::b::Foo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000233 Spec.OldHeader = "foo.h";
234 Spec.OldCC = "foo.cc";
235 Spec.NewHeader = "new_foo.h";
236 Spec.NewCC = "new_foo.cc";
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000237 std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000238 auto Results = runClangMoveOnCode(Spec);
239 EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
240 EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
241 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
Haojian Wudaf4cb82016-09-23 13:28:38 +0000242 EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
Haojian Wu357ef992016-09-21 13:18:19 +0000243}
244
245TEST(ClangMove, MoveHeaderOnly) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000246 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000247 Spec.Names = {std::string("a::b::Foo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000248 Spec.OldHeader = "foo.h";
249 Spec.NewHeader = "new_foo.h";
250 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000251 EXPECT_EQ(2u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000252 EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
253 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
254}
255
256TEST(ClangMove, MoveCCOnly) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000257 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000258 Spec.Names = {std::string("a::b::Foo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000259 Spec.OldCC = "foo.cc";
260 Spec.NewCC = "new_foo.cc";
Haojian Wu9abbeaa2016-10-06 08:59:24 +0000261 std::string ExpectedHeader = "#include \"foo.h\"\n\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000262 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000263 EXPECT_EQ(2u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000264 EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
Haojian Wudaf4cb82016-09-23 13:28:38 +0000265 EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
Haojian Wu357ef992016-09-21 13:18:19 +0000266}
267
268TEST(ClangMove, MoveNonExistClass) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000269 move::MoveDefinitionSpec Spec;
NAKAMURA Takumi0cfbbae2016-10-17 05:09:58 +0000270 Spec.Names = {std::string("NonExistFoo")};
Haojian Wu357ef992016-09-21 13:18:19 +0000271 Spec.OldHeader = "foo.h";
272 Spec.OldCC = "foo.cc";
273 Spec.NewHeader = "new_foo.h";
274 Spec.NewCC = "new_foo.cc";
275 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000276 EXPECT_EQ(0u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000277}
278
Haojian Wu2930be12016-11-08 19:55:13 +0000279TEST(ClangMove, MoveAll) {
280 std::vector<std::string> TestHeaders = {
281 "class A {\npublic:\n int f();\n};",
282 // forward declaration.
283 "class B;\nclass A {\npublic:\n int f();\n};",
284 // template forward declaration.
285 "template <typename T> class B;\nclass A {\npublic:\n int f();\n};",
286 "namespace a {}\nclass A {\npublic:\n int f();\n};",
287 "namespace a {}\nusing namespace a;\nclass A {\npublic:\n int f();\n};",
288 };
289 const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
Haojian Wub15c8da2016-11-24 10:17:17 +0000290 move::MoveDefinitionSpec Spec;
Haojian Wu2930be12016-11-08 19:55:13 +0000291 Spec.Names.push_back("A");
292 Spec.OldHeader = "foo.h";
293 Spec.OldCC = "foo.cc";
294 Spec.NewHeader = "new_foo.h";
295 Spec.NewCC = "new_foo.cc";
296 for (const auto& Header : TestHeaders) {
297 auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
298 EXPECT_EQ(Header, Results[Spec.NewHeader]);
299 EXPECT_EQ("", Results[Spec.OldHeader]);
300 EXPECT_EQ("", Results[Spec.OldCC]);
301 }
302}
303
304TEST(ClangMove, MoveAllMultipleClasses) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000305 move::MoveDefinitionSpec Spec;
Haojian Wu2930be12016-11-08 19:55:13 +0000306 std::vector<std::string> TestHeaders = {
307 "class C;\nclass A {\npublic:\n int f();\n};\nclass B {};",
308 "class C;\nclass B;\nclass A {\npublic:\n int f();\n};\nclass B {};",
309 };
310 const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
311 Spec.Names = {std::string("A"), std::string("B")};
312 Spec.OldHeader = "foo.h";
313 Spec.OldCC = "foo.cc";
314 Spec.NewHeader = "new_foo.h";
315 Spec.NewCC = "new_foo.cc";
316 for (const auto& Header : TestHeaders) {
317 auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
318 EXPECT_EQ(Header, Results[Spec.NewHeader]);
319 EXPECT_EQ("", Results[Spec.OldHeader]);
320 EXPECT_EQ("", Results[Spec.OldCC]);
321 }
322}
323
324TEST(ClangMove, DontMoveAll) {
325 const char ExpectedHeader[] = "#ifndef NEW_FOO_H\n"
326 "#define NEW_FOO_H\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000327 "\n"
Haojian Wu2930be12016-11-08 19:55:13 +0000328 "class A {\npublic:\n int f();\n};\n"
Haojian Wu53315a72016-11-15 09:06:59 +0000329 "\n"
Haojian Wu2930be12016-11-08 19:55:13 +0000330 "#endif // NEW_FOO_H\n";
331 const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
332 std::vector<std::string> TestHeaders = {
Haojian Wu53315a72016-11-15 09:06:59 +0000333 "class B {};\nclass A {\npublic:\n int f();\n};\n",
334 "void f() {};\nclass A {\npublic:\n int f();\n};\n",
Haojian Wu2930be12016-11-08 19:55:13 +0000335 };
Haojian Wub15c8da2016-11-24 10:17:17 +0000336 move::MoveDefinitionSpec Spec;
Haojian Wu2930be12016-11-08 19:55:13 +0000337 Spec.Names.push_back("A");
338 Spec.OldHeader = "foo.h";
339 Spec.OldCC = "foo.cc";
340 Spec.NewHeader = "new_foo.h";
341 Spec.NewCC = "new_foo.cc";
342 for (const auto& Header : TestHeaders) {
343 auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
344 EXPECT_EQ(ExpectedHeader, Results[Spec.NewHeader]);
345 // The expected old header should not contain class A definition.
Haojian Wu53315a72016-11-15 09:06:59 +0000346 std::string ExpectedOldHeader = Header.substr(0, Header.size() - 32);
Haojian Wu2930be12016-11-08 19:55:13 +0000347 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
348 }
349}
350
Eric Liu47a42d52016-12-06 10:12:23 +0000351TEST(ClangMove, IgnoreUnsupportedKindsAndMoveAll) {
352 const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
353 std::vector<std::string> TestHeaders = {
354 "typedef int Int;\nclass A {\npublic:\n int f();\n};\n",
355 "using Int = int;\nclass A {\npublic:\n int f();\n};\n",
356 "enum Color { RED };\nclass A {\npublic:\n int f();\n};\n",
357 };
358 move::MoveDefinitionSpec Spec;
359 Spec.Names.push_back("A");
360 Spec.OldHeader = "foo.h";
361 Spec.OldCC = "foo.cc";
362 Spec.NewHeader = "new_foo.h";
363 Spec.NewCC = "new_foo.cc";
364 for (const auto &Header : TestHeaders) {
365 auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
366 EXPECT_EQ(Header, Results[Spec.NewHeader]);
367 EXPECT_EQ("", Results[Spec.OldHeader]);
368 }
369}
370
Haojian Wu24675392016-11-14 14:46:48 +0000371TEST(ClangMove, MacroInFunction) {
372 const char TestHeader[] = "#define INT int\n"
373 "class A {\npublic:\n int f();\n};\n"
374 "class B {};\n";
375 const char TestCode[] = "#include \"foo.h\"\n"
376 "INT A::f() { return 0; }\n";
377 const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
378 "INT A::f() { return 0; }\n";
Haojian Wub15c8da2016-11-24 10:17:17 +0000379 move::MoveDefinitionSpec Spec;
Haojian Wu24675392016-11-14 14:46:48 +0000380 Spec.Names.push_back("A");
381 Spec.OldHeader = "foo.h";
382 Spec.OldCC = "foo.cc";
383 Spec.NewHeader = "new_foo.h";
384 Spec.NewCC = "new_foo.cc";
385 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
386 EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
387}
388
Haojian Wudc4edba2016-12-13 15:35:47 +0000389TEST(ClangMove, DefinitionInMacro) {
390 const char TestHeader[] = "#define DEF(CLASS) void CLASS##_::f() {}\n"
391 "class A_ {\nvoid f();\n};\n"
392 "class B {};\n";
393 const char TestCode[] = "#include \"foo.h\"\n"
394 "DEF(A)\n";
395 const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
396 "DEF(A)\n";
397 move::MoveDefinitionSpec Spec;
398 Spec.Names.push_back("A_");
399 Spec.OldHeader = "foo.h";
400 Spec.OldCC = "foo.cc";
401 Spec.NewHeader = "new_foo.h";
402 Spec.NewCC = "new_foo.cc";
403 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
404 EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
405}
406
Haojian Wu53315a72016-11-15 09:06:59 +0000407TEST(ClangMove, WellFormattedCode) {
408 const std::string CommonHeader =
409 "namespace a {\n"
410 "namespace b {\n"
411 "namespace c {\n"
412 "class C;\n"
413 "\n"
414 "class A {\npublic:\n void f();\n void f2();\n};\n"
415 "} // namespace c\n"
416 "} // namespace b\n"
417 "\n"
418 "namespace d {\n"
419 "namespace e {\n"
420 "class B {\npublic:\n void f();\n};\n"
421 "} // namespace e\n"
422 "} // namespace d\n"
423 "} // namespace a\n";
424 const std::string CommonCode = "\n"
425 "namespace a {\n"
426 "namespace b {\n"
427 "namespace c {\n"
428 "void A::f() {}\n"
429 "\n"
430 "void A::f2() {}\n"
431 "} // namespace c\n"
432 "} // namespace b\n"
433 "\n"
434 "namespace d {\n"
435 "namespace e {\n"
436 "void B::f() {}\n"
437 "} // namespace e\n"
438 "} // namespace d\n"
439 "} // namespace a\n";
440 // Add dummy class to prevent behavior of moving all declarations from header.
441 const std::string TestHeader = CommonHeader + "class D {};\n";
442 const std::string TestCode = "#include \"foo.h\"\n" + CommonCode;
443 const std::string ExpectedNewHeader = "#ifndef NEW_FOO_H\n"
444 "#define NEW_FOO_H\n"
445 "\n" +
446 CommonHeader +
447 "\n"
448 "#endif // NEW_FOO_H\n";
449 const std::string ExpectedNewCC = "#include \"new_foo.h\"\n" + CommonCode;
Haojian Wub15c8da2016-11-24 10:17:17 +0000450 move::MoveDefinitionSpec Spec;
Haojian Wu53315a72016-11-15 09:06:59 +0000451 Spec.Names.push_back("a::b::c::A");
452 Spec.Names.push_back("a::d::e::B");
453 Spec.OldHeader = "foo.h";
454 Spec.OldCC = "foo.cc";
455 Spec.NewHeader = "new_foo.h";
456 Spec.NewCC = "new_foo.cc";
457 auto Results = runClangMoveOnCode(Spec, TestHeader.c_str(), TestCode.c_str());
458 EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
459 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
460}
461
Haojian Wu48ac3042016-11-23 10:04:19 +0000462TEST(ClangMove, AddDependentNewHeader) {
463 const char TestHeader[] = "class A {};\n"
464 "class B {};\n";
465 const char TestCode[] = "#include \"foo.h\"\n";
466 const char ExpectedOldHeader[] = "#include \"new_foo.h\"\nclass B {};\n";
467 const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
468 "#define NEW_FOO_H\n"
469 "\n"
470 "class A {};\n"
471 "\n"
472 "#endif // NEW_FOO_H\n";
Haojian Wub15c8da2016-11-24 10:17:17 +0000473 move::MoveDefinitionSpec Spec;
Haojian Wu48ac3042016-11-23 10:04:19 +0000474 Spec.Names.push_back("A");
475 Spec.OldHeader = "foo.h";
476 Spec.OldCC = "foo.cc";
477 Spec.NewHeader = "new_foo.h";
478 Spec.NewCC = "new_foo.cc";
479 Spec.OldDependOnNew = true;
480 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
481 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
482 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
483}
484
485TEST(ClangMove, AddDependentOldHeader) {
486 const char TestHeader[] = "class A {};\n"
487 "class B {};\n";
488 const char TestCode[] = "#include \"foo.h\"\n";
489 const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
490 "#define NEW_FOO_H\n"
491 "\n"
492 "#include \"foo.h\"\n"
493 "\n"
494 "class B {};\n"
495 "\n"
496 "#endif // NEW_FOO_H\n";
497 const char ExpectedOldHeader[] = "class A {};\n";
Haojian Wub15c8da2016-11-24 10:17:17 +0000498 move::MoveDefinitionSpec Spec;
Haojian Wu48ac3042016-11-23 10:04:19 +0000499 Spec.Names.push_back("B");
500 Spec.OldHeader = "foo.h";
501 Spec.OldCC = "foo.cc";
502 Spec.NewHeader = "new_foo.h";
503 Spec.NewCC = "new_foo.cc";
504 Spec.NewDependOnOld = true;
505 auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
506 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
507 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
508}
509
Haojian Wub15c8da2016-11-24 10:17:17 +0000510TEST(ClangMove, DumpDecls) {
511 const char TestHeader[] = "template <typename T>\n"
512 "class A {\n"
513 " public:\n"
514 " void f();\n"
515 " template <typename U> void h();\n"
516 " static int b;\n"
517 "};\n"
518 "\n"
519 "template <typename T> void A<T>::f() {}\n"
520 "\n"
521 "template <typename T>\n"
522 "template <typename U>\n"
523 "void A<T>::h() {}\n"
524 "\n"
525 "template <typename T> int A<T>::b = 2;\n"
526 "\n"
527 "template <> class A<int> {};\n"
528 "\n"
529 "class B {};\n"
530 "\n"
531 "namespace a {\n"
532 "class Move1 {};\n"
533 "void f1() {}\n"
534 "void f2();\n"
535 "} // namespace a\n"
536 "\n"
537 "namespace a {\n"
538 "namespace b {\n"
539 "class Move1 { public : void f(); };\n"
540 "void f() {}\n"
541 "} // namespace b\n"
542 "} // namespace a\n";
543 const char TestCode[] = "#include \"foo.h\"\n";
544 move::MoveDefinitionSpec Spec;
545 Spec.Names.push_back("B");
546 Spec.OldHeader = "foo.h";
547 Spec.OldCC = "foo.cc";
548 Spec.NewHeader = "new_foo.h";
549 Spec.NewCC = "new_foo.cc";
550 DeclarationReporter Reporter;
551 std::vector<DeclarationReporter::DeclarationPair> ExpectedDeclarations = {
552 {"A", "Class"}, {"B", "Class"}, {"a::Move1", "Class"},
553 {"a::f1", "Function"}, {"a::f2", "Function"}, {"a::b::Move1", "Class"},
554 {"a::b::f", "Function"}};
555 runClangMoveOnCode(Spec, TestHeader, TestCode, &Reporter);
556 const auto& Results = Reporter.getDeclarationList();
557 auto ActualDeclIter = Results.begin();
558 auto ExpectedDeclIter = ExpectedDeclarations.begin();
NAKAMURA Takumi5843abc2016-11-28 14:27:37 +0000559 while (ActualDeclIter != Results.end() &&
560 ExpectedDeclIter != ExpectedDeclarations.end()) {
Haojian Wub15c8da2016-11-24 10:17:17 +0000561 EXPECT_EQ(*ActualDeclIter, *ExpectedDeclIter);
562 ++ActualDeclIter;
563 ++ExpectedDeclIter;
564 }
565 ASSERT_TRUE(ActualDeclIter == Results.end());
566 ASSERT_TRUE(ExpectedDeclIter == ExpectedDeclarations.end());
567}
568
Haojian Wu357ef992016-09-21 13:18:19 +0000569} // namespace
570} // namespce move
571} // namespace clang