[PATCH] D26015: Correctly classify main file includes if there is a prefix added
jbangert updated this revision to Diff 84001. jbangert updated the summary for this revision. jbangert added a comment. - Add header to unit test fixture. https://reviews.llvm.org/D26015 Files: clang-tidy/utils/IncludeSorter.cpp unittests/clang-tidy/IncludeInserterTest.cpp Index: unittests/clang-tidy/IncludeInserterTest.cpp === --- unittests/clang-tidy/IncludeInserterTest.cpp +++ unittests/clang-tidy/IncludeInserterTest.cpp @@ -73,6 +73,17 @@ bool IsAngledInclude() const override { return false; } }; +class EarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase { +public: + EarlyInAlphabetHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context) + : IncludeInserterCheckBase(CheckName, Context) {} + + std::vector HeadersToInclude() const override { +return {"a/header.h"}; + } + bool IsAngledInclude() const override { return false; } +}; + class MultipleHeaderInserterCheck : public IncludeInserterCheckBase { public: MultipleHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context) @@ -114,6 +125,7 @@ "insert_includes_test_header.h", "\n"}, // Non system headers + {"a/header.h", "\n"}, {"path/to/a/header.h", "\n"}, {"path/to/z/header.h", "\n"}, {"path/to/header.h", "\n"}, @@ -522,6 +534,77 @@ "insert_includes_test_header.cc")); } +TEST(IncludeInserterTest, DontInsertDuplicateIncludeEvenIfMiscategorized) { + const char *PreCode = R"( +#include "clang_tidy/tests/insert_includes_test_header.h" + +#include +#include +#include + +#include "a/header.h" +#include "path/to/a/header.h" +#include "path/to/header.h" + +void foo() { + int a = 0; +})"; + + const char *PostCode = R"( +#include "clang_tidy/tests/insert_includes_test_header.h" + +#include +#include +#include + +#include "a/header.h" +#include "path/to/a/header.h" +#include "path/to/header.h" + +void foo() { + int a = 0; +})"; + + EXPECT_EQ(PostCode, runCheckOnCode( + PreCode, "workspace_folder/clang_tidy/tests/" + "insert_includes_test_header.cc")); +} + +TEST(IncludeInserterTest, HandleOrderInSubdirectory) { + const char *PreCode = R"( +#include "clang_tidy/tests/insert_includes_test_header.h" + +#include +#include +#include + +#include "path/to/a/header.h" +#include "path/to/header.h" + +void foo() { + int a = 0; +})"; + + const char *PostCode = R"( +#include "clang_tidy/tests/insert_includes_test_header.h" + +#include +#include +#include + +#include "a/header.h" +#include "path/to/a/header.h" +#include "path/to/header.h" + +void foo() { + int a = 0; +})"; + + EXPECT_EQ(PostCode, runCheckOnCode( + PreCode, "workspace_folder/clang_tidy/tests/" + "insert_includes_test_header.cc")); +} + } // anonymous namespace } // namespace tidy } // namespace clang Index: clang-tidy/utils/IncludeSorter.cpp === --- clang-tidy/utils/IncludeSorter.cpp +++ clang-tidy/utils/IncludeSorter.cpp @@ -61,7 +61,8 @@ : IncludeSorter::IK_CXXSystemInclude; } StringRef CanonicalInclude = MakeCanonicalName(IncludeFile, Style); - if (CanonicalFile.equals(CanonicalInclude)) { + if (CanonicalFile.endswith(CanonicalInclude) + || CanonicalInclude.endswith(CanonicalFile)) { return IncludeSorter::IK_MainTUInclude; } if (Style == IncludeSorter::IS_Google) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 94282. jbangert added a comment. - Merge branch 'master' of http://llvm.org/git/clang into replace_template https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,40 +60,94 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); } +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + auto Callback = ReplaceNodeWithTemplate::create("id", "FOO"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, id("id", declStmt()), **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expect
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert accepted this revision. jbangert marked 2 inline comments as done. jbangert added inline comments. Comment at: unittests/Tooling/RefactoringCallbacksTest.cpp:101 + std::string Expected = "void f() { FOO }"; + ReplaceNodeWithTemplate Callback("id", "FOO"); + expectRewritten(Code, Expected, id("id", declStmt()), Callback); ioeric wrote: > Have you rerun the tests? Does this still build? ninja check-clang-tools works. https://reviews.llvm.org/D29621 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29622: Add a batch query and replace tool based on AST matchers.
jbangert updated this revision to Diff 94297. jbangert added a comment. Fix command line tool. https://reviews.llvm.org/D29622 Files: clang-query/CMakeLists.txt clang-query/QueryReplace.cpp clang-query/QueryReplace.h clang-query/replace-tool/CMakeLists.txt clang-query/replace-tool/ClangQueryReplace.cpp test/CMakeLists.txt test/clang-query/replacement.c Index: test/clang-query/replacement.c === --- /dev/null +++ test/clang-query/replacement.c @@ -0,0 +1,5 @@ +// RUN: cp %s %t.c +// RUN: clang-query-replace --spec '{Query: "varDecl(hasName(\"version\"), hasInitializer(integerLiteral().bind(\"init\"))).bind(\"decl\")", FromId: "decl", ToTemplate: "string version = \"$$-${init}\""}' %t.c -- +// RUN: FileCheck --match-full-lines %s < %t.c +int version = 4; +// CHECK: string version = "$-4"; Index: test/CMakeLists.txt === --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -44,6 +44,7 @@ clang-include-fixer clang-move clang-query + clang-query-replace clang-rename clang-reorder-fields clang-tidy Index: clang-query/replace-tool/ClangQueryReplace.cpp === --- /dev/null +++ clang-query/replace-tool/ClangQueryReplace.cpp @@ -0,0 +1,85 @@ +//=== ClangQueryReplace.cpp - clang-query-replace tool ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// +// +// This tool automatically modifies source files based on AST matchers. +// +// A given AST matcher is applied to the source, and a bound node in +// this matcher is replaced by the result of substituting the text +// corresponding to other bound nodes into a string template. +// +// For example: +// clang-query-replace --spec < +#include +#include + +using namespace clang; +using namespace clang::query; +using namespace llvm; + +using std::error_code; +using clang::tooling::CommonOptionsParser; + +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); +static cl::OptionCategory ClangQueryCategory("clang-query-replace options"); + +static cl::list Commands("spec", + cl::desc("YAML action specification"), + cl::value_desc("spec"), + cl::cat(ClangQueryCategory)); + +int main(int argc, const char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + + CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory); + if (Commands.empty()) { +llvm::errs() << "Must specify at least one --spec \n"; +return 1; + } + + tooling::RefactoringTool Refactor(OptionsParser.getCompilations(), +OptionsParser.getSourcePathList()); + + QueryReplaceTool Tool(Refactor.getReplacements()); + for (auto &SpecYaml : Commands) { + +llvm::Expected Spec = +QueryReplaceSpec::parseFromYAML(SpecYaml); +if (llvm::Error Error = Spec.takeError()) + llvm::report_fatal_error(std::move(Error), false); +if (llvm::Error Error = Tool.addOperation(*Spec)) + llvm::report_fatal_error(std::move(Error), false); + } + + return Refactor.runAndSave(tooling::newFrontendActionFactory(&Tool).get()); +} Index: clang-query/replace-tool/CMakeLists.txt === --- /dev/null +++ clang-query/replace-tool/CMakeLists.txt @@ -0,0 +1,14 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_clang_executable(clang-query-replace ClangQueryReplace.cpp) +target_link_libraries(clang-query-replace + clangAST + clangASTMatchers + clangBasic + clangDynamicASTMatchers + clangFrontend + clangQuery + clangTooling + ) + +install(TARGETS clang-query-replace RUNTIME DESTINATION bin) \ No newline at end of file Index: clang-query/QueryReplace.h === --- /dev/null +++ clang-query/QueryReplace.h @@ -0,0 +1,58 @@ +//===--- QueryReplace.h - clang-query-replace --*- C++-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERYREPLACE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERYREPLACE_H + +#include "clang/AST/ASTConsumer.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/Dynamic/Parser.h" +#include "clang/Tooling/RefactoringCallbacks.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include +#include +#i
[PATCH] D29622: Add a batch query and replace tool based on AST matchers.
jbangert created this revision. Herald added a subscriber: mgorny. This requires https://reviews.llvm.org/D29613. It adds a new tool, clang-query-replace that replaces and AST node with the result of evaluating a simple template language. https://reviews.llvm.org/D29622 Files: clang-query/CMakeLists.txt clang-query/QueryReplace.cpp clang-query/QueryReplace.h clang-query/replace-tool/CMakeLists.txt clang-query/replace-tool/ClangQueryReplace.cpp test/CMakeLists.txt test/clang-query/replacement.c Index: test/clang-query/replacement.c === --- /dev/null +++ test/clang-query/replacement.c @@ -0,0 +1,6 @@ +// RUN: clang-query-replace --spec '{Query: "varDecl(hasName(\"version\"), +// hasInitializer(integerLiteral().bind(\"init\"))).bind(\"decl\")", FromId: +// "decl", ToTemplate: "string version = \"$$-${init}\""}' %s -- && FileCheck %s +// < %; +int version = 4; +// CHECK: string version = "$-4"; Index: test/CMakeLists.txt === --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -46,6 +46,7 @@ clang-include-fixer clang-move clang-query + clang-query-replace clang-rename clang-reorder-fields clang-tidy @@ -56,11 +57,9 @@ # Unit tests ExtraToolsUnitTests ) - add_lit_testsuite(check-clang-tools "Running the Clang extra tools' regression tests" ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${CLANG_TOOLS_TEST_DEPS} ARGS ${CLANG_TOOLS_TEST_EXTRA_ARGS} ) set_target_properties(check-clang-tools PROPERTIES FOLDER "Clang extra tools' tests") - Index: clang-query/replace-tool/ClangQueryReplace.cpp === --- /dev/null +++ clang-query/replace-tool/ClangQueryReplace.cpp @@ -0,0 +1,86 @@ +//=== ClangQueryReplace.cpp - clang-query-replace tool ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// +// +// This tool automatically modifies source files based on AST matchers. +// +// A given AST matcher is applied to the source, and a bound node in +// this matcher is replaced by the result of substituting the text +// corresponding to other bound nodes into a string template. +// +// For example: +// clang-query-replace --spec < +#include +#include + +using namespace clang; +using namespace clang::query; +using namespace llvm; + +using std::error_code; +using clang::tooling::CommonOptionsParser; + +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); +static cl::OptionCategory ClangQueryCategory("clang-query-replace options"); + +static cl::list Commands("spec", + cl::desc("YAML action specification"), + cl::value_desc("spec"), + cl::cat(ClangQueryCategory)); + +int main(int argc, const char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + + CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory); + if (Commands.empty()) { +llvm::errs() << "Must specify at least one --spec \n"; +return 1; + } + + tooling::RefactoringTool Refactor(OptionsParser.getCompilations(), +OptionsParser.getSourcePathList()); + + QueryReplaceTool Tool(Refactor.getReplacements()); + for (auto &SpecYaml : Commands) { +llvm::ErrorOr Spec = +QueryReplaceSpec::parseFromJSON(SpecYaml); +if (error_code EC = Spec.getError()) { + llvm::errs() << " Error " << EC.message() + << " while parsing spec: " << SpecYaml << "\n"; + return 1; +} +Tool.addOperation(*Spec); + } + + return Refactor.runAndSave(tooling::newFrontendActionFactory(&Tool).get()); +} Index: clang-query/replace-tool/CMakeLists.txt === --- /dev/null +++ clang-query/replace-tool/CMakeLists.txt @@ -0,0 +1,14 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_clang_executable(clang-query-replace ClangQueryReplace.cpp) +target_link_libraries(clang-query-replace + clangAST + clangASTMatchers + clangBasic + clangDynamicASTMatchers + clangFrontend + clangQuery + clangTooling + ) + +install(TARGETS clang-query-replace RUNTIME DESTINATION bin) \ No newline at end of file Index: clang-query/QueryReplace.h === --- /dev/null +++ clang-query/QueryReplace.h @@ -0,0 +1,58 @@ +//===--- ReplaceSpec.h - clang-query-replace *- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert created this revision. This is the first change as part of developing a clang-query based search and replace tool. https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,40 +60,65 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + ReplaceNodeWithTemplate Callback("id", "FOO"); + expectRewritten(Code, Expected, id("id", declStmt()), Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + ReplaceNodeWithTemplate Callback("decl", "long x = ${init}"); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { string x = \"$-1\"; }"; + ReplaceNodeWithTemplate Callback("decl", "string x = \"$$-${init}\""); + expectRewritten(
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 87574. jbangert added a comment. Address code feedback & Reformat with clang-format --style llvm. https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,39 +60,64 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + ReplaceNodeWithTemplate Callback("id", "FOO"); + expectRewritten(Code, Expected, id("id", declStmt()), Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + ReplaceNodeWithTemplate Callback("decl", "long x = ${init}"); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { string x = \"$-1\"; }"; + ReplaceNodeWithTemplate Callback("decl", "string x = \"$$-${init}\""); + expe
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 87575. jbangert added a comment. - change to push_back https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,39 +60,64 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + ReplaceNodeWithTemplate Callback("id", "FOO"); + expectRewritten(Code, Expected, id("id", declStmt()), Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + ReplaceNodeWithTemplate Callback("decl", "long x = ${init}"); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { string x = \"$-1\"; }"; + ReplaceNodeWithTemplate Callback("decl", "string x = \"$$-${init}\""); + expectRewritten(Code, Expected, +
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert marked 2 inline comments as done. jbangert added a comment. (marking other comments as done). https://reviews.llvm.org/D29621 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert marked 5 inline comments as done. jbangert added a comment. Thank you for the initial feedback! Comment at: include/clang/Tooling/RefactoringCallbacks.h:61 +MatchFinder.addMatcher(Matcher, Callback); +Callbacks.emplace_back(Callback); + } sbenza wrote: > Why emplace_back instead of push_back? Changed to push_back. Is there ever an advantage to using push_back over emplace_back (the latter falls back to a copy constructor). https://reviews.llvm.org/D29621 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 87579. jbangert added a comment. - use iter https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,39 +60,64 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + ReplaceNodeWithTemplate Callback("id", "FOO"); + expectRewritten(Code, Expected, id("id", declStmt()), Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + ReplaceNodeWithTemplate Callback("decl", "long x = ${init}"); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { string x = \"$-1\"; }"; + ReplaceNodeWithTemplate Callback("decl", "string x = \"$$-${init}\""); + expectRewritten(Code, Expected, + id("dec
[PATCH] D29622: Add a batch query and replace tool based on AST matchers.
jbangert updated this revision to Diff 87580. jbangert marked 7 inline comments as done. jbangert added a comment. Response to initial code review. https://reviews.llvm.org/D29622 Files: clang-query/CMakeLists.txt clang-query/QueryReplace.cpp clang-query/QueryReplace.h clang-query/replace-tool/CMakeLists.txt clang-query/replace-tool/ClangQueryReplace.cpp test/CMakeLists.txt test/clang-query/replacement.c Index: test/clang-query/replacement.c === --- /dev/null +++ test/clang-query/replacement.c @@ -0,0 +1,3 @@ +// RUN: clang-query-replace --spec '{Query: "varDecl(hasName(\"version\"), hasInitializer(integerLiteral().bind(\"init\"))).bind(\"decl\")", FromId: "decl", ToTemplate: "string version = \"$$-${init}\""}' %s -- && FileCheck %s < %s +int version = 4; +// CHECK: string version = "$-4"; Index: test/CMakeLists.txt === --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -47,6 +47,7 @@ clang-include-fixer clang-move clang-query + clang-query-replace clang-rename clang-reorder-fields clang-tidy @@ -57,11 +58,9 @@ # Unit tests ExtraToolsUnitTests ) - add_lit_testsuite(check-clang-tools "Running the Clang extra tools' regression tests" ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${CLANG_TOOLS_TEST_DEPS} ARGS ${CLANG_TOOLS_TEST_EXTRA_ARGS} ) set_target_properties(check-clang-tools PROPERTIES FOLDER "Clang extra tools' tests") - Index: clang-query/replace-tool/ClangQueryReplace.cpp === --- /dev/null +++ clang-query/replace-tool/ClangQueryReplace.cpp @@ -0,0 +1,85 @@ +//=== ClangQueryReplace.cpp - clang-query-replace tool ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// +// +// This tool automatically modifies source files based on AST matchers. +// +// A given AST matcher is applied to the source, and a bound node in +// this matcher is replaced by the result of substituting the text +// corresponding to other bound nodes into a string template. +// +// For example: +// clang-query-replace --spec < +#include +#include + +using namespace clang; +using namespace clang::query; +using namespace llvm; + +using std::error_code; +using clang::tooling::CommonOptionsParser; + +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); +static cl::OptionCategory ClangQueryCategory("clang-query-replace options"); + +static cl::list Commands("spec", + cl::desc("YAML action specification"), + cl::value_desc("spec"), + cl::cat(ClangQueryCategory)); + +int main(int argc, const char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + + CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory); + if (Commands.empty()) { +llvm::errs() << "Must specify at least one --spec \n"; +return 1; + } + + tooling::RefactoringTool Refactor(OptionsParser.getCompilations(), +OptionsParser.getSourcePathList()); + + QueryReplaceTool Tool(Refactor.getReplacements()); + for (auto &SpecYaml : Commands) { + +llvm::Expected Spec = +QueryReplaceSpec::parseFromYAML(SpecYaml); +if (llvm::Error Error = Spec.takeError()) + llvm::report_fatal_error(std::move(Error), false); +if (llvm::Error Error = Tool.addOperation(*Spec)) + llvm::report_fatal_error(std::move(Error), false); + } + + return Refactor.runAndSave(tooling::newFrontendActionFactory(&Tool).get()); +} Index: clang-query/replace-tool/CMakeLists.txt === --- /dev/null +++ clang-query/replace-tool/CMakeLists.txt @@ -0,0 +1,14 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_clang_executable(clang-query-replace ClangQueryReplace.cpp) +target_link_libraries(clang-query-replace + clangAST + clangASTMatchers + clangBasic + clangDynamicASTMatchers + clangFrontend + clangQuery + clangTooling + ) + +install(TARGETS clang-query-replace RUNTIME DESTINATION bin) \ No newline at end of file Index: clang-query/QueryReplace.h === --- /dev/null +++ clang-query/QueryReplace.h @@ -0,0 +1,58 @@ +//===--- QueryReplace.h - clang-query-replace --*- C++-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA
[PATCH] D29622: Add a batch query and replace tool based on AST matchers.
jbangert added a comment. Thank you for the feedback, addressed and reformatted using llvm style. Comment at: clang-query/QueryReplace.h:35-36 + + /// \brief Replacement text. %"identifier" will be substituted by the text of + /// an identifier. + std::string ToTemplate; sbenza wrote: > klimek wrote: > > This doesn't seem to come up in the test? (and I don't understand what it's > > trying to tell me :) > In the other change the identifier was specified with ${identifier}, not > %"identifier". > They should be consistent, no? I edited the comment for consistency. This indeed has an older syntax. https://reviews.llvm.org/D29622 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert marked 2 inline comments as done. jbangert added a comment. Fixed the test -- I am still getting used to the different ninja test targets. Comment at: lib/Tooling/RefactoringCallbacks.cpp:160 +llvm::Expected> +ReplaceNodeWithTemplate::create(StringRef FromId, StringRef ToTemplate) { + std::vector ParsedTemplate; ioeric wrote: > Is this covered in the test? Now it is. https://reviews.llvm.org/D29621 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 87879. jbangert added a comment. - fix test https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,39 +60,68 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); +} + +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + auto Callback = ReplaceNodeWithTemplate::create("id", "FOO"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, id("id", declStmt()), **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { string x = \"$-1\"; }"; + auto Callback = Repl
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 89420. jbangert marked an inline comment as done. jbangert added a comment. - additional tests https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,40 +60,94 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); } +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + auto Callback = ReplaceNodeWithTemplate::create("id", "FOO"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, id("id", declStmt()), **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f(
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert accepted this revision. jbangert added a comment. Thanks, added tests for parser failures. https://reviews.llvm.org/D29621 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 89730. jbangert marked an inline comment as done. jbangert added a comment. use llvm::report_fatal_error instead of unreachable. https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,40 +60,94 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); } +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + auto Callback = ReplaceNodeWithTemplate::create("id", "FOO"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, id("id", declStmt()), **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }";
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert added inline comments. Comment at: lib/Tooling/RefactoringCallbacks.cpp:213 +llvm::errs() << "Node " << Element.Value + << " used in replacement template not bound in Matcher \n"; +llvm_unreachable("Unbound node in replacement template."); sbenza wrote: > I don't know if stderr is the best place for this error output. > Maybe we should take a sink of some sort in the constructor. There's a FIXME: above that addresses the need for better error handling, and this one just duplicated their workaround. Ultimately, clang::tooling:: should probably provide infrastructure for reporting problems (I would imagine all refactoring tools have errors occassionally, and they need some way of reporting/handling them). Comment at: lib/Tooling/RefactoringCallbacks.cpp:214 + << " used in replacement template not bound in Matcher \n"; +llvm_unreachable("Unbound node in replacement template."); + } sbenza wrote: > I don't think this is ok. > afaik, llvm_unreachable leads to undefined behavior if it is reached in opt > mode. > This error can be triggered from user input. We should not fail that way. Using llvm::report_fatal_error for now. See the above for better error handling. https://reviews.llvm.org/D29621 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D29621: Add ASTMatchRefactorer and ReplaceNodeWithTemplate to RefactoringCallbacks
jbangert updated this revision to Diff 98203. jbangert added a comment. Ran check-clang https://reviews.llvm.org/D29621 Files: include/clang/Tooling/RefactoringCallbacks.h lib/Tooling/RefactoringCallbacks.cpp unittests/Tooling/RefactoringCallbacksTest.cpp Index: unittests/Tooling/RefactoringCallbacksTest.cpp === --- unittests/Tooling/RefactoringCallbacksTest.cpp +++ unittests/Tooling/RefactoringCallbacksTest.cpp @@ -7,31 +7,30 @@ // //===--===// -#include "clang/Tooling/RefactoringCallbacks.h" #include "RewriterTestContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/RefactoringCallbacks.h" #include "gtest/gtest.h" namespace clang { namespace tooling { using namespace ast_matchers; template -void expectRewritten(const std::string &Code, - const std::string &Expected, - const T &AMatcher, - RefactoringCallback &Callback) { - MatchFinder Finder; +void expectRewritten(const std::string &Code, const std::string &Expected, + const T &AMatcher, RefactoringCallback &Callback) { + std::map FileToReplace; + ASTMatchRefactorer Finder(FileToReplace); Finder.addMatcher(AMatcher, &Callback); std::unique_ptr Factory( tooling::newFrontendActionFactory(&Finder)); ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code)) << "Parsing error in \"" << Code << "\""; RewriterTestContext Context; FileID ID = Context.createInMemoryFile("input.cc", Code); - EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(), + EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"], Context.Rewrite)); EXPECT_EQ(Expected, Context.getRewrittenText(ID)); } @@ -61,40 +60,94 @@ std::string Code = "void f() { int i = 1; }"; std::string Expected = "void f() { int i = 2; }"; ReplaceStmtWithText Callback("id", "2"); - expectRewritten(Code, Expected, id("id", expr(integerLiteral())), - Callback); + expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback); } TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { std::string Code = "void f() { int i = false ? 1 : i * 2; }"; std::string Expected = "void f() { int i = i * 2; }"; ReplaceStmtWithStmt Callback("always-false", "should-be"); - expectRewritten(Code, Expected, - id("always-false", conditionalOperator( - hasCondition(cxxBoolLiteral(equals(false))), - hasFalseExpression(id("should-be", expr(), + expectRewritten( + Code, Expected, + id("always-false", + conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))), + hasFalseExpression(id("should-be", expr(), Callback); } TEST(RefactoringCallbacksTest, ReplacesIfStmt) { std::string Code = "bool a; void f() { if (a) f(); else a = true; }"; std::string Expected = "bool a; void f() { f(); }"; ReplaceIfStmtWithItsBody Callback("id", true); - expectRewritten(Code, Expected, - id("id", ifStmt( - hasCondition(implicitCastExpr(hasSourceExpression( - declRefExpr(to(varDecl(hasName("a"), + expectRewritten( + Code, Expected, + id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression( + declRefExpr(to(varDecl(hasName("a"), Callback); } TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Code = "void f() { if (false) int i = 0; }"; std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), - Callback); + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false), + Callback); } +TEST(RefactoringCallbacksTest, TemplateJustText) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { FOO }"; + auto Callback = ReplaceNodeWithTemplate::create("id", "FOO"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, id("id", declStmt()), **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateSimpleSubst) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { long x = 1; }"; + auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}"); + EXPECT_FALSE(Callback.takeError()); + expectRewritten(Code, Expected, + id("decl", varDecl(hasInitializer(id("init", expr(), + **Callback); +} + +TEST(RefactoringCallbacksTest, TemplateLiteral) { + std::string Code = "void f() { int i = 1; }"; + std::string Expected = "void f() { string x = \"$-1\"; }"; + auto Callback =