217 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- unittests/AST/StmtPrinterTest.cpp --- Statement printer tests ------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file contains tests for Stmt::printPretty() and related methods.
 | |
| //
 | |
| // Search this file for WRONG to see test cases that are producing something
 | |
| // completely wrong, invalid C++ or just misleading.
 | |
| //
 | |
| // These tests have a coding convention:
 | |
| // * statements to be printed should be contained within a function named 'A'
 | |
| //   unless it should have some special name (e.g., 'operator+');
 | |
| // * additional helper declarations are 'Z', 'Y', 'X' and so on.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "clang/AST/ASTContext.h"
 | |
| #include "clang/ASTMatchers/ASTMatchFinder.h"
 | |
| #include "clang/Tooling/Tooling.h"
 | |
| #include "llvm/ADT/SmallString.h"
 | |
| #include "gtest/gtest.h"
 | |
| 
 | |
| using namespace clang;
 | |
| using namespace ast_matchers;
 | |
| using namespace tooling;
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S) {
 | |
|   assert(S != nullptr && "Expected non-null Stmt");
 | |
|   PrintingPolicy Policy = Context->getPrintingPolicy();
 | |
|   S->printPretty(Out, /*Helper*/ nullptr, Policy);
 | |
| }
 | |
| 
 | |
| class PrintMatch : public MatchFinder::MatchCallback {
 | |
|   SmallString<1024> Printed;
 | |
|   unsigned NumFoundStmts;
 | |
| 
 | |
| public:
 | |
|   PrintMatch() : NumFoundStmts(0) {}
 | |
| 
 | |
|   virtual void run(const MatchFinder::MatchResult &Result) {
 | |
|     const Stmt *S = Result.Nodes.getStmtAs<Stmt>("id");
 | |
|     if (!S)
 | |
|       return;
 | |
|     NumFoundStmts++;
 | |
|     if (NumFoundStmts > 1)
 | |
|       return;
 | |
| 
 | |
|     llvm::raw_svector_ostream Out(Printed);
 | |
|     PrintStmt(Out, Result.Context, S);
 | |
|   }
 | |
| 
 | |
|   StringRef getPrinted() const {
 | |
|     return Printed;
 | |
|   }
 | |
| 
 | |
|   unsigned getNumFoundStmts() const {
 | |
|     return NumFoundStmts;
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <typename T>
 | |
| ::testing::AssertionResult
 | |
| PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
 | |
|                    const T &NodeMatch, StringRef ExpectedPrinted) {
 | |
| 
 | |
|   PrintMatch Printer;
 | |
|   MatchFinder Finder;
 | |
|   Finder.addMatcher(NodeMatch, &Printer);
 | |
|   std::unique_ptr<FrontendActionFactory> Factory(
 | |
|       newFrontendActionFactory(&Finder));
 | |
| 
 | |
|   if (!runToolOnCodeWithArgs(Factory->create(), Code, Args))
 | |
|     return testing::AssertionFailure()
 | |
|       << "Parsing error in \"" << Code.str() << "\"";
 | |
| 
 | |
|   if (Printer.getNumFoundStmts() == 0)
 | |
|     return testing::AssertionFailure()
 | |
|         << "Matcher didn't find any statements";
 | |
| 
 | |
|   if (Printer.getNumFoundStmts() > 1)
 | |
|     return testing::AssertionFailure()
 | |
|         << "Matcher should match only one statement "
 | |
|            "(found " << Printer.getNumFoundStmts() << ")";
 | |
| 
 | |
|   if (Printer.getPrinted() != ExpectedPrinted)
 | |
|     return ::testing::AssertionFailure()
 | |
|       << "Expected \"" << ExpectedPrinted.str() << "\", "
 | |
|          "got \"" << Printer.getPrinted().str() << "\"";
 | |
| 
 | |
|   return ::testing::AssertionSuccess();
 | |
| }
 | |
| 
 | |
| ::testing::AssertionResult
 | |
| PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch,
 | |
|                         StringRef ExpectedPrinted) {
 | |
|   std::vector<std::string> Args;
 | |
|   Args.push_back("-std=c++98");
 | |
|   Args.push_back("-Wno-unused-value");
 | |
|   return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
 | |
| }
 | |
| 
 | |
| ::testing::AssertionResult PrintedStmtCXX98Matches(
 | |
|                                               StringRef Code,
 | |
|                                               StringRef ContainingFunction,
 | |
|                                               StringRef ExpectedPrinted) {
 | |
|   std::vector<std::string> Args;
 | |
|   Args.push_back("-std=c++98");
 | |
|   Args.push_back("-Wno-unused-value");
 | |
|   return PrintedStmtMatches(Code,
 | |
|                             Args,
 | |
|                             functionDecl(hasName(ContainingFunction),
 | |
|                                          has(compoundStmt(has(stmt().bind("id"))))),
 | |
|                             ExpectedPrinted);
 | |
| }
 | |
