Clang Project

clang_source_code/unittests/AST/StmtPrinterTest.cpp
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
21#include "ASTPrint.h"
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"
27
28using namespace clang;
29using namespace ast_matchers;
30using namespace tooling;
31
32namespace {
33
34enum class StdVer { CXX98CXX11CXX14CXX17CXX2a };
35
36DeclarationMatcher FunctionBodyMatcher(StringRef ContainingFunction) {
37  return functionDecl(hasName(ContainingFunction),
38                      has(compoundStmt(has(stmt().bind("id")))));
39}
40
41template <typename T>
42::testing::AssertionResult
43PrintedStmtCXXMatches(StdVer Standard, StringRef Code, const T &NodeMatch,
44                      StringRef ExpectedPrinted,
45                      PolicyAdjusterType PolicyAdjuster = None) {
46  const char *StdOpt;
47  switch (Standard) {
48  case StdVer::CXX98StdOpt = "-std=c++98"break;
49  case StdVer::CXX11StdOpt = "-std=c++11"break;
50  case StdVer::CXX14StdOpt = "-std=c++14"break;
51  case StdVer::CXX17StdOpt = "-std=c++17"break;
52  case StdVer::CXX2aStdOpt = "-std=c++2a"break;
53  }
54
55  std::vector<std::stringArgs = {
56    StdOpt,
57    "-Wno-unused-value",
58  };
59  return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
60                            PolicyAdjuster);
61}
62
63template <typename T>
64::testing::AssertionResult
65PrintedStmtMSMatches(StringRef Code, const T &NodeMatch,
66                     StringRef ExpectedPrinted,
67                     PolicyAdjusterType PolicyAdjuster = None) {
68  std::vector<std::stringArgs = {
69    "-std=c++98",
70    "-target""i686-pc-win32",
71    "-fms-extensions",
72    "-Wno-unused-value",
73  };
74  return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
75                            PolicyAdjuster);
76}
77
78template <typename T>
79::testing::AssertionResult
80PrintedStmtObjCMatches(StringRef Code, const T &NodeMatch,
81                       StringRef ExpectedPrinted,
82                       PolicyAdjusterType PolicyAdjuster = None) {
83  std::vector<std::stringArgs = {
84    "-ObjC",
85    "-fobjc-runtime=macosx-10.12.0",
86  };
87  return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
88                            PolicyAdjuster);
89}
90
91// unnamed namespace
92
93TEST(StmtPrinter, TestIntegerLiteral) {
94  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
95    "void A() {"
96    "  1, -1, 1U, 1u,"
97    "  1L, 1l, -1L, 1UL, 1ul,"
98    "  1LL, -1LL, 1ULL;"
99    "}",
100    FunctionBodyMatcher("A"),
101    "1 , -1 , 1U , 1U , "
102    "1L , 1L , -1L , 1UL , 1UL , "
103    "1LL , -1LL , 1ULL"));
104    // Should be: with semicolon
105}
106
107TEST(StmtPrinter, TestMSIntegerLiteral) {
108  ASSERT_TRUE(PrintedStmtMSMatches(
109    "void A() {"
110    "  1i8, -1i8, 1ui8, "
111    "  1i16, -1i16, 1ui16, "
112    "  1i32, -1i32, 1ui32, "
113    "  1i64, -1i64, 1ui64;"
114    "}",
115    FunctionBodyMatcher("A"),
116    "1i8 , -1i8 , 1Ui8 , "
117    "1i16 , -1i16 , 1Ui16 , "
118    "1 , -1 , 1U , "
119    "1LL , -1LL , 1ULL"));
120    // Should be: with semicolon
121}
122
123TEST(StmtPrinter, TestFloatingPointLiteral) {
124  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
125    "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }",
126    FunctionBodyMatcher("A"),
127    "1.F , -1.F , 1. , -1. , 1.L , -1.L"));
128    // Should be: with semicolon
129}
130
131TEST(StmtPrinter, TestCXXConversionDeclImplicit) {
132  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
133    "struct A {"
134      "operator void *();"
135      "A operator&(A);"
136    "};"
137    "void bar(void *);"
138    "void foo(A a, A b) {"
139    "  bar(a & b);"
140    "}",
141    cxxMemberCallExpr(anything()).bind("id"),
142    "a & b"));
143}
144
145TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
146  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
147    "struct A {"
148      "operator void *();"
149      "A operator&(A);"
150    "};"
151    "void bar(void *);"
152    "void foo(A a, A b) {"
153    "  auto x = (a & b).operator void *();"
154    "}",
155    cxxMemberCallExpr(anything()).bind("id"),
156    "(a & b)"));
157    // WRONG; Should be: (a & b).operator void *()
158}
159
160TEST(StmtPrinter, TestNoImplicitBases) {
161  const char *CPPSource = R"(
162class A {
163  int field;
164  int member() { return field; }
165};
166)";
167  // No implicit 'this'.
168  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
169      CPPSource, memberExpr(anything()).bind("id"), "field",
170      PolicyAdjusterType(
171          [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; })));
172  // Print implicit 'this'.
173  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
174      CPPSource, memberExpr(anything()).bind("id"), "this->field"));
175
176  const char *ObjCSource = R"(
177@interface I {
178   int ivar;
179}
180@end
181@implementation I
182- (int) method {
183  return ivar;
184}
185@end
186      )";
187  // No implicit 'self'.
188  ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
189                                     "return ivar;\n",
190                                     PolicyAdjusterType([](PrintingPolicy &PP) {
191                                       PP.SuppressImplicitBase = true;
192                                     })));
193  // Print implicit 'self'.
194  ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
195                                     "return self->ivar;\n"));
196}
197