diff options
-rw-r--r-- | llvm/include/llvm/ADT/Optional.h | 14 | ||||
-rw-r--r-- | llvm/lib/Support/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Support/Optional.cpp | 15 | ||||
-rw-r--r-- | llvm/unittests/ADT/OptionalTest.cpp | 52 | ||||
-rw-r--r-- | llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h | 15 |
5 files changed, 95 insertions, 2 deletions
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index 76937d632ae..56eafb156e8 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -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>=(const T &X, const Optional<T> &Y) { 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 diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 2a6810672b1..7e791594587 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -106,6 +106,7 @@ add_llvm_library(LLVMSupport MemoryBuffer.cpp MD5.cpp NativeFormatting.cpp + Optional.cpp Options.cpp Parallel.cpp PluginLoader.cpp diff --git a/llvm/lib/Support/Optional.cpp b/llvm/lib/Support/Optional.cpp new file mode 100644 index 00000000000..765b25df13d --- /dev/null +++ b/llvm/lib/Support/Optional.cpp @@ -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"; +} diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp index 20bc9da4d59..e6997ef8be7 100644 --- a/llvm/unittests/ADT/OptionalTest.cpp +++ b/llvm/unittests/ADT/OptionalTest.cpp @@ -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, OperatorGreaterEqual) { 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 diff --git a/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h b/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h index fd993db1602..f4430f8de47 100644 --- a/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h +++ b/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h @@ -42,8 +42,9 @@ auto printable(const T &V) -> decltype(StreamSwitch<T>::printable(V)) { // 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)(std::declval<llvm::raw_ostream &>() << 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 |