Skip to content

Commit

Permalink
[clang-move] Support moving multiple classes in one run.
Browse files Browse the repository at this point in the history
Reviewers: ioeric

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D25309

llvm-svn: 283526
  • Loading branch information
hokein committed Oct 7, 2016
1 parent 9ff8e87 commit a709e38
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 16 deletions.
22 changes: 17 additions & 5 deletions clang-tools-extra/clang-move/ClangMove.cpp
Expand Up @@ -287,31 +287,43 @@ ClangMoveTool::ClangMoveTool(
: 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<StringRef, 4> ClassNames;
llvm::StringRef(Spec.Names).split(ClassNames, ',');
Optional<ast_matchers::internal::Matcher<NamedDecl>> InMovedClassNames;
for (StringRef ClassName : ClassNames) {
llvm::StringRef GlobalClassName = ClassName.trim().ltrim(':');
const auto HasName = hasName(("::" + GlobalClassName).str());
InMovedClassNames =
InMovedClassNames ? anyOf(*InMovedClassNames, HasName) : HasName;
}
if (!InMovedClassNames) {
llvm::errs() << "No classes being moved.\n";
return;
}

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);
Expand Down
5 changes: 3 additions & 2 deletions clang-tools-extra/clang-move/ClangMove.h
Expand Up @@ -37,8 +37,9 @@ class ClangMoveTool : public ast_matchers::MatchFinder::MatchCallback {
};

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.
Expand Down
8 changes: 5 additions & 3 deletions clang-tools-extra/clang-move/tool/ClangMoveMain.cpp
Expand Up @@ -37,8 +37,10 @@ std::error_code CreateNewFile(const llvm::Twine &path) {

cl::OptionCategory ClangMoveCategory("clang-move options");

cl::opt<std::string> Name("name", cl::desc("The name of class being moved."),
cl::cat(ClangMoveCategory));
cl::opt<std::string>
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<std::string>
OldHeader("old_header",
Expand Down Expand Up @@ -86,7 +88,7 @@ int main(int argc, const char **argv) {
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;
Expand Down
Expand Up @@ -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"
}
]
27 changes: 27 additions & 0 deletions clang-tools-extra/test/clang-move/Inputs/multiple_class_test.cpp
@@ -0,0 +1,27 @@
#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 Move4::f() {
return 0;
}

int NoMove::f() {
return 0;
}
} // namespace c
30 changes: 30 additions & 0 deletions clang-tools-extra/test/clang-move/Inputs/multiple_class_test.h
@@ -0,0 +1,30 @@
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 Move4 {
public:
int f();
};

class NoMove {
public:
int f();
};
} // namespace c
4 changes: 2 additions & 2 deletions clang-tools-extra/test/clang-move/move-class.cpp
Expand Up @@ -3,15 +3,15 @@
// 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
// RUN: FileCheck -input-file=%T/clang-move/test.h %s -implicit-check-not='{{namespace.*}}'
//
// 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
Expand Down
58 changes: 58 additions & 0 deletions clang-tools-extra/test/clang-move/move-multiple-classes.cpp
@@ -0,0 +1,58 @@
// 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,c::Move4" -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: class Move4 {
// 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: int Move4::f() { return 0; }
// CHECK-NEW-TEST-CPP: } // namespace c
8 changes: 4 additions & 4 deletions clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp
Expand Up @@ -210,7 +210,7 @@ runClangMoveOnCode(const move::ClangMoveTool::MoveDefinitionSpec &Spec) {

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";
Expand All @@ -225,7 +225,7 @@ TEST(ClangMove, MoveHeaderAndCC) {

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);
Expand All @@ -236,7 +236,7 @@ TEST(ClangMove, MoveHeaderOnly) {

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";
Expand All @@ -248,7 +248,7 @@ TEST(ClangMove, MoveCCOnly) {

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";
Expand Down

0 comments on commit a709e38

Please sign in to comment.