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