FixItTest.cpp 8.3 KB

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