1 //===- unittest/Tooling/FixitTest.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 "TestVisitor.h" 11 #include "clang/Basic/Diagnostic.h" 12 #include "clang/Tooling/FixIt.h" 13 14 using namespace clang; 15 16 using tooling::fixit::getText; 17 using tooling::fixit::createRemoval; 18 using tooling::fixit::createReplacement; 19 20 namespace { 21 22 struct CallsVisitor : TestVisitor<CallsVisitor> { 23 bool VisitCallExpr(CallExpr *Expr) { 24 OnCall(Expr, Context); 25 return true; 26 } 27 28 std::function<void(CallExpr *, ASTContext *Context)> OnCall; 29 }; 30 31 std::string LocationToString(SourceLocation Loc, ASTContext *Context) { 32 return Loc.printToString(Context->getSourceManager()); 33 } 34 35 TEST(FixItTest, getText) { 36 CallsVisitor Visitor; 37 38 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 39 EXPECT_EQ("foo(x, y)", getText(*CE, *Context)); 40 EXPECT_EQ("foo(x, y)", getText(CE->getSourceRange(), *Context)); 41 42 Expr *P0 = CE->getArg(0); 43 Expr *P1 = CE->getArg(1); 44 EXPECT_EQ("x", getText(*P0, *Context)); 45 EXPECT_EQ("y", getText(*P1, *Context)); 46 }; 47 Visitor.runOver("void foo(int x, int y) { foo(x, y); }"); 48 49 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 50 EXPECT_EQ("APPLY(foo, x, y)", getText(*CE, *Context)); 51 }; 52 Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n" 53 "void foo(int x, int y) { APPLY(foo, x, y); }"); 54 } 55 56 TEST(FixItTest, getTextWithMacro) { 57 CallsVisitor Visitor; 58 59 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 60 EXPECT_EQ("F OO", getText(*CE, *Context)); 61 Expr *P0 = CE->getArg(0); 62 Expr *P1 = CE->getArg(1); 63 EXPECT_EQ("", getText(*P0, *Context)); 64 EXPECT_EQ("", getText(*P1, *Context)); 65 }; 66 Visitor.runOver("#define F foo(\n" 67 "#define OO x, y)\n" 68 "void foo(int x, int y) { F OO ; }"); 69 70 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 71 EXPECT_EQ("", getText(*CE, *Context)); 72 Expr *P0 = CE->getArg(0); 73 Expr *P1 = CE->getArg(1); 74 EXPECT_EQ("x", getText(*P0, *Context)); 75 EXPECT_EQ("y", getText(*P1, *Context)); 76 }; 77 Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n" 78 "void foo(int x, int y) { FOO(x,y) }"); 79 } 80 81 TEST(FixItTest, createRemoval) { 82 CallsVisitor Visitor; 83 84 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 85 FixItHint Hint = createRemoval(*CE); 86 EXPECT_EQ("foo(x, y)", getText(Hint.RemoveRange.getAsRange(), *Context)); 87 EXPECT_TRUE(Hint.InsertFromRange.isInvalid()); 88 EXPECT_TRUE(Hint.CodeToInsert.empty()); 89 90 Expr *P0 = CE->getArg(0); 91 FixItHint Hint0 = createRemoval(*P0); 92 EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), *Context)); 93 EXPECT_TRUE(Hint0.InsertFromRange.isInvalid()); 94 EXPECT_TRUE(Hint0.CodeToInsert.empty()); 95 96 Expr *P1 = CE->getArg(1); 97 FixItHint Hint1 = createRemoval(*P1); 98 EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), *Context)); 99 EXPECT_TRUE(Hint1.InsertFromRange.isInvalid()); 100 EXPECT_TRUE(Hint1.CodeToInsert.empty()); 101 }; 102 Visitor.runOver("void foo(int x, int y) { foo(x, y); }"); 103 104 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 105 Expr *P0 = CE->getArg(0); 106 FixItHint Hint0 = createRemoval(*P0); 107 EXPECT_EQ("x + y", getText(Hint0.RemoveRange.getAsRange(), *Context)); 108 109 Expr *P1 = CE->getArg(1); 110 FixItHint Hint1 = createRemoval(*P1); 111 EXPECT_EQ("y + x", getText(Hint1.RemoveRange.getAsRange(), *Context)); 112 }; 113 Visitor.runOver("void foo(int x, int y) { foo(x + y, y + x); }"); 114 } 115 116 TEST(FixItTest, createRemovalWithMacro) { 117 CallsVisitor Visitor; 118 119 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 120 FixItHint Hint = createRemoval(*CE); 121 EXPECT_EQ("FOO", getText(Hint.RemoveRange.getAsRange(), *Context)); 122 EXPECT_TRUE(Hint.InsertFromRange.isInvalid()); 123 EXPECT_TRUE(Hint.CodeToInsert.empty()); 124 125 Expr *P0 = CE->getArg(0); 126 FixItHint Hint0 = createRemoval(*P0); 127 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>", 128 LocationToString(Hint0.RemoveRange.getBegin(), Context)); 129 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>", 130 LocationToString(Hint0.RemoveRange.getEnd(), Context)); 131 EXPECT_TRUE(Hint0.InsertFromRange.isInvalid()); 132 EXPECT_TRUE(Hint0.CodeToInsert.empty()); 133 134 Expr *P1 = CE->getArg(1); 135 FixItHint Hint1 = createRemoval(*P1); 136 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:20>", 137 LocationToString(Hint1.RemoveRange.getBegin(), Context)); 138 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:20>", 139 LocationToString(Hint1.RemoveRange.getEnd(), Context)); 140 EXPECT_TRUE(Hint1.InsertFromRange.isInvalid()); 141 EXPECT_TRUE(Hint1.CodeToInsert.empty()); 142 }; 143 Visitor.runOver("#define FOO foo(1, 1)\n" 144 "void foo(int x, int y) { FOO; }"); 145 146 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 147 FixItHint Hint = createRemoval(*CE); 148 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:37>", 149 LocationToString(Hint.RemoveRange.getBegin(), Context)); 150 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:45>", 151 LocationToString(Hint.RemoveRange.getEnd(), Context)); 152 EXPECT_TRUE(Hint.InsertFromRange.isInvalid()); 153 EXPECT_TRUE(Hint.CodeToInsert.empty()); 154 }; 155 Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n" 156 "void foo(int x, int y) { FOO(x,y) }"); 157 } 158 159 TEST(FixItTest, createReplacement) { 160 CallsVisitor Visitor; 161 162 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 163 Expr *P0 = CE->getArg(0); 164 Expr *P1 = CE->getArg(1); 165 FixItHint Hint0 = createReplacement(*P0, *P1, *Context); 166 FixItHint Hint1 = createReplacement(*P1, *P0, *Context); 167 168 // Validate Hint0 fields. 169 EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), *Context)); 170 EXPECT_TRUE(Hint0.InsertFromRange.isInvalid()); 171 EXPECT_EQ(Hint0.CodeToInsert, "y"); 172 173 // Validate Hint1 fields. 174 EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), *Context)); 175 EXPECT_TRUE(Hint1.InsertFromRange.isInvalid()); 176 EXPECT_EQ(Hint1.CodeToInsert, "x"); 177 }; 178 179 Visitor.runOver("void foo(int x, int y) { foo(x, y); }"); 180 181 Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n" 182 "void foo(int x, int y) { APPLY(foo, x, y); }"); 183 184 Visitor.runOver("#define APPLY(f, P) f(P)\n" 185 "#define PAIR(x, y) x, y\n" 186 "void foo(int x, int y) { APPLY(foo, PAIR(x, y)); }\n"); 187 } 188 189 TEST(FixItTest, createReplacementWithMacro) { 190 CallsVisitor Visitor; 191 192 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 193 Expr *P0 = CE->getArg(0); 194 Expr *P1 = CE->getArg(1); 195 FixItHint Hint = createReplacement(*P0, *P1, *Context); 196 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>", 197 LocationToString(Hint.RemoveRange.getBegin(), Context)); 198 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>", 199 LocationToString(Hint.RemoveRange.getEnd(), Context)); 200 EXPECT_TRUE(Hint.InsertFromRange.isInvalid()); 201 EXPECT_TRUE(Hint.CodeToInsert.empty()); 202 }; 203 204 Visitor.runOver("#define FOO foo(1, 1)\n" 205 "void foo(int x, int y) { FOO; }"); 206 207 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 208 Expr *P0 = CE->getArg(0); 209 Expr *P1 = CE->getArg(1); 210 FixItHint Hint = createReplacement(*P0, *P1, *Context); 211 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:2:30>", 212 LocationToString(Hint.RemoveRange.getBegin(), Context)); 213 EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:2:30>", 214 LocationToString(Hint.RemoveRange.getEnd(), Context)); 215 EXPECT_TRUE(Hint.InsertFromRange.isInvalid()); 216 EXPECT_EQ("y", Hint.CodeToInsert); 217 }; 218 Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n" 219 "void foo(int x, int y) { FOO(x,y) }"); 220 221 Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { 222 Expr *P0 = CE->getArg(0); 223 Expr *P1 = CE->getArg(1); 224 FixItHint Hint = createReplacement(*P0, *P1, *Context); 225 EXPECT_EQ("x + y", getText(Hint.RemoveRange.getAsRange(), *Context)); 226 EXPECT_TRUE(Hint.InsertFromRange.isInvalid()); 227 EXPECT_EQ("y + x", Hint.CodeToInsert); 228 }; 229 Visitor.runOver("void foo(int x, int y) { foo(x + y, y + x); }"); 230 } 231 232 } // end anonymous namespace 233