StmtPrinterTest.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. //===- unittests/AST/StmtPrinterTest.cpp --- Statement printer tests ------===//
  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. //
  9. // This file contains tests for Stmt::printPretty() and related methods.
  10. //
  11. // Search this file for WRONG to see test cases that are producing something
  12. // completely wrong, invalid C++ or just misleading.
  13. //
  14. // These tests have a coding convention:
  15. // * statements to be printed should be contained within a function named 'A'
  16. // unless it should have some special name (e.g., 'operator+');
  17. // * additional helper declarations are 'Z', 'Y', 'X' and so on.
  18. //
  19. //===----------------------------------------------------------------------===//
  20. #include "ASTPrint.h"
  21. #include "clang/AST/ASTContext.h"
  22. #include "clang/ASTMatchers/ASTMatchFinder.h"
  23. #include "clang/Tooling/Tooling.h"
  24. #include "llvm/ADT/SmallString.h"
  25. #include "gtest/gtest.h"
  26. using namespace clang;
  27. using namespace ast_matchers;
  28. using namespace tooling;
  29. namespace {
  30. enum class StdVer { CXX98, CXX11, CXX14, CXX17, CXX2a };
  31. DeclarationMatcher FunctionBodyMatcher(StringRef ContainingFunction) {
  32. return functionDecl(hasName(ContainingFunction),
  33. has(compoundStmt(has(stmt().bind("id")))));
  34. }
  35. template <typename T>
  36. ::testing::AssertionResult
  37. PrintedStmtCXXMatches(StdVer Standard, StringRef Code, const T &NodeMatch,
  38. StringRef ExpectedPrinted,
  39. PolicyAdjusterType PolicyAdjuster = None) {
  40. const char *StdOpt;
  41. switch (Standard) {
  42. case StdVer::CXX98: StdOpt = "-std=c++98"; break;
  43. case StdVer::CXX11: StdOpt = "-std=c++11"; break;
  44. case StdVer::CXX14: StdOpt = "-std=c++14"; break;
  45. case StdVer::CXX17: StdOpt = "-std=c++17"; break;
  46. case StdVer::CXX2a: StdOpt = "-std=c++2a"; break;
  47. }
  48. std::vector<std::string> Args = {
  49. StdOpt,
  50. "-Wno-unused-value",
  51. };
  52. return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
  53. PolicyAdjuster);
  54. }
  55. template <typename T>
  56. ::testing::AssertionResult
  57. PrintedStmtMSMatches(StringRef Code, const T &NodeMatch,
  58. StringRef ExpectedPrinted,
  59. PolicyAdjusterType PolicyAdjuster = None) {
  60. std::vector<std::string> Args = {
  61. "-std=c++98",
  62. "-target", "i686-pc-win32",
  63. "-fms-extensions",
  64. "-Wno-unused-value",
  65. };
  66. return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
  67. PolicyAdjuster);
  68. }
  69. template <typename T>
  70. ::testing::AssertionResult
  71. PrintedStmtObjCMatches(StringRef Code, const T &NodeMatch,
  72. StringRef ExpectedPrinted,
  73. PolicyAdjusterType PolicyAdjuster = None) {
  74. std::vector<std::string> Args = {
  75. "-ObjC",
  76. "-fobjc-runtime=macosx-10.12.0",
  77. };
  78. return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
  79. PolicyAdjuster);
  80. }
  81. } // unnamed namespace
  82. TEST(StmtPrinter, TestIntegerLiteral) {
  83. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
  84. "void A() {"
  85. " 1, -1, 1U, 1u,"
  86. " 1L, 1l, -1L, 1UL, 1ul,"
  87. " 1LL, -1LL, 1ULL;"
  88. "}",
  89. FunctionBodyMatcher("A"),
  90. "1 , -1 , 1U , 1U , "
  91. "1L , 1L , -1L , 1UL , 1UL , "
  92. "1LL , -1LL , 1ULL"));
  93. // Should be: with semicolon
  94. }
  95. TEST(StmtPrinter, TestMSIntegerLiteral) {
  96. ASSERT_TRUE(PrintedStmtMSMatches(
  97. "void A() {"
  98. " 1i8, -1i8, 1ui8, "
  99. " 1i16, -1i16, 1ui16, "
  100. " 1i32, -1i32, 1ui32, "
  101. " 1i64, -1i64, 1ui64;"
  102. "}",
  103. FunctionBodyMatcher("A"),
  104. "1i8 , -1i8 , 1Ui8 , "
  105. "1i16 , -1i16 , 1Ui16 , "
  106. "1 , -1 , 1U , "
  107. "1LL , -1LL , 1ULL"));
  108. // Should be: with semicolon
  109. }
  110. TEST(StmtPrinter, TestFloatingPointLiteral) {
  111. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
  112. "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }",
  113. FunctionBodyMatcher("A"),
  114. "1.F , -1.F , 1. , -1. , 1.L , -1.L"));
  115. // Should be: with semicolon
  116. }
  117. TEST(StmtPrinter, TestCXXConversionDeclImplicit) {
  118. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
  119. "struct A {"
  120. "operator void *();"
  121. "A operator&(A);"
  122. "};"
  123. "void bar(void *);"
  124. "void foo(A a, A b) {"
  125. " bar(a & b);"
  126. "}",
  127. cxxMemberCallExpr(anything()).bind("id"),
  128. "a & b"));
  129. }
  130. TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
  131. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
  132. "struct A {"
  133. "operator void *();"
  134. "A operator&(A);"
  135. "};"
  136. "void bar(void *);"
  137. "void foo(A a, A b) {"
  138. " auto x = (a & b).operator void *();"
  139. "}",
  140. cxxMemberCallExpr(anything()).bind("id"),
  141. "(a & b)"));
  142. // WRONG; Should be: (a & b).operator void *()
  143. }
  144. TEST(StmtPrinter, TestCXXLamda) {
  145. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
  146. "void A() {"
  147. " auto l = [] { };"
  148. "}",
  149. lambdaExpr(anything()).bind("id"),
  150. "[] {\n"
  151. "}"));
  152. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
  153. "void A() {"
  154. " int a = 0, b = 1;"
  155. " auto l = [a,b](int c, float d) { };"
  156. "}",
  157. lambdaExpr(anything()).bind("id"),
  158. "[a, b](int c, float d) {\n"
  159. "}"));
  160. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14,
  161. "void A() {"
  162. " auto l = [](auto a, int b, auto c, int, auto) { };"
  163. "}",
  164. lambdaExpr(anything()).bind("id"),
  165. "[](auto a, int b, auto c, int, auto) {\n"
  166. "}"));
  167. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX2a,
  168. "void A() {"
  169. " auto l = []<typename T1, class T2, int I,"
  170. " template<class, typename> class T3>"
  171. " (int a, auto, int, auto d) { };"
  172. "}",
  173. lambdaExpr(anything()).bind("id"),
  174. "[]<typename T1, class T2, int I, template <class, typename> class T3>(int a, auto, int, auto d) {\n"
  175. "}"));
  176. }
  177. TEST(StmtPrinter, TestNoImplicitBases) {
  178. const char *CPPSource = R"(
  179. class A {
  180. int field;
  181. int member() { return field; }
  182. };
  183. )";
  184. // No implicit 'this'.
  185. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
  186. CPPSource, memberExpr(anything()).bind("id"), "field",
  187. PolicyAdjusterType(
  188. [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; })));
  189. // Print implicit 'this'.
  190. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
  191. CPPSource, memberExpr(anything()).bind("id"), "this->field"));
  192. const char *ObjCSource = R"(
  193. @interface I {
  194. int ivar;
  195. }
  196. @end
  197. @implementation I
  198. - (int) method {
  199. return ivar;
  200. }
  201. @end
  202. )";
  203. // No implicit 'self'.
  204. ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
  205. "return ivar;\n",
  206. PolicyAdjusterType([](PrintingPolicy &PP) {
  207. PP.SuppressImplicitBase = true;
  208. })));
  209. // Print implicit 'self'.
  210. ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
  211. "return self->ivar;\n"));
  212. }
  213. TEST(StmtPrinter, TerseOutputWithLambdas) {
  214. const char *CPPSource = "auto lamb = []{ return 0; };";
  215. // body is printed when TerseOutput is off(default).
  216. ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11, CPPSource,
  217. lambdaExpr(anything()).bind("id"),
  218. "[] {\n return 0;\n}"));
  219. // body not printed when TerseOutput is on.
  220. ASSERT_TRUE(PrintedStmtCXXMatches(
  221. StdVer::CXX11, CPPSource, lambdaExpr(anything()).bind("id"), "[] {}",
  222. PolicyAdjusterType([](PrintingPolicy &PP) { PP.TerseOutput = true; })));
  223. }