| 
 | |
| ::testing::AssertionResult
 | |
| PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
 | |
|                         StringRef ExpectedPrinted) {
 | |
|   std::vector<std::string> Args;
 | |
|   Args.push_back("-std=c++11");
 | |
|   Args.push_back("-Wno-unused-value");
 | |
|   return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
 | |
| }
 | |
| 
 | |
| ::testing::AssertionResult PrintedStmtMSMatches(
 | |
|                                               StringRef Code,
 | |
|                                               StringRef ContainingFunction,
 | |
|                                               StringRef ExpectedPrinted) {
 | |
|   std::vector<std::string> Args;
 | |
|   Args.push_back("-target");
 | |
|   Args.push_back("i686-pc-win32");
 | |
|   Args.push_back("-std=c++98");
 | |
|   Args.push_back("-fms-extensions");
 | |
|   Args.push_back("-Wno-unused-value");
 | |
|   return PrintedStmtMatches(Code,
 | |
|                             Args,
 | |
|                             functionDecl(hasName(ContainingFunction),
 | |
|                                          has(compoundStmt(has(stmt().bind("id"))))),
 | |
|                             ExpectedPrinted);
 | |
| }
 | |
| 
 | |
| } // unnamed namespace
 | |
| 
 | |
| TEST(StmtPrinter, TestIntegerLiteral) {
 | |
|   ASSERT_TRUE(PrintedStmtCXX98Matches(
 | |
|     "void A() {"
 | |
|     "  1, -1, 1U, 1u,"
 | |
|     "  1L, 1l, -1L, 1UL, 1ul,"
 | |
|     "  1LL, -1LL, 1ULL;"
 | |
|     "}",
 | |
|     "A",
 | |
|     "1 , -1 , 1U , 1U , "
 | |
|     "1L , 1L , -1L , 1UL , 1UL , "
 | |
|     "1LL , -1LL , 1ULL"));
 | |
|     // Should be: with semicolon
 | |
| }
 | |
| 
 | |
| TEST(StmtPrinter, TestMSIntegerLiteral) {
 | |
|   ASSERT_TRUE(PrintedStmtMSMatches(
 | |
|     "void A() {"
 | |
|     "  1i8, -1i8, 1ui8, "
 | |
|     "  1i16, -1i16, 1ui16, "
 | |
|     "  1i32, -1i32, 1ui32, "
 | |
|     "  1i64, -1i64, 1ui64;"
 | |
|     "}",
 | |
|     "A",
 | |
|     "1i8 , -1i8 , 1Ui8 , "
 | |
|     "1i16 , -1i16 , 1Ui16 , "
 | |
|     "1 , -1 , 1U , "
 | |
|     "1LL , -1LL , 1ULL"));
 | |
|     // Should be: with semicolon
 | |
| }
 | |
| 
 | |
| TEST(StmtPrinter, TestFloatingPointLiteral) {
 | |
|   ASSERT_TRUE(PrintedStmtCXX98Matches(
 | |
|     "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }",
 | |
|     "A",
 | |
|     "1.F , -1.F , 1. , -1. , 1.L , -1.L"));
 | |
|     // Should be: with semicolon
 | |
| }
 | |
| 
 | |
| TEST(StmtPrinter, TestCXXConversionDeclImplicit) {
 | |
|   ASSERT_TRUE(PrintedStmtCXX98Matches(
 | |
|     "struct A {"
 | |
|       "operator void *();"
 | |
|       "A operator&(A);"
 | |
|     "};"
 | |
|     "void bar(void *);"
 | |
|     "void foo(A a, A b) {"
 | |
|     "  bar(a & b);"
 | |
|     "}",
 | |
|     memberCallExpr(anything()).bind("id"),
 | |
|     "a & b"));
 | |
| }
 | |
| 
 | |
| TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
 | |
|   ASSERT_TRUE(PrintedStmtCXX11Matches(
 | |
|     "struct A {"
 | |
|       "operator void *();"
 | |
|       "A operator&(A);"
 | |
|     "};"
 | |
|     "void bar(void *);"
 | |
|     "void foo(A a, A b) {"
 | |
|     "  auto x = (a & b).operator void *();"
 | |
|     "}",
 | |
|     memberCallExpr(anything()).bind("id"),
 | |
|     "(a & b)"));
 | |
|     // WRONG; Should be: (a & b).operator void *()
 | |
| }
 |