1320d9666SChandler Carruth //===- unittest/Tooling/RefactoringCallbacksTest.cpp ----------------------===//
21975e034SDaniel Jasper //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61975e034SDaniel Jasper //
71975e034SDaniel Jasper //===----------------------------------------------------------------------===//
81975e034SDaniel Jasper
91975e034SDaniel Jasper #include "RewriterTestContext.h"
10320d9666SChandler Carruth #include "clang/ASTMatchers/ASTMatchFinder.h"
11fa0b3bb7SChandler Carruth #include "clang/ASTMatchers/ASTMatchers.h"
12fc9213e0SEric Liu #include "clang/Tooling/RefactoringCallbacks.h"
13949cc509SDouglas Gregor #include "gtest/gtest.h"
141975e034SDaniel Jasper
151975e034SDaniel Jasper namespace clang {
166389dd14SDaniel Jasper namespace tooling {
176389dd14SDaniel Jasper
186389dd14SDaniel Jasper using namespace ast_matchers;
191975e034SDaniel Jasper
201975e034SDaniel Jasper template <typename T>
expectRewritten(const std::string & Code,const std::string & Expected,const T & AMatcher,RefactoringCallback & Callback)21fc9213e0SEric Liu void expectRewritten(const std::string &Code, const std::string &Expected,
22fc9213e0SEric Liu const T &AMatcher, RefactoringCallback &Callback) {
23fc9213e0SEric Liu std::map<std::string, Replacements> FileToReplace;
24fc9213e0SEric Liu ASTMatchRefactorer Finder(FileToReplace);
25*027899daSAlexander Kornienko Finder.addMatcher(traverse(TK_AsIs, AMatcher), &Callback);
26b8984329SAhmed Charles std::unique_ptr<tooling::FrontendActionFactory> Factory(
271975e034SDaniel Jasper tooling::newFrontendActionFactory(&Finder));
281975e034SDaniel Jasper ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code))
291975e034SDaniel Jasper << "Parsing error in \"" << Code << "\"";
301975e034SDaniel Jasper RewriterTestContext Context;
311975e034SDaniel Jasper FileID ID = Context.createInMemoryFile("input.cc", Code);
32fc9213e0SEric Liu EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"],
331975e034SDaniel Jasper Context.Rewrite));
341975e034SDaniel Jasper EXPECT_EQ(Expected, Context.getRewrittenText(ID));
351975e034SDaniel Jasper }
361975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,ReplacesStmtsWithString)371975e034SDaniel Jasper TEST(RefactoringCallbacksTest, ReplacesStmtsWithString) {
381975e034SDaniel Jasper std::string Code = "void f() { int i = 1; }";
391975e034SDaniel Jasper std::string Expected = "void f() { ; }";
401975e034SDaniel Jasper ReplaceStmtWithText Callback("id", ";");
41dee011b7SDmitri Gribenko expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
421975e034SDaniel Jasper }
431975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,ReplacesStmtsInCalledMacros)441975e034SDaniel Jasper TEST(RefactoringCallbacksTest, ReplacesStmtsInCalledMacros) {
451975e034SDaniel Jasper std::string Code = "#define A void f() { int i = 1; }\nA";
461975e034SDaniel Jasper std::string Expected = "#define A void f() { ; }\nA";
471975e034SDaniel Jasper ReplaceStmtWithText Callback("id", ";");
48dee011b7SDmitri Gribenko expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
491975e034SDaniel Jasper }
501975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,IgnoresStmtsInUncalledMacros)511975e034SDaniel Jasper TEST(RefactoringCallbacksTest, IgnoresStmtsInUncalledMacros) {
521975e034SDaniel Jasper std::string Code = "#define A void f() { int i = 1; }";
531975e034SDaniel Jasper std::string Expected = "#define A void f() { int i = 1; }";
541975e034SDaniel Jasper ReplaceStmtWithText Callback("id", ";");
55dee011b7SDmitri Gribenko expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
561975e034SDaniel Jasper }
571975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,ReplacesInteger)581975e034SDaniel Jasper TEST(RefactoringCallbacksTest, ReplacesInteger) {
591975e034SDaniel Jasper std::string Code = "void f() { int i = 1; }";
601975e034SDaniel Jasper std::string Expected = "void f() { int i = 2; }";
611975e034SDaniel Jasper ReplaceStmtWithText Callback("id", "2");
62dee011b7SDmitri Gribenko expectRewritten(Code, Expected, expr(integerLiteral()).bind("id"), Callback);
631975e034SDaniel Jasper }
641975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,ReplacesStmtWithStmt)651975e034SDaniel Jasper TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) {
661975e034SDaniel Jasper std::string Code = "void f() { int i = false ? 1 : i * 2; }";
671975e034SDaniel Jasper std::string Expected = "void f() { int i = i * 2; }";
681975e034SDaniel Jasper ReplaceStmtWithStmt Callback("always-false", "should-be");
69fc9213e0SEric Liu expectRewritten(
70fc9213e0SEric Liu Code, Expected,
71fc9213e0SEric Liu conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))),
72dee011b7SDmitri Gribenko hasFalseExpression(expr().bind("should-be")))
73dee011b7SDmitri Gribenko .bind("always-false"),
741975e034SDaniel Jasper Callback);
751975e034SDaniel Jasper }
761975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,ReplacesIfStmt)771975e034SDaniel Jasper TEST(RefactoringCallbacksTest, ReplacesIfStmt) {
781975e034SDaniel Jasper std::string Code = "bool a; void f() { if (a) f(); else a = true; }";
791975e034SDaniel Jasper std::string Expected = "bool a; void f() { f(); }";
801975e034SDaniel Jasper ReplaceIfStmtWithItsBody Callback("id", true);
81dee011b7SDmitri Gribenko expectRewritten(Code, Expected,
82dee011b7SDmitri Gribenko ifStmt(hasCondition(implicitCastExpr(hasSourceExpression(
83dee011b7SDmitri Gribenko declRefExpr(to(varDecl(hasName("a"))))))))
84dee011b7SDmitri Gribenko .bind("id"),
851975e034SDaniel Jasper Callback);
861975e034SDaniel Jasper }
871975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,RemovesEntireIfOnEmptyElse)881975e034SDaniel Jasper TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) {
891975e034SDaniel Jasper std::string Code = "void f() { if (false) int i = 0; }";
901975e034SDaniel Jasper std::string Expected = "void f() { }";
911975e034SDaniel Jasper ReplaceIfStmtWithItsBody Callback("id", false);
92dee011b7SDmitri Gribenko expectRewritten(
93dee011b7SDmitri Gribenko Code, Expected,
94dee011b7SDmitri Gribenko ifStmt(hasCondition(cxxBoolLiteral(equals(false)))).bind("id"), Callback);
951975e034SDaniel Jasper }
961975e034SDaniel Jasper
TEST(RefactoringCallbacksTest,TemplateJustText)97fc9213e0SEric Liu TEST(RefactoringCallbacksTest, TemplateJustText) {
98fc9213e0SEric Liu std::string Code = "void f() { int i = 1; }";
99fc9213e0SEric Liu std::string Expected = "void f() { FOO }";
100fc9213e0SEric Liu auto Callback = ReplaceNodeWithTemplate::create("id", "FOO");
101fc9213e0SEric Liu EXPECT_FALSE(Callback.takeError());
102dee011b7SDmitri Gribenko expectRewritten(Code, Expected, declStmt().bind("id"), **Callback);
103fc9213e0SEric Liu }
104fc9213e0SEric Liu
TEST(RefactoringCallbacksTest,TemplateSimpleSubst)105fc9213e0SEric Liu TEST(RefactoringCallbacksTest, TemplateSimpleSubst) {
106fc9213e0SEric Liu std::string Code = "void f() { int i = 1; }";
107fc9213e0SEric Liu std::string Expected = "void f() { long x = 1; }";
108fc9213e0SEric Liu auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}");
109fc9213e0SEric Liu EXPECT_FALSE(Callback.takeError());
110fc9213e0SEric Liu expectRewritten(Code, Expected,
111dee011b7SDmitri Gribenko varDecl(hasInitializer(expr().bind("init"))).bind("decl"),
112fc9213e0SEric Liu **Callback);
113fc9213e0SEric Liu }
114fc9213e0SEric Liu
TEST(RefactoringCallbacksTest,TemplateLiteral)115fc9213e0SEric Liu TEST(RefactoringCallbacksTest, TemplateLiteral) {
116fc9213e0SEric Liu std::string Code = "void f() { int i = 1; }";
117fc9213e0SEric Liu std::string Expected = "void f() { string x = \"$-1\"; }";
118fc9213e0SEric Liu auto Callback = ReplaceNodeWithTemplate::create("decl",
119fc9213e0SEric Liu "string x = \"$$-${init}\"");
120fc9213e0SEric Liu EXPECT_FALSE(Callback.takeError());
121fc9213e0SEric Liu expectRewritten(Code, Expected,
122dee011b7SDmitri Gribenko varDecl(hasInitializer(expr().bind("init"))).bind("decl"),
123fc9213e0SEric Liu **Callback);
124fc9213e0SEric Liu }
125fc9213e0SEric Liu
ExpectStringError(const std::string & Expected,llvm::Error E)126fc9213e0SEric Liu static void ExpectStringError(const std::string &Expected,
127fc9213e0SEric Liu llvm::Error E) {
128fc9213e0SEric Liu std::string Found;
129fc9213e0SEric Liu handleAllErrors(std::move(E), [&](const llvm::StringError &SE) {
130fc9213e0SEric Liu llvm::raw_string_ostream Stream(Found);
131fc9213e0SEric Liu SE.log(Stream);
132fc9213e0SEric Liu });
133fc9213e0SEric Liu EXPECT_EQ(Expected, Found);
134fc9213e0SEric Liu }
135fc9213e0SEric Liu
TEST(RefactoringCallbacksTest,TemplateUnterminated)136fc9213e0SEric Liu TEST(RefactoringCallbacksTest, TemplateUnterminated) {
137fc9213e0SEric Liu auto Callback = ReplaceNodeWithTemplate::create("decl",
138fc9213e0SEric Liu "string x = \"$$-${init\"");
139fc9213e0SEric Liu ExpectStringError("Unterminated ${...} in replacement template near ${init\"",
140fc9213e0SEric Liu Callback.takeError());
141fc9213e0SEric Liu }
142fc9213e0SEric Liu
TEST(RefactoringCallbacksTest,TemplateUnknownDollar)143fc9213e0SEric Liu TEST(RefactoringCallbacksTest, TemplateUnknownDollar) {
144fc9213e0SEric Liu auto Callback = ReplaceNodeWithTemplate::create("decl",
145fc9213e0SEric Liu "string x = \"$<");
146fc9213e0SEric Liu ExpectStringError("Invalid $ in replacement template near $<",
147fc9213e0SEric Liu Callback.takeError());
148fc9213e0SEric Liu }
149fc9213e0SEric Liu
150*027899daSAlexander Kornienko } // namespace tooling
1511975e034SDaniel Jasper } // end namespace clang
152