1 //===- unittests/AST/StmtPrinterTest.cpp --- Statement printer tests ------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains tests for Stmt::printPretty() and related methods.
11 // Search this file for WRONG to see test cases that are producing something
12 // completely wrong, invalid C++ or just misleading.
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.
19 //===----------------------------------------------------------------------===//
22 #include "clang/AST/ASTContext.h"
23 #include "clang/ASTMatchers/ASTMatchFinder.h"
24 #include "clang/Tooling/Tooling.h"
25 #include "llvm/ADT/SmallString.h"
26 #include "gtest/gtest.h"
28 using namespace clang
;
29 using namespace ast_matchers
;
30 using namespace tooling
;
34 enum class StdVer
{ CXX98
, CXX11
, CXX14
, CXX17
, CXX20
};
36 DeclarationMatcher
FunctionBodyMatcher(StringRef ContainingFunction
) {
37 return functionDecl(hasName(ContainingFunction
),
38 has(compoundStmt(has(stmt().bind("id")))));
41 static void PrintStmt(raw_ostream
&Out
, const ASTContext
*Context
,
42 const Stmt
*S
, PrintingPolicyAdjuster PolicyAdjuster
) {
43 assert(S
!= nullptr && "Expected non-null Stmt");
44 PrintingPolicy Policy
= Context
->getPrintingPolicy();
46 PolicyAdjuster(Policy
);
47 S
->printPretty(Out
, /*Helper*/ nullptr, Policy
);
50 template <typename Matcher
>
51 ::testing::AssertionResult
52 PrintedStmtMatches(StringRef Code
, const std::vector
<std::string
> &Args
,
53 const Matcher
&NodeMatch
, StringRef ExpectedPrinted
,
54 PrintingPolicyAdjuster PolicyAdjuster
= nullptr) {
55 return PrintedNodeMatches
<Stmt
>(Code
, Args
, NodeMatch
, ExpectedPrinted
, "",
56 PrintStmt
, PolicyAdjuster
);
60 ::testing::AssertionResult
61 PrintedStmtCXXMatches(StdVer Standard
, StringRef Code
, const T
&NodeMatch
,
62 StringRef ExpectedPrinted
,
63 PrintingPolicyAdjuster PolicyAdjuster
= nullptr) {
66 case StdVer::CXX98
: StdOpt
= "-std=c++98"; break;
67 case StdVer::CXX11
: StdOpt
= "-std=c++11"; break;
68 case StdVer::CXX14
: StdOpt
= "-std=c++14"; break;
69 case StdVer::CXX17
: StdOpt
= "-std=c++17"; break;
71 StdOpt
= "-std=c++20";
75 std::vector
<std::string
> Args
= {
79 return PrintedStmtMatches(Code
, Args
, NodeMatch
, ExpectedPrinted
,
84 ::testing::AssertionResult
85 PrintedStmtMSMatches(StringRef Code
, const T
&NodeMatch
,
86 StringRef ExpectedPrinted
,
87 PrintingPolicyAdjuster PolicyAdjuster
= nullptr) {
88 std::vector
<std::string
> Args
= {
90 "-target", "i686-pc-win32",
94 return PrintedStmtMatches(Code
, Args
, NodeMatch
, ExpectedPrinted
,
99 ::testing::AssertionResult
100 PrintedStmtObjCMatches(StringRef Code
, const T
&NodeMatch
,
101 StringRef ExpectedPrinted
,
102 PrintingPolicyAdjuster PolicyAdjuster
= nullptr) {
103 std::vector
<std::string
> Args
= {
105 "-fobjc-runtime=macosx-10.12.0",
107 return PrintedStmtMatches(Code
, Args
, NodeMatch
, ExpectedPrinted
,
111 } // unnamed namespace
113 TEST(StmtPrinter
, TestIntegerLiteral
) {
114 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98
,
117 " 1L, 1l, -1L, 1UL, 1ul,"
120 FunctionBodyMatcher("A"),
121 "1 , -1 , 1U , 1U , "
122 "1L , 1L , -1L , 1UL , 1UL , "
123 "1LL , -1LL , 1ULL"));
124 // Should be: with semicolon
127 TEST(StmtPrinter
, TestMSIntegerLiteral
) {
128 ASSERT_TRUE(PrintedStmtMSMatches(
131 " 1i16, -1i16, 1ui16, "
132 " 1i32, -1i32, 1ui32, "
133 " 1i64, -1i64, 1ui64;"
135 FunctionBodyMatcher("A"),
136 "1i8 , -1i8 , 1Ui8 , "
137 "1i16 , -1i16 , 1Ui16 , "
139 "1LL , -1LL , 1ULL"));
140 // Should be: with semicolon
143 TEST(StmtPrinter
, TestFloatingPointLiteral
) {
144 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98
,
145 "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }",
146 FunctionBodyMatcher("A"),
147 "1.F , -1.F , 1. , -1. , 1.L , -1.L"));
148 // Should be: with semicolon
151 TEST(StmtPrinter
, TestStringLiteralOperatorTemplate_Pack
) {
152 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11
,
154 template <char...> constexpr double operator""_c() { return 42; }
156 constexpr auto waldo = 42_c;
159 FunctionBodyMatcher("A"),
160 "constexpr auto waldo = 42_c;\n"));
163 TEST(StmtPrinter
, TestStringLiteralOperatorTemplate_Class
) {
164 ASSERT_TRUE(PrintedStmtCXXMatches(
168 template <unsigned N> constexpr C(const char (&)[N]) : n(N) {}
171 template <C c> constexpr auto operator""_c() { return c.n; }
173 constexpr auto waldo = "abc
"_c;
176 FunctionBodyMatcher("A"),
177 "constexpr auto waldo = operator\"\"_c<C{4}>();\n"));
180 TEST(StmtPrinter
, TestCXXConversionDeclImplicit
) {
181 ASSERT_TRUE(PrintedStmtCXXMatches(
188 "void foo(A a, A b) {"
191 traverse(TK_AsIs
, cxxMemberCallExpr(anything()).bind("id")), "a & b"));
194 TEST(StmtPrinter
, TestCXXConversionDeclExplicit
) {
195 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11
,
201 "void foo(A a, A b) {"
202 " auto x = (a & b).operator void *();"
204 cxxMemberCallExpr(anything()).bind("id"),
206 // WRONG; Should be: (a & b).operator void *()
209 TEST(StmtPrinter
, TestCXXLamda
) {
210 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11
,
214 lambdaExpr(anything()).bind("id"),
218 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11
,
221 " auto l = [a,b](int c, float d) { };"
223 lambdaExpr(anything()).bind("id"),
224 "[a, b](int c, float d) {\n"
227 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14
,
229 " auto l = [](auto a, int b, auto c, int, auto) { };"
231 lambdaExpr(anything()).bind("id"),
232 "[](auto a, int b, auto c, int, auto) {\n"
236 PrintedStmtCXXMatches(StdVer::CXX20
,
238 " auto l = []<typename T1, class T2, int I,"
239 " template<class, typename> class T3>"
240 " (int a, auto, int, auto d) { };"
242 lambdaExpr(anything()).bind("id"),
243 "[]<typename T1, class T2, int I, template <class, "
244 "typename> class T3>(int a, auto, int, auto d) {\n"
248 TEST(StmtPrinter
, TestNoImplicitBases
) {
249 const char *CPPSource
= R
"(
252 int member() { return field; }
255 // No implicit 'this'.
256 ASSERT_TRUE(PrintedStmtCXXMatches(
257 StdVer::CXX11
, CPPSource
, memberExpr(anything()).bind("id"), "field",
259 [](PrintingPolicy
&PP
) { PP
.SuppressImplicitBase
= true; }));
260 // Print implicit 'this'.
261 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11
,
262 CPPSource
, memberExpr(anything()).bind("id"), "this->field"));
264 const char *ObjCSource
= R
"(
275 // No implicit 'self'.
276 ASSERT_TRUE(PrintedStmtObjCMatches(
277 ObjCSource
, returnStmt().bind("id"), "return ivar;\n",
279 [](PrintingPolicy
&PP
) { PP
.SuppressImplicitBase
= true; }));
280 // Print implicit 'self'.
281 ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource
, returnStmt().bind("id"),
282 "return self->ivar;\n"));
285 TEST(StmtPrinter
, TerseOutputWithLambdas
) {
286 const char *CPPSource
= "auto lamb = []{ return 0; };";
288 // body is printed when TerseOutput is off(default).
289 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11
, CPPSource
,
290 lambdaExpr(anything()).bind("id"),
291 "[] {\n return 0;\n}"));
293 // body not printed when TerseOutput is on.
294 ASSERT_TRUE(PrintedStmtCXXMatches(
295 StdVer::CXX11
, CPPSource
, lambdaExpr(anything()).bind("id"), "[] {}",
297 [](PrintingPolicy
&PP
) { PP
.TerseOutput
= true; }));
300 TEST(StmtPrinter
, ParamsUglified
) {
301 llvm::StringLiteral Code
= R
"cpp(
302 template <typename _T, int _I, template <typename> class _C>
304 return typename _C<_T>::_F(_I, __j);
307 auto Clean
= [](PrintingPolicy
&Policy
) {
308 Policy
.CleanUglifiedParameters
= true;
311 ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14
, Code
,
312 returnStmt().bind("id"),
313 "return typename _C<_T>::_F(_I, __j);\n"));
315 PrintedStmtCXXMatches(StdVer::CXX14
, Code
, returnStmt().bind("id"),
316 "return typename C<T>::_F(I, j);\n", Clean
));