xref: /llvm-project/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp (revision 98f0bf74ca6d7aa9b3c2b240693824f085aa6675)
1ffe9f00cSFangrui Song //===-- ClangMoveTests.cpp - clang-move unit tests ------------------------===//
2357ef999SHaojian Wu //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6357ef999SHaojian Wu //
7357ef999SHaojian Wu //===----------------------------------------------------------------------===//
8357ef999SHaojian Wu 
9b719245aSAlexander Kornienko #include "Move.h"
10357ef999SHaojian Wu #include "unittests/Tooling/RewriterTestContext.h"
11357ef999SHaojian Wu #include "clang/Format/Format.h"
12357ef999SHaojian Wu #include "clang/Frontend/FrontendActions.h"
13357ef999SHaojian Wu #include "clang/Frontend/TextDiagnosticPrinter.h"
14357ef999SHaojian Wu #include "clang/Rewrite/Core/Rewriter.h"
15357ef999SHaojian Wu #include "clang/Tooling/Refactoring.h"
16357ef999SHaojian Wu #include "clang/Tooling/Tooling.h"
17357ef999SHaojian Wu #include "llvm/ADT/StringRef.h"
18bce181c6SEric Liu #include "gmock/gmock-matchers.h"
19357ef999SHaojian Wu #include "gtest/gtest.h"
20357ef999SHaojian Wu #include <string>
21357ef999SHaojian Wu #include <vector>
22357ef999SHaojian Wu 
23357ef999SHaojian Wu namespace clang {
24357ef999SHaojian Wu namespace move {
25357ef999SHaojian Wu namespace {
26357ef999SHaojian Wu 
27357ef999SHaojian Wu const char TestHeader[] = "namespace a {\n"
289abbeaadSHaojian Wu                           "class C1; // test\n"
2929c38f75SHaojian Wu                           "template <typename T> class C2;\n"
30357ef999SHaojian Wu                           "namespace b {\n"
319abbeaadSHaojian Wu                           "// This is a Foo class\n"
329abbeaadSHaojian Wu                           "// which is used in\n"
339abbeaadSHaojian Wu                           "// test.\n"
34357ef999SHaojian Wu                           "class Foo {\n"
35357ef999SHaojian Wu                           "public:\n"
36357ef999SHaojian Wu                           "  void f();\n"
37357ef999SHaojian Wu                           "\n"
38357ef999SHaojian Wu                           "private:\n"
39357ef999SHaojian Wu                           "  C1 *c1;\n"
40357ef999SHaojian Wu                           "  static int b;\n"
419abbeaadSHaojian Wu                           "}; // abc\n"
42357ef999SHaojian Wu                           "\n"
43357ef999SHaojian Wu                           "class Foo2 {\n"
44357ef999SHaojian Wu                           "public:\n"
45357ef999SHaojian Wu                           "  int f();\n"
46357ef999SHaojian Wu                           "};\n"
47357ef999SHaojian Wu                           "} // namespace b\n"
48357ef999SHaojian Wu                           "} // namespace a\n";
49357ef999SHaojian Wu 
50357ef999SHaojian Wu const char TestCC[] = "#include \"foo.h\"\n"
51357ef999SHaojian Wu                       "namespace a {\n"
52357ef999SHaojian Wu                       "namespace b {\n"
53357ef999SHaojian Wu                       "namespace {\n"
549abbeaadSHaojian Wu                       "// comment1.\n"
55357ef999SHaojian Wu                       "void f1() {}\n"
569abbeaadSHaojian Wu                       "/// comment2.\n"
57357ef999SHaojian Wu                       "int kConstInt1 = 0;\n"
58357ef999SHaojian Wu                       "} // namespace\n"
59357ef999SHaojian Wu                       "\n"
609abbeaadSHaojian Wu                       "/* comment 3*/\n"
61357ef999SHaojian Wu                       "static int kConstInt2 = 1;\n"
62357ef999SHaojian Wu                       "\n"
639abbeaadSHaojian Wu                       "/** comment4\n"
649abbeaadSHaojian Wu                       " */\n"
65357ef999SHaojian Wu                       "static int help() {\n"
66357ef999SHaojian Wu                       "  int a = 0;\n"
67357ef999SHaojian Wu                       "  return a;\n"
68357ef999SHaojian Wu                       "}\n"
69357ef999SHaojian Wu                       "\n"
709abbeaadSHaojian Wu                       "// comment5\n"
719abbeaadSHaojian Wu                       "// comment5\n"
723626516bSHaojian Wu                       "void Foo::f() {\n"
733626516bSHaojian Wu                       "  f1();\n"
743626516bSHaojian Wu                       "  kConstInt1;\n"
753626516bSHaojian Wu                       "  kConstInt2;\n"
763626516bSHaojian Wu                       "  help();\n"
773626516bSHaojian Wu                       "}\n"
78357ef999SHaojian Wu                       "\n"
799abbeaadSHaojian Wu                       "/////////////\n"
809abbeaadSHaojian Wu                       "// comment //\n"
819abbeaadSHaojian Wu                       "/////////////\n"
82357ef999SHaojian Wu                       "int Foo::b = 2;\n"
83357ef999SHaojian Wu                       "int Foo2::f() {\n"
843626516bSHaojian Wu                       "  kConstInt1;\n"
853626516bSHaojian Wu                       "  kConstInt2;\n"
863626516bSHaojian Wu                       "  help();\n"
87357ef999SHaojian Wu                       "  f1();\n"
88357ef999SHaojian Wu                       "  return 1;\n"
89357ef999SHaojian Wu                       "}\n"
90357ef999SHaojian Wu                       "} // namespace b\n"
91357ef999SHaojian Wu                       "} // namespace a\n";
92357ef999SHaojian Wu 
93357ef999SHaojian Wu const char ExpectedTestHeader[] = "namespace a {\n"
949abbeaadSHaojian Wu                                   "class C1; // test\n"
9529c38f75SHaojian Wu                                   "template <typename T> class C2;\n"
96357ef999SHaojian Wu                                   "namespace b {\n"
97357ef999SHaojian Wu                                   "\n"
98357ef999SHaojian Wu                                   "class Foo2 {\n"
99357ef999SHaojian Wu                                   "public:\n"
100357ef999SHaojian Wu                                   "  int f();\n"
101357ef999SHaojian Wu                                   "};\n"
102357ef999SHaojian Wu                                   "} // namespace b\n"
103357ef999SHaojian Wu                                   "} // namespace a\n";
104357ef999SHaojian Wu 
105357ef999SHaojian Wu const char ExpectedTestCC[] = "#include \"foo.h\"\n"
106357ef999SHaojian Wu                               "namespace a {\n"
107357ef999SHaojian Wu                               "namespace b {\n"
108357ef999SHaojian Wu                               "namespace {\n"
1099abbeaadSHaojian Wu                               "// comment1.\n"
110357ef999SHaojian Wu                               "void f1() {}\n"
1119abbeaadSHaojian Wu                               "/// comment2.\n"
112357ef999SHaojian Wu                               "int kConstInt1 = 0;\n"
113357ef999SHaojian Wu                               "} // namespace\n"
114357ef999SHaojian Wu                               "\n"
1159abbeaadSHaojian Wu                               "/* comment 3*/\n"
116357ef999SHaojian Wu                               "static int kConstInt2 = 1;\n"
117357ef999SHaojian Wu                               "\n"
1189abbeaadSHaojian Wu                               "/** comment4\n"
1199abbeaadSHaojian Wu                               " */\n"
120357ef999SHaojian Wu                               "static int help() {\n"
121357ef999SHaojian Wu                               "  int a = 0;\n"
122357ef999SHaojian Wu                               "  return a;\n"
123357ef999SHaojian Wu                               "}\n"
124357ef999SHaojian Wu                               "\n"
125357ef999SHaojian Wu                               "int Foo2::f() {\n"
1263626516bSHaojian Wu                               "  kConstInt1;\n"
1273626516bSHaojian Wu                               "  kConstInt2;\n"
1283626516bSHaojian Wu                               "  help();\n"
129357ef999SHaojian Wu                               "  f1();\n"
130357ef999SHaojian Wu                               "  return 1;\n"
131357ef999SHaojian Wu                               "}\n"
132357ef999SHaojian Wu                               "} // namespace b\n"
133357ef999SHaojian Wu                               "} // namespace a\n";
134357ef999SHaojian Wu 
135220c755dSHaojian Wu const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
136220c755dSHaojian Wu                                  "#define NEW_FOO_H\n"
13753315a7bSHaojian Wu                                  "\n"
138220c755dSHaojian Wu                                  "namespace a {\n"
1399abbeaadSHaojian Wu                                  "class C1; // test\n"
14053315a7bSHaojian Wu                                  "\n"
14129c38f75SHaojian Wu                                  "template <typename T> class C2;\n"
142357ef999SHaojian Wu                                  "namespace b {\n"
1439abbeaadSHaojian Wu                                  "// This is a Foo class\n"
1449abbeaadSHaojian Wu                                  "// which is used in\n"
1459abbeaadSHaojian Wu                                  "// test.\n"
146357ef999SHaojian Wu                                  "class Foo {\n"
147357ef999SHaojian Wu                                  "public:\n"
148357ef999SHaojian Wu                                  "  void f();\n"
149357ef999SHaojian Wu                                  "\n"
150357ef999SHaojian Wu                                  "private:\n"
151357ef999SHaojian Wu                                  "  C1 *c1;\n"
152357ef999SHaojian Wu                                  "  static int b;\n"
1539abbeaadSHaojian Wu                                  "}; // abc\n"
154357ef999SHaojian Wu                                  "} // namespace b\n"
155220c755dSHaojian Wu                                  "} // namespace a\n"
15653315a7bSHaojian Wu                                  "\n"
157220c755dSHaojian Wu                                  "#endif // NEW_FOO_H\n";
158357ef999SHaojian Wu 
159daf4cb8bSHaojian Wu const char ExpectedNewCC[] = "namespace a {\n"
160357ef999SHaojian Wu                              "namespace b {\n"
161357ef999SHaojian Wu                              "namespace {\n"
1629abbeaadSHaojian Wu                              "// comment1.\n"
163357ef999SHaojian Wu                              "void f1() {}\n"
1643626516bSHaojian Wu                              "\n"
1659abbeaadSHaojian Wu                              "/// comment2.\n"
166357ef999SHaojian Wu                              "int kConstInt1 = 0;\n"
167357ef999SHaojian Wu                              "} // namespace\n"
16853315a7bSHaojian Wu                              "\n"
1699abbeaadSHaojian Wu                              "/* comment 3*/\n"
170357ef999SHaojian Wu                              "static int kConstInt2 = 1;\n"
17153315a7bSHaojian Wu                              "\n"
1729abbeaadSHaojian Wu                              "/** comment4\n"
1739abbeaadSHaojian Wu                              " */\n"
174357ef999SHaojian Wu                              "static int help() {\n"
175357ef999SHaojian Wu                              "  int a = 0;\n"
176357ef999SHaojian Wu                              "  return a;\n"
177357ef999SHaojian Wu                              "}\n"
17853315a7bSHaojian Wu                              "\n"
1799abbeaadSHaojian Wu                              "// comment5\n"
1809abbeaadSHaojian Wu                              "// comment5\n"
1813626516bSHaojian Wu                              "void Foo::f() {\n"
1823626516bSHaojian Wu                              "  f1();\n"
1833626516bSHaojian Wu                              "  kConstInt1;\n"
1843626516bSHaojian Wu                              "  kConstInt2;\n"
1853626516bSHaojian Wu                              "  help();\n"
1863626516bSHaojian Wu                              "}\n"
18753315a7bSHaojian Wu                              "\n"
1889abbeaadSHaojian Wu                              "/////////////\n"
1899abbeaadSHaojian Wu                              "// comment //\n"
1909abbeaadSHaojian Wu                              "/////////////\n"
191357ef999SHaojian Wu                              "int Foo::b = 2;\n"
192357ef999SHaojian Wu                              "} // namespace b\n"
193357ef999SHaojian Wu                              "} // namespace a\n";
194357ef999SHaojian Wu 
195db53a52fSEric Liu #ifdef _WIN32
196db53a52fSEric Liu const char WorkingDir[] = "C:\\test";
197db53a52fSEric Liu #else
198db53a52fSEric Liu const char WorkingDir[] = "/test";
199db53a52fSEric Liu #endif
200db53a52fSEric Liu 
201db53a52fSEric Liu const char TestHeaderName[] = "foo.h";
202db53a52fSEric Liu const char TestCCName[] = "foo.cc";
203db53a52fSEric Liu 
204357ef999SHaojian Wu std::map<std::string, std::string>
runClangMoveOnCode(const move::MoveDefinitionSpec & Spec,const char * const Header=TestHeader,const char * const CC=TestCC,DeclarationReporter * const Reporter=nullptr)205b15c8da0SHaojian Wu runClangMoveOnCode(const move::MoveDefinitionSpec &Spec,
2062930be14SHaojian Wu                    const char *const Header = TestHeader,
207b15c8da0SHaojian Wu                    const char *const CC = TestCC,
208b15c8da0SHaojian Wu                    DeclarationReporter *const Reporter = nullptr) {
209357ef999SHaojian Wu   clang::RewriterTestContext Context;
210357ef999SHaojian Wu 
211*98f0bf74SMartin Storsjö   llvm::SmallString<16> Dir(WorkingDir);
212*98f0bf74SMartin Storsjö   llvm::sys::path::native(Dir);
213*98f0bf74SMartin Storsjö   Context.InMemoryFileSystem->setCurrentWorkingDirectory(Dir);
214db53a52fSEric Liu 
215357ef999SHaojian Wu   std::map<llvm::StringRef, clang::FileID> FileToFileID;
216357ef999SHaojian Wu 
217e65b1029SMalcolm Parsons   auto CreateFiles = [&Context, &FileToFileID](llvm::StringRef Name,
218e65b1029SMalcolm Parsons                                                llvm::StringRef Code) {
219357ef999SHaojian Wu     if (!Name.empty()) {
220357ef999SHaojian Wu       FileToFileID[Name] = Context.createInMemoryFile(Name, Code);
221357ef999SHaojian Wu     }
222357ef999SHaojian Wu   };
223357ef999SHaojian Wu   CreateFiles(Spec.NewCC, "");
224357ef999SHaojian Wu   CreateFiles(Spec.NewHeader, "");
225db53a52fSEric Liu   CreateFiles(TestHeaderName, Header);
226db53a52fSEric Liu   CreateFiles(TestCCName, CC);
227357ef999SHaojian Wu 
228357ef999SHaojian Wu   std::map<std::string, tooling::Replacements> FileToReplacements;
229*98f0bf74SMartin Storsjö   ClangMoveContext MoveContext = {Spec, FileToReplacements, Dir.c_str(), "LLVM",
230b15c8da0SHaojian Wu                                   Reporter != nullptr};
231b15c8da0SHaojian Wu 
2321c705d9cSJonas Devlieghere   auto Factory = std::make_unique<clang::move::ClangMoveActionFactory>(
233b15c8da0SHaojian Wu       &MoveContext, Reporter);
234357ef999SHaojian Wu 
235357ef999SHaojian Wu   tooling::runToolOnCodeWithArgs(
236db53a52fSEric Liu       Factory->create(), CC, Context.InMemoryFileSystem,
237db53a52fSEric Liu       {"-std=c++11", "-fparse-all-comments", "-I."}, TestCCName, "clang-move",
238db53a52fSEric Liu       std::make_shared<PCHContainerOperations>());
239357ef999SHaojian Wu   formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
240357ef999SHaojian Wu   // The Key is file name, value is the new code after moving the class.
241357ef999SHaojian Wu   std::map<std::string, std::string> Results;
242357ef999SHaojian Wu   for (const auto &It : FileToReplacements) {
24383953233SSimon Marchi     // The path may come out as "./foo.h", normalize to "foo.h".
24483953233SSimon Marchi     SmallString<32> FilePath (It.first);
24583953233SSimon Marchi     llvm::sys::path::remove_dots(FilePath);
24683953233SSimon Marchi     Results[FilePath.str().str()] = Context.getRewrittenText(FileToFileID[FilePath]);
247357ef999SHaojian Wu   }
248357ef999SHaojian Wu   return Results;
249357ef999SHaojian Wu }
250357ef999SHaojian Wu 
TEST(ClangMove,MoveHeaderAndCC)251357ef999SHaojian Wu TEST(ClangMove, MoveHeaderAndCC) {
252b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
2530cfbbaecSNAKAMURA Takumi   Spec.Names = {std::string("a::b::Foo")};
254357ef999SHaojian Wu   Spec.OldHeader = "foo.h";
255357ef999SHaojian Wu   Spec.OldCC = "foo.cc";
256357ef999SHaojian Wu   Spec.NewHeader = "new_foo.h";
257357ef999SHaojian Wu   Spec.NewCC = "new_foo.cc";
2589abbeaadSHaojian Wu   std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n\n";
259357ef999SHaojian Wu   auto Results = runClangMoveOnCode(Spec);
260357ef999SHaojian Wu   EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
261357ef999SHaojian Wu   EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
262357ef999SHaojian Wu   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
263daf4cb8bSHaojian Wu   EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
264357ef999SHaojian Wu }
265357ef999SHaojian Wu 
TEST(ClangMove,MoveHeaderOnly)266357ef999SHaojian Wu TEST(ClangMove, MoveHeaderOnly) {
267b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
2680cfbbaecSNAKAMURA Takumi   Spec.Names = {std::string("a::b::Foo")};
269357ef999SHaojian Wu   Spec.OldHeader = "foo.h";
270357ef999SHaojian Wu   Spec.NewHeader = "new_foo.h";
271357ef999SHaojian Wu   auto Results = runClangMoveOnCode(Spec);
27262ba4462SHaojian Wu   EXPECT_EQ(2u, Results.size());
273357ef999SHaojian Wu   EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
274357ef999SHaojian Wu   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
275357ef999SHaojian Wu }
276357ef999SHaojian Wu 
TEST(ClangMove,MoveCCOnly)277357ef999SHaojian Wu TEST(ClangMove, MoveCCOnly) {
278b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
2790cfbbaecSNAKAMURA Takumi   Spec.Names = {std::string("a::b::Foo")};
280357ef999SHaojian Wu   Spec.OldCC = "foo.cc";
281357ef999SHaojian Wu   Spec.NewCC = "new_foo.cc";
2829abbeaadSHaojian Wu   std::string ExpectedHeader = "#include \"foo.h\"\n\n";
283357ef999SHaojian Wu   auto Results = runClangMoveOnCode(Spec);
28462ba4462SHaojian Wu   EXPECT_EQ(2u, Results.size());
285357ef999SHaojian Wu   EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
286daf4cb8bSHaojian Wu   EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
287357ef999SHaojian Wu }
288357ef999SHaojian Wu 
TEST(ClangMove,MoveNonExistClass)289357ef999SHaojian Wu TEST(ClangMove, MoveNonExistClass) {
290b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
2910cfbbaecSNAKAMURA Takumi   Spec.Names = {std::string("NonExistFoo")};
292357ef999SHaojian Wu   Spec.OldHeader = "foo.h";
293357ef999SHaojian Wu   Spec.OldCC = "foo.cc";
294357ef999SHaojian Wu   Spec.NewHeader = "new_foo.h";
295357ef999SHaojian Wu   Spec.NewCC = "new_foo.cc";
296357ef999SHaojian Wu   auto Results = runClangMoveOnCode(Spec);
29762ba4462SHaojian Wu   EXPECT_EQ(0u, Results.size());
298357ef999SHaojian Wu }
299357ef999SHaojian Wu 
TEST(ClangMove,HeaderIncludeSelf)300fb68ca18SHaojian Wu TEST(ClangMove, HeaderIncludeSelf) {
301fb68ca18SHaojian Wu   move::MoveDefinitionSpec Spec;
302fb68ca18SHaojian Wu   Spec.Names = {std::string("Foo")};
303fb68ca18SHaojian Wu   Spec.OldHeader = "foo.h";
304fb68ca18SHaojian Wu   Spec.OldCC = "foo.cc";
305fb68ca18SHaojian Wu   Spec.NewHeader = "new_foo.h";
306fb68ca18SHaojian Wu   Spec.NewCC = "new_foo.cc";
307fb68ca18SHaojian Wu 
308fb68ca18SHaojian Wu   const char TestHeader[] = "#ifndef FOO_H\n"
309fb68ca18SHaojian Wu                             "#define FOO_H\n"
310fb68ca18SHaojian Wu                             "#include \"foo.h\"\n"
311fb68ca18SHaojian Wu                             "class Foo {};\n"
312fb68ca18SHaojian Wu                             "#endif\n";
313fb68ca18SHaojian Wu   const char TestCode[] = "#include \"foo.h\"";
314fb68ca18SHaojian Wu   const char ExpectedNewHeader[] = "#ifndef FOO_H\n"
315fb68ca18SHaojian Wu                                    "#define FOO_H\n"
316fb68ca18SHaojian Wu                                    "#include \"new_foo.h\"\n"
317fb68ca18SHaojian Wu                                    "class Foo {};\n"
318fb68ca18SHaojian Wu                                    "#endif\n";
319fb68ca18SHaojian Wu   const char ExpectedNewCC[] = "#include \"new_foo.h\"";
320fb68ca18SHaojian Wu   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
321fb68ca18SHaojian Wu   EXPECT_EQ("", Results[Spec.OldHeader]);
322fb68ca18SHaojian Wu   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
323fb68ca18SHaojian Wu   EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
324fb68ca18SHaojian Wu }
325fb68ca18SHaojian Wu 
TEST(ClangMove,MoveAll)3262930be14SHaojian Wu TEST(ClangMove, MoveAll) {
3272930be14SHaojian Wu   std::vector<std::string> TestHeaders = {
3282930be14SHaojian Wu     "class A {\npublic:\n  int f();\n};",
3292930be14SHaojian Wu     // forward declaration.
3302930be14SHaojian Wu     "class B;\nclass A {\npublic:\n  int f();\n};",
3312930be14SHaojian Wu     // template forward declaration.
3322930be14SHaojian Wu     "template <typename T> class B;\nclass A {\npublic:\n  int f();\n};",
3332930be14SHaojian Wu     "namespace a {}\nclass A {\npublic:\n  int f();\n};",
3342930be14SHaojian Wu     "namespace a {}\nusing namespace a;\nclass A {\npublic:\n  int f();\n};",
3352930be14SHaojian Wu   };
3362930be14SHaojian Wu   const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
337b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
3382930be14SHaojian Wu   Spec.Names.push_back("A");
3392930be14SHaojian Wu   Spec.OldHeader = "foo.h";
3402930be14SHaojian Wu   Spec.OldCC = "foo.cc";
3412930be14SHaojian Wu   Spec.NewHeader = "new_foo.h";
3422930be14SHaojian Wu   Spec.NewCC = "new_foo.cc";
3432930be14SHaojian Wu   for (const auto& Header : TestHeaders) {
3442930be14SHaojian Wu     auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
3452930be14SHaojian Wu     EXPECT_EQ(Header, Results[Spec.NewHeader]);
3462930be14SHaojian Wu     EXPECT_EQ("", Results[Spec.OldHeader]);
3472930be14SHaojian Wu     EXPECT_EQ("", Results[Spec.OldCC]);
3482930be14SHaojian Wu   }
3492930be14SHaojian Wu }
3502930be14SHaojian Wu 
TEST(ClangMove,MoveAllMultipleClasses)3512930be14SHaojian Wu TEST(ClangMove, MoveAllMultipleClasses) {
352b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
3532930be14SHaojian Wu   std::vector<std::string> TestHeaders = {
3542930be14SHaojian Wu     "class C;\nclass A {\npublic:\n  int f();\n};\nclass B {};",
3552930be14SHaojian Wu     "class C;\nclass B;\nclass A {\npublic:\n  int f();\n};\nclass B {};",
3562930be14SHaojian Wu   };
3572930be14SHaojian Wu   const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
3582930be14SHaojian Wu   Spec.Names = {std::string("A"), std::string("B")};
3592930be14SHaojian Wu   Spec.OldHeader = "foo.h";
3602930be14SHaojian Wu   Spec.OldCC = "foo.cc";
3612930be14SHaojian Wu   Spec.NewHeader = "new_foo.h";
3622930be14SHaojian Wu   Spec.NewCC = "new_foo.cc";
3632930be14SHaojian Wu   for (const auto& Header : TestHeaders) {
3642930be14SHaojian Wu     auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
3652930be14SHaojian Wu     EXPECT_EQ(Header, Results[Spec.NewHeader]);
3662930be14SHaojian Wu     EXPECT_EQ("", Results[Spec.OldHeader]);
3672930be14SHaojian Wu     EXPECT_EQ("", Results[Spec.OldCC]);
3682930be14SHaojian Wu   }
3692930be14SHaojian Wu }
3702930be14SHaojian Wu 
TEST(ClangMove,DontMoveAll)3712930be14SHaojian Wu TEST(ClangMove, DontMoveAll) {
3722930be14SHaojian Wu   const char ExpectedHeader[] = "#ifndef NEW_FOO_H\n"
3732930be14SHaojian Wu                                 "#define NEW_FOO_H\n"
37453315a7bSHaojian Wu                                 "\n"
3752930be14SHaojian Wu                                 "class A {\npublic:\n  int f();\n};\n"
37653315a7bSHaojian Wu                                 "\n"
3772930be14SHaojian Wu                                 "#endif // NEW_FOO_H\n";
3782930be14SHaojian Wu   const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
3792930be14SHaojian Wu   std::vector<std::string> TestHeaders = {
38053315a7bSHaojian Wu     "class B {};\nclass A {\npublic:\n  int f();\n};\n",
38153315a7bSHaojian Wu     "void f() {};\nclass A {\npublic:\n  int f();\n};\n",
3822930be14SHaojian Wu   };
383b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
3842930be14SHaojian Wu   Spec.Names.push_back("A");
3852930be14SHaojian Wu   Spec.OldHeader = "foo.h";
3862930be14SHaojian Wu   Spec.OldCC = "foo.cc";
3872930be14SHaojian Wu   Spec.NewHeader = "new_foo.h";
3882930be14SHaojian Wu   Spec.NewCC = "new_foo.cc";
3892930be14SHaojian Wu   for (const auto& Header : TestHeaders) {
3902930be14SHaojian Wu     auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
3912930be14SHaojian Wu     EXPECT_EQ(ExpectedHeader, Results[Spec.NewHeader]);
3922930be14SHaojian Wu     // The expected old header should not contain class A definition.
39353315a7bSHaojian Wu     std::string ExpectedOldHeader = Header.substr(0, Header.size() - 32);
3942930be14SHaojian Wu     EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
3952930be14SHaojian Wu   }
3962930be14SHaojian Wu }
3972930be14SHaojian Wu 
TEST(ClangMove,IgnoreMacroSymbolsAndMoveAll)398d4786347SHaojian Wu TEST(ClangMove, IgnoreMacroSymbolsAndMoveAll) {
399d4786347SHaojian Wu   const char TestCode[] = "#include \"foo.h\"";
400d4786347SHaojian Wu   std::vector<std::string> TestHeaders = {
401d4786347SHaojian Wu     "#define DEFINE_Foo int Foo = 1;\nDEFINE_Foo;\nclass Bar {};\n",
402d4786347SHaojian Wu     "#define DEFINE(x) int var_##x = 1;\nDEFINE(foo);\nclass Bar {};\n",
403d4786347SHaojian Wu   };
404d4786347SHaojian Wu   move::MoveDefinitionSpec Spec;
405d4786347SHaojian Wu   Spec.Names.push_back("Bar");
406d4786347SHaojian Wu   Spec.OldHeader = "foo.h";
407d4786347SHaojian Wu   Spec.OldCC = "foo.cc";
408d4786347SHaojian Wu   Spec.NewHeader = "new_foo.h";
409d4786347SHaojian Wu   Spec.NewCC = "new_foo.cc";
410d4786347SHaojian Wu 
411d4786347SHaojian Wu   for (const auto& Header : TestHeaders) {
412d4786347SHaojian Wu     auto Results = runClangMoveOnCode(Spec, Header.c_str(), TestCode);
413d4786347SHaojian Wu     EXPECT_EQ("", Results[Spec.OldHeader]);
414d4786347SHaojian Wu     EXPECT_EQ(Header, Results[Spec.NewHeader]);
415d4786347SHaojian Wu   }
416d4786347SHaojian Wu }
417d4786347SHaojian Wu 
TEST(ClangMove,MacroInFunction)41824675398SHaojian Wu TEST(ClangMove, MacroInFunction) {
41924675398SHaojian Wu   const char TestHeader[] = "#define INT int\n"
42024675398SHaojian Wu                             "class A {\npublic:\n  int f();\n};\n"
42124675398SHaojian Wu                             "class B {};\n";
42224675398SHaojian Wu   const char TestCode[] = "#include \"foo.h\"\n"
42324675398SHaojian Wu                           "INT A::f() { return 0; }\n";
42424675398SHaojian Wu   const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
42524675398SHaojian Wu                                  "INT A::f() { return 0; }\n";
426b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
42724675398SHaojian Wu   Spec.Names.push_back("A");
42824675398SHaojian Wu   Spec.OldHeader = "foo.h";
42924675398SHaojian Wu   Spec.OldCC = "foo.cc";
43024675398SHaojian Wu   Spec.NewHeader = "new_foo.h";
43124675398SHaojian Wu   Spec.NewCC = "new_foo.cc";
43224675398SHaojian Wu   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
43324675398SHaojian Wu   EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
43424675398SHaojian Wu }
43524675398SHaojian Wu 
TEST(ClangMove,DefinitionInMacro)436dc4edba5SHaojian Wu TEST(ClangMove, DefinitionInMacro) {
437dc4edba5SHaojian Wu   const char TestHeader[] = "#define DEF(CLASS) void CLASS##_::f() {}\n"
438cee2059fSHaojian Wu                             "#define DEF2(CLASS, ...) void CLASS##_::f2() {}\n"
439cee2059fSHaojian Wu                             "class A_ {\nvoid f();\nvoid f2();\n};\n"
440dc4edba5SHaojian Wu                             "class B {};\n";
441dc4edba5SHaojian Wu   const char TestCode[] = "#include \"foo.h\"\n"
442cee2059fSHaojian Wu                           "DEF(A)\n\n"
443cee2059fSHaojian Wu                           "DEF2(A,\n"
444cee2059fSHaojian Wu                           "     123)\n";
445dc4edba5SHaojian Wu   const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
446cee2059fSHaojian Wu                                  "DEF(A)\n\n"
447cee2059fSHaojian Wu                                  "DEF2(A, 123)\n";
448dc4edba5SHaojian Wu   move::MoveDefinitionSpec Spec;
449dc4edba5SHaojian Wu   Spec.Names.push_back("A_");
450dc4edba5SHaojian Wu   Spec.OldHeader = "foo.h";
451dc4edba5SHaojian Wu   Spec.OldCC = "foo.cc";
452dc4edba5SHaojian Wu   Spec.NewHeader = "new_foo.h";
453dc4edba5SHaojian Wu   Spec.NewCC = "new_foo.cc";
454dc4edba5SHaojian Wu   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
455dc4edba5SHaojian Wu   EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
456dc4edba5SHaojian Wu }
457dc4edba5SHaojian Wu 
TEST(ClangMove,WellFormattedCode)45853315a7bSHaojian Wu TEST(ClangMove, WellFormattedCode) {
45953315a7bSHaojian Wu   const std::string CommonHeader =
46053315a7bSHaojian Wu       "namespace a {\n"
46153315a7bSHaojian Wu       "namespace b {\n"
46253315a7bSHaojian Wu       "namespace c {\n"
46353315a7bSHaojian Wu       "class C;\n"
46453315a7bSHaojian Wu       "\n"
46553315a7bSHaojian Wu       "class A {\npublic:\n  void f();\n  void f2();\n};\n"
46653315a7bSHaojian Wu       "} // namespace c\n"
46753315a7bSHaojian Wu       "} // namespace b\n"
46853315a7bSHaojian Wu       "\n"
46953315a7bSHaojian Wu       "namespace d {\n"
47053315a7bSHaojian Wu       "namespace e {\n"
47153315a7bSHaojian Wu       "class B {\npublic:\n  void f();\n};\n"
47253315a7bSHaojian Wu       "} // namespace e\n"
47353315a7bSHaojian Wu       "} // namespace d\n"
47453315a7bSHaojian Wu       "} // namespace a\n";
47553315a7bSHaojian Wu   const std::string CommonCode = "\n"
47653315a7bSHaojian Wu                                  "namespace a {\n"
47753315a7bSHaojian Wu                                  "namespace b {\n"
47853315a7bSHaojian Wu                                  "namespace c {\n"
47953315a7bSHaojian Wu                                  "void A::f() {}\n"
48053315a7bSHaojian Wu                                  "\n"
48153315a7bSHaojian Wu                                  "void A::f2() {}\n"
48253315a7bSHaojian Wu                                  "} // namespace c\n"
48353315a7bSHaojian Wu                                  "} // namespace b\n"
48453315a7bSHaojian Wu                                  "\n"
48553315a7bSHaojian Wu                                  "namespace d {\n"
48653315a7bSHaojian Wu                                  "namespace e {\n"
48753315a7bSHaojian Wu                                  "void B::f() {}\n"
48853315a7bSHaojian Wu                                  "} // namespace e\n"
48953315a7bSHaojian Wu                                  "} // namespace d\n"
49053315a7bSHaojian Wu                                  "} // namespace a\n";
49153315a7bSHaojian Wu   // Add dummy class to prevent behavior of moving all declarations from header.
49253315a7bSHaojian Wu   const std::string TestHeader = CommonHeader + "class D {};\n";
49353315a7bSHaojian Wu   const std::string TestCode = "#include \"foo.h\"\n" + CommonCode;
49453315a7bSHaojian Wu   const std::string ExpectedNewHeader = "#ifndef NEW_FOO_H\n"
49553315a7bSHaojian Wu                                         "#define NEW_FOO_H\n"
49653315a7bSHaojian Wu                                         "\n" +
49753315a7bSHaojian Wu                                         CommonHeader +
49853315a7bSHaojian Wu                                         "\n"
49953315a7bSHaojian Wu                                         "#endif // NEW_FOO_H\n";
50053315a7bSHaojian Wu   const std::string ExpectedNewCC = "#include \"new_foo.h\"\n" + CommonCode;
501b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
50253315a7bSHaojian Wu   Spec.Names.push_back("a::b::c::A");
50353315a7bSHaojian Wu   Spec.Names.push_back("a::d::e::B");
50453315a7bSHaojian Wu   Spec.OldHeader = "foo.h";
50553315a7bSHaojian Wu   Spec.OldCC = "foo.cc";
50653315a7bSHaojian Wu   Spec.NewHeader = "new_foo.h";
50753315a7bSHaojian Wu   Spec.NewCC = "new_foo.cc";
50853315a7bSHaojian Wu   auto Results = runClangMoveOnCode(Spec, TestHeader.c_str(), TestCode.c_str());
50953315a7bSHaojian Wu   EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
51053315a7bSHaojian Wu   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
51153315a7bSHaojian Wu }
51253315a7bSHaojian Wu 
TEST(ClangMove,AddDependentNewHeader)51348ac304cSHaojian Wu TEST(ClangMove, AddDependentNewHeader) {
51448ac304cSHaojian Wu   const char TestHeader[] = "class A {};\n"
51548ac304cSHaojian Wu                             "class B {};\n";
51648ac304cSHaojian Wu   const char TestCode[] = "#include \"foo.h\"\n";
51748ac304cSHaojian Wu   const char ExpectedOldHeader[] = "#include \"new_foo.h\"\nclass B {};\n";
51848ac304cSHaojian Wu   const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
51948ac304cSHaojian Wu                                    "#define NEW_FOO_H\n"
52048ac304cSHaojian Wu                                    "\n"
52148ac304cSHaojian Wu                                    "class A {};\n"
52248ac304cSHaojian Wu                                    "\n"
52348ac304cSHaojian Wu                                    "#endif // NEW_FOO_H\n";
524b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
52548ac304cSHaojian Wu   Spec.Names.push_back("A");
52648ac304cSHaojian Wu   Spec.OldHeader = "foo.h";
52748ac304cSHaojian Wu   Spec.OldCC = "foo.cc";
52848ac304cSHaojian Wu   Spec.NewHeader = "new_foo.h";
52948ac304cSHaojian Wu   Spec.NewCC = "new_foo.cc";
53048ac304cSHaojian Wu   Spec.OldDependOnNew = true;
53148ac304cSHaojian Wu   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
53248ac304cSHaojian Wu   EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
53348ac304cSHaojian Wu   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
53448ac304cSHaojian Wu }
53548ac304cSHaojian Wu 
TEST(ClangMove,AddDependentOldHeader)53648ac304cSHaojian Wu TEST(ClangMove, AddDependentOldHeader) {
53748ac304cSHaojian Wu   const char TestHeader[] = "class A {};\n"
53848ac304cSHaojian Wu                             "class B {};\n";
53948ac304cSHaojian Wu   const char TestCode[] = "#include \"foo.h\"\n";
54048ac304cSHaojian Wu   const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
54148ac304cSHaojian Wu                                    "#define NEW_FOO_H\n"
54248ac304cSHaojian Wu                                    "\n"
54348ac304cSHaojian Wu                                    "#include \"foo.h\"\n"
54448ac304cSHaojian Wu                                    "\n"
54548ac304cSHaojian Wu                                    "class B {};\n"
54648ac304cSHaojian Wu                                    "\n"
54748ac304cSHaojian Wu                                    "#endif // NEW_FOO_H\n";
54848ac304cSHaojian Wu   const char ExpectedOldHeader[] = "class A {};\n";
549b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
55048ac304cSHaojian Wu   Spec.Names.push_back("B");
55148ac304cSHaojian Wu   Spec.OldHeader = "foo.h";
55248ac304cSHaojian Wu   Spec.OldCC = "foo.cc";
55348ac304cSHaojian Wu   Spec.NewHeader = "new_foo.h";
55448ac304cSHaojian Wu   Spec.NewCC = "new_foo.cc";
55548ac304cSHaojian Wu   Spec.NewDependOnOld = true;
55648ac304cSHaojian Wu   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
55748ac304cSHaojian Wu   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
55848ac304cSHaojian Wu   EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
55948ac304cSHaojian Wu }
56048ac304cSHaojian Wu 
TEST(ClangMove,DumpDecls)561b15c8da0SHaojian Wu TEST(ClangMove, DumpDecls) {
562b15c8da0SHaojian Wu   const char TestHeader[] = "template <typename T>\n"
563b15c8da0SHaojian Wu                             "class A {\n"
564b15c8da0SHaojian Wu                             " public:\n"
565b15c8da0SHaojian Wu                             "  void f();\n"
566b15c8da0SHaojian Wu                             "  template <typename U> void h();\n"
567b15c8da0SHaojian Wu                             "  static int b;\n"
568b15c8da0SHaojian Wu                             "};\n"
569b15c8da0SHaojian Wu                             "\n"
570b15c8da0SHaojian Wu                             "template <typename T> void A<T>::f() {}\n"
571b15c8da0SHaojian Wu                             "\n"
572b15c8da0SHaojian Wu                             "template <typename T>\n"
573b15c8da0SHaojian Wu                             "template <typename U>\n"
574b15c8da0SHaojian Wu                             "void A<T>::h() {}\n"
575b15c8da0SHaojian Wu                             "\n"
576b15c8da0SHaojian Wu                             "template <typename T> int A<T>::b = 2;\n"
577b15c8da0SHaojian Wu                             "\n"
578b15c8da0SHaojian Wu                             "template <> class A<int> {};\n"
579b15c8da0SHaojian Wu                             "\n"
580b15c8da0SHaojian Wu                             "class B {};\n"
581b15c8da0SHaojian Wu                             "\n"
582b15c8da0SHaojian Wu                             "namespace a {\n"
583b15c8da0SHaojian Wu                             "class Move1 {};\n"
584b15c8da0SHaojian Wu                             "void f1() {}\n"
585bce181c6SEric Liu                             "template <typename T>"
586bce181c6SEric Liu                             "void f2(T t);\n"
587b15c8da0SHaojian Wu                             "} // namespace a\n"
588b15c8da0SHaojian Wu                             "\n"
58903c8963cSHaojian Wu                             "class ForwardClass;\n"
590b15c8da0SHaojian Wu                             "namespace a {\n"
591b15c8da0SHaojian Wu                             "namespace b {\n"
592b15c8da0SHaojian Wu                             "class Move1 { public : void f(); };\n"
593b15c8da0SHaojian Wu                             "void f() {}\n"
59485867727SHaojian Wu                             "enum E1 { Green };\n"
59585867727SHaojian Wu                             "enum class E2 { Red };\n"
59685867727SHaojian Wu                             "typedef int Int2;\n"
59703c8963cSHaojian Wu                             "typedef A<double> A_d;"
59885867727SHaojian Wu                             "using Int = int;\n"
599bce181c6SEric Liu                             "template <typename T>\n"
600bce181c6SEric Liu                             "using AA = A<T>;\n"
6014a92050cSHaojian Wu                             "extern int kGlobalInt;\n"
6024a92050cSHaojian Wu                             "extern const char* const kGlobalStr;\n"
603b15c8da0SHaojian Wu                             "} // namespace b\n"
604d4786347SHaojian Wu                             "} // namespace a\n"
605d4786347SHaojian Wu                             "#define DEFINE_FOO class Foo {};\n"
606d4786347SHaojian Wu                             "DEFINE_FOO\n";
607b15c8da0SHaojian Wu   const char TestCode[] = "#include \"foo.h\"\n";
608b15c8da0SHaojian Wu   move::MoveDefinitionSpec Spec;
609b15c8da0SHaojian Wu   Spec.Names.push_back("B");
610b15c8da0SHaojian Wu   Spec.OldHeader = "foo.h";
611b15c8da0SHaojian Wu   Spec.OldCC = "foo.cc";
612b15c8da0SHaojian Wu   Spec.NewHeader = "new_foo.h";
613b15c8da0SHaojian Wu   Spec.NewCC = "new_foo.cc";
614b15c8da0SHaojian Wu   DeclarationReporter Reporter;
615bce181c6SEric Liu   std::vector<DeclarationReporter::Declaration> ExpectedDeclarations = {
616bce181c6SEric Liu       {"A", "Class", true},
617bce181c6SEric Liu       {"B", "Class", false},
618bce181c6SEric Liu       {"a::Move1", "Class", false},
619bce181c6SEric Liu       {"a::f1", "Function", false},
620bce181c6SEric Liu       {"a::f2", "Function", true},
621bce181c6SEric Liu       {"a::b::Move1", "Class", false},
622bce181c6SEric Liu       {"a::b::f", "Function", false},
623bce181c6SEric Liu       {"a::b::E1", "Enum", false},
624bce181c6SEric Liu       {"a::b::E2", "Enum", false},
625bce181c6SEric Liu       {"a::b::Int2", "TypeAlias", false},
626bce181c6SEric Liu       {"a::b::A_d", "TypeAlias", false},
627bce181c6SEric Liu       {"a::b::Int", "TypeAlias", false},
628bce181c6SEric Liu       {"a::b::AA", "TypeAlias", true},
629bce181c6SEric Liu       {"a::b::kGlobalInt", "Variable", false},
630bce181c6SEric Liu       {"a::b::kGlobalStr", "Variable", false}};
631b15c8da0SHaojian Wu   runClangMoveOnCode(Spec, TestHeader, TestCode, &Reporter);
632bce181c6SEric Liu   std::vector<DeclarationReporter::Declaration> Results;
63385867727SHaojian Wu   for (const auto &DelPair : Reporter.getDeclarationList())
634bce181c6SEric Liu     Results.push_back(DelPair);
635bce181c6SEric Liu   EXPECT_THAT(ExpectedDeclarations,
636bce181c6SEric Liu               testing::UnorderedElementsAreArray(Results));
637b15c8da0SHaojian Wu }
638b15c8da0SHaojian Wu 
639357ef999SHaojian Wu } // namespace
640dd5571d5SKazuaki Ishizaki } // namespace move
641357ef999SHaojian Wu } // namespace clang
642