SourceCodeTest.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. //===- unittest/Tooling/SourceCodeTest.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 "clang/Tooling/Transformer/SourceCode.h"
  9. #include "TestVisitor.h"
  10. #include "clang/Basic/Diagnostic.h"
  11. #include "llvm/Testing/Support/Annotations.h"
  12. #include "llvm/Testing/Support/SupportHelpers.h"
  13. #include <gmock/gmock.h>
  14. #include <gtest/gtest.h>
  15. using namespace clang;
  16. using llvm::ValueIs;
  17. using tooling::getExtendedText;
  18. using tooling::getRangeForEdit;
  19. using tooling::getText;
  20. namespace {
  21. struct IntLitVisitor : TestVisitor<IntLitVisitor> {
  22. bool VisitIntegerLiteral(IntegerLiteral *Expr) {
  23. OnIntLit(Expr, Context);
  24. return true;
  25. }
  26. std::function<void(IntegerLiteral *, ASTContext *Context)> OnIntLit;
  27. };
  28. struct CallsVisitor : TestVisitor<CallsVisitor> {
  29. bool VisitCallExpr(CallExpr *Expr) {
  30. OnCall(Expr, Context);
  31. return true;
  32. }
  33. std::function<void(CallExpr *, ASTContext *Context)> OnCall;
  34. };
  35. // Equality matcher for `clang::CharSourceRange`, which lacks `operator==`.
  36. MATCHER_P(EqualsRange, R, "") {
  37. return arg.isTokenRange() == R.isTokenRange() &&
  38. arg.getBegin() == R.getBegin() && arg.getEnd() == R.getEnd();
  39. }
  40. static ::testing::Matcher<CharSourceRange> AsRange(const SourceManager &SM,
  41. llvm::Annotations::Range R) {
  42. return EqualsRange(CharSourceRange::getCharRange(
  43. SM.getLocForStartOfFile(SM.getMainFileID()).getLocWithOffset(R.Begin),
  44. SM.getLocForStartOfFile(SM.getMainFileID()).getLocWithOffset(R.End)));
  45. }
  46. TEST(SourceCodeTest, getText) {
  47. CallsVisitor Visitor;
  48. Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
  49. EXPECT_EQ("foo(x, y)", getText(*CE, *Context));
  50. };
  51. Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
  52. Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
  53. EXPECT_EQ("APPLY(foo, x, y)", getText(*CE, *Context));
  54. };
  55. Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n"
  56. "void foo(int x, int y) { APPLY(foo, x, y); }");
  57. }
  58. TEST(SourceCodeTest, getTextWithMacro) {
  59. CallsVisitor Visitor;
  60. Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
  61. EXPECT_EQ("F OO", getText(*CE, *Context));
  62. Expr *P0 = CE->getArg(0);
  63. Expr *P1 = CE->getArg(1);
  64. EXPECT_EQ("", getText(*P0, *Context));
  65. EXPECT_EQ("", getText(*P1, *Context));
  66. };
  67. Visitor.runOver("#define F foo(\n"
  68. "#define OO x, y)\n"
  69. "void foo(int x, int y) { F OO ; }");
  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. TEST(SourceCodeTest, getExtendedText) {
  81. CallsVisitor Visitor;
  82. Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
  83. EXPECT_EQ("foo(x, y);",
  84. getExtendedText(*CE, tok::TokenKind::semi, *Context));
  85. Expr *P0 = CE->getArg(0);
  86. Expr *P1 = CE->getArg(1);
  87. EXPECT_EQ("x", getExtendedText(*P0, tok::TokenKind::semi, *Context));
  88. EXPECT_EQ("x,", getExtendedText(*P0, tok::TokenKind::comma, *Context));
  89. EXPECT_EQ("y", getExtendedText(*P1, tok::TokenKind::semi, *Context));
  90. };
  91. Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
  92. Visitor.runOver("void foo(int x, int y) { if (true) foo(x, y); }");
  93. Visitor.runOver("int foo(int x, int y) { if (true) return 3 + foo(x, y); }");
  94. Visitor.runOver("void foo(int x, int y) { for (foo(x, y);;) ++x; }");
  95. Visitor.runOver(
  96. "bool foo(int x, int y) { for (;foo(x, y);) x = 1; return true; }");
  97. Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
  98. EXPECT_EQ("foo()", getExtendedText(*CE, tok::TokenKind::semi, *Context));
  99. };
  100. Visitor.runOver("bool foo() { if (foo()) return true; return false; }");
  101. Visitor.runOver("void foo() { int x; for (;; foo()) ++x; }");
  102. Visitor.runOver("int foo() { return foo() + 3; }");
  103. }
  104. TEST(SourceCodeTest, EditRangeWithMacroExpansionsShouldSucceed) {
  105. // The call expression, whose range we are extracting, includes two macro
  106. // expansions.
  107. llvm::Annotations Code(R"cpp(
  108. #define M(a) a * 13
  109. int foo(int x, int y);
  110. int a = $r[[foo(M(1), M(2))]];
  111. )cpp");
  112. CallsVisitor Visitor;
  113. Visitor.OnCall = [&Code](CallExpr *CE, ASTContext *Context) {
  114. auto Range = CharSourceRange::getTokenRange(CE->getSourceRange());
  115. EXPECT_THAT(getRangeForEdit(Range, *Context),
  116. ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
  117. };
  118. Visitor.runOver(Code.code());
  119. }
  120. TEST(SourceCodeTest, EditWholeMacroExpansionShouldSucceed) {
  121. llvm::Annotations Code(R"cpp(
  122. #define FOO 10
  123. int a = $r[[FOO]];
  124. )cpp");
  125. IntLitVisitor Visitor;
  126. Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) {
  127. auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
  128. EXPECT_THAT(getRangeForEdit(Range, *Context),
  129. ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
  130. };
  131. Visitor.runOver(Code.code());
  132. }
  133. TEST(SourceCodeTest, EditPartialMacroExpansionShouldFail) {
  134. std::string Code = R"cpp(
  135. #define BAR 10+
  136. int c = BAR 3.0;
  137. )cpp";
  138. IntLitVisitor Visitor;
  139. Visitor.OnIntLit = [](IntegerLiteral *Expr, ASTContext *Context) {
  140. auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
  141. EXPECT_FALSE(getRangeForEdit(Range, *Context).hasValue());
  142. };
  143. Visitor.runOver(Code);
  144. }
  145. TEST(SourceCodeTest, EditWholeMacroArgShouldSucceed) {
  146. llvm::Annotations Code(R"cpp(
  147. #define FOO(a) a + 7.0;
  148. int a = FOO($r[[10]]);
  149. )cpp");
  150. IntLitVisitor Visitor;
  151. Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) {
  152. auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
  153. EXPECT_THAT(getRangeForEdit(Range, *Context),
  154. ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
  155. };
  156. Visitor.runOver(Code.code());
  157. }
  158. TEST(SourceCodeTest, EditPartialMacroArgShouldSucceed) {
  159. llvm::Annotations Code(R"cpp(
  160. #define FOO(a) a + 7.0;
  161. int a = FOO($r[[10]] + 10.0);
  162. )cpp");
  163. IntLitVisitor Visitor;
  164. Visitor.OnIntLit = [&Code](IntegerLiteral *Expr, ASTContext *Context) {
  165. auto Range = CharSourceRange::getTokenRange(Expr->getSourceRange());
  166. EXPECT_THAT(getRangeForEdit(Range, *Context),
  167. ValueIs(AsRange(Context->getSourceManager(), Code.range("r"))));
  168. };
  169. Visitor.runOver(Code.code());
  170. }
  171. } // end anonymous namespace