blob: 4a883c38c858f590733a5b7cb2dc94e1b50b8515 [file] [log] [blame]
Chandler Carruth320d9662012-12-04 09:45:34 +00001//===- unittest/Tooling/RefactoringCallbacksTest.cpp ----------------------===//
Daniel Jasper7e222822012-07-16 09:18:17 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Daniel Jasper7e222822012-07-16 09:18:17 +00006//
7//===----------------------------------------------------------------------===//
8
Daniel Jasper1975e032012-07-17 08:03:01 +00009#include "RewriterTestContext.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000010#include "clang/ASTMatchers/ASTMatchFinder.h"
Chandler Carruthfa0b3bb2012-12-04 09:53:37 +000011#include "clang/ASTMatchers/ASTMatchers.h"
Eric Liufc9213e2017-05-10 07:48:45 +000012#include "clang/Tooling/RefactoringCallbacks.h"
Douglas Gregor949cc502012-10-23 23:13:50 +000013#include "gtest/gtest.h"
Daniel Jasper7e222822012-07-16 09:18:17 +000014
15namespace clang {
Daniel Jasper6389dd12012-07-17 08:37:03 +000016namespace tooling {
17
18using namespace ast_matchers;
Daniel Jasper7e222822012-07-16 09:18:17 +000019
20template <typename T>
Eric Liufc9213e2017-05-10 07:48:45 +000021void expectRewritten(const std::string &Code, const std::string &Expected,
22 const T &AMatcher, RefactoringCallback &Callback) {
23 std::map<std::string, Replacements> FileToReplace;
24 ASTMatchRefactorer Finder(FileToReplace);
Daniel Jasper7e222822012-07-16 09:18:17 +000025 Finder.addMatcher(AMatcher, &Callback);
Ahmed Charlesb8984322014-03-07 20:03:18 +000026 std::unique_ptr<tooling::FrontendActionFactory> Factory(
Daniel Jasper7e222822012-07-16 09:18:17 +000027 tooling::newFrontendActionFactory(&Finder));
28 ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code))
29 << "Parsing error in \"" << Code << "\"";
30 RewriterTestContext Context;
31 FileID ID = Context.createInMemoryFile("input.cc", Code);
Eric Liufc9213e2017-05-10 07:48:45 +000032 EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"],
Daniel Jasper7e222822012-07-16 09:18:17 +000033 Context.Rewrite));
34 EXPECT_EQ(Expected, Context.getRewrittenText(ID));
35}
36
37TEST(RefactoringCallbacksTest, ReplacesStmtsWithString) {
38 std::string Code = "void f() { int i = 1; }";
39 std::string Expected = "void f() { ; }";
40 ReplaceStmtWithText Callback("id", ";");
Dmitri Gribenkodee011b2019-08-20 13:02:28 +000041 expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
Daniel Jasper7e222822012-07-16 09:18:17 +000042}
43
44TEST(RefactoringCallbacksTest, ReplacesStmtsInCalledMacros) {
45 std::string Code = "#define A void f() { int i = 1; }\nA";
46 std::string Expected = "#define A void f() { ; }\nA";
47 ReplaceStmtWithText Callback("id", ";");
Dmitri Gribenkodee011b2019-08-20 13:02:28 +000048 expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
Daniel Jasper7e222822012-07-16 09:18:17 +000049}
50
51TEST(RefactoringCallbacksTest, IgnoresStmtsInUncalledMacros) {
52 std::string Code = "#define A void f() { int i = 1; }";
53 std::string Expected = "#define A void f() { int i = 1; }";
54 ReplaceStmtWithText Callback("id", ";");
Dmitri Gribenkodee011b2019-08-20 13:02:28 +000055 expectRewritten(Code, Expected, declStmt().bind("id"), Callback);
Daniel Jasper7e222822012-07-16 09:18:17 +000056}
57
58TEST(RefactoringCallbacksTest, ReplacesInteger) {
59 std::string Code = "void f() { int i = 1; }";
60 std::string Expected = "void f() { int i = 2; }";
61 ReplaceStmtWithText Callback("id", "2");
Dmitri Gribenkodee011b2019-08-20 13:02:28 +000062 expectRewritten(Code, Expected, expr(integerLiteral()).bind("id"), Callback);
Daniel Jasper7e222822012-07-16 09:18:17 +000063}
64
65TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) {
66 std::string Code = "void f() { int i = false ? 1 : i * 2; }";
67 std::string Expected = "void f() { int i = i * 2; }";
68 ReplaceStmtWithStmt Callback("always-false", "should-be");
Eric Liufc9213e2017-05-10 07:48:45 +000069 expectRewritten(
70 Code, Expected,
Dmitri Gribenkodee011b2019-08-20 13:02:28 +000071 conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))),
72 hasFalseExpression(expr().bind("should-be")))
73 .bind("always-false"),
Daniel Jasper7e222822012-07-16 09:18:17 +000074 Callback);
75}
76
77TEST(RefactoringCallbacksTest, ReplacesIfStmt) {
78 std::string Code = "bool a; void f() { if (a) f(); else a = true; }";
79 std::string Expected = "bool a; void f() { f(); }";
80 ReplaceIfStmtWithItsBody Callback("id", true);
Dmitri Gribenkodee011b2019-08-20 13:02:28 +000081 expectRewritten(Code, Expected,
82 ifStmt(hasCondition(implicitCastExpr(hasSourceExpression(
83 declRefExpr(to(varDecl(hasName("a"))))))))
84 .bind("id"),
85 Callback);
Daniel Jasper7e222822012-07-16 09:18:17 +000086}
87
88TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) {
89 std::string Code = "void f() { if (false) int i = 0; }";
90 std::string Expected = "void f() { }";
91 ReplaceIfStmtWithItsBody Callback("id", false);
Dmitri Gribenkodee011b2019-08-20 13:02:28 +000092 expectRewritten(
93 Code, Expected,
94 ifStmt(hasCondition(cxxBoolLiteral(equals(false)))).bind("id"), Callback);
Daniel Jasper7e222822012-07-16 09:18:17 +000095}
96
Eric Liufc9213e2017-05-10 07:48:45 +000097TEST(RefactoringCallbacksTest, TemplateJustText) {
98 std::string Code = "void f() { int i = 1; }";
99 std::string Expected = "void f() { FOO }";
100 auto Callback = ReplaceNodeWithTemplate::create("id", "FOO");
101 EXPECT_FALSE(Callback.takeError());
Dmitri Gribenkodee011b2019-08-20 13:02:28 +0000102 expectRewritten(Code, Expected, declStmt().bind("id"), **Callback);
Eric Liufc9213e2017-05-10 07:48:45 +0000103}
104
105TEST(RefactoringCallbacksTest, TemplateSimpleSubst) {
106 std::string Code = "void f() { int i = 1; }";
107 std::string Expected = "void f() { long x = 1; }";
108 auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}");
109 EXPECT_FALSE(Callback.takeError());
110 expectRewritten(Code, Expected,
Dmitri Gribenkodee011b2019-08-20 13:02:28 +0000111 varDecl(hasInitializer(expr().bind("init"))).bind("decl"),
Eric Liufc9213e2017-05-10 07:48:45 +0000112 **Callback);
113}
114
115TEST(RefactoringCallbacksTest, TemplateLiteral) {
116 std::string Code = "void f() { int i = 1; }";
117 std::string Expected = "void f() { string x = \"$-1\"; }";
118 auto Callback = ReplaceNodeWithTemplate::create("decl",
119 "string x = \"$$-${init}\"");
120 EXPECT_FALSE(Callback.takeError());
121 expectRewritten(Code, Expected,
Dmitri Gribenkodee011b2019-08-20 13:02:28 +0000122 varDecl(hasInitializer(expr().bind("init"))).bind("decl"),
Eric Liufc9213e2017-05-10 07:48:45 +0000123 **Callback);
124}
125
126static void ExpectStringError(const std::string &Expected,
127 llvm::Error E) {
128 std::string Found;
129 handleAllErrors(std::move(E), [&](const llvm::StringError &SE) {
130 llvm::raw_string_ostream Stream(Found);
131 SE.log(Stream);
132 });
133 EXPECT_EQ(Expected, Found);
134}
135
136TEST(RefactoringCallbacksTest, TemplateUnterminated) {
137 auto Callback = ReplaceNodeWithTemplate::create("decl",
138 "string x = \"$$-${init\"");
139 ExpectStringError("Unterminated ${...} in replacement template near ${init\"",
140 Callback.takeError());
141}
142
143TEST(RefactoringCallbacksTest, TemplateUnknownDollar) {
144 auto Callback = ReplaceNodeWithTemplate::create("decl",
145 "string x = \"$<");
146 ExpectStringError("Invalid $ in replacement template near $<",
147 Callback.takeError());
148}
149
150
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000151} // end namespace ast_matchers
Daniel Jasper7e222822012-07-16 09:18:17 +0000152} // end namespace clang