Index: clang-move/ClangMove.h =================================================================== --- clang-move/ClangMove.h +++ clang-move/ClangMove.h @@ -37,8 +37,9 @@ }; struct MoveDefinitionSpec { - // A fully qualified name, e.g. "X", "a::X". - std::string Name; + // A comma-separated list of fully qualified names, e.g. "Foo", + // "a::Foo, b::Foo". + std::string Names; // The file path of old header, can be relative path and absolute path. std::string OldHeader; // The file path of old cc, can be relative path and absolute path. Index: clang-move/ClangMove.cpp =================================================================== --- clang-move/ClangMove.cpp +++ clang-move/ClangMove.cpp @@ -287,31 +287,43 @@ : Spec(MoveSpec), FileToReplacements(FileToReplacements), OriginalRunningDirectory(OriginalRunningDirectory), FallbackStyle(FallbackStyle) { - Spec.Name = llvm::StringRef(Spec.Name).ltrim(':'); if (!Spec.NewHeader.empty()) CCIncludes.push_back("#include \"" + Spec.NewHeader + "\"\n"); } void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) { - std::string FullyQualifiedName = "::" + Spec.Name; + SmallVector ClassNames; + llvm::StringRef(Spec.Names).split(ClassNames, ','); + Optional> InMovedClassNames; + for (StringRef ClassName : ClassNames) { + // Removed the preceding and trailing space of ClassName. + // And removed the global scope operator "::" since we always regard the + // ClassName as a global name. + llvm::StringRef GlobalClassName = ClassName.trim(' ').ltrim(':'); + const auto HasName = hasName(("::" + GlobalClassName).str()); + InMovedClassNames = + InMovedClassNames ? anyOf(*InMovedClassNames, HasName) : HasName; + } + assert(InMovedClassNames); + auto InOldHeader = isExpansionInFile( MakeAbsolutePath(OriginalRunningDirectory, Spec.OldHeader)); auto InOldCC = isExpansionInFile( MakeAbsolutePath(OriginalRunningDirectory, Spec.OldCC)); auto InOldFiles = anyOf(InOldHeader, InOldCC); auto InMovedClass = - hasDeclContext(cxxRecordDecl(hasName(FullyQualifiedName))); + hasDeclContext(cxxRecordDecl(*InMovedClassNames)); // Match moved class declarations. auto MovedClass = cxxRecordDecl( - InOldFiles, hasName(FullyQualifiedName), isDefinition(), + InOldFiles, *InMovedClassNames, isDefinition(), hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()))); Finder->addMatcher(MovedClass.bind("moved_class"), this); // Match moved class methods (static methods included) which are defined // outside moved class declaration. Finder->addMatcher(cxxMethodDecl(InOldFiles, - ofClass(hasName(FullyQualifiedName)), + ofClass(*InMovedClassNames), isDefinition()) .bind("class_method"), this); Index: clang-move/tool/ClangMoveMain.cpp =================================================================== --- clang-move/tool/ClangMoveMain.cpp +++ clang-move/tool/ClangMoveMain.cpp @@ -37,8 +37,10 @@ cl::OptionCategory ClangMoveCategory("clang-move options"); -cl::opt Name("name", cl::desc("The name of class being moved."), - cl::cat(ClangMoveCategory)); +cl::opt + Names("names", cl::desc("A comma-separated list of the names of classes " + "being moved, e.g. \"Foo\", \"a::Foo, b::Foo\"."), + cl::cat(ClangMoveCategory)); cl::opt OldHeader("old_header", @@ -86,7 +88,7 @@ tooling::RefactoringTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); move::ClangMoveTool::MoveDefinitionSpec Spec; - Spec.Name = Name; + Spec.Names = Names; Spec.OldHeader = OldHeader; Spec.NewHeader = NewHeader; Spec.OldCC = OldCC; Index: test/clang-move/Inputs/database_template.json =================================================================== --- test/clang-move/Inputs/database_template.json +++ test/clang-move/Inputs/database_template.json @@ -3,5 +3,10 @@ "directory": "$test_dir/build", "command": "clang++ -o test.o $test_dir/test.cpp", "file": "$test_dir/test.cpp" +}, +{ + "directory": "$test_dir/build", + "command": "clang++ -o test.o $test_dir/multiple_class_test.cpp", + "file": "$test_dir/multiple_class_test.cpp" } ] Index: test/clang-move/Inputs/multiple_class_test.h =================================================================== --- /dev/null +++ test/clang-move/Inputs/multiple_class_test.h @@ -0,0 +1,25 @@ +namespace a { +class Move1 { +public: + int f(); +}; +} // namespace a + +namespace b { +class Move2 { +public: + int f(); +}; +} // namespace b + +namespace c { +class Move3 { +public: + int f(); +}; + +class NoMove { +public: + int f(); +}; +} // namespace c Index: test/clang-move/Inputs/multiple_class_test.cpp =================================================================== --- /dev/null +++ test/clang-move/Inputs/multiple_class_test.cpp @@ -0,0 +1,22 @@ +#include "multiple_class_test.h" + +namespace a { +int Move1::f() { + return 0; +} +} // namespace a + +namespace b { +int Move2::f() { + return 0; +} +} // namespace b + +namespace c { +int Move3::f() { + return 0; +} +int NoMove::f() { + return 0; +} +} // namespace c Index: test/clang-move/move-class.cpp =================================================================== --- test/clang-move/move-class.cpp +++ test/clang-move/move-class.cpp @@ -3,7 +3,7 @@ // RUN: cp %S/Inputs/test* %T/clang-move/ // RUN: touch %T/clang-move/test2.h // RUN: cd %T/clang-move -// RUN: clang-move -name="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=../clang-move/test.cpp -old_header=../clang-move/test.h %T/clang-move/test.cpp +// RUN: clang-move -names="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=../clang-move/test.cpp -old_header=../clang-move/test.h %T/clang-move/test.cpp // RUN: FileCheck -input-file=%T/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s // RUN: FileCheck -input-file=%T/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s // RUN: FileCheck -input-file=%T/clang-move/test.cpp -check-prefix=CHECK-OLD-TEST-CPP %s @@ -11,7 +11,7 @@ // // RUN: cp %S/Inputs/test* %T/clang-move/ // RUN: cd %T/clang-move -// RUN: clang-move -name="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=%T/clang-move/test.cpp -old_header=%T/clang-move/test.h %T/clang-move/test.cpp +// RUN: clang-move -names="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=%T/clang-move/test.cpp -old_header=%T/clang-move/test.h %T/clang-move/test.cpp // RUN: FileCheck -input-file=%T/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s // RUN: FileCheck -input-file=%T/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s // RUN: FileCheck -input-file=%T/clang-move/test.cpp -check-prefix=CHECK-OLD-TEST-CPP %s Index: test/clang-move/move-multiple-classes.cpp =================================================================== --- /dev/null +++ test/clang-move/move-multiple-classes.cpp @@ -0,0 +1,53 @@ +// RUN: mkdir -p %T/clang-move/build +// RUN: sed 's|$test_dir|%/T/clang-move|g' %S/Inputs/database_template.json > %T/clang-move/compile_commands.json +// RUN: cp %S/Inputs/multiple_class_test* %T/clang-move/ +// RUN: cd %T/clang-move +// RUN: clang-move -names="a::Move1, b::Move2,c::Move3" -new_cc=%T/clang-move/new_multiple_class_test.cpp -new_header=%T/clang-move/new_multiple_class_test.h -old_cc=%T/clang-move/multiple_class_test.cpp -old_header=../clang-move/multiple_class_test.h %T/clang-move/multiple_class_test.cpp +// RUN: FileCheck -input-file=%T/clang-move/new_multiple_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s +// RUN: FileCheck -input-file=%T/clang-move/new_multiple_class_test.h -check-prefix=CHECK-NEW-TEST-H %s +// RUN: FileCheck -input-file=%T/clang-move/multiple_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP %s +// RUN: FileCheck -input-file=%T/clang-move/multiple_class_test.h -check-prefix=CHECK-OLD-TEST-H %s +// +// CHECK-OLD-TEST-H: namespace c { +// CHECK-OLD-TEST-H: class NoMove { +// CHECK-OLD-TEST-H: public: +// CHECK-OLD-TEST-H: int f(); +// CHECK-OLD-TEST-H: }; +// CHECK-OLD-TEST-H: } // namespace c + +// CHECK-OLD-TEST-CPP: #include "{{.*}}multiple_class_test.h" +// CHECK-OLD-TEST-CPP: namespace c { +// CHECK-OLD-TEST-CPP: int NoMove::f() { +// CHECK-OLD-TEST-CPP: return 0; +// CHECK-OLD-TEST-CPP: } +// CHECK-OLD-TEST-CPP: } // namespace c + +// CHECK-NEW-TEST-H: namespace a { +// CHECK-NEW-TEST-H: class Move1 { +// CHECK-NEW-TEST-H: public: +// CHECK-NEW-TEST-H: int f(); +// CHECK-NEW-TEST-H: }; +// CHECK-NEW-TEST-H: } // namespace a +// CHECK-NEW-TEST-H: namespace b { +// CHECK-NEW-TEST-H: class Move2 { +// CHECK-NEW-TEST-H: public: +// CHECK-NEW-TEST-H: int f(); +// CHECK-NEW-TEST-H: }; +// CHECK-NEW-TEST-H: } // namespace b +// CHECK-NEW-TEST-H: namespace c { +// CHECK-NEW-TEST-H: class Move3 { +// CHECK-NEW-TEST-H: public: +// CHECK-NEW-TEST-H: int f(); +// CHECK-NEW-TEST-H: }; +// CHECK-NEW-TEST-H: } // namespace c + +// CHECK-NEW-TEST-CPP: #include "{{.*}}new_multiple_class_test.h" +// CHECK-NEW-TEST-CPP: namespace a { +// CHECK-NEW-TEST-CPP: int Move1::f() { return 0; } +// CHECK-NEW-TEST-CPP: } // namespace a +// CHECK-NEW-TEST-CPP: namespace b { +// CHECK-NEW-TEST-CPP: int Move2::f() { return 0; } +// CHECK-NEW-TEST-CPP: } // namespace b +// CHECK-NEW-TEST-CPP: namespace c { +// CHECK-NEW-TEST-CPP: int Move3::f() { return 0; } +// CHECK-NEW-TEST-CPP: } // namespace c Index: unittests/clang-move/ClangMoveTests.cpp =================================================================== --- unittests/clang-move/ClangMoveTests.cpp +++ unittests/clang-move/ClangMoveTests.cpp @@ -210,7 +210,7 @@ TEST(ClangMove, MoveHeaderAndCC) { move::ClangMoveTool::MoveDefinitionSpec Spec; - Spec.Name = "a::b::Foo"; + Spec.Names = "a::b::Foo"; Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; Spec.NewHeader = "new_foo.h"; @@ -225,7 +225,7 @@ TEST(ClangMove, MoveHeaderOnly) { move::ClangMoveTool::MoveDefinitionSpec Spec; - Spec.Name = "a::b::Foo"; + Spec.Names = "a::b::Foo"; Spec.OldHeader = "foo.h"; Spec.NewHeader = "new_foo.h"; auto Results = runClangMoveOnCode(Spec); @@ -236,7 +236,7 @@ TEST(ClangMove, MoveCCOnly) { move::ClangMoveTool::MoveDefinitionSpec Spec; - Spec.Name = "a::b::Foo"; + Spec.Names = "a::b::Foo"; Spec.OldCC = "foo.cc"; Spec.NewCC = "new_foo.cc"; std::string ExpectedHeader = "#include \"foo.h\"\n\n"; @@ -248,7 +248,7 @@ TEST(ClangMove, MoveNonExistClass) { move::ClangMoveTool::MoveDefinitionSpec Spec; - Spec.Name = "NonExistFoo"; + Spec.Names = "NonExistFoo"; Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; Spec.NewHeader = "new_foo.h";