642 lines · cpp
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-exception6//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 _WIN32196const char WorkingDir[] = "C:\\test";197#else198const char WorkingDir[] = "/test";199#endif200 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(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 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, TestHeader, 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("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 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.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 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("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 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("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 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("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 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("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 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("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 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("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 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("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 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("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} // namespace640} // namespace move641} // namespace clang642