153276d12SEtienne Bergeron //===- unittest/Tooling/FixitTest.cpp ------------------------------------===//
253276d12SEtienne Bergeron //
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
653276d12SEtienne Bergeron //
753276d12SEtienne Bergeron //===----------------------------------------------------------------------===//
853276d12SEtienne Bergeron
953276d12SEtienne Bergeron #include "clang/Tooling/FixIt.h"
10*a7691deeSSam McCall #include "clang/ASTMatchers/ASTMatchFinder.h"
11*a7691deeSSam McCall #include "clang/ASTMatchers/ASTMatchers.h"
12*a7691deeSSam McCall #include "clang/Testing/TestAST.h"
13*a7691deeSSam McCall #include "gtest/gtest.h"
1453276d12SEtienne Bergeron
1553276d12SEtienne Bergeron using namespace clang;
1653276d12SEtienne Bergeron
1753276d12SEtienne Bergeron using tooling::fixit::getText;
1853276d12SEtienne Bergeron using tooling::fixit::createRemoval;
1953276d12SEtienne Bergeron using tooling::fixit::createReplacement;
2053276d12SEtienne Bergeron
2153276d12SEtienne Bergeron namespace {
2253276d12SEtienne Bergeron
onlyCall(ASTContext & Ctx)23*a7691deeSSam McCall const CallExpr &onlyCall(ASTContext &Ctx) {
24*a7691deeSSam McCall using namespace ast_matchers;
25*a7691deeSSam McCall auto Calls = match(callExpr().bind(""), Ctx);
26*a7691deeSSam McCall EXPECT_EQ(Calls.size(), 1u);
27*a7691deeSSam McCall return *Calls.front().getNodeAs<CallExpr>("");
2853276d12SEtienne Bergeron }
2953276d12SEtienne Bergeron
TEST(FixItTest,getText)3053276d12SEtienne Bergeron TEST(FixItTest, getText) {
31*a7691deeSSam McCall TestAST AST("void foo(int x, int y) { foo(x, y); }");
32*a7691deeSSam McCall const CallExpr &CE = onlyCall(AST.context());
33*a7691deeSSam McCall EXPECT_EQ("foo(x, y)", getText(CE, AST.context()));
34*a7691deeSSam McCall EXPECT_EQ("foo(x, y)", getText(CE.getSourceRange(), AST.context()));
35*a7691deeSSam McCall EXPECT_EQ("x", getText(*CE.getArg(0), AST.context()));
36*a7691deeSSam McCall EXPECT_EQ("y", getText(*CE.getArg(1), AST.context()));
3753276d12SEtienne Bergeron
38*a7691deeSSam McCall AST = TestAST("#define APPLY(f, x, y) f(x, y)\n"
3953276d12SEtienne Bergeron "void foo(int x, int y) { APPLY(foo, x, y); }");
40*a7691deeSSam McCall const CallExpr &CE2 = onlyCall(AST.context());
41*a7691deeSSam McCall EXPECT_EQ("APPLY(foo, x, y)", getText(CE2, AST.context()));
4253276d12SEtienne Bergeron }
4353276d12SEtienne Bergeron
TEST(FixItTest,getTextWithMacro)4453276d12SEtienne Bergeron TEST(FixItTest, getTextWithMacro) {
45*a7691deeSSam McCall TestAST AST("#define F foo(\n"
4653276d12SEtienne Bergeron "#define OO x, y)\n"
4753276d12SEtienne Bergeron "void foo(int x, int y) { F OO ; }");
48*a7691deeSSam McCall const CallExpr &CE = onlyCall(AST.context());
49*a7691deeSSam McCall EXPECT_EQ("F OO", getText(CE, AST.context()));
50*a7691deeSSam McCall EXPECT_EQ("", getText(*CE.getArg(0), AST.context()));
51*a7691deeSSam McCall EXPECT_EQ("", getText(*CE.getArg(1), AST.context()));
5253276d12SEtienne Bergeron
53*a7691deeSSam McCall AST = TestAST("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
5453276d12SEtienne Bergeron "void foo(int x, int y) { FOO(x,y) }");
55*a7691deeSSam McCall const CallExpr &CE2 = onlyCall(AST.context());
56*a7691deeSSam McCall EXPECT_EQ("", getText(CE2, AST.context()));
57*a7691deeSSam McCall EXPECT_EQ("x", getText(*CE2.getArg(0), AST.context()));
58*a7691deeSSam McCall EXPECT_EQ("y", getText(*CE2.getArg(1), AST.context()));
5953276d12SEtienne Bergeron }
6053276d12SEtienne Bergeron
TEST(FixItTest,createRemoval)6153276d12SEtienne Bergeron TEST(FixItTest, createRemoval) {
62*a7691deeSSam McCall TestAST AST("void foo(int x, int y) { foo(x, y); }");
63*a7691deeSSam McCall const CallExpr &CE = onlyCall(AST.context());
6453276d12SEtienne Bergeron
65*a7691deeSSam McCall FixItHint Hint = createRemoval(CE);
66*a7691deeSSam McCall EXPECT_EQ("foo(x, y)", getText(Hint.RemoveRange.getAsRange(), AST.context()));
6753276d12SEtienne Bergeron EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
6853276d12SEtienne Bergeron EXPECT_TRUE(Hint.CodeToInsert.empty());
6953276d12SEtienne Bergeron
70*a7691deeSSam McCall FixItHint Hint0 = createRemoval(*CE.getArg(0));
71*a7691deeSSam McCall EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), AST.context()));
7253276d12SEtienne Bergeron EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
7353276d12SEtienne Bergeron EXPECT_TRUE(Hint0.CodeToInsert.empty());
7453276d12SEtienne Bergeron
75*a7691deeSSam McCall FixItHint Hint1 = createRemoval(*CE.getArg(1));
76*a7691deeSSam McCall EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), AST.context()));
7753276d12SEtienne Bergeron EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
7853276d12SEtienne Bergeron EXPECT_TRUE(Hint1.CodeToInsert.empty());
7953276d12SEtienne Bergeron
80*a7691deeSSam McCall AST = TestAST("void foo(int x, int y) { foo(x + y, y + x); }");
81*a7691deeSSam McCall const CallExpr &CE2 = onlyCall(AST.context());
82*a7691deeSSam McCall Hint0 = createRemoval(*CE2.getArg(0));
83*a7691deeSSam McCall EXPECT_EQ("x + y", getText(Hint0.RemoveRange.getAsRange(), AST.context()));
8453276d12SEtienne Bergeron
85*a7691deeSSam McCall Hint1 = createRemoval(*CE2.getArg(1));
86*a7691deeSSam McCall EXPECT_EQ("y + x", getText(Hint1.RemoveRange.getAsRange(), AST.context()));
8753276d12SEtienne Bergeron }
8853276d12SEtienne Bergeron
TEST(FixItTest,createRemovalWithMacro)8953276d12SEtienne Bergeron TEST(FixItTest, createRemovalWithMacro) {
90*a7691deeSSam McCall TestAST AST("#define FOO foo(1, 1)\n"
91*a7691deeSSam McCall "void foo(int x, int y) { FOO; }");
92*a7691deeSSam McCall const CallExpr &CE = onlyCall(AST.context());
93*a7691deeSSam McCall FixItHint Hint = createRemoval(CE);
94*a7691deeSSam McCall EXPECT_EQ("FOO", getText(Hint.RemoveRange.getAsRange(), AST.context()));
9553276d12SEtienne Bergeron EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
9653276d12SEtienne Bergeron EXPECT_TRUE(Hint.CodeToInsert.empty());
9753276d12SEtienne Bergeron
98*a7691deeSSam McCall FixItHint Hint0 = createRemoval(*CE.getArg(0));
99*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:17>",
100*a7691deeSSam McCall Hint0.RemoveRange.getBegin().printToString(AST.sourceManager()));
101*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:17>",
102*a7691deeSSam McCall Hint0.RemoveRange.getEnd().printToString(AST.sourceManager()));
10353276d12SEtienne Bergeron EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
10453276d12SEtienne Bergeron EXPECT_TRUE(Hint0.CodeToInsert.empty());
10553276d12SEtienne Bergeron
106*a7691deeSSam McCall FixItHint Hint1 = createRemoval(*CE.getArg(1));
107*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:20>",
108*a7691deeSSam McCall Hint1.RemoveRange.getBegin().printToString(AST.sourceManager()));
109*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:20>",
110*a7691deeSSam McCall Hint1.RemoveRange.getEnd().printToString(AST.sourceManager()));
11153276d12SEtienne Bergeron EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
11253276d12SEtienne Bergeron EXPECT_TRUE(Hint1.CodeToInsert.empty());
11353276d12SEtienne Bergeron
114*a7691deeSSam McCall AST = TestAST("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
115*a7691deeSSam McCall "void foo(int x, int y) { FOO(x,y) }");
116*a7691deeSSam McCall const CallExpr &CE2 = onlyCall(AST.context());
117*a7691deeSSam McCall Hint = createRemoval(CE2);
118*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:37>",
119*a7691deeSSam McCall Hint.RemoveRange.getBegin().printToString(AST.sourceManager()));
120*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:45>",
121*a7691deeSSam McCall Hint.RemoveRange.getEnd().printToString(AST.sourceManager()));
12253276d12SEtienne Bergeron EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
12353276d12SEtienne Bergeron EXPECT_TRUE(Hint.CodeToInsert.empty());
12453276d12SEtienne Bergeron }
12553276d12SEtienne Bergeron
TEST(FixItTest,createReplacement)12653276d12SEtienne Bergeron TEST(FixItTest, createReplacement) {
127*a7691deeSSam McCall for (const char *Code : {
128*a7691deeSSam McCall "void foo(int x, int y) { foo(x, y); }",
12953276d12SEtienne Bergeron
130*a7691deeSSam McCall "#define APPLY(f, x, y) f(x, y)\n"
131*a7691deeSSam McCall "void foo(int x, int y) { APPLY(foo, x, y); }",
132*a7691deeSSam McCall
133*a7691deeSSam McCall "#define APPLY(f, P) f(P)\n"
134*a7691deeSSam McCall "#define PAIR(x, y) x, y\n"
135*a7691deeSSam McCall "void foo(int x, int y) { APPLY(foo, PAIR(x, y)); }\n",
136*a7691deeSSam McCall }) {
137*a7691deeSSam McCall TestAST AST(Code);
138*a7691deeSSam McCall const CallExpr &CE = onlyCall(AST.context());
139*a7691deeSSam McCall const Expr *P0 = CE.getArg(0);
140*a7691deeSSam McCall const Expr *P1 = CE.getArg(1);
141*a7691deeSSam McCall FixItHint Hint0 = createReplacement(*P0, *P1, AST.context());
142*a7691deeSSam McCall FixItHint Hint1 = createReplacement(*P1, *P0, AST.context());
14353276d12SEtienne Bergeron
14453276d12SEtienne Bergeron // Validate Hint0 fields.
145*a7691deeSSam McCall EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), AST.context()));
14653276d12SEtienne Bergeron EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
14753276d12SEtienne Bergeron EXPECT_EQ(Hint0.CodeToInsert, "y");
14853276d12SEtienne Bergeron
14953276d12SEtienne Bergeron // Validate Hint1 fields.
150*a7691deeSSam McCall EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), AST.context()));
15153276d12SEtienne Bergeron EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
15253276d12SEtienne Bergeron EXPECT_EQ(Hint1.CodeToInsert, "x");
153*a7691deeSSam McCall }
15453276d12SEtienne Bergeron }
15553276d12SEtienne Bergeron
TEST(FixItTest,createReplacementWithMacro)15653276d12SEtienne Bergeron TEST(FixItTest, createReplacementWithMacro) {
157*a7691deeSSam McCall TestAST AST("#define FOO foo(1, 1)\n"
158*a7691deeSSam McCall "void foo(int x, int y) { FOO; }");
159*a7691deeSSam McCall const CallExpr &CE = onlyCall(AST.context());
160*a7691deeSSam McCall FixItHint Hint =
161*a7691deeSSam McCall createReplacement(*CE.getArg(0), *CE.getArg(1), AST.context());
162*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:17>",
163*a7691deeSSam McCall Hint.RemoveRange.getBegin().printToString(AST.sourceManager()));
164*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:1:17>",
165*a7691deeSSam McCall Hint.RemoveRange.getEnd().printToString(AST.sourceManager()));
16653276d12SEtienne Bergeron EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
16753276d12SEtienne Bergeron EXPECT_TRUE(Hint.CodeToInsert.empty());
16853276d12SEtienne Bergeron
169*a7691deeSSam McCall AST = TestAST("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
170*a7691deeSSam McCall "void foo(int x, int y) { FOO(x,y) }");
171*a7691deeSSam McCall const CallExpr &CE2 = onlyCall(AST.context());
172*a7691deeSSam McCall Hint = createReplacement(*CE2.getArg(0), *CE2.getArg(1), AST.context());
173*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:2:30>",
174*a7691deeSSam McCall Hint.RemoveRange.getEnd().printToString(AST.sourceManager()));
175*a7691deeSSam McCall EXPECT_EQ("input.mm:2:26 <Spelling=input.mm:2:30>",
176*a7691deeSSam McCall Hint.RemoveRange.getBegin().printToString(AST.sourceManager()));
17753276d12SEtienne Bergeron EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
17853276d12SEtienne Bergeron EXPECT_EQ("y", Hint.CodeToInsert);
17953276d12SEtienne Bergeron
180*a7691deeSSam McCall AST = TestAST("void foo(int x, int y) { foo(x + y, y + x); }");
181*a7691deeSSam McCall const CallExpr &CE3 = onlyCall(AST.context());
182*a7691deeSSam McCall Hint = createReplacement(*CE3.getArg(0), *CE3.getArg(1), AST.context());
183*a7691deeSSam McCall EXPECT_EQ("x + y", getText(Hint.RemoveRange.getAsRange(), AST.context()));
18453276d12SEtienne Bergeron EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
18553276d12SEtienne Bergeron EXPECT_EQ("y + x", Hint.CodeToInsert);
18653276d12SEtienne Bergeron }
18753276d12SEtienne Bergeron
18853276d12SEtienne Bergeron } // end anonymous namespace
189