[llvm] r324876 - [gtest] Support raw_ostream printing functions more comprehensively.

Sam McCall via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 12 02:20:09 PST 2018


Author: sammccall
Date: Mon Feb 12 02:20:09 2018
New Revision: 324876

URL: http://llvm.org/viewvc/llvm-project?rev=324876&view=rev
Log:
[gtest] Support raw_ostream printing functions more comprehensively.

Summary:
These are functions like operator<<(raw_ostream&, Foo).

Previously these were only supported for messages. In the assertion
  EXPECT_EQ(A, B) << C;
the local modifications would explicitly try to use raw_ostream printing for C.
However A and B would look for a std::ostream printing function, and often fall
back to gtest's default "168 byte object <00 01 FE 42 ...>".

This patch pulls out the raw_ostream support into a new header under `custom/`.

I changed the mechanism: instead of a convertible stream, we wrap the printed
value in a proxy object to allow it to be sent to a std::ostream.
I think the new way is clearer.

I also changed the policy: we prefer raw_ostream printers over std::ostream
ones. This is because the fallback printers are defined using std::ostream,
while all the raw_ostream printers should be "good".

Reviewers: ilya-biryukov, chandlerc

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D43091

Added:
    llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h
Modified:
    llvm/trunk/utils/unittest/googletest/include/gtest/gtest-message.h
    llvm/trunk/utils/unittest/googletest/include/gtest/gtest-printers.h

Modified: llvm/trunk/utils/unittest/googletest/include/gtest/gtest-message.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/unittest/googletest/include/gtest/gtest-message.h?rev=324876&r1=324875&r2=324876&view=diff
==============================================================================
--- llvm/trunk/utils/unittest/googletest/include/gtest/gtest-message.h (original)
+++ llvm/trunk/utils/unittest/googletest/include/gtest/gtest-message.h Mon Feb 12 02:20:09 2018
@@ -49,36 +49,7 @@
 #include <limits>
 
 #include "gtest/internal/gtest-port.h"
-
-#if !GTEST_NO_LLVM_RAW_OSTREAM
-#include "llvm/Support/raw_os_ostream.h"
-
-// LLVM INTERNAL CHANGE: To allow operator<< to work with both
-// std::ostreams and LLVM's raw_ostreams, we define a special
-// std::ostream with an implicit conversion to raw_ostream& and stream
-// to that.  This causes the compiler to prefer std::ostream overloads
-// but still find raw_ostream& overloads.
-namespace llvm {
-class convertible_fwd_ostream : public std::ostream {
-  raw_os_ostream ros_;
-
-public:
-  convertible_fwd_ostream(std::ostream& os)
-    : std::ostream(os.rdbuf()), ros_(*this) {}
-  operator raw_ostream&() { return ros_; }
-};
-}
-template <typename T>
-inline void GTestStreamToHelper(std::ostream& os, const T& val) {
-  llvm::convertible_fwd_ostream cos(os);
-  cos << val;
-}
-#else
-template <typename T>
-inline void GTestStreamToHelper(std::ostream& os, const T& val) {
-  os << val;
-}
-#endif
+#include "gtest/internal/custom/raw-ostream.h"
 
 // Ensures that there is at least one operator<< in the global namespace.
 // See Message& operator<<(...) below for why.
@@ -157,12 +128,8 @@ class GTEST_API_ Message {
     // from the global namespace.  With this using declaration,
     // overloads of << defined in the global namespace and those
     // visible via Koenig lookup are both exposed in this function.
-#if GTEST_NO_LLVM_RAW_OSTREAM
     using ::operator <<;
-    *ss_ << val;
-#else
-    ::GTestStreamToHelper(*ss_, val);
-#endif
+    *ss_ << llvm_gtest::printable(val);
     return *this;
   }
 
@@ -184,11 +151,7 @@ class GTEST_API_ Message {
     if (pointer == NULL) {
       *ss_ << "(null)";
     } else {
-#if GTEST_NO_LLVM_RAW_OSTREAM
-      *ss_ << pointer;
-#else
-      ::GTestStreamToHelper(*ss_, pointer);
-#endif
+      *ss_ << llvm_gtest::printable(pointer);
     }
     return *this;
   }

