blob: 4f6fb2da6dcefb93215a95bddff9a2afe154bdf9 [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"
32 "class C1;\n"
33 "namespace b {\n"
34 "class Foo {\n"
35 "public:\n"
36 " void f();\n"
37 "\n"
38 "private:\n"
39 " C1 *c1;\n"
40 " static int b;\n"
41 "};\n"
42 "\n"
43 "class Foo2 {\n"
44 "public:\n"
45 " int f();\n"
46 "};\n"
47 "} // namespace b\n"
48 "} // namespace a\n";
49
50const char TestCC[] = "#include \"foo.h\"\n"
51 "namespace a {\n"
52 "namespace b {\n"
53 "namespace {\n"
54 "void f1() {}\n"
55 "int kConstInt1 = 0;\n"
56 "} // namespace\n"
57 "\n"
58 "static int kConstInt2 = 1;\n"
59 "\n"
60 "static int help() {\n"
61 " int a = 0;\n"
62 " return a;\n"
63 "}\n"
64 "\n"
65 "void Foo::f() { f1(); }\n"
66 "\n"
67 "int Foo::b = 2;\n"
68 "int Foo2::f() {\n"
69 " f1();\n"
70 " return 1;\n"
71 "}\n"
72 "} // namespace b\n"
73 "} // namespace a\n";
74
75const char ExpectedTestHeader[] = "namespace a {\n"
76 "class C1;\n"
77 "namespace b {\n"
78 "\n"
79 "class Foo2 {\n"
80 "public:\n"
81 " int f();\n"
82 "};\n"
83 "} // namespace b\n"
84 "} // namespace a\n";
85
86const char ExpectedTestCC[] = "#include \"foo.h\"\n"
87 "namespace a {\n"
88 "namespace b {\n"
89 "namespace {\n"
90 "void f1() {}\n"
91 "int kConstInt1 = 0;\n"
92 "} // namespace\n"
93 "\n"
94 "static int kConstInt2 = 1;\n"
95 "\n"
96 "static int help() {\n"
97 " int a = 0;\n"
98 " return a;\n"
99 "}\n"
100 "\n"
101 "int Foo2::f() {\n"
102 " f1();\n"
103 " return 1;\n"
104 "}\n"
105 "} // namespace b\n"
106 "} // namespace a\n";
107
108const char ExpectedNewHeader[] = "namespace a {\n"
109 "class C1;\n"
110 "namespace b {\n"
111 "class Foo {\n"
112 "public:\n"
113 " void f();\n"
114 "\n"
115 "private:\n"
116 " C1 *c1;\n"
117 " static int b;\n"
118 "};\n"
119 "} // namespace b\n"
120 "} // namespace a\n";
121
Haojian Wudaf4cb82016-09-23 13:28:38 +0000122const char ExpectedNewCC[] = "namespace a {\n"
Haojian Wu357ef992016-09-21 13:18:19 +0000123 "namespace b {\n"
124 "namespace {\n"
125 "void f1() {}\n"
126 "int kConstInt1 = 0;\n"
127 "} // namespace\n"
128 "static int kConstInt2 = 1;\n"
129 "static int help() {\n"
130 " int a = 0;\n"
131 " return a;\n"
132 "}\n"
133 "void Foo::f() { f1(); }\n"
134 "int Foo::b = 2;\n"
135 "} // namespace b\n"
136 "} // namespace a\n";
137
138std::map<std::string, std::string>
139runClangMoveOnCode(const move::ClangMoveTool::MoveDefinitionSpec &Spec) {
140 clang::RewriterTestContext Context;
141
142 std::map<llvm::StringRef, clang::FileID> FileToFileID;
143 std::vector<std::pair<std::string, std::string>> FileToSourceText = {
144 {TestHeaderName, TestHeader}, {TestCCName, TestCC}};
145
146 auto CreateFiles = [&FileToSourceText, &Context, &FileToFileID](
147 llvm::StringRef Name, llvm::StringRef Code) {
148 if (!Name.empty()) {
149 FileToSourceText.emplace_back(Name, Code);
150 FileToFileID[Name] = Context.createInMemoryFile(Name, Code);
151 }
152 };
153 CreateFiles(Spec.NewCC, "");
154 CreateFiles(Spec.NewHeader, "");
155 CreateFiles(Spec.OldHeader, TestHeader);
156 CreateFiles(Spec.OldCC, TestCC);
157
158 std::map<std::string, tooling::Replacements> FileToReplacements;
Haojian Wud2a6d7b2016-10-04 09:05:31 +0000159 llvm::SmallString<128> InitialDirectory;
160 std::error_code EC = llvm::sys::fs::current_path(InitialDirectory);
161 assert(!EC);
162 (void)EC;
Haojian Wu357ef992016-09-21 13:18:19 +0000163 auto Factory = llvm::make_unique<clang::move::ClangMoveActionFactory>(
Haojian Wu253d5962016-10-06 08:29:32 +0000164 Spec, FileToReplacements, InitialDirectory.str(), "LLVM");
Haojian Wu357ef992016-09-21 13:18:19 +0000165
166 tooling::runToolOnCodeWithArgs(
167 Factory->create(), TestCC, {"-std=c++11"}, TestCCName, "clang-move",
168 std::make_shared<PCHContainerOperations>(), FileToSourceText);
169 formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
170 // The Key is file name, value is the new code after moving the class.
171 std::map<std::string, std::string> Results;
172 for (const auto &It : FileToReplacements) {
173 StringRef FilePath = It.first;
174 Results[FilePath] = Context.getRewrittenText(FileToFileID[FilePath]);
175 }
176 return Results;
177}
178
179TEST(ClangMove, MoveHeaderAndCC) {
180 move::ClangMoveTool::MoveDefinitionSpec Spec;
181 Spec.Name = "a::b::Foo";
182 Spec.OldHeader = "foo.h";
183 Spec.OldCC = "foo.cc";
184 Spec.NewHeader = "new_foo.h";
185 Spec.NewCC = "new_foo.cc";
Haojian Wudaf4cb82016-09-23 13:28:38 +0000186 std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000187 auto Results = runClangMoveOnCode(Spec);
188 EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
189 EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
190 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
Haojian Wudaf4cb82016-09-23 13:28:38 +0000191 EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
Haojian Wu357ef992016-09-21 13:18:19 +0000192}
193
194TEST(ClangMove, MoveHeaderOnly) {
195 move::ClangMoveTool::MoveDefinitionSpec Spec;
196 Spec.Name = "a::b::Foo";
197 Spec.OldHeader = "foo.h";
198 Spec.NewHeader = "new_foo.h";
199 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000200 EXPECT_EQ(2u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000201 EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
202 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
203}
204
205TEST(ClangMove, MoveCCOnly) {
206 move::ClangMoveTool::MoveDefinitionSpec Spec;
207 Spec.Name = "a::b::Foo";
208 Spec.OldCC = "foo.cc";
209 Spec.NewCC = "new_foo.cc";
Haojian Wudaf4cb82016-09-23 13:28:38 +0000210 std::string ExpectedHeader = "#include \"foo.h\"\n";
Haojian Wu357ef992016-09-21 13:18:19 +0000211 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000212 EXPECT_EQ(2u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000213 EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
Haojian Wudaf4cb82016-09-23 13:28:38 +0000214 EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
Haojian Wu357ef992016-09-21 13:18:19 +0000215}
216
217TEST(ClangMove, MoveNonExistClass) {
218 move::ClangMoveTool::MoveDefinitionSpec Spec;
219 Spec.Name = "NonExistFoo";
220 Spec.OldHeader = "foo.h";
221 Spec.OldCC = "foo.cc";
222 Spec.NewHeader = "new_foo.h";
223 Spec.NewCC = "new_foo.cc";
224 auto Results = runClangMoveOnCode(Spec);
Haojian Wu62ba4462016-09-21 15:19:04 +0000225 EXPECT_EQ(0u, Results.size());
Haojian Wu357ef992016-09-21 13:18:19 +0000226}
227
228} // namespace
229} // namespce move
230} // namespace clang