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
23namespace clang {
24namespace move {
25namespace {
26
27const 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
50const 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
93const 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
105const 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
135const 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
159const 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
196const char WorkingDir[] = "C:\\test";
197#else
198const char WorkingDir[] = "/test";
199#endif
200
201const char TestHeaderName[] = "foo.h";
202const char TestCCName[] = "foo.cc";
203
204std::map<std::string, std::string>
205runClangMoveOnCode(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(path&: 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, Content: 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: Spec, .FileToReplacements: FileToReplacements, .OriginalRunningDirectory: Dir.c_str(), .FallbackStyle: "LLVM",
230 .DumpDeclarations: Reporter != nullptr};
231
232 auto Factory = std::make_unique<clang::move::ClangMoveActionFactory>(
233 args: &MoveContext, args: Reporter);
234
235 tooling::runToolOnCodeWithArgs(
236 ToolAction: Factory->create(), Code: CC, VFS: Context.InMemoryFileSystem,
237 Args: {"-std=c++11", "-fparse-all-comments", "-I."}, FileName: TestCCName, ToolName: "clang-move",
238 PCHContainerOps: std::make_shared<PCHContainerOperations>());
239 formatAndApplyAllReplacements(FileToReplaces: FileToReplacements, Rewrite&: Context.Rewrite, Style: "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(path&: FilePath);
246 Results[FilePath.str().str()] = Context.getRewrittenText(ID: FileToFileID[FilePath]);
247 }
248 return Results;
249}
250
251TEST(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
266TEST(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
277TEST(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
289TEST(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
300TEST(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, Header: TestHeader, CC: TestCode);
321 EXPECT_EQ("", Results[Spec.OldHeader]);
322 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
323 EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
324}
325
326TEST(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(Elt: "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: Header.c_str(), CC: Code);
345 EXPECT_EQ(Header, Results[Spec.NewHeader]);
346 EXPECT_EQ("", Results[Spec.OldHeader]);
347 EXPECT_EQ("", Results[Spec.OldCC]);
348 }
349}
350
351TEST(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: Header.c_str(), CC: Code);
365 EXPECT_EQ(Header, Results[Spec.NewHeader]);
366 EXPECT_EQ("", Results[Spec.OldHeader]);
367 EXPECT_EQ("", Results[Spec.OldCC]);
368 }
369}
370
371TEST(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(Elt: "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: Header.c_str(), CC: 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(pos: 0, n: Header.size() - 32);
394 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
395 }
396}
397
398TEST(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(Elt: "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: Header.c_str(), CC: TestCode);
413 EXPECT_EQ("", Results[Spec.OldHeader]);
414 EXPECT_EQ(Header, Results[Spec.NewHeader]);
415 }
416}
417
418TEST(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(Elt: "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, Header: TestHeader, CC: TestCode);
433 EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
434}
435
436TEST(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(Elt: "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, Header: TestHeader, CC: TestCode);
455 EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
456}
457
458TEST(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(Elt: "a::b::c::A");
503 Spec.Names.push_back(Elt: "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, Header: TestHeader.c_str(), CC: TestCode.c_str());
509 EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
510 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
511}
512
513TEST(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(Elt: "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, Header: TestHeader, CC: TestCode);
532 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
533 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
534}
535
536TEST(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(Elt: "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, Header: TestHeader, CC: TestCode);
557 EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
558 EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
559}
560
561TEST(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(Elt: "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, Header: TestHeader, CC: TestCode, Reporter: &Reporter);
632 std::vector<DeclarationReporter::Declaration> Results;
633 for (const auto &DelPair : Reporter.getDeclarationList())
634 Results.push_back(x: DelPair);
635 EXPECT_THAT(ExpectedDeclarations,
636 testing::UnorderedElementsAreArray(Results));
637}
638
639} // namespace
640} // namespace move
641} // namespace clang
642

source code of clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp