llvm.org GIT mirror llvm / a2b3508
[Support] Make support types more easily printable. Summary: Error's new operator<< is the first way to print an error without consuming it. formatv() can now print objects with an operator<< that works with raw_ostream. Reviewers: bkramer Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D48966 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336412 91177308-0d34-0410-b5e6-96231b3b80d8 Sam McCall 1 year, 3 months ago
5 changed file(s) with 95 addition(s) and 20 deletion(s). Raw diff Collapse all Expand all
301301 return Tmp;
302302 }
303303
304 friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) {
305 if (auto P = E.getPtr())
306 P->log(OS);
307 else
308 OS << "success";
309 return OS;
310 }
311
304312 ErrorInfoBase *Payload = nullptr;
305313 };
306314
236236 // for type T containing a method whose signature is:
237237 // void format(const T &Obj, raw_ostream &Stream, StringRef Options)
238238 // Then this method is invoked as described in Step 1.
239 // 3. If an appropriate operator<< for raw_ostream exists, it will be used.
240 // For this to work, (raw_ostream& << const T&) must return raw_ostream&.
239241 //
240242 // If a match cannot be found through either of the above methods, a compiler
241243 // error is generated.
257259 std::make_tuple(detail::build_format_adapter(std::forward(Vals))...));
258260 }
259261
260 // Allow a formatv_object to be formatted (no options supported).
261 template struct format_provider> {
262 static void format(const formatv_object &V, raw_ostream &OS, StringRef) {
263 OS << V;
264 }
265 };
266
267262 } // end namespace llvm
268263
269264 #endif // LLVM_SUPPORT_FORMATVARIADIC_H
3737 }
3838 };
3939
40 template
41 class stream_operator_format_adapter : public format_adapter {
42 T Item;
43
44 public:
45 explicit stream_operator_format_adapter(T &&Item)
46 : Item(std::forward(Item)) {}
47
48 void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; }
49 };
50
4051 template class missing_format_adapter;
4152
4253 // Test if format_provider is defined on T and contains a member function
5869 (sizeof(test>(nullptr)) == 1);
5970 };
6071
72 // Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
73 template class has_StreamOperator {
74 public:
75 using ConstRefT = const typename std::decay::type &;
76
77 template
78 static char test(typename std::enable_if<
79 std::is_same()
80 << std::declval()),
81 llvm::raw_ostream &>::value,
82 int *>::type);
83
84 template static double test(...);
85
86 static bool const value = (sizeof(test(nullptr)) == 1);
87 };
88
6189 // Simple template that decides whether a type T should use the member-function
6290 // based format() invocation.
6391 template
76104 bool, !uses_format_member::value && has_FormatProvider::value> {
77105 };
78106
107 // Simple template that decides whether a type T should use the operator<<
108 // based format() invocation. This takes last priority.
109 template
110 struct uses_stream_operator
111 : public std::integral_constant::value &&
112 !uses_format_provider::value &&
113 has_StreamOperator::value> {};
114
79115 // Simple template that decides whether a type T has neither a member-function
80116 // nor format_provider based implementation that it can use. Mostly used so
81117 // that the compiler spits out a nice diagnostic when a type with no format
82118 // implementation can be located.
83119 template
84120 struct uses_missing_provider
85 : public std::integral_constant
86 !uses_format_member::value &&
87 !uses_format_provider::value> {};
121 : public std::integral_constant::value &&
122 !uses_format_provider::value &&
123 !uses_stream_operator::value> {
124 };
88125
89126 template
90127 typename std::enable_if::value, T>::type
100137 }
101138
102139 template
140 typename std::enable_if::value,
141 stream_operator_format_adapter>::type
142 build_format_adapter(T &&Item) {
143 return stream_operator_format_adapter(std::forward(Item));
144 }
145
146 template
103147 typename std::enable_if::value,
104148 missing_format_adapter>::type
105149 build_format_adapter(T &&Item) {
3131
3232 // Log this error to a stream.
3333 void log(raw_ostream &OS) const override {
34 OS << "CustomError { " << getInfo() << "}";
34 OS << "CustomError {" << getInfo() << "}";
3535 }
3636
3737 std::error_code convertToErrorCode() const override {
701701 EXPECT_EQ(toString(Error::success()).compare(""), 0);
702702
703703 Error E1 = make_error(0);
704 EXPECT_EQ(toString(std::move(E1)).compare("CustomError { 0}"), 0);
704 EXPECT_EQ(toString(std::move(E1)).compare("CustomError {0}"), 0);
705705
706706 Error E2 = make_error(0);
707707 handleAllErrors(std::move(E2), [](const CustomError &CE) {
708 EXPECT_EQ(CE.message().compare("CustomError { 0}"), 0);
708 EXPECT_EQ(CE.message().compare("CustomError {0}"), 0);
709709 });
710710
711711 Error E3 = joinErrors(make_error(0), make_error(1));
712712 EXPECT_EQ(toString(std::move(E3))
713 .compare("CustomError { 0}\n"
714 "CustomError { 1}"),
713 .compare("CustomError {0}\n"
714 "CustomError {1}"),
715715 0);
716 }
717
718 TEST(Error, Stream) {
719 {
720 Error OK = Error::success();
721 std::string Buf;
722 llvm::raw_string_ostream S(Buf);
723 S << OK;
724 EXPECT_EQ("success", S.str());
725 consumeError(std::move(OK));
726 }
727 {
728 Error E1 = make_error(0);
729 std::string Buf;
730 llvm::raw_string_ostream S(Buf);
731 S << E1;
732 EXPECT_EQ("CustomError {0}", S.str());
733 consumeError(std::move(E1));
734 }
716735 }
717736
718737 TEST(Error, ErrorMatchers) {
719738 EXPECT_THAT_ERROR(Error::success(), Succeeded());
720739 EXPECT_NONFATAL_FAILURE(
721740 EXPECT_THAT_ERROR(make_error(0), Succeeded()),
722 "Expected: succeeded\n Actual: failed (CustomError { 0})");
741 "Expected: succeeded\n Actual: failed (CustomError {0})");
723742
724743 EXPECT_THAT_ERROR(make_error(0), Failed());
725744 EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()),
747766 Failed(testing::Property(&CustomError::getInfo, 1))),
748767 "Expected: failed with Error of given type and the error is an object "
749768 "whose given property is equal to 1\n"
750 " Actual: failed (CustomError { 0})");
769 " Actual: failed (CustomError {0})");
751770 EXPECT_THAT_ERROR(make_error(0), Failed());
752771
753772 EXPECT_THAT_EXPECTED(Expected(0), Succeeded());
754773 EXPECT_NONFATAL_FAILURE(
755774 EXPECT_THAT_EXPECTED(Expected(make_error(0)),
756775 Succeeded()),
757 "Expected: succeeded\n Actual: failed (CustomError { 0})");
776 "Expected: succeeded\n Actual: failed (CustomError {0})");
758777
759778 EXPECT_THAT_EXPECTED(Expected(make_error(0)), Failed());
760779 EXPECT_NONFATAL_FAILURE(
766785 EXPECT_THAT_EXPECTED(Expected(make_error(0)),
767786 HasValue(0)),
768787 "Expected: succeeded with value (is equal to 0)\n"
769 " Actual: failed (CustomError { 0})");
788 " Actual: failed (CustomError {0})");
770789 EXPECT_NONFATAL_FAILURE(
771790 EXPECT_THAT_EXPECTED(Expected(1), HasValue(0)),
772791 "Expected: succeeded with value (is equal to 0)\n"
786805 EXPECT_THAT_EXPECTED(Expected(make_error(0)),
787806 HasValue(testing::Gt(1))),
788807 "Expected: succeeded with value (is > 1)\n"
789 " Actual: failed (CustomError { 0})");
808 " Actual: failed (CustomError {0})");
790809 }
791810
792811 } // end anon namespace
670670 EXPECT_EQ(0, R.Copied);
671671 EXPECT_EQ(0, R.Moved);
672672 }
673
674 namespace adl {
675 struct X {};
676 raw_ostream &operator<<(raw_ostream &OS, const X &) { return OS << "X"; }
677 } // namespace adl
678 TEST(FormatVariadicTest, FormatStreamable) {
679 adl::X X;
680 EXPECT_EQ("X", formatv("{0}", X).str());
681 }