Modified: llvm/trunk/utils/unittest/googletest/include/gtest/gtest-printers.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/unittest/googletest/include/gtest/gtest-printers.h?rev=324876&r1=324875&r2=324876&view=diff
==============================================================================
--- llvm/trunk/utils/unittest/googletest/include/gtest/gtest-printers.h (original)
+++ llvm/trunk/utils/unittest/googletest/include/gtest/gtest-printers.h Mon Feb 12 02:20:09 2018
@@ -102,6 +102,7 @@
 #include <vector>
 #include "gtest/internal/gtest-port.h"
 #include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/custom/raw-ostream.h"
 
 #if GTEST_HAS_STD_TUPLE_
 # include <tuple>
@@ -246,7 +247,7 @@ void DefaultPrintNonContainerTo(const T&
   // impossible to define #1 (e.g. when foo is ::std, defining
   // anything in it is undefined behavior unless you are a compiler
   // vendor.).
-  *os << value;
+  *os << ::llvm_gtest::printable(value);
 }
 
 }  // namespace testing_internal

Added: llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h?rev=324876&view=auto
==============================================================================
--- llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h (added)
+++ llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h Mon Feb 12 02:20:09 2018
@@ -0,0 +1,74 @@
+//===-- raw-ostream.h - Support for printing using raw_ostream --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file is not part of gtest, but extends it to support LLVM libraries.
+// This is not a public API for testing - it's a detail of LLVM's gtest.
+//
+// gtest allows providing printers for custom types by defining operator<<.
+// In LLVM, operator<< usually takes llvm:raw_ostream& instead of std::ostream&.
+//
+// This file defines a template printable(V), which returns a version of V that
+// can be streamed into a std::ostream.
+//
+// This interface is chosen so that in the default case (printable(V) is V),
+// the main gtest code calls operator<<(OS, V) itself. gtest-printers carefully
+// controls the lookup to enable fallback printing (see testing::internal2).
+//===----------------------------------------------------------------------===//
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_
+
+namespace llvm_gtest {
+// StreamSwitch is a trait that tells us how to stream a T into a std::ostream.
+// By default, we just stream the T directly. We'll specialize this later.
+template <typename T, typename Enable = void> struct StreamSwitch {
+  static const T& printable(const T& V) { return V; }
+};
+
+// printable() returns a version of its argument that can be streamed into a
+// std::ostream. This may be the argument itself, or some other representation.
+template <typename T>
+auto printable(const T &V) -> decltype(StreamSwitch<T>::printable(V)) {
+  // We delegate to the trait, to allow partial specialization.
+  return StreamSwitch<T>::printable(V);
+}
+} // namespace llvm_gtest
+
+// If raw_ostream support is enabled, we specialize for types with operator<<
+// that takes a raw_ostream.
+#if !GTEST_NO_LLVM_RAW_OSTREAM
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include <ostream>
+namespace llvm_gtest {
+
+// The printable() of a raw_ostream-enabled type T is a RawStreamProxy<T>.
+// It uses raw_os_ostream to write the wrapped value to a std::ostream.
+template <typename T>
+struct RawStreamProxy {
+  const T& V;
+  friend std::ostream &operator<<(std::ostream &S, const RawStreamProxy<T> &V) {
+    llvm::raw_os_ostream OS(S);
+    OS << V.V;
+    return S;
+  }
+};
+
+// We enable raw_ostream treatment if `(raw_ostream&) << (const T&)` is valid.
+// We don't want implicit conversions on the RHS (e.g. to bool!), so "consume"
+// the possible conversion by passing something convertible to const T& instead.
+template <typename T> struct ConvertibleTo { operator T(); };
+template <typename T>
+struct StreamSwitch<T, decltype((void)(std::declval<llvm::raw_ostream &>()
+                                       << ConvertibleTo<const T &>()))> {
+  static const RawStreamProxy<T> printable(const T &V) { return {V}; }
+};
+} // namespace llvm_gtest
+#endif  // !GTEST_NO_LLVM_RAW_OSTREAM
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_




More information about the llvm-commits mailing list