Index: lldb/trunk/include/lldb/Core/Error.h =================================================================== --- lldb/trunk/include/lldb/Core/Error.h +++ lldb/trunk/include/lldb/Core/Error.h @@ -19,6 +19,8 @@ #include "lldb/lldb-private.h" +#include "llvm/Support/FormatVariadic.h" + namespace lldb_private { class Log; @@ -258,6 +260,11 @@ int SetErrorStringWithVarArg(const char *format, va_list args); + template + void SetErrorStringWithFormatv(const char *format, Args &&... args) { + SetErrorString(llvm::formatv(format, std::forward(args)...).str()); + } + //------------------------------------------------------------------ /// Test for success condition. /// Index: lldb/trunk/include/lldb/Core/Log.h =================================================================== --- lldb/trunk/include/lldb/Core/Log.h +++ lldb/trunk/include/lldb/Core/Log.h @@ -25,6 +25,8 @@ #include "lldb/Core/PluginInterface.h" #include "lldb/lldb-private.h" +#include "llvm/Support/FormatVariadic.h" + //---------------------------------------------------------------------- // Logging Options //---------------------------------------------------------------------- @@ -43,7 +45,7 @@ //---------------------------------------------------------------------- namespace lldb_private { -class Log { +class Log final { public: //------------------------------------------------------------------ // Callback definitions for abstracted plug-in log access. @@ -102,42 +104,32 @@ Log(const lldb::StreamSP &stream_sp); - virtual ~Log(); + ~Log(); + + void PutCString(const char *cstr); + void PutString(llvm::StringRef str); - virtual void PutCString(const char *cstr); - virtual void PutString(llvm::StringRef str); + template void Format(const char *fmt, Args &&... args) { + PutString(llvm::formatv(fmt, std::forward(args)...).str()); + } // CLEANUP: Add llvm::raw_ostream &Stream() function. - virtual void Printf(const char *format, ...) - __attribute__((format(printf, 2, 3))); + void Printf(const char *format, ...) __attribute__((format(printf, 2, 3))); - virtual void VAPrintf(const char *format, va_list args); + void VAPrintf(const char *format, va_list args); - virtual void LogIf(uint32_t mask, const char *fmt, ...) + void LogIf(uint32_t mask, const char *fmt, ...) __attribute__((format(printf, 3, 4))); - virtual void Debug(const char *fmt, ...) - __attribute__((format(printf, 2, 3))); - - virtual void DebugVerbose(const char *fmt, ...) - __attribute__((format(printf, 2, 3))); + void Debug(const char *fmt, ...) __attribute__((format(printf, 2, 3))); - virtual void Error(const char *fmt, ...) - __attribute__((format(printf, 2, 3))); - - virtual void VAError(const char *format, va_list args); - - virtual void FatalError(int err, const char *fmt, ...) - __attribute__((format(printf, 3, 4))); + void Error(const char *fmt, ...) __attribute__((format(printf, 2, 3))); - virtual void Verbose(const char *fmt, ...) - __attribute__((format(printf, 2, 3))); + void VAError(const char *format, va_list args); - virtual void Warning(const char *fmt, ...) - __attribute__((format(printf, 2, 3))); + void Verbose(const char *fmt, ...) __attribute__((format(printf, 2, 3))); - virtual void WarningVerbose(const char *fmt, ...) - __attribute__((format(printf, 2, 3))); + void Warning(const char *fmt, ...) __attribute__((format(printf, 2, 3))); Flags &GetOptions(); Index: lldb/trunk/include/lldb/Core/ModuleSpec.h =================================================================== --- lldb/trunk/include/lldb/Core/ModuleSpec.h +++ lldb/trunk/include/lldb/Core/ModuleSpec.h @@ -240,7 +240,7 @@ if (m_object_mod_time != llvm::sys::TimePoint<>()) { if (dumped_something) strm.PutCString(", "); - strm.Printf("object_mod_time = 0x%" PRIx64, + strm.Format("object_mod_time = {0:x+}", uint64_t(llvm::sys::toTimeT(m_object_mod_time))); } } Index: lldb/trunk/include/lldb/Core/Stream.h =================================================================== --- lldb/trunk/include/lldb/Core/Stream.h +++ lldb/trunk/include/lldb/Core/Stream.h @@ -19,6 +19,8 @@ #include "lldb/Core/Flags.h" #include "lldb/lldb-private.h" +#include "llvm/Support/FormatVariadic.h" + namespace lldb_private { //---------------------------------------------------------------------- @@ -485,6 +487,10 @@ size_t PrintfVarArg(const char *format, va_list args); + template void Format(const char *format, Args &&... args) { + PutCString(llvm::formatv(format, std::forward(args)...).str()); + } + //------------------------------------------------------------------ /// Output a quoted C string value to the stream. /// Index: lldb/trunk/include/lldb/Host/FileSpec.h =================================================================== --- lldb/trunk/include/lldb/Host/FileSpec.h +++ lldb/trunk/include/lldb/Host/FileSpec.h @@ -22,6 +22,8 @@ #include "lldb/Host/PosixApi.h" #include "lldb/lldb-private.h" +#include "llvm/Support/FormatVariadic.h" + namespace lldb_private { //---------------------------------------------------------------------- @@ -759,4 +761,30 @@ } // namespace lldb_private +namespace llvm { + +/// Implementation of format_provider for FileSpec. +/// +/// The options string of a FileSpec has the grammar: +/// +/// file_spec_options :: (empty) | F | D +/// +/// ======================================================= +/// | style | Meaning | Example | +/// ------------------------------------------------------- +/// | | | Input | Output | +/// ======================================================= +/// | F | Only print filename | /foo/bar | bar | +/// | D | Only print directory | /foo/bar | /foo/ | +/// | (empty) | Print file and dir | | | +/// ======================================================= +/// +/// Any other value is considered an invalid format string. +/// +template <> struct format_provider { + static void format(const lldb_private::FileSpec &F, llvm::raw_ostream &Stream, + StringRef Style); +}; +} + #endif // liblldb_FileSpec_h_ Index: lldb/trunk/include/lldb/Interpreter/CommandReturnObject.h =================================================================== --- lldb/trunk/include/lldb/Interpreter/CommandReturnObject.h +++ lldb/trunk/include/lldb/Interpreter/CommandReturnObject.h @@ -21,6 +21,7 @@ #include "lldb/lldb-private.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" #include @@ -113,6 +114,21 @@ void AppendErrorWithFormat(const char *format, ...) __attribute__((format(printf, 2, 3))); + template + void AppendMessageWithFormatv(const char *format, Args &&... args) { + AppendMessage(llvm::formatv(format, std::forward(args)...).str()); + } + + template + void AppendWarningWithFormatv(const char *format, Args &&... args) { + AppendWarning(llvm::formatv(format, std::forward(args)...).str()); + } + + template + void AppendErrorWithFormatv(const char *format, Args &&... args) { + AppendError(llvm::formatv(format, std::forward(args)...).str()); + } + void SetError(const Error &error, const char *fallback_error_cstr = nullptr); void SetError(llvm::StringRef error_cstr); Index: lldb/trunk/source/Breakpoint/BreakpointOptions.cpp =================================================================== --- lldb/trunk/source/Breakpoint/BreakpointOptions.cpp +++ lldb/trunk/source/Breakpoint/BreakpointOptions.cpp @@ -86,8 +86,8 @@ found_something = true; interp_language = ScriptInterpreter::StringToLanguage(interpreter_str); if (interp_language == eScriptLanguageUnknown) { - error.SetErrorStringWithFormat("Unknown breakpoint command language: %s.", - interpreter_str.c_str()); + error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.", + interpreter_str); return data_up; } data_up->interpreter = interp_language; Index: lldb/trunk/source/Commands/CommandObjectApropos.cpp =================================================================== --- lldb/trunk/source/Commands/CommandObjectApropos.cpp +++ lldb/trunk/source/Commands/CommandObjectApropos.cpp @@ -90,9 +90,9 @@ m_interpreter.GetDebugger().Apropos(search_word, properties); if (num_properties) { const bool dump_qualified_name = true; - result.AppendMessageWithFormat( - "\nThe following settings variables may relate to '%s': \n\n", - args[0].c_str()); + result.AppendMessageWithFormatv( + "\nThe following settings variables may relate to '{0}': \n\n", + args[0].ref); for (size_t i = 0; i < num_properties; ++i) properties[i]->DumpDescription( m_interpreter, result.GetOutputStream(), 0, dump_qualified_name); Index: lldb/trunk/source/Core/Log.cpp =================================================================== --- lldb/trunk/source/Core/Log.cpp +++ lldb/trunk/source/Core/Log.cpp @@ -138,20 +138,6 @@ } //---------------------------------------------------------------------- -// Print debug strings if and only if the global debug option is set to -// a non-zero value. -//---------------------------------------------------------------------- -void Log::DebugVerbose(const char *format, ...) { - if (!GetOptions().AllSet(LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE)) - return; - - va_list args; - va_start(args, format); - VAPrintf(format, args); - va_end(args); -} - -//---------------------------------------------------------------------- // Log only if all of the bits are set //---------------------------------------------------------------------- void Log::LogIf(uint32_t bits, const char *format, ...) { @@ -186,24 +172,6 @@ } //---------------------------------------------------------------------- -// Printing of errors that ARE fatal. Exit with ERR exit code -// immediately. -//---------------------------------------------------------------------- -void Log::FatalError(int err, const char *format, ...) { - char *arg_msg = nullptr; - va_list args; - va_start(args, format); - ::vasprintf(&arg_msg, format, args); - va_end(args); - - if (arg_msg != nullptr) { - Printf("error: %s", arg_msg); - ::free(arg_msg); - } - ::exit(err); -} - -//---------------------------------------------------------------------- // Printing of warnings that are not fatal only if verbose mode is // enabled. //---------------------------------------------------------------------- @@ -218,27 +186,6 @@ } //---------------------------------------------------------------------- -// Printing of warnings that are not fatal only if verbose mode is -// enabled. -//---------------------------------------------------------------------- -void Log::WarningVerbose(const char *format, ...) { - if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE)) - return; - - char *arg_msg = nullptr; - va_list args; - va_start(args, format); - ::vasprintf(&arg_msg, format, args); - va_end(args); - - if (arg_msg == nullptr) - return; - - Printf("warning: %s", arg_msg); - free(arg_msg); -} - -//---------------------------------------------------------------------- // Printing of warnings that are not fatal. //---------------------------------------------------------------------- void Log::Warning(const char *format, ...) { Index: lldb/trunk/source/Host/common/FileSpec.cpp =================================================================== --- lldb/trunk/source/Host/common/FileSpec.cpp +++ lldb/trunk/source/Host/common/FileSpec.cpp @@ -354,10 +354,10 @@ m_is_resolved = true; } - Normalize(resolved, syntax); + Normalize(resolved, m_syntax); llvm::StringRef resolve_path_ref(resolved.c_str()); - size_t dir_end = ParentPathEnd(resolve_path_ref, syntax); + size_t dir_end = ParentPathEnd(resolve_path_ref, m_syntax); if (dir_end == 0) { m_filename.SetString(resolve_path_ref); return; @@ -366,11 +366,11 @@ m_directory.SetString(resolve_path_ref.substr(0, dir_end)); size_t filename_begin = dir_end; - size_t root_dir_start = RootDirStart(resolve_path_ref, syntax); + size_t root_dir_start = RootDirStart(resolve_path_ref, m_syntax); while (filename_begin != llvm::StringRef::npos && filename_begin < resolve_path_ref.size() && filename_begin != root_dir_start && - IsPathSeparator(resolve_path_ref[filename_begin], syntax)) + IsPathSeparator(resolve_path_ref[filename_begin], m_syntax)) ++filename_begin; m_filename.SetString((filename_begin == llvm::StringRef::npos || filename_begin >= resolve_path_ref.size()) @@ -1386,3 +1386,46 @@ } bool FileSpec::IsAbsolute() const { return !FileSpec::IsRelative(); } + +void llvm::format_provider::format(const FileSpec &F, + raw_ostream &Stream, + StringRef Style) { + assert( + (Style.empty() || Style.equals_lower("F") || Style.equals_lower("D")) && + "Invalid FileSpec style!"); + + StringRef dir = F.GetDirectory().GetStringRef(); + StringRef file = F.GetFilename().GetStringRef(); + + if (dir.empty() && file.empty()) { + Stream << "(empty)"; + return; + } + + if (Style.equals_lower("F")) { + Stream << (file.empty() ? "(empty)" : file); + return; + } + + // Style is either D or empty, either way we need to print the directory. + if (!dir.empty()) { + // Directory is stored in normalized form, which might be different + // than preferred form. In order to handle this, we need to cut off + // the filename, then denormalize, then write the entire denorm'ed + // directory. + llvm::SmallString<64> denormalized_dir = dir; + Denormalize(denormalized_dir, F.GetPathSyntax()); + Stream << denormalized_dir; + Stream << GetPreferredPathSeparator(F.GetPathSyntax()); + } + + if (Style.equals_lower("D")) { + // We only want to print the directory, so now just exit. + if (dir.empty()) + Stream << "(empty)"; + return; + } + + if (!file.empty()) + Stream << file; +} Index: lldb/trunk/source/Symbol/ClangASTContext.cpp =================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp +++ lldb/trunk/source/Symbol/ClangASTContext.cpp @@ -9,6 +9,9 @@ #include "lldb/Symbol/ClangASTContext.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" + // C Includes // C++ Includes #include // std::once @@ -6739,10 +6742,7 @@ if (array) { CompilerType element_type(getASTContext(), array->getElementType()); if (element_type.GetCompleteType()) { - char element_name[64]; - ::snprintf(element_name, sizeof(element_name), "[%" PRIu64 "]", - static_cast(idx)); - child_name.assign(element_name); + child_name = llvm::formatv("[{0}]", idx); child_byte_size = element_type.GetByteSize( exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; @@ -8883,8 +8883,8 @@ std::string base_class_type_name(base_class_qual_type.getAsString()); // Indent and print the base class type name - s->Printf("\n%*s%s ", depth + DEPTH_INCREMENT, "", - base_class_type_name.c_str()); + s->Format("\n{0}{1}", llvm::fmt_repeat(" ", depth + DEPTH_INCREMENT), + base_class_type_name); clang::TypeInfo base_class_type_info = getASTContext()->getTypeInfo(base_class_qual_type); Index: lldb/trunk/source/Target/Target.cpp =================================================================== --- lldb/trunk/source/Target/Target.cpp +++ lldb/trunk/source/Target/Target.cpp @@ -1554,11 +1554,9 @@ if (load_addr == LLDB_INVALID_ADDRESS) { ModuleSP addr_module_sp(resolved_addr.GetModule()); if (addr_module_sp && addr_module_sp->GetFileSpec()) - error.SetErrorStringWithFormat( - "%s[0x%" PRIx64 "] can't be resolved, %s in not currently loaded", - addr_module_sp->GetFileSpec().GetFilename().AsCString(""), - resolved_addr.GetFileAddress(), - addr_module_sp->GetFileSpec().GetFilename().AsCString("")); + error.SetErrorStringWithFormatv( + "{0:F}[{1:x+}] can't be resolved, {0:F} is not currently loaded", + addr_module_sp->GetFileSpec(), resolved_addr.GetFileAddress()); else error.SetErrorStringWithFormat("0x%" PRIx64 " can't be resolved", resolved_addr.GetFileAddress()); Index: lldb/trunk/unittests/Host/FileSpecTest.cpp =================================================================== --- lldb/trunk/unittests/Host/FileSpecTest.cpp +++ lldb/trunk/unittests/Host/FileSpecTest.cpp @@ -260,3 +260,27 @@ << "Original path: " << test.first; } } + +TEST(FileSpecTest, FormatFileSpec) { + auto win = FileSpec::ePathSyntaxWindows; + + FileSpec F; + EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str()); + EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str()); + EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str()); + + F = FileSpec("C:\\foo\\bar.txt", false, win); + EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str()); + EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str()); + EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str()); + + F = FileSpec("foo\\bar.txt", false, win); + EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str()); + EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str()); + EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str()); + + F = FileSpec("foo", false, win); + EXPECT_EQ("foo", llvm::formatv("{0}", F).str()); + EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str()); + EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str()); +} \ No newline at end of file