[llvm] r351548 - [ADT] Add streaming operators for llvm::Optional

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 18 04:52:03 PST 2019


Author: labath
Date: Fri Jan 18 04:52:03 2019
New Revision: 351548

URL: http://llvm.org/viewvc/llvm-project?rev=351548&view=rev
Log:
[ADT] Add streaming operators for llvm::Optional

Summary:
The operators simply print the underlying value or "None".

The trickier part of this patch is making sure the streaming operators
work even in unit tests (which was my primary motivation, though I can
also see them being useful elsewhere). Since the stream operator was a
template, implicit conversions did not kick in, and our gtest glue code
was explicitly introducing an implicit conversion to make sure other
implicit conversions do not kick in :P. I resolve that by specializing
llvm_gtest::StreamSwitch for llvm:Optional<T>.

Reviewers: sammccall, dblaikie

Reviewed By: sammccall

Subscribers: mgorny, dexonsmith, kristina, llvm-commits

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

Added:
    llvm/trunk/lib/Support/Optional.cpp
Modified:
    llvm/trunk/include/llvm/ADT/Optional.h
    llvm/trunk/lib/Support/CMakeLists.txt
    llvm/trunk/unittests/ADT/OptionalTest.cpp
    llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h

Modified: llvm/trunk/include/llvm/ADT/Optional.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Optional.h?rev=351548&r1=351547&r2=351548&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/Optional.h (original)
+++ llvm/trunk/include/llvm/ADT/Optional.h Fri Jan 18 04:52:03 2019
@@ -27,6 +27,8 @@
 
 namespace llvm {
 
+class raw_ostream;
+
 namespace optional_detail {
 /// Storage for any type.
 template <typename T, bool = isPodLike<T>::value> struct OptionalStorage {
@@ -323,6 +325,18 @@ template <typename T> bool operator>=(co
   return !(X < Y);
 }
 
+raw_ostream &operator<<(raw_ostream &OS, NoneType);
+
+template <typename T, typename = decltype(std::declval<raw_ostream &>()
+                                          << std::declval<const T &>())>
+raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
+  if (O)
+    OS << *O;
+  else
+    OS << None;
+  return OS;
+}
+
 } // end namespace llvm
 
 #endif // LLVM_ADT_OPTIONAL_H

Modified: llvm/trunk/lib/Support/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CMakeLists.txt?rev=351548&r1=351547&r2=351548&view=diff
==============================================================================
--- llvm/trunk/lib/Support/CMakeLists.txt (original)
+++ llvm/trunk/lib/Support/CMakeLists.txt Fri Jan 18 04:52:03 2019
@@ -106,6 +106,7 @@ add_llvm_library(LLVMSupport
   MemoryBuffer.cpp
   MD5.cpp
   NativeFormatting.cpp
+  Optional.cpp
   Options.cpp
   Parallel.cpp
   PluginLoader.cpp

Added: llvm/trunk/lib/Support/Optional.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Optional.cpp?rev=351548&view=auto
==============================================================================
--- llvm/trunk/lib/Support/Optional.cpp (added)
+++ llvm/trunk/lib/Support/Optional.cpp Fri Jan 18 04:52:03 2019
@@ -0,0 +1,15 @@
+//===- Optional.cpp - Optional values ---------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+llvm::raw_ostream &llvm::operator<<(raw_ostream &OS, NoneType) {
+  return OS << "None";
+}

Modified: llvm/trunk/unittests/ADT/OptionalTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/OptionalTest.cpp?rev=351548&r1=351547&r2=351548&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/OptionalTest.cpp (original)
+++ llvm/trunk/unittests/ADT/OptionalTest.cpp Fri Jan 18 04:52:03 2019
@@ -8,6 +8,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -518,5 +521,52 @@ TEST_F(OptionalTest, OperatorGreaterEqua
   CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
 }
 
-} // end anonymous namespace
+struct ComparableAndStreamable {
+  friend bool operator==(ComparableAndStreamable,
+                         ComparableAndStreamable) LLVM_ATTRIBUTE_USED {
+    return true;
+  }
+
+  friend raw_ostream &operator<<(raw_ostream &OS, ComparableAndStreamable) {
+    return OS << "ComparableAndStreamable";
+  }
+
+  static Optional<ComparableAndStreamable> get() {
+    return ComparableAndStreamable();
+  }
+};
+
+TEST_F(OptionalTest, StreamOperator) {
+  auto to_string = [](Optional<ComparableAndStreamable> O) {
+    SmallString<16> S;
+    raw_svector_ostream OS(S);
+    OS << O;
+    return S;
+  };
+  EXPECT_EQ("ComparableAndStreamable",
+            to_string(ComparableAndStreamable::get()));
+  EXPECT_EQ("None", to_string(None));
+}
+
+struct Comparable {
+  friend bool operator==(Comparable, Comparable) LLVM_ATTRIBUTE_USED {
+    return true;
+  }
+  static Optional<Comparable> get() { return Comparable(); }
+};
 
+TEST_F(OptionalTest, UseInUnitTests) {
+  // Test that we invoke the streaming operators when pretty-printing values in
+  // EXPECT macros.
+  EXPECT_NONFATAL_FAILURE(EXPECT_EQ(llvm::None, ComparableAndStreamable::get()),
+                          R"(Expected: llvm::None
+      Which is: None
+To be equal to: ComparableAndStreamable::get()
+      Which is: ComparableAndStreamable)");
+
+  // Test that it is still possible to compare objects which do not have a
+  // custom streaming operator.
+  EXPECT_NONFATAL_FAILURE(EXPECT_EQ(llvm::None, Comparable::get()), "object");
+}
+
+} // end anonymous namespace

Modified: 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=351548&r1=351547&r2=351548&view=diff
==============================================================================
--- llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h (original)
+++ llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h Fri Jan 18 04:52:03 2019
@@ -42,8 +42,9 @@ auto printable(const T &V) -> decltype(S
 // 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/ADT/Optional.h"
 #include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/raw_ostream.h"
 #include <ostream>
 namespace llvm_gtest {
 
@@ -68,6 +69,18 @@ struct StreamSwitch<T, decltype((void)(s
                                        << ConvertibleTo<const T &>()))> {
   static const RawStreamProxy<T> printable(const T &V) { return {V}; }
 };
+
+// llvm::Optional has a template operator<<, which means it will not accept any
+// implicit conversions, so we need to special-case it here.
+template <typename T>
+struct StreamSwitch<llvm::Optional<T>,
+                    decltype((void)(std::declval<llvm::raw_ostream &>()
+                                    << std::declval<llvm::Optional<T>>()))> {
+  static const RawStreamProxy<llvm::Optional<T>>
+  printable(const llvm::Optional<T> &V) {
+    return {V};
+  }
+};
 } // namespace llvm_gtest
 #endif  // !GTEST_NO_LLVM_RAW_OSTREAM
 




More information about the llvm-commits mailing list