xref: /llvm-project/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp (revision 98f0bf74ca6d7aa9b3c2b240693824f085aa6675)
1 //===-- ClangMoveTests.cpp - clang-move unit tests ------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Move.h"
10 #include "unittests/Tooling/RewriterTestContext.h"
11 #include "clang/Format/Format.h"
12 #include "clang/Frontend/FrontendActions.h"
13 #include "clang/Frontend/TextDiagnosticPrinter.h"
14 #include "clang/Rewrite/Core/Rewriter.h"
15 #include "clang/Tooling/Refactoring.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "gmock/gmock-matchers.h"
19 #include "gtest/gtest.h"
20 #include <string>
21 #include <vector>
22 
23 namespace clang {
24 namespace move {
25 namespace {
26 
27 const char TestHeader[] = "namespace a {\n"
28                           "class C1; // test\n"
29                           "template <typename T> class C2;\n"
30                           "namespace b {\n"
31                           "// This is a Foo class\n"
32                           "// which is used in\n"
33                           "// test.\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                           "}; // abc\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 
50 const char TestCC[] = "#include \"foo.h\"\n"
51                       "namespace a {\n"
52                       "namespace b {\n"
53                       "namespace {\n"
54                       "// comment1.\n"
55                       "void f1() {}\n"
56                       "/// comment2.\n"
57                       "int kConstInt1 = 0;\n"
58                       "} // namespace\n"
59                       "\n"
60                       "/* comment 3*/\n"
61                       "static int kConstInt2 = 1;\n"
62                       "\n"
63                       "/** comment4\n"
64                       " */\n"
65                       "static int help() {\n"
66                       "  int a = 0;\n"
67                       "  return a;\n"
68                       "}\n"
69                       "\n"
70                       "// comment5\n"
71                       "// comment5\n"
72                       "void Foo::f() {\n"
73                       "  f1();\n"
74                       "  kConstInt1;\n"
75                       "  kConstInt2;\n"
76                       "  help();\n"
77                       "}\n"
78                       "\n"
79                       "/////////////\n"
80                       "// comment //\n"
81                       "/////////////\n"
82                       "int Foo::b = 2;\n"
83                       "int Foo2::f() {\n"
84                       "  kConstInt1;\n"
85                       "  kConstInt2;\n"
86                       "  help();\n"
87                       "  f1();\n"
88                       "  return 1;\n"
89                       "}\n"
90                       "} // namespace b\n"
91                       "} // namespace a\n";
92 
93 const char ExpectedTestHeader[] = "namespace a {\n"
94                                   "class C1; // test\n"
95                                   "template <typename T> class C2;\n"
96                                   "namespace b {\n"
97                                   "\n"
98                                   "class Foo2 {\n"
99                                   "public:\n"
100                                   "  int f();\n"
101                                   "};\n"
102                                   "} // namespace b\n"
103                                   "} // namespace a\n";
104 
105 const char ExpectedTestCC[] = "#include \"foo.h\"\n"
106                               "namespace a {\n"
107                               "namespace b {\n"
108                               "namespace {\n"
109                               "// comment1.\n"
110                               "void f1() {}\n"
111                               "/// comment2.\n"
112                               "int kConstInt1 = 0;\n"
113                               "} // namespace\n"
114                               "\n"
115                               "/* comment 3*/\n"
116                               "static int kConstInt2 = 1;\n"
117                               "\n"
118                               "/** comment4\n"
119                               " */\n"
120                               "static int help() {\n"
121                               "  int a = 0;\n"
122                               "  return a;\n"
123                               "}\n"
124                               "\n"
125                               "int Foo2::f() {\n"
126                               "  kConstInt1;\n"
127                               "  kConstInt2;\n"
128                               "  help();\n"
129                               "  f1();\n"
130                               "  return 1;\n"
131                               "}\n"
132                               "} // namespace b\n"
133                               "} // namespace a\n";
134 
135 const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
136                                  "#define NEW_FOO_H\n"
137                                  "\n"
138                                  "namespace a {\n"
139                                  "class C1; // test\n"
140                                  "\n"
141                                  "template <typename T> class C2;\n"
142                                  "namespace b {\n"
143                                  "// This is a Foo class\n"
144                                  "// which is used in\n"
145                                  "// test.\n"
146                                  "class Foo {\n"
147                                  "public:\n"
148                                  "  void f();\n"
149                                  "\n"
150                                  "private:\n"
151                                  "  C1 *c1;\n"
152                                  "  static int b;\n"
153                                  "}; // abc\n"
154                                  "} // namespace b\n"
155                                  "} // namespace a\n"
156                                  "\n"
157                                  "#endif // NEW_FOO_H\n";
158 
159 const char ExpectedNewCC[] = "namespace a {\n"
160                              "namespace b {\n"
161                              "namespace {\n"
162                              "// comment1.\n"
163                              "void f1() {}\n"
164                              "\n"
165                              "/// comment2.\n"
166                              "int kConstInt1 = 0;\n"
167                              "} // namespace\n"
168                              "\n"
169                              "/* comment 3*/\n"
170                              "static int kConstInt2 = 1;\n"
171                              "\n"
172                              "/** comment4\n"
173                              " */\n"
174                              "static int help() {\n"
175                              "  int a = 0;\n"
176                              "  return a;\n"
177                              "}\n"
178                              "\n"
179                              "// comment5\n"
180                              "// comment5\n"
181                              "void Foo::f() {\n"
182                              "  f1();\n"
183                              "  kConstInt1;\n"
184                              "  kConstInt2;\n"
185                              "  help();\n"
186                              "}\n"
187                              "\n"
188                              "/////////////\n"
189                              "// comment //\n"
190                              "/////////////\n"
191                              "int Foo::b = 2;\n"
192                              "} // namespace b\n"
193                              "} // namespace a\n";
194 
195 #ifdef _WIN32
196 const char WorkingDir[] = "C:\\test";
197 #else
198 const char WorkingDir[] = "/test";
199 #endif
200 
201 const char TestHeaderName[] = "foo.h";
202 const char TestCCName[] = "foo.cc";
203 
204 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)205 runClangMoveOnCode(const move::MoveDefinitionSpec &Spec,
206                    const char *const Header = TestHeader,
207                    const char *const CC = TestCC,
208                    DeclarationReporter *const Reporter = nullptr) {
209   clang::RewriterTestContext Context;
210 
211   llvm::SmallString<16> Dir(WorkingDir);
212   llvm::sys::path::native(Dir);
213   Context.InMemoryFileSystem->setCurrentWorkingDirectory(Dir);
214 
215   std::map<llvm::StringRef, clang::FileID> FileToFileID;
216 
217   auto CreateFiles = [&Context, &FileToFileID](llvm::StringRef Name,
218                                                llvm::StringRef Code) {
219     if (!Name.empty()) {
220       FileToFileID[Name] = Context.createInMemoryFile(Name, Code);
221     }
222   };
223   CreateFiles(Spec.NewCC, "");
224   CreateFiles(Spec.NewHeader, "");
225   CreateFiles(TestHeaderName, Header);
226   CreateFiles(TestCCName, CC);
227 
228   std::map<std::string, tooling::Replacements> FileToReplacements;
229   ClangMoveContext MoveContext = {Spec, FileToReplacements, Dir.c_str(), "LLVM",
230                                   Reporter != nullptr};
231 
232   auto Factory = std::make_unique<clang::move::ClangMoveActionFactory>(
233       &MoveContext, Reporter);
234 
235   tooling::runToolOnCodeWithArgs(
236       Factory->create(), CC, Context.InMemoryFileSystem,
237       {"-std=c++11", "-fparse-all-comments", "-I."}, TestCCName, "clang-move",
238       std::make_shared<PCHContainerOperations>());
239   formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
240   // The Key is file name, value is the new code after moving the class.
241   std::map<std::string, std::string> Results;
242   for (const auto &It : FileToReplacements) {
243     // The path may come out as "./foo.h", normalize to "foo.h".
244     SmallString<32> FilePath (It.first);
245     llvm::sys::path::remove_dots(FilePath);
246     Results[FilePath.str().str()] = Context.getRewrittenText(FileToFileID[FilePath]);
247   }
248   return Results;
249 }
250 
TEST(ClangMove,MoveHeaderAndCC)251 TEST(ClangMove, MoveHeaderAndCC) {
252   move::MoveDefinitionSpec Spec;
253   Spec.Names = {std::string("a::b::Foo")};
254   Spec.OldHeader = "foo.h";
255   Spec.OldCC = "foo.cc";
256   Spec.NewHeader = "new_foo.h";
257   Spec.NewCC = "new_foo.cc";
258   std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n\n";
259   auto Results = runClangMoveOnCode(Spec);
260   EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
261   EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
262   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
263   EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
264 }
265 
TEST(ClangMove,MoveHeaderOnly)266 TEST(ClangMove, MoveHeaderOnly) {
267   move::MoveDefinitionSpec Spec;
268   Spec.Names = {std::string("a::b::Foo")};
269   Spec.OldHeader = "foo.h";
270   Spec.NewHeader = "new_foo.h";
271   auto Results = runClangMoveOnCode(Spec);
272   EXPECT_EQ(2u, Results.size());
273   EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
274   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
275 }
276 
TEST(ClangMove,MoveCCOnly)277 TEST(ClangMove, MoveCCOnly) {
278   move::MoveDefinitionSpec Spec;
279   Spec.Names = {std::string("a::b::Foo")};
280   Spec.OldCC = "foo.cc";
281   Spec.NewCC = "new_foo.cc";
282   std::string ExpectedHeader = "#include \"foo.h\"\n\n";
283   auto Results = runClangMoveOnCode(Spec);
284   EXPECT_EQ(2u, Results.size());
285   EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
286   EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
287 }
288 
TEST(ClangMove,MoveNonExistClass)289 TEST(ClangMove, MoveNonExistClass) {
290   move::MoveDefinitionSpec Spec;
291   Spec.Names = {std::string("NonExistFoo")};
292   Spec.OldHeader = "foo.h";
293   Spec.OldCC = "foo.cc";
294   Spec.NewHeader = "new_foo.h";
295   Spec.NewCC = "new_foo.cc";
296   auto Results = runClangMoveOnCode(Spec);
297   EXPECT_EQ(0u, Results.size());
298 }
299 
TEST(ClangMove,HeaderIncludeSelf)300 TEST(ClangMove, HeaderIncludeSelf) {
301   move::MoveDefinitionSpec Spec;
302   Spec.Names = {std::string("Foo")};
303   Spec.OldHeader = "foo.h";
304   Spec.OldCC = "foo.cc";
305   Spec.NewHeader = "new_foo.h";
306   Spec.NewCC = "new_foo.cc";
307 
308   const char TestHeader[] = "#ifndef FOO_H\n"
309                             "#define FOO_H\n"
310                             "#include \"foo.h\"\n"
311                             "class Foo {};\n"
312                             "#endif\n";
313   const char TestCode[] = "#include \"foo.h\"";
314   const char ExpectedNewHeader[] = "#ifndef FOO_H\n"
315                                    "#define FOO_H\n"
316                                    "#include \"new_foo.h\"\n"
317                                    "class Foo {};\n"
318                                    "#endif\n";
319   const char ExpectedNewCC[] = "#include \"new_foo.h\"";
320   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
321   EXPECT_EQ("", Results[Spec.OldHeader]);
322   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
323   EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
324 }
325 
TEST(ClangMove,MoveAll)326 TEST(ClangMove, MoveAll) {
327   std::vector<std::string> TestHeaders = {
328     "class A {\npublic:\n  int f();\n};",
329     // forward declaration.
330     "class B;\nclass A {\npublic:\n  int f();\n};",
331     // template forward declaration.
332     "template <typename T> class B;\nclass A {\npublic:\n  int f();\n};",
333     "namespace a {}\nclass A {\npublic:\n  int f();\n};",
334     "namespace a {}\nusing namespace a;\nclass A {\npublic:\n  int f();\n};",
335   };
336   const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
337   move::MoveDefinitionSpec Spec;
338   Spec.Names.push_back("A");
339   Spec.OldHeader = "foo.h";
340   Spec.OldCC = "foo.cc";
341   Spec.NewHeader = "new_foo.h";
342   Spec.NewCC = "new_foo.cc";
343   for (const auto& Header : TestHeaders) {
344     auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
345     EXPECT_EQ(Header, Results[Spec.NewHeader]);
346     EXPECT_EQ("", Results[Spec.OldHeader]);
347     EXPECT_EQ("", Results[Spec.OldCC]);
348   }
349 }
350 
TEST(ClangMove,MoveAllMultipleClasses)351 TEST(ClangMove, MoveAllMultipleClasses) {
352   move::MoveDefinitionSpec Spec;
353   std::vector<std::string> TestHeaders = {
354     "class C;\nclass A {\npublic:\n  int f();\n};\nclass B {};",
355     "class C;\nclass B;\nclass A {\npublic:\n  int f();\n};\nclass B {};",
356   };
357   const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
358   Spec.Names = {std::string("A"), std::string("B")};
359   Spec.OldHeader = "foo.h";
360   Spec.OldCC = "foo.cc";
361   Spec.NewHeader = "new_foo.h";
362   Spec.NewCC = "new_foo.cc";
363   for (const auto& Header : TestHeaders) {
364     auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
365     EXPECT_EQ(Header, Results[Spec.NewHeader]);
366     EXPECT_EQ("", Results[Spec.OldHeader]);
367     EXPECT_EQ("", Results[Spec.OldCC]);
368   }
369 }
370 
TEST(ClangMove,DontMoveAll)371 TEST(ClangMove, DontMoveAll) {
372   const char ExpectedHeader[] = "#ifndef NEW_FOO_H\n"
373                                 "#define NEW_FOO_H\n"
374                                 "\n"
375                                 "class A {\npublic:\n  int f();\n};\n"
376                                 "\n"
377                                 "#endif // NEW_FOO_H\n";
378   const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
379   std::vector<std::string> TestHeaders = {
380     "class B {};\nclass A {\npublic:\n  int f();\n};\n",
381     "void f() {};\nclass A {\npublic:\n  int f();\n};\n",
382   };
383   move::MoveDefinitionSpec Spec;
384   Spec.Names.push_back("A");
385   Spec.OldHeader = "foo.h";
386   Spec.OldCC = "foo.cc";
387   Spec.NewHeader = "new_foo.h";
388   Spec.NewCC = "new_foo.cc";
389   for (const auto& Header : TestHeaders) {
390     auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
391     EXPECT_EQ(ExpectedHeader, Results[Spec.NewHeader]);
392     // The expected old header should not contain class A definition.
393     std::string ExpectedOldHeader = Header.substr(0, Header.size() - 32);
394     EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
395   }
396 }
397 
TEST(ClangMove,IgnoreMacroSymbolsAndMoveAll)398 TEST(ClangMove, IgnoreMacroSymbolsAndMoveAll) {
399   const char TestCode[] = "#include \"foo.h\"";
400   std::vector<std::string> TestHeaders = {
401     "#define DEFINE_Foo int Foo = 1;\nDEFINE_Foo;\nclass Bar {};\n",
402     "#define DEFINE(x) int var_##x = 1;\nDEFINE(foo);\nclass Bar {};\n",
403   };
404   move::MoveDefinitionSpec Spec;
405   Spec.Names.push_back("Bar");
406   Spec.OldHeader = "foo.h";
407   Spec.OldCC = "foo.cc";
408   Spec.NewHeader = "new_foo.h";
409   Spec.NewCC = "new_foo.cc";
410 
411   for (const auto& Header : TestHeaders) {
412     auto Results = runClangMoveOnCode(Spec, Header.c_str(), TestCode);
413     EXPECT_EQ("", Results[Spec.OldHeader]);
414     EXPECT_EQ(Header, Results[Spec.NewHeader]);
415   }
416 }
417 
TEST(ClangMove,MacroInFunction)418 TEST(ClangMove, MacroInFunction) {
419   const char TestHeader[] = "#define INT int\n"
420                             "class A {\npublic:\n  int f();\n};\n"
421                             "class B {};\n";
422   const char TestCode[] = "#include \"foo.h\"\n"
423                           "INT A::f() { return 0; }\n";
424   const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
425                                  "INT A::f() { return 0; }\n";
426   move::MoveDefinitionSpec Spec;
427   Spec.Names.push_back("A");
428   Spec.OldHeader = "foo.h";
429   Spec.OldCC = "foo.cc";
430   Spec.NewHeader = "new_foo.h";
431   Spec.NewCC = "new_foo.cc";
432   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
433   EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
434 }
435 
TEST(ClangMove,DefinitionInMacro)436 TEST(ClangMove, DefinitionInMacro) {
437   const char TestHeader[] = "#define DEF(CLASS) void CLASS##_::f() {}\n"
438                             "#define DEF2(CLASS, ...) void CLASS##_::f2() {}\n"
439                             "class A_ {\nvoid f();\nvoid f2();\n};\n"
440                             "class B {};\n";
441   const char TestCode[] = "#include \"foo.h\"\n"
442                           "DEF(A)\n\n"
443                           "DEF2(A,\n"
444                           "     123)\n";
445   const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
446                                  "DEF(A)\n\n"
447                                  "DEF2(A, 123)\n";
448   move::MoveDefinitionSpec Spec;
449   Spec.Names.push_back("A_");
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, TestCode);
455   EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
456 }
457 
TEST(ClangMove,WellFormattedCode)458 TEST(ClangMove, WellFormattedCode) {
459   const std::string CommonHeader =
460       "namespace a {\n"
461       "namespace b {\n"
462       "namespace c {\n"
463       "class C;\n"
464       "\n"
465       "class A {\npublic:\n  void f();\n  void f2();\n};\n"
466       "} // namespace c\n"
467       "} // namespace b\n"
468       "\n"
469       "namespace d {\n"
470       "namespace e {\n"
471       "class B {\npublic:\n  void f();\n};\n"
472       "} // namespace e\n"
473       "} // namespace d\n"
474       "} // namespace a\n";
475   const std::string CommonCode = "\n"
476                                  "namespace a {\n"
477                                  "namespace b {\n"
478                                  "namespace c {\n"
479                                  "void A::f() {}\n"
480                                  "\n"
481                                  "void A::f2() {}\n"
482                                  "} // namespace c\n"
483                                  "} // namespace b\n"
484                                  "\n"
485                                  "namespace d {\n"
486                                  "namespace e {\n"
487                                  "void B::f() {}\n"
488                                  "} // namespace e\n"
489                                  "} // namespace d\n"
490                                  "} // namespace a\n";
491   // Add dummy class to prevent behavior of moving all declarations from header.
492   const std::string TestHeader = CommonHeader + "class D {};\n";
493   const std::string TestCode = "#include \"foo.h\"\n" + CommonCode;
494   const std::string ExpectedNewHeader = "#ifndef NEW_FOO_H\n"
495                                         "#define NEW_FOO_H\n"
496                                         "\n" +
497                                         CommonHeader +
498                                         "\n"
499                                         "#endif // NEW_FOO_H\n";
500   const std::string ExpectedNewCC = "#include \"new_foo.h\"\n" + CommonCode;
501   move::MoveDefinitionSpec Spec;
502   Spec.Names.push_back("a::b::c::A");
503   Spec.Names.push_back("a::d::e::B");
504   Spec.OldHeader = "foo.h";
505   Spec.OldCC = "foo.cc";
506   Spec.NewHeader = "new_foo.h";
507   Spec.NewCC = "new_foo.cc";
508   auto Results = runClangMoveOnCode(Spec, TestHeader.c_str(), TestCode.c_str());
509   EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
510   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
511 }
512 
TEST(ClangMove,AddDependentNewHeader)513 TEST(ClangMove, AddDependentNewHeader) {
514   const char TestHeader[] = "class A {};\n"
515                             "class B {};\n";
516   const char TestCode[] = "#include \"foo.h\"\n";
517   const char ExpectedOldHeader[] = "#include \"new_foo.h\"\nclass B {};\n";
518   const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
519                                    "#define NEW_FOO_H\n"
520                                    "\n"
521                                    "class A {};\n"
522                                    "\n"
523                                    "#endif // NEW_FOO_H\n";
524   move::MoveDefinitionSpec Spec;
525   Spec.Names.push_back("A");
526   Spec.OldHeader = "foo.h";
527   Spec.OldCC = "foo.cc";
528   Spec.NewHeader = "new_foo.h";
529   Spec.NewCC = "new_foo.cc";
530   Spec.OldDependOnNew = true;
531   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
532   EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
533   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
534 }
535 
TEST(ClangMove,AddDependentOldHeader)536 TEST(ClangMove, AddDependentOldHeader) {
537   const char TestHeader[] = "class A {};\n"
538                             "class B {};\n";
539   const char TestCode[] = "#include \"foo.h\"\n";
540   const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
541                                    "#define NEW_FOO_H\n"
542                                    "\n"
543                                    "#include \"foo.h\"\n"
544                                    "\n"
545                                    "class B {};\n"
546                                    "\n"
547                                    "#endif // NEW_FOO_H\n";
548   const char ExpectedOldHeader[] = "class A {};\n";
549   move::MoveDefinitionSpec Spec;
550   Spec.Names.push_back("B");
551   Spec.OldHeader = "foo.h";
552   Spec.OldCC = "foo.cc";
553   Spec.NewHeader = "new_foo.h";
554   Spec.NewCC = "new_foo.cc";
555   Spec.NewDependOnOld = true;
556   auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
557   EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
558   EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
559 }
560 
TEST(ClangMove,DumpDecls)561 TEST(ClangMove, DumpDecls) {
562   const char TestHeader[] = "template <typename T>\n"
563                             "class A {\n"
564                             " public:\n"
565                             "  void f();\n"
566                             "  template <typename U> void h();\n"
567                             "  static int b;\n"
568                             "};\n"
569                             "\n"
570                             "template <typename T> void A<T>::f() {}\n"
571                             "\n"
572                             "template <typename T>\n"
573                             "template <typename U>\n"
574                             "void A<T>::h() {}\n"
575                             "\n"
576                             "template <typename T> int A<T>::b = 2;\n"
577                             "\n"
578                             "template <> class A<int> {};\n"
579                             "\n"
580                             "class B {};\n"
581                             "\n"
582                             "namespace a {\n"
583                             "class Move1 {};\n"
584                             "void f1() {}\n"
585                             "template <typename T>"
586                             "void f2(T t);\n"
587                             "} // namespace a\n"
588                             "\n"
589                             "class ForwardClass;\n"
590                             "namespace a {\n"
591                             "namespace b {\n"
592                             "class Move1 { public : void f(); };\n"
593                             "void f() {}\n"
594                             "enum E1 { Green };\n"
595                             "enum class E2 { Red };\n"
596                             "typedef int Int2;\n"
597                             "typedef A<double> A_d;"
598                             "using Int = int;\n"
599                             "template <typename T>\n"
600                             "using AA = A<T>;\n"
601                             "extern int kGlobalInt;\n"
602                             "extern const char* const kGlobalStr;\n"
603                             "} // namespace b\n"
604                             "} // namespace a\n"
605                             "#define DEFINE_FOO class Foo {};\n"
606                             "DEFINE_FOO\n";
607   const char TestCode[] = "#include \"foo.h\"\n";
608   move::MoveDefinitionSpec Spec;
609   Spec.Names.push_back("B");
610   Spec.OldHeader = "foo.h";
611   Spec.OldCC = "foo.cc";
612   Spec.NewHeader = "new_foo.h";
613   Spec.NewCC = "new_foo.cc";
614   DeclarationReporter Reporter;
615   std::vector<DeclarationReporter::Declaration> ExpectedDeclarations = {
616       {"A", "Class", true},
617       {"B", "Class", false},
618       {"a::Move1", "Class", false},
619       {"a::f1", "Function", false},
620       {"a::f2", "Function", true},
621       {"a::b::Move1", "Class", false},
622       {"a::b::f", "Function", false},
623       {"a::b::E1", "Enum", false},
624       {"a::b::E2", "Enum", false},
625       {"a::b::Int2", "TypeAlias", false},
626       {"a::b::A_d", "TypeAlias", false},
627       {"a::b::Int", "TypeAlias", false},
628       {"a::b::AA", "TypeAlias", true},
629       {"a::b::kGlobalInt", "Variable", false},
630       {"a::b::kGlobalStr", "Variable", false}};
631   runClangMoveOnCode(Spec, TestHeader, TestCode, &Reporter);
632   std::vector<DeclarationReporter::Declaration> Results;
633   for (const auto &DelPair : Reporter.getDeclarationList())
634     Results.push_back(DelPair);
635   EXPECT_THAT(ExpectedDeclarations,
636               testing::UnorderedElementsAreArray(Results));
637 }
638 
639 } // namespace
640 } // namespace move
641 } // namespace clang
642