Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
This revision was automatically updated to reflect the committed changes. Closed by commit rL282070: [clang-move] A prototype tool for moving class definition to new file. (authored by hokein). Changed prior to commit: https://reviews.llvm.org/D24243?vs=72031&id=72033#toc Repository: rL LLVM https://reviews.llvm.org/D24243 Files: clang-tools-extra/trunk/CMakeLists.txt clang-tools-extra/trunk/clang-move/CMakeLists.txt clang-tools-extra/trunk/clang-move/ClangMove.cpp clang-tools-extra/trunk/clang-move/ClangMove.h clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp clang-tools-extra/trunk/unittests/CMakeLists.txt clang-tools-extra/trunk/unittests/clang-move/CMakeLists.txt clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp Index: clang-tools-extra/trunk/CMakeLists.txt === --- clang-tools-extra/trunk/CMakeLists.txt +++ clang-tools-extra/trunk/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(change-namespace) add_subdirectory(clang-query) +add_subdirectory(clang-move) add_subdirectory(include-fixer) add_subdirectory(pp-trace) add_subdirectory(tool-template) Index: clang-tools-extra/trunk/unittests/CMakeLists.txt === --- clang-tools-extra/trunk/unittests/CMakeLists.txt +++ clang-tools-extra/trunk/unittests/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(change-namespace) add_subdirectory(clang-apply-replacements) +add_subdirectory(clang-move) add_subdirectory(clang-query) add_subdirectory(clang-tidy) add_subdirectory(include-fixer) Index: clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp === --- clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp +++ clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,226 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + " static int b;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "void Foo::f() { f1(); }\n" + "\n" + "int Foo::b = 2;\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespac
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein updated this revision to Diff 72031. hokein added a comment. Improve the way of detecting whether #include in old_header. https://reviews.llvm.org/D24243 Files: CMakeLists.txt clang-move/CMakeLists.txt clang-move/ClangMove.cpp clang-move/ClangMove.h clang-move/tool/CMakeLists.txt clang-move/tool/ClangMoveMain.cpp unittests/CMakeLists.txt unittests/clang-move/CMakeLists.txt unittests/clang-move/ClangMoveTests.cpp Index: unittests/clang-move/ClangMoveTests.cpp === --- /dev/null +++ unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,226 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + " static int b;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "void Foo::f() { f1(); }\n" + "\n" + "int Foo::b = 2;\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " voi
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein updated this revision to Diff 72027. hokein added a comment. Update dependency. https://reviews.llvm.org/D24243 Files: CMakeLists.txt clang-move/CMakeLists.txt clang-move/ClangMove.cpp clang-move/ClangMove.h clang-move/tool/CMakeLists.txt clang-move/tool/ClangMoveMain.cpp unittests/CMakeLists.txt unittests/clang-move/CMakeLists.txt unittests/clang-move/ClangMoveTests.cpp Index: unittests/clang-move/ClangMoveTests.cpp === --- /dev/null +++ unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,226 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + " static int b;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "void Foo::f() { f1(); }\n" + "\n" + "int Foo::b = 2;\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" +
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein updated this revision to Diff 71631. hokein added a comment. Support fully quailified name only. https://reviews.llvm.org/D24243 Files: CMakeLists.txt clang-move/CMakeLists.txt clang-move/ClangMove.cpp clang-move/ClangMove.h clang-move/tool/CMakeLists.txt clang-move/tool/ClangMoveMain.cpp unittests/CMakeLists.txt unittests/clang-move/CMakeLists.txt unittests/clang-move/ClangMoveTests.cpp Index: unittests/clang-move/ClangMoveTests.cpp === --- /dev/null +++ unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,226 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + " static int b;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "void Foo::f() { f1(); }\n" + "\n" + "int Foo::b = 2;\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" +
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
ioeric accepted this revision. ioeric added a comment. This revision is now accepted and ready to land. lg Comment at: unittests/clang-move/ClangMoveTests.cpp:122 @@ +121,3 @@ + +const char ExpectedNewCC[] = "#include \"foo.h\"\n" + "namespace a {\n" It's fine for this patch, but I think we also want to add newlines be between moved declarations, especially if there were newlines in the original code. https://reviews.llvm.org/D24243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein added inline comments. Comment at: clang-move/ClangMove.cpp:104 @@ +103,3 @@ + std::reverse(Namespaces.begin(), Namespaces.end()); + return Namespaces; +} Aha, I see. I misused the `findLocationAfterToken` previously. Comment at: clang-move/ClangMove.cpp:130 @@ +129,3 @@ + // Add #Includes. + std::string AllIncludesString; + // FIXME: Filter out the old_header.h and add header guard. For anonymous namespace, `getNamespaces` just makes it an empty string. Apart from that, we have to deal with other exceptions, for instance: ``` namespace a { void A::f() {} } ``` What we want is namespace `a`, but `getQualifiedNameAsString` returns `a::A::f`. Thus, using `getQualifiedNameAsString` wouldn't simplify the code at the moment. https://reviews.llvm.org/D24243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein updated this revision to Diff 71506. hokein marked 2 inline comments as done. hokein added a comment. Herald added a subscriber: mgorny. Address review comments. https://reviews.llvm.org/D24243 Files: CMakeLists.txt clang-move/CMakeLists.txt clang-move/ClangMove.cpp clang-move/ClangMove.h clang-move/tool/CMakeLists.txt clang-move/tool/ClangMoveMain.cpp unittests/CMakeLists.txt unittests/clang-move/CMakeLists.txt unittests/clang-move/ClangMoveTests.cpp Index: unittests/clang-move/ClangMoveTests.cpp === --- /dev/null +++ unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,226 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + " static int b;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "void Foo::f() { f1(); }\n" + "\n" + "int Foo::b = 2;\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n"
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
ioeric added inline comments. Comment at: clang-move/ClangMove.cpp:103 @@ +102,3 @@ + const clang::SourceManager *SM) { + // Gets the ending ";". + auto EndLoc = clang::Lexer::getLocForEndOfToken(D->getLocEnd(), 0, *SM, hokein wrote: > ioeric wrote: > > Consider the code below to also include trailing comment. > > clang::SourceLocation after_semi = clang::Lexer::findLocationAfterToken( > > D->getLocEnd, clang::tok::semi, *SM, > > result.Context->getLangOpts(), > > /*SkipTrailingWhitespaceAndNewLine=*/true); > > > But this code could not handle cases where the declaration definition has no > semi at the end, such as "void f() {}" Please see the comment for `findLocationAfterToken`. > If the token is not found or the location is inside a macro, the returned > source location will be invalid. Comment at: clang-move/ClangMove.cpp:129 @@ +128,3 @@ + for (const auto &MovedDecl : Decls) { +std::vector DeclNamespaces = GetNamespaces(MovedDecl.Decl); +auto CurrentIt = CurrentNamespaces.begin(); hokein wrote: > ioeric wrote: > > Is it possible to restrict all `MovedDecl.Decl` to NamedDecl so that we can > > use `getQualifiedNameAsString` instead of having a second implementation of > > retrieving namespaces. > > > > Also how is anonymous namespace handled here? > > > > > Yeah, `getQualifiedNameAsString` looks like a simpler way, but it doesn't > suitable for our usage here. > > The `getQualifiedNameAsString` includes the name of the class. For instance, > a class method decl like `void A::f() {}` defined in global namespace, it > retruns `A::f` which is not intended. > > It handles anonymous namespace by wrapping like `namespace { ... } // > namespace`, see the test. > I think it should be relatively easy to split the qualified name returned by `getQualifiedNameAsString `. > It handles anonymous namespace by wrapping like namespace { ... } // > namespace, see the test. I mean...wouldn't `getNamespaces` return something like "a::(anonymous)" for anonymous namespace? How do you handle this? Comment at: clang-move/ClangMove.h:39 @@ +38,3 @@ + struct MoveDefinitionSpec { +std::string Name; +std::string OldHeader; hokein wrote: > ioeric wrote: > > Should the `Name` be fully qualified? > It's not required. The name can be fully/partially qualified, e.g., > `::a::b::X`, `a::b::X`, `b::X`, `X`, which has the same behavior with > `hasName` ast matcher. > > It the given name is partially qualified, it will match all the class whose > name ends with the given name. > It the given name is partially qualified, it will match all the class whose > name ends with the given name. In this case, all matched classes will be moved right? Might want to mention this in the comment. Comment at: clang-move/ClangMove.h:65 @@ +64,3 @@ + + const MoveDefinitionSpec &Spec; + // The Key is file path, value is the replacements being applied to the file. hokein wrote: > ioeric wrote: > > Is there any reason why you made this a reference? > To avoid the cost of making a copy of the structure. If the copy is not that expensive, I'd just make a copy so that I don't need to worry about the life-cycle of `Spec`. https://reviews.llvm.org/D24243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein updated this revision to Diff 70538. hokein marked 19 inline comments as done. hokein added a comment. Herald added a subscriber: beanz. - Address review comments. https://reviews.llvm.org/D24243 Files: CMakeLists.txt clang-move/CMakeLists.txt clang-move/ClangMove.cpp clang-move/ClangMove.h clang-move/tool/CMakeLists.txt clang-move/tool/ClangMoveMain.cpp unittests/CMakeLists.txt unittests/clang-move/CMakeLists.txt unittests/clang-move/ClangMoveTests.cpp Index: unittests/clang-move/ClangMoveTests.cpp === --- /dev/null +++ unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,226 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + " static int b;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "void Foo::f() { f1(); }\n" + "\n" + "int Foo::b = 2;\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "int kConstInt1 = 0;\n" + "} // namespace\n" + "\n" + "static int kConstInt2 = 1;\n" + "\n" + "static int help() {\n" + " int a = 0;\n" + " return a;\n" + "}\n" + "\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein added inline comments. Comment at: clang-move/ClangMove.cpp:38 @@ +37,3 @@ + const clang::Module * /*Imported*/) override { +if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc))) { + if (IsAngled) { ioeric wrote: > Might want to comment on how #include "old_header" is handled here? Currently the old_header is also copied to new file. Comment at: clang-move/ClangMove.cpp:103 @@ +102,3 @@ + const clang::SourceManager *SM) { + // Gets the ending ";". + auto EndLoc = clang::Lexer::getLocForEndOfToken(D->getLocEnd(), 0, *SM, ioeric wrote: > Consider the code below to also include trailing comment. > clang::SourceLocation after_semi = clang::Lexer::findLocationAfterToken( > D->getLocEnd, clang::tok::semi, *SM, > result.Context->getLangOpts(), > /*SkipTrailingWhitespaceAndNewLine=*/true); > But this code could not handle cases where the declaration definition has no semi at the end, such as "void f() {}" Comment at: clang-move/ClangMove.cpp:125 @@ +124,3 @@ + + // Add moved class definition and its related declarations. All declarations + // in same namespace are grouped together. ioeric wrote: > If two declarations in the same namespace are not consecutive in the vector > (i.e. there is a decl in a different ns between them), will they be put into > two canonical namespace blocks? Yes, only declarations which are consecutive in the vector and in the same namespace are put in one namespace block. Comment at: clang-move/ClangMove.cpp:129 @@ +128,3 @@ + for (const auto &MovedDecl : Decls) { +std::vector DeclNamespaces = GetNamespaces(MovedDecl.Decl); +auto CurrentIt = CurrentNamespaces.begin(); ioeric wrote: > Is it possible to restrict all `MovedDecl.Decl` to NamedDecl so that we can > use `getQualifiedNameAsString` instead of having a second implementation of > retrieving namespaces. > > Also how is anonymous namespace handled here? > > Yeah, `getQualifiedNameAsString` looks like a simpler way, but it doesn't suitable for our usage here. The `getQualifiedNameAsString` includes the name of the class. For instance, a class method decl like `void A::f() {}` defined in global namespace, it retruns `A::f` which is not intended. It handles anonymous namespace by wrapping like `namespace { ... } // namespace`, see the test. Comment at: clang-move/ClangMove.cpp:199 @@ +198,3 @@ + + // Match functions defined in anonymous namespace. + Finder->addMatcher( ioeric wrote: > What about static functions? Good catch, I missed it. Added. Comment at: clang-move/ClangMove.cpp:210 @@ +209,3 @@ + this); +} + ioeric wrote: > FIXME: support out-of-line member variable initializations etc? Or is it > already covered? Add support now. Comment at: clang-move/ClangMove.cpp:240 @@ +239,3 @@ +llvm::StringRef FileName) { + if (!Spec.OldHeader.empty() && FileName.endswith(Spec.OldHeader)) { +HeaderIncludes.push_back(IncludeLine.str()); ioeric wrote: > No braces. > > Also, I am worrying if `endswith` is a safe way to compare files. For > example, what if `FileName` is relative path? The `FileName` is from the `PPCallbacks::InclusionDirective` APIs. From my experience, it seems always to be an absolute file path either I pass a relative file path or a absolute path to clang-move, but this is no guarantee in the document. Using `endswith` is the most reliable way so far. Comment at: clang-move/ClangMove.h:39 @@ +38,3 @@ + struct MoveDefinitionSpec { +std::string Name; +std::string OldHeader; ioeric wrote: > Should the `Name` be fully qualified? It's not required. The name can be fully/partially qualified, e.g., `::a::b::X`, `a::b::X`, `b::X`, `X`, which has the same behavior with `hasName` ast matcher. It the given name is partially qualified, it will match all the class whose name ends with the given name. Comment at: clang-move/ClangMove.h:65 @@ +64,3 @@ + + const MoveDefinitionSpec &Spec; + // The Key is file path, value is the replacements being applied to the file. ioeric wrote: > Is there any reason why you made this a reference? To avoid the cost of making a copy of the structure. Comment at: clang-move/ClangMove.h:83 @@ +82,3 @@ +public: + explicit ClangMoveAction( + const ClangMoveTool::MoveDefinitionSpec &spec, Eugene.Zelenko wrote: > Is explicit necessary? The `explicit` keyword can prevent the copy-list-initialization like `ClangMoveAction a = {spec, file_to_replacement}`. I'm fine to remove it since it is trival. Comment at: clang-move/tool/Cl
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
ioeric added a comment. NIce! Some initial comments. Comment at: clang-move/ClangMove.cpp:38 @@ +37,3 @@ + const clang::Module * /*Imported*/) override { +if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc))) { + if (IsAngled) { Might want to comment on how #include "old_header" is handled here? Comment at: clang-move/ClangMove.cpp:39 @@ +38,3 @@ +if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc))) { + if (IsAngled) { +MoveTool->addIncludes("#include <" + FileName.str() + ">\n", Braces not needed. Comment at: clang-move/ClangMove.cpp:103 @@ +102,3 @@ + const clang::SourceManager *SM) { + // Gets the ending ";". + auto EndLoc = clang::Lexer::getLocForEndOfToken(D->getLocEnd(), 0, *SM, Consider the code below to also include trailing comment. clang::SourceLocation after_semi = clang::Lexer::findLocationAfterToken( D->getLocEnd, clang::tok::semi, *SM, result.Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); Comment at: clang-move/ClangMove.cpp:113 @@ +112,3 @@ +clang::tooling::Replacements +createInsertedReplacements(const std::vector &Includes, + const std::vector &Decls, Intuitively, it would be easier and more efficient if you construct the code as a string and then insert the code with one replacement. Comment at: clang-move/ClangMove.cpp:119 @@ +118,3 @@ + // Add #Includes. + // FIXME: Filter out the old_header.h. + for (const auto &Include : Includes) { FIXME: add header guard for new header file. Comment at: clang-move/ClangMove.cpp:125 @@ +124,3 @@ + + // Add moved class definition and its related declarations. All declarations + // in same namespace are grouped together. If two declarations in the same namespace are not consecutive in the vector (i.e. there is a decl in a different ns between them), will they be put into two canonical namespace blocks? Comment at: clang-move/ClangMove.cpp:129 @@ +128,3 @@ + for (const auto &MovedDecl : Decls) { +std::vector DeclNamespaces = GetNamespaces(MovedDecl.Decl); +auto CurrentIt = CurrentNamespaces.begin(); Is it possible to restrict all `MovedDecl.Decl` to NamedDecl so that we can use `getQualifiedNameAsString` instead of having a second implementation of retrieving namespaces. Also how is anonymous namespace handled here? Comment at: clang-move/ClangMove.cpp:157 @@ +156,3 @@ + +clang::tooling::Replacement InsertedReplacement( +FileName, 0, 0, getDeclarationSourceText(MovedDecl.Decl, MovedDecl.SM)); FIXME: also consider comments for the declaration. Comment at: clang-move/ClangMove.cpp:199 @@ +198,3 @@ + + // Match functions defined in anonymous namespace. + Finder->addMatcher( What about static functions? Comment at: clang-move/ClangMove.cpp:210 @@ +209,3 @@ + this); +} + FIXME: support out-of-line member variable initializations etc? Or is it already covered? Comment at: clang-move/ClangMove.cpp:240 @@ +239,3 @@ +llvm::StringRef FileName) { + if (!Spec.OldHeader.empty() && FileName.endswith(Spec.OldHeader)) { +HeaderIncludes.push_back(IncludeLine.str()); No braces. Also, I am worrying if `endswith` is a safe way to compare files. For example, what if `FileName` is relative path? Comment at: clang-move/ClangMove.cpp:254 @@ +253,3 @@ + MovedDecl.Decl->getLocEnd(), 0, *MovedDecl.SM, clang::LangOptions()); + clang::tooling::Replacement RemovedReplacement( + *MovedDecl.SM, clang::CharSourceRange::getTokenRange( nit: `RemovedReplacement` sounds like the replacement itself is being removed. `RemoveReplacement` would be better IMO. Comment at: clang-move/ClangMove.h:39 @@ +38,3 @@ + struct MoveDefinitionSpec { +std::string Name; +std::string OldHeader; Should the `Name` be fully qualified? Comment at: clang-move/ClangMove.h:52 @@ +51,3 @@ + + void registerMatchers(clang::ast_matchers::MatchFinder *match_finder); + Variable style. Here and some more below. Comment at: clang-move/ClangMove.h:59 @@ +58,3 @@ + + void addIncludes(llvm::StringRef include_line, llvm::StringRef file_name); + A comment for what this function does would be appreciated. Comment at: clang-move/ClangMove.h:65 @@ +64,3 @@ + + const MoveDefinitionSpec &Spec; + // The Key is file path, value is the replacements being applied to the file. --
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
Eugene.Zelenko added a comment. Probably old_source/new_source will be better, because different extensions are used for C++ files. https://reviews.llvm.org/D24243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
Eugene.Zelenko added inline comments. Comment at: clang-move/ClangMove.h:13 @@ +12,3 @@ + +#include +#include Isn't C++ headers should be after Clang headers? https://reviews.llvm.org/D24243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
Eugene.Zelenko added a subscriber: Eugene.Zelenko. Comment at: clang-move/ClangMove.h:33 @@ +32,3 @@ +clang::SourceManager *SM; +MovedDecl() : Decl(nullptr), SM(nullptr) {} +MovedDecl(const clang::Decl *Decl, clang::SourceManager *SM) Please add empty line before. Why don't use C++11 members initialization and = default? Comment at: clang-move/ClangMove.h:83 @@ +82,3 @@ +public: + explicit ClangMoveAction( + const ClangMoveTool::MoveDefinitionSpec &spec, Is explicit necessary? Comment at: clang-move/ClangMove.h:106 @@ +105,3 @@ + : Spec(Spec), FileToReplacements(FileToReplacements) {} + clang::FrontendAction *create() override { +return new ClangMoveAction(Spec, FileToReplacements); Please add empty line before. https://reviews.llvm.org/D24243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
omtcyfz added inline comments. Comment at: clang-move/ClangMove.h:25 @@ +24,3 @@ + +// TODO(hokein): Make it support more types, e.g. function definitions. +// Currently only support moving class definition. `FIXME`? https://reviews.llvm.org/D24243 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein updated this revision to Diff 70363. hokein added a comment. Fix function name style. https://reviews.llvm.org/D24243 Files: CMakeLists.txt clang-move/CMakeLists.txt clang-move/ClangMove.cpp clang-move/ClangMove.h clang-move/tool/CMakeLists.txt clang-move/tool/ClangMoveMain.cpp unittests/CMakeLists.txt unittests/clang-move/CMakeLists.txt unittests/clang-move/ClangMoveTests.cpp Index: unittests/clang-move/ClangMoveTests.cpp === --- /dev/null +++ unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,198 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "} // namespace\n" + "void Foo::f() { f1(); }\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "} // namespace\n" + "\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "} // namespace\n" + "void Foo::f() { f1(); }\n" + "} // namespace b\n" + "} // namespace a\n"; + +std::map +runClangMoveOnCode(const move::ClangMoveTool::MoveDefinitionSpec &Spec) { + clang::RewriterTestContext Con
Re: [PATCH] D24243: [clang-move] A prototype tool for moving class definition to new file.
hokein updated this revision to Diff 70362. hokein added a comment. Minor cleanup. https://reviews.llvm.org/D24243 Files: CMakeLists.txt clang-move/CMakeLists.txt clang-move/ClangMove.cpp clang-move/ClangMove.h clang-move/tool/CMakeLists.txt clang-move/tool/ClangMoveMain.cpp unittests/CMakeLists.txt unittests/clang-move/CMakeLists.txt unittests/clang-move/ClangMoveTests.cpp Index: unittests/clang-move/ClangMoveTests.cpp === --- /dev/null +++ unittests/clang-move/ClangMoveTests.cpp @@ -0,0 +1,198 @@ +//===-- ClangMoveTest.cpp - clang-move unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ClangMove.h" +#include "unittests/Tooling/RewriterTestContext.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace move { +namespace { + +const char TestHeaderName[] = "foo.h"; + +const char TestCCName[] = "foo.cc"; + +const char TestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + "};\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char TestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "} // namespace\n" + "void Foo::f() { f1(); }\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "\n" + "class Foo2 {\n" + "public:\n" + " int f();\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedTestCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "} // namespace\n" + "\n" + "int Foo2::f() {\n" + " f1();\n" + " return 1;\n" + "}\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewHeader[] = "namespace a {\n" + "class C1;\n" + "namespace b {\n" + "class Foo {\n" + "public:\n" + " void f();\n" + "\n" + "private:\n" + " C1 *c1;\n" + "};\n" + "} // namespace b\n" + "} // namespace a\n"; + +const char ExpectedNewCC[] = "#include \"foo.h\"\n" + "namespace a {\n" + "namespace b {\n" + "namespace {\n" + "void f1() {}\n" + "} // namespace\n" + "void Foo::f() { f1(); }\n" + "} // namespace b\n" + "} // namespace a\n"; + +std::map +runClangMoveOnCode(const move::ClangMoveTool::MoveDefinitionSpec &Spec) { + clang::RewriterTestContext Context; + +