SourceCodeBuildersTest.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. //===- unittest/Tooling/SourceCodeBuildersTest.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/SourceCodeBuilders.h"
  9. #include "clang/ASTMatchers/ASTMatchFinder.h"
  10. #include "clang/ASTMatchers/ASTMatchers.h"
  11. #include "clang/Tooling/Tooling.h"
  12. #include "llvm/Testing/Support/SupportHelpers.h"
  13. #include "gmock/gmock.h"
  14. #include "gtest/gtest.h"
  15. using namespace clang;
  16. using namespace tooling;
  17. using namespace ast_matchers;
  18. namespace {
  19. using MatchResult = MatchFinder::MatchResult;
  20. using llvm::ValueIs;
  21. // Create a valid translation unit from a statement.
  22. static std::string wrapSnippet(StringRef StatementCode) {
  23. return ("struct S { S(); S(int); int field; };\n"
  24. "S operator+(const S &a, const S &b);\n"
  25. "auto test_snippet = []{" +
  26. StatementCode + "};")
  27. .str();
  28. }
  29. static DeclarationMatcher wrapMatcher(const StatementMatcher &Matcher) {
  30. return varDecl(hasName("test_snippet"),
  31. hasDescendant(compoundStmt(hasAnySubstatement(Matcher))));
  32. }
  33. struct TestMatch {
  34. // The AST unit from which `result` is built. We bundle it because it backs
  35. // the result. Users are not expected to access it.
  36. std::unique_ptr<ASTUnit> AstUnit;
  37. // The result to use in the test. References `ast_unit`.
  38. MatchResult Result;
  39. };
  40. // Matches `Matcher` against the statement `StatementCode` and returns the
  41. // result. Handles putting the statement inside a function and modifying the
  42. // matcher correspondingly. `Matcher` should match one of the statements in
  43. // `StatementCode` exactly -- that is, produce exactly one match. However,
  44. // `StatementCode` may contain other statements not described by `Matcher`.
  45. static llvm::Optional<TestMatch> matchStmt(StringRef StatementCode,
  46. StatementMatcher Matcher) {
  47. auto AstUnit = buildASTFromCode(wrapSnippet(StatementCode));
  48. if (AstUnit == nullptr) {
  49. ADD_FAILURE() << "AST construction failed";
  50. return llvm::None;
  51. }
  52. ASTContext &Context = AstUnit->getASTContext();
  53. auto Matches = ast_matchers::match(wrapMatcher(Matcher), Context);
  54. // We expect a single, exact match for the statement.
  55. if (Matches.size() != 1) {
  56. ADD_FAILURE() << "Wrong number of matches: " << Matches.size();
  57. return llvm::None;
  58. }
  59. return TestMatch{std::move(AstUnit), MatchResult(Matches[0], &Context)};
  60. }
  61. static void testPredicate(bool (*Pred)(const Expr &), StringRef Snippet,
  62. bool Expected) {
  63. auto StmtMatch = matchStmt(Snippet, expr().bind("expr"));
  64. ASSERT_TRUE(StmtMatch) << "Snippet: " << Snippet;
  65. EXPECT_EQ(Expected, Pred(*StmtMatch->Result.Nodes.getNodeAs<Expr>("expr")))
  66. << "Snippet: " << Snippet;
  67. }
  68. // Tests the predicate on the call argument, assuming `Snippet` is a function
  69. // call.
  70. static void testPredicateOnArg(bool (*Pred)(const Expr &), StringRef Snippet,
  71. bool Expected) {
  72. auto StmtMatch = matchStmt(
  73. Snippet, expr(ignoringImplicit(callExpr(hasArgument(
  74. 0, ignoringElidableConstructorCall(expr().bind("arg")))))));
  75. ASSERT_TRUE(StmtMatch) << "Snippet: " << Snippet;
  76. EXPECT_EQ(Expected, Pred(*StmtMatch->Result.Nodes.getNodeAs<Expr>("arg")))
  77. << "Snippet: " << Snippet;
  78. }
  79. TEST(SourceCodeBuildersTest, needParensAfterUnaryOperator) {
  80. testPredicate(needParensAfterUnaryOperator, "3 + 5;", true);
  81. testPredicate(needParensAfterUnaryOperator, "true ? 3 : 5;", true);
  82. testPredicate(needParensAfterUnaryOperator, "S(3) + S(5);", true);
  83. testPredicate(needParensAfterUnaryOperator, "int x; x;", false);
  84. testPredicate(needParensAfterUnaryOperator, "int(3.0);", false);
  85. testPredicate(needParensAfterUnaryOperator, "void f(); f();", false);
  86. testPredicate(needParensAfterUnaryOperator, "int a[3]; a[0];", false);
  87. testPredicate(needParensAfterUnaryOperator, "S x; x.field;", false);
  88. testPredicate(needParensAfterUnaryOperator, "int x = 1; --x;", false);
  89. testPredicate(needParensAfterUnaryOperator, "int x = 1; -x;", false);
  90. }
  91. TEST(SourceCodeBuildersTest, needParensAfterUnaryOperatorInImplicitConversion) {
  92. // The binary operation will be embedded in various implicit
  93. // expressions. Verify they are ignored.
  94. testPredicateOnArg(needParensAfterUnaryOperator, "void f(S); f(3 + 5);",
  95. true);
  96. }
  97. TEST(SourceCodeBuildersTest, mayEverNeedParens) {
  98. testPredicate(mayEverNeedParens, "3 + 5;", true);
  99. testPredicate(mayEverNeedParens, "true ? 3 : 5;", true);
  100. testPredicate(mayEverNeedParens, "int x = 1; --x;", true);
  101. testPredicate(mayEverNeedParens, "int x = 1; -x;", true);
  102. testPredicate(mayEverNeedParens, "int x; x;", false);
  103. testPredicate(mayEverNeedParens, "int(3.0);", false);
  104. testPredicate(mayEverNeedParens, "void f(); f();", false);
  105. testPredicate(mayEverNeedParens, "int a[3]; a[0];", false);
  106. testPredicate(mayEverNeedParens, "S x; x.field;", false);
  107. }
  108. TEST(SourceCodeBuildersTest, mayEverNeedParensInImplictConversion) {
  109. // The binary operation will be embedded in various implicit
  110. // expressions. Verify they are ignored.
  111. testPredicateOnArg(mayEverNeedParens, "void f(S); f(3 + 5);", true);
  112. }
  113. static void testBuilder(
  114. llvm::Optional<std::string> (*Builder)(const Expr &, const ASTContext &),
  115. StringRef Snippet, StringRef Expected) {
  116. auto StmtMatch = matchStmt(Snippet, expr().bind("expr"));
  117. ASSERT_TRUE(StmtMatch);
  118. EXPECT_THAT(Builder(*StmtMatch->Result.Nodes.getNodeAs<Expr>("expr"),
  119. *StmtMatch->Result.Context),
  120. ValueIs(Expected));
  121. }
  122. TEST(SourceCodeBuildersTest, BuildParensUnaryOp) {
  123. testBuilder(buildParens, "-4;", "(-4)");
  124. }
  125. TEST(SourceCodeBuildersTest, BuildParensBinOp) {
  126. testBuilder(buildParens, "4 + 4;", "(4 + 4)");
  127. }
  128. TEST(SourceCodeBuildersTest, BuildParensValue) {
  129. testBuilder(buildParens, "4;", "4");
  130. }
  131. TEST(SourceCodeBuildersTest, BuildParensSubscript) {
  132. testBuilder(buildParens, "int a[3]; a[0];", "a[0]");
  133. }
  134. TEST(SourceCodeBuildersTest, BuildParensCall) {
  135. testBuilder(buildParens, "int f(int); f(4);", "f(4)");
  136. }
  137. TEST(SourceCodeBuildersTest, BuildAddressOfValue) {
  138. testBuilder(buildAddressOf, "S x; x;", "&x");
  139. }
  140. TEST(SourceCodeBuildersTest, BuildAddressOfPointerDereference) {
  141. testBuilder(buildAddressOf, "S *x; *x;", "x");
  142. }
  143. TEST(SourceCodeBuildersTest, BuildAddressOfPointerDereferenceIgnoresParens) {
  144. testBuilder(buildAddressOf, "S *x; *(x);", "x");
  145. }
  146. TEST(SourceCodeBuildersTest, BuildAddressOfBinaryOperation) {
  147. testBuilder(buildAddressOf, "S x; x + x;", "&(x + x)");
  148. }
  149. TEST(SourceCodeBuildersTest, BuildDereferencePointer) {
  150. testBuilder(buildDereference, "S *x; x;", "*x");
  151. }
  152. TEST(SourceCodeBuildersTest, BuildDereferenceValueAddress) {
  153. testBuilder(buildDereference, "S x; &x;", "x");
  154. }
  155. TEST(SourceCodeBuildersTest, BuildDereferenceValueAddressIgnoresParens) {
  156. testBuilder(buildDereference, "S x; &(x);", "x");
  157. }
  158. TEST(SourceCodeBuildersTest, BuildDereferenceBinaryOperation) {
  159. testBuilder(buildDereference, "S *x; x + 1;", "*(x + 1)");
  160. }
  161. TEST(SourceCodeBuildersTest, BuildDotValue) {
  162. testBuilder(buildDot, "S x; x;", "x.");
  163. }
  164. TEST(SourceCodeBuildersTest, BuildDotPointerDereference) {
  165. testBuilder(buildDot, "S *x; *x;", "x->");
  166. }
  167. TEST(SourceCodeBuildersTest, BuildDotPointerDereferenceIgnoresParens) {
  168. testBuilder(buildDot, "S *x; *(x);", "x->");
  169. }
  170. TEST(SourceCodeBuildersTest, BuildDotBinaryOperation) {
  171. testBuilder(buildDot, "S x; x + x;", "(x + x).");
  172. }
  173. TEST(SourceCodeBuildersTest, BuildDotPointerDereferenceExprWithParens) {
  174. testBuilder(buildDot, "S *x; *(x + 1);", "(x + 1)->");
  175. }
  176. TEST(SourceCodeBuildersTest, BuildArrowPointer) {
  177. testBuilder(buildArrow, "S *x; x;", "x->");
  178. }
  179. TEST(SourceCodeBuildersTest, BuildArrowValueAddress) {
  180. testBuilder(buildArrow, "S x; &x;", "x.");
  181. }
  182. TEST(SourceCodeBuildersTest, BuildArrowValueAddressIgnoresParens) {
  183. testBuilder(buildArrow, "S x; &(x);", "x.");
  184. }
  185. TEST(SourceCodeBuildersTest, BuildArrowBinaryOperation) {
  186. testBuilder(buildArrow, "S *x; x + 1;", "(x + 1)->");
  187. }
  188. TEST(SourceCodeBuildersTest, BuildArrowValueAddressWithParens) {
  189. testBuilder(buildArrow, "S x; &(true ? x : x);", "(true ? x : x).");
  190. }
  191. } // namespace