RefactoringCallbacksTest.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //===- unittest/Tooling/RefactoringCallbacksTest.cpp ----------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "RewriterTestContext.h"
  9. #include "clang/ASTMatchers/ASTMatchFinder.h"
  10. #include "clang/ASTMatchers/ASTMatchers.h"
  11. #include "clang/Tooling/RefactoringCallbacks.h"
  12. #include "gtest/gtest.h"
  13. namespace clang {
  14. namespace tooling {
  15. using namespace ast_matchers;
  16. template <typename T>
  17. void expectRewritten(const std::string &Code, const std::string &Expected,
  18. const T &AMatcher, RefactoringCallback &Callback) {
  19. std::map<std::string, Replacements> FileToReplace;
  20. ASTMatchRefactorer Finder(FileToReplace);
  21. Finder.addMatcher(AMatcher, &Callback);
  22. std::unique_ptr<tooling::FrontendActionFactory> Factory(
  23. tooling::newFrontendActionFactory(&Finder));
  24. ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code))
  25. << "Parsing error in \"" << Code << "\"";
  26. RewriterTestContext Context;
  27. FileID ID = Context.createInMemoryFile("input.cc", Code);
  28. EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"],
  29. Context.Rewrite));
  30. EXPECT_EQ(Expected, Context.getRewrittenText(ID));
  31. }
  32. TEST(RefactoringCallbacksTest, ReplacesStmtsWithString) {
  33. std::string Code = "void f() { int i = 1; }";
  34. std::string Expected = "void f() { ; }";
  35. ReplaceStmtWithText Callback("id", ";");
  36. expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
  37. }
  38. TEST(RefactoringCallbacksTest, ReplacesStmtsInCalledMacros) {
  39. std::string Code = "#define A void f() { int i = 1; }\nA";
  40. std::string Expected = "#define A void f() { ; }\nA";
  41. ReplaceStmtWithText Callback("id", ";");
  42. expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
  43. }
  44. TEST(RefactoringCallbacksTest, IgnoresStmtsInUncalledMacros) {
  45. std::string Code = "#define A void f() { int i = 1; }";
  46. std::string Expected = "#define A void f() { int i = 1; }";
  47. ReplaceStmtWithText Callback("id", ";");
  48. expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
  49. }
  50. TEST(RefactoringCallbacksTest, ReplacesInteger) {
  51. std::string Code = "void f() { int i = 1; }";
  52. std::string Expected = "void f() { int i = 2; }";
  53. ReplaceStmtWithText Callback("id", "2");
  54. expectRewritten(Code, Expected, expr(integerLiteral()).bind("id"), Callback);
  55. }
  56. TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) {
  57. std::string Code = "void f() { int i = false ? 1 : i * 2; }";
  58. std::string Expected = "void f() { int i = i * 2; }";
  59. ReplaceStmtWithStmt Callback("always-false", "should-be");
  60. expectRewritten(
  61. Code, Expected,
  62. conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))),
  63. hasFalseExpression(expr().bind("should-be")))
  64. .bind("always-false"),
  65. Callback);
  66. }
  67. TEST(RefactoringCallbacksTest, ReplacesIfStmt) {
  68. std::string Code = "bool a; void f() { if (a) f(); else a = true; }";
  69. std::string Expected = "bool a; void f() { f(); }";
  70. ReplaceIfStmtWithItsBody Callback("id", true);
  71. expectRewritten(Code, Expected,
  72. ifStmt(hasCondition(implicitCastExpr(hasSourceExpression(
  73. declRefExpr(to(varDecl(hasName("a"))))))))
  74. .bind("id"),
  75. Callback);
  76. }
  77. TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) {
  78. std::string Code = "void f() { if (false) int i = 0; }";
  79. std::string Expected = "void f() { }";
  80. ReplaceIfStmtWithItsBody Callback("id", false);
  81. expectRewritten(
  82. Code, Expected,
  83. ifStmt(hasCondition(cxxBoolLiteral(equals(false)))).bind("id"), Callback);
  84. }
  85. TEST(RefactoringCallbacksTest, TemplateJustText) {
  86. std::string Code = "void f() { int i = 1; }";
  87. std::string Expected = "void f() { FOO }";
  88. auto Callback = ReplaceNodeWithTemplate::create("id", "FOO");
  89. EXPECT_FALSE(Callback.takeError());
  90. expectRewritten(Code, Expected, declStmt().bind("id"), **Callback);
  91. }
  92. TEST(RefactoringCallbacksTest, TemplateSimpleSubst) {
  93. std::string Code = "void f() { int i = 1; }";
  94. std::string Expected = "void f() { long x = 1; }";
  95. auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}");
  96. EXPECT_FALSE(Callback.takeError());
  97. expectRewritten(Code, Expected,
  98. varDecl(hasInitializer(expr().bind("init"))).bind("decl"),
  99. **Callback);
  100. }
  101. TEST(RefactoringCallbacksTest, TemplateLiteral) {
  102. std::string Code = "void f() { int i = 1; }";
  103. std::string Expected = "void f() { string x = \"$-1\"; }";
  104. auto Callback = ReplaceNodeWithTemplate::create("decl",
  105. "string x = \"$$-${init}\"");
  106. EXPECT_FALSE(Callback.takeError());
  107. expectRewritten(Code, Expected,
  108. varDecl(hasInitializer(expr().bind("init"))).bind("decl"),
  109. **Callback);
  110. }
  111. static void ExpectStringError(const std::string &Expected,
  112. llvm::Error E) {
  113. std::string Found;
  114. handleAllErrors(std::move(E), [&](const llvm::StringError &SE) {
  115. llvm::raw_string_ostream Stream(Found);
  116. SE.log(Stream);
  117. });
  118. EXPECT_EQ(Expected, Found);
  119. }
  120. TEST(RefactoringCallbacksTest, TemplateUnterminated) {
  121. auto Callback = ReplaceNodeWithTemplate::create("decl",
  122. "string x = \"$$-${init\"");
  123. ExpectStringError("Unterminated ${...} in replacement template near ${init\"",
  124. Callback.takeError());
  125. }
  126. TEST(RefactoringCallbacksTest, TemplateUnknownDollar) {
  127. auto Callback = ReplaceNodeWithTemplate::create("decl",
  128. "string x = \"$<");
  129. ExpectStringError("Invalid $ in replacement template near $<",
  130. Callback.takeError());
  131. }
  132. } // end namespace ast_matchers
  133. } // end namespace clang