1 //===- unittests/AST/StmtPrinterTest.cpp --- Statement printer tests ------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains tests for Stmt::printPretty() and related methods. 11 // 12 // Search this file for WRONG to see test cases that are producing something 13 // completely wrong, invalid C++ or just misleading. 14 // 15 // These tests have a coding convention: 16 // * statements to be printed should be contained within a function named 'A' 17 // unless it should have some special name (e.g., 'operator+'); 18 // * additional helper declarations are 'Z', 'Y', 'X' and so on. 19 // 20 //===----------------------------------------------------------------------===// 21 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 28 using namespace clang; 29 using namespace ast_matchers; 30 using namespace tooling; 31 32 namespace { 33 34 using PolicyAdjusterType = 35 Optional<llvm::function_ref<void(PrintingPolicy &Policy)>>; 36 37 void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S, 38 PolicyAdjusterType PolicyAdjuster) { 39 assert(S != nullptr && "Expected non-null Stmt"); 40 PrintingPolicy Policy = Context->getPrintingPolicy(); 41 if (PolicyAdjuster) 42 (*PolicyAdjuster)(Policy); 43 S->printPretty(Out, /*Helper*/ nullptr, Policy); 44 } 45 46 class PrintMatch : public MatchFinder::MatchCallback { 47 SmallString<1024> Printed; 48 unsigned NumFoundStmts; 49 PolicyAdjusterType PolicyAdjuster; 50 51 public: 52 PrintMatch(PolicyAdjusterType PolicyAdjuster) 53 : NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {} 54 55 void run(const MatchFinder::MatchResult &Result) override { 56 const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id"); 57 if (!S) 58 return; 59 NumFoundStmts++; 60 if (NumFoundStmts > 1) 61 return; 62 63 llvm::raw_svector_ostream Out(Printed); 64 PrintStmt(Out, Result.Context, S, PolicyAdjuster); 65 } 66 67 StringRef getPrinted() const { 68 return Printed; 69 } 70 71 unsigned getNumFoundStmts() const { 72 return NumFoundStmts; 73 } 74 }; 75 76 template <typename T> 77 ::testing::AssertionResult 78 PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args, 79 const T &NodeMatch, StringRef ExpectedPrinted, 80 PolicyAdjusterType PolicyAdjuster = None) { 81 82 PrintMatch Printer(PolicyAdjuster); 83 MatchFinder Finder; 84 Finder.addMatcher(NodeMatch, &Printer); 85 std::unique_ptr<FrontendActionFactory> Factory( 86 newFrontendActionFactory(&Finder)); 87 88 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) 89 return testing::AssertionFailure() 90 << "Parsing error in \"" << Code.str() << "\""; 91 92 if (Printer.getNumFoundStmts() == 0) 93 return testing::AssertionFailure() 94 << "Matcher didn't find any statements"; 95 96 if (Printer.getNumFoundStmts() > 1) 97 return testing::AssertionFailure() 98 << "Matcher should match only one statement " 99 "(found " << Printer.getNumFoundStmts() << ")"; 100 101 if (Printer.getPrinted() != ExpectedPrinted) 102 return ::testing::AssertionFailure() 103 << "Expected \"" << ExpectedPrinted.str() << "\", " 104 "got \"" << Printer.getPrinted().str() << "\""; 105 106 return ::testing::AssertionSuccess(); 107 } 108 109 ::testing::AssertionResult 110 PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch, 111 StringRef ExpectedPrinted) { 112 std::vector<std::string> Args; 113 Args.push_back("-std=c++98"); 114 Args.push_back("-Wno-unused-value"); 115 return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted); 116 } 117 118 ::testing::AssertionResult PrintedStmtCXX98Matches( 119 StringRef Code, 120 StringRef ContainingFunction, 121 StringRef ExpectedPrinted) { 122 std::vector<std::string> Args; 123 Args.push_back("-std=c++98"); 124 Args.push_back("-Wno-unused-value"); 125 return PrintedStmtMatches(Code, 126 Args, 127 functionDecl(hasName(ContainingFunction), 128 has(compoundStmt(has(stmt().bind("id"))))), 129 ExpectedPrinted); 130 } 131 132 ::testing::AssertionResult 133 PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch, 134 StringRef ExpectedPrinted, 135 PolicyAdjusterType PolicyAdjuster = None) { 136 std::vector<std::string> Args; 137 Args.push_back("-std=c++11"); 138 Args.push_back("-Wno-unused-value"); 139 return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, 140 PolicyAdjuster); 141 } 142 143 ::testing::AssertionResult PrintedStmtMSMatches( 144 StringRef Code, 145 StringRef ContainingFunction, 146 StringRef ExpectedPrinted) { 147 std::vector<std::string> Args; 148 Args.push_back("-target"); 149 Args.push_back("i686-pc-win32"); 150 Args.push_back("-std=c++98"); 151 Args.push_back("-fms-extensions"); 152 Args.push_back("-Wno-unused-value"); 153 return PrintedStmtMatches(Code, 154 Args, 155 functionDecl(hasName(ContainingFunction), 156 has(compoundStmt(has(stmt().bind("id"))))), 157 ExpectedPrinted); 158 } 159 160 ::testing::AssertionResult 161 PrintedStmtObjCMatches(StringRef Code, const StatementMatcher &NodeMatch, 162 StringRef ExpectedPrinted, 163 PolicyAdjusterType PolicyAdjuster = None) { 164 std::vector<std::string> Args; 165 Args.push_back("-ObjC"); 166 Args.push_back("-fobjc-runtime=macosx-10.12.0"); 167 return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, 168 PolicyAdjuster); 169 } 170 171 } // unnamed namespace 172 173 TEST(StmtPrinter, TestIntegerLiteral) { 174 ASSERT_TRUE(PrintedStmtCXX98Matches( 175 "void A() {" 176 " 1, -1, 1U, 1u," 177 " 1L, 1l, -1L, 1UL, 1ul," 178 " 1LL, -1LL, 1ULL;" 179 "}", 180 "A", 181 "1 , -1 , 1U , 1U , " 182 "1L , 1L , -1L , 1UL , 1UL , " 183 "1LL , -1LL , 1ULL")); 184 // Should be: with semicolon 185 } 186 187 TEST(StmtPrinter, TestMSIntegerLiteral) { 188 ASSERT_TRUE(PrintedStmtMSMatches( 189 "void A() {" 190 " 1i8, -1i8, 1ui8, " 191 " 1i16, -1i16, 1ui16, " 192 " 1i32, -1i32, 1ui32, " 193 " 1i64, -1i64, 1ui64;" 194 "}", 195 "A", 196 "1i8 , -1i8 , 1Ui8 , " 197 "1i16 , -1i16 , 1Ui16 , " 198 "1 , -1 , 1U , " 199 "1LL , -1LL , 1ULL")); 200 // Should be: with semicolon 201 } 202 203 TEST(StmtPrinter, TestFloatingPointLiteral) { 204 ASSERT_TRUE(PrintedStmtCXX98Matches( 205 "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }", 206 "A", 207 "1.F , -1.F , 1. , -1. , 1.L , -1.L")); 208 // Should be: with semicolon 209 } 210 211 TEST(StmtPrinter, TestCXXConversionDeclImplicit) { 212 ASSERT_TRUE(PrintedStmtCXX98Matches( 213 "struct A {" 214 "operator void *();" 215 "A operator&(A);" 216 "};" 217 "void bar(void *);" 218 "void foo(A a, A b) {" 219 " bar(a & b);" 220 "}", 221 cxxMemberCallExpr(anything()).bind("id"), 222 "a & b")); 223 } 224 225 TEST(StmtPrinter, TestCXXConversionDeclExplicit) { 226 ASSERT_TRUE(PrintedStmtCXX11Matches( 227 "struct A {" 228 "operator void *();" 229 "A operator&(A);" 230 "};" 231 "void bar(void *);" 232 "void foo(A a, A b) {" 233 " auto x = (a & b).operator void *();" 234 "}", 235 cxxMemberCallExpr(anything()).bind("id"), 236 "(a & b)")); 237 // WRONG; Should be: (a & b).operator void *() 238 } 239 240 TEST(StmtPrinter, TestNoImplicitBases) { 241 const char *CPPSource = R"( 242 class A { 243 int field; 244 int member() { return field; } 245 }; 246 )"; 247 // No implicit 'this'. 248 ASSERT_TRUE(PrintedStmtCXX11Matches( 249 CPPSource, memberExpr(anything()).bind("id"), "field", 250 PolicyAdjusterType( 251 [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; }))); 252 // Print implicit 'this'. 253 ASSERT_TRUE(PrintedStmtCXX11Matches( 254 CPPSource, memberExpr(anything()).bind("id"), "this->field")); 255 256 const char *ObjCSource = R"( 257 @interface I { 258 int ivar; 259 } 260 @end 261 @implementation I 262 - (int) method { 263 return ivar; 264 } 265 @end 266 )"; 267 // No implicit 'self'. 268 ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"), 269 "return ivar;\n", 270 PolicyAdjusterType([](PrintingPolicy &PP) { 271 PP.SuppressImplicitBase = true; 272 }))); 273 // Print implicit 'self'. 274 ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"), 275 "return self->ivar;\n")); 276 } 277