diff --git a/lldb/include/lldb/Utility/Stream.h b/lldb/include/lldb/Utility/Stream.h index 13455552131d..d0b60a4f5fe3 100644 --- a/lldb/include/lldb/Utility/Stream.h +++ b/lldb/include/lldb/Utility/Stream.h @@ -225,6 +225,16 @@ public: /// in one statement. Stream &operator<<(char ch); + /// Output the result of a formatv expression to the stream. + /// + /// \param[in] obj + /// A formatv_object_base produced by llvm::formatv(). + /// + /// \return + /// A reference to this class so multiple things can be streamed + /// in one statement. + Stream &operator<<(const llvm::formatv_object_base &obj); + Stream &operator<<(uint8_t uval) = delete; Stream &operator<<(uint16_t uval) = delete; Stream &operator<<(uint32_t uval) = delete; @@ -361,8 +371,10 @@ public: size_t PrintfVarArg(const char *format, va_list args); + /// Forwards the arguments to llvm::formatv and writes to the stream. + /// FIXME: instead of this API, consider using llvm::formatv directly. template void Format(const char *format, Args &&... args) { - PutCString(llvm::formatv(format, std::forward(args)...).str()); + *this << llvm::formatv(format, std::forward(args)...); } /// Output a quoted C string value to the stream. diff --git a/lldb/source/Core/UserSettingsController.cpp b/lldb/source/Core/UserSettingsController.cpp index 5408d64b4064..206b2072ddaf 100644 --- a/lldb/source/Core/UserSettingsController.cpp +++ b/lldb/source/Core/UserSettingsController.cpp @@ -55,7 +55,7 @@ void Properties::DumpAllPropertyValues(const ExecutionContext *exe_ctx, bool is_json) { if (is_json) { llvm::json::Value json = m_collection_sp->ToJSON(exe_ctx); - strm.Printf("%s", llvm::formatv("{0:2}", json).str().c_str()); + strm << llvm::formatv("{0:2}", json); } else m_collection_sp->DumpValue(exe_ctx, strm, dump_mask); } diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp index 521de3ddd538..def6cc462f76 100644 --- a/lldb/source/Interpreter/OptionValueProperties.cpp +++ b/lldb/source/Interpreter/OptionValueProperties.cpp @@ -380,11 +380,9 @@ Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx, if (dump_mask & ~eDumpOptionName) strm.PutChar(' '); } - if (is_json) { - strm.Printf( - "%s", - llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str()); - } else + if (is_json) + strm << llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)); + else value_sp->DumpValue(exe_ctx, strm, dump_mask); } return error; diff --git a/lldb/source/Target/TraceDumper.cpp b/lldb/source/Target/TraceDumper.cpp index fa732fa87c52..5e87deb2ac9c 100644 --- a/lldb/source/Target/TraceDumper.cpp +++ b/lldb/source/Target/TraceDumper.cpp @@ -156,9 +156,10 @@ public: m_s.Format(" {0}: ", item.id); if (m_options.show_timestamps) { - m_s.Format("[{0}] ", item.timestamp - ? formatv("{0:3} ns", *item.timestamp).str() - : "unavailable"); + if (item.timestamp) + m_s << formatv("[{0:3} ns]", *item.timestamp); + else + m_s << "[unavailable]"; } if (item.event) { diff --git a/lldb/source/Utility/Stream.cpp b/lldb/source/Utility/Stream.cpp index e9632c3e1fc1..fbe7bdb6dd27 100644 --- a/lldb/source/Utility/Stream.cpp +++ b/lldb/source/Utility/Stream.cpp @@ -183,6 +183,12 @@ Stream &Stream::operator<<(const void *p) { return *this; } +// Stream the result of a formatv expression to this stream. +Stream &Stream::operator<<(const llvm::formatv_object_base &obj) { + obj.format(m_forwarder); + return *this; +} + // Get the current indentation level unsigned Stream::GetIndentLevel() const { return m_indent_level; } diff --git a/lldb/unittests/Utility/StreamTest.cpp b/lldb/unittests/Utility/StreamTest.cpp index c63dfda6947f..7fb8bfd0ef3d 100644 --- a/lldb/unittests/Utility/StreamTest.cpp +++ b/lldb/unittests/Utility/StreamTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Utility/StreamString.h" +#include "llvm/Support/FormatVariadic.h" #include "gtest/gtest.h" using namespace lldb_private; @@ -416,6 +417,14 @@ TEST_F(StreamTest, ShiftOperatorStrings) { EXPECT_EQ("cstring\nllvm::StringRef\n", TakeValue()); } +TEST_F(StreamTest, ShiftOperatorFormatv) { + s << llvm::formatv("x{0}y", 42); + EXPECT_EQ("x42y", TakeValue()); + + s << llvm::formatv("{0} {1}", "hello", "world") << '!'; + EXPECT_EQ("hello world!", TakeValue()); +} + TEST_F(StreamTest, ShiftOperatorPtr) { // This test is a bit tricky because pretty much everything related to // pointer printing seems to lead to UB or IB. So let's make the most basic