5757#include " llvm/ADT/STLExtras.h"
5858#include " llvm/ADT/StringRef.h"
5959#include " llvm/Support/Compiler.h"
60+ #include " llvm/Support/Regex.h"
6061#include " llvm/TargetParser/Triple.h"
6162
6263#include < cctype>
@@ -658,6 +659,37 @@ static char ConvertValueObjectStyleToChar(
658659 return ' \0 ' ;
659660}
660661
662+ // / Options supported by format_provider<T> for integral arithmetic types.
663+ // / See table in FormatProviders.h.
664+ static llvm::Regex LLVMFormatPattern{" x[-+]?\\ d*|n|d" , llvm::Regex::IgnoreCase};
665+
666+ static bool DumpValueWithLLVMFormat (Stream &s, llvm::StringRef options,
667+ ValueObject &valobj) {
668+ std::string formatted;
669+ std::string llvm_format = (" {0:" + options + " }" ).str ();
670+
671+ auto type_info = valobj.GetTypeInfo ();
672+ if ((type_info & eTypeIsInteger) && LLVMFormatPattern.match (options)) {
673+ if (type_info & eTypeIsSigned) {
674+ bool success = false ;
675+ int64_t integer = valobj.GetValueAsSigned (0 , &success);
676+ if (success)
677+ formatted = llvm::formatv (llvm_format.data (), integer);
678+ } else {
679+ bool success = false ;
680+ uint64_t integer = valobj.GetValueAsUnsigned (0 , &success);
681+ if (success)
682+ formatted = llvm::formatv (llvm_format.data (), integer);
683+ }
684+ }
685+
686+ if (formatted.empty ())
687+ return false ;
688+
689+ s.Write (formatted.data (), formatted.size ());
690+ return true ;
691+ }
692+
661693static bool DumpValue (Stream &s, const SymbolContext *sc,
662694 const ExecutionContext *exe_ctx,
663695 const FormatEntity::Entry &entry, ValueObject *valobj) {
@@ -728,9 +760,12 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
728760 return RunScriptFormatKeyword (s, sc, exe_ctx, valobj, entry.string .c_str ());
729761 }
730762
731- llvm::StringRef subpath (entry.string );
763+ auto split = llvm::StringRef (entry.string ).split (' :' );
764+ auto subpath = split.first ;
765+ auto llvm_format = split.second ;
766+
732767 // simplest case ${var}, just print valobj's value
733- if (entry. string .empty ()) {
768+ if (subpath .empty ()) {
734769 if (entry.printf_format .empty () && entry.fmt == eFormatDefault &&
735770 entry.number == ValueObject::eValueObjectRepresentationStyleValue)
736771 was_plain_var = true ;
@@ -739,22 +774,19 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
739774 target = valobj;
740775 } else // this is ${var.something} or multiple .something nested
741776 {
742- if (entry. string [0 ] == ' [' )
777+ if (subpath [0 ] == ' [' )
743778 was_var_indexed = true ;
744779 ScanBracketedRange (subpath, close_bracket_index,
745780 var_name_final_if_array_range, index_lower,
746781 index_higher);
747782
748783 Status error;
749784
750- const std::string &expr_path = entry.string ;
751-
752- LLDB_LOGF (log, " [Debugger::FormatPrompt] symbol to expand: %s" ,
753- expr_path.c_str ());
785+ LLDB_LOG (log, " [Debugger::FormatPrompt] symbol to expand: {0}" , subpath);
754786
755787 target =
756788 valobj
757- ->GetValueForExpressionPath (expr_path. c_str () , &reason_to_stop,
789+ ->GetValueForExpressionPath (subpath , &reason_to_stop,
758790 &final_value_type, options, &what_next)
759791 .get ();
760792
@@ -883,8 +915,18 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
883915 }
884916
885917 if (!is_array_range) {
886- LLDB_LOGF (log,
887- " [Debugger::FormatPrompt] dumping ordinary printable output" );
918+ if (!llvm_format.empty ()) {
919+ if (DumpValueWithLLVMFormat (s, llvm_format, *target)) {
920+ LLDB_LOGF (log, " dumping using llvm format" );
921+ return true ;
922+ } else {
923+ LLDB_LOG (
924+ log,
925+ " empty output using llvm format '{0}' - with type info flags {1}" ,
926+ entry.printf_format , target->GetTypeInfo ());
927+ }
928+ }
929+ LLDB_LOGF (log, " dumping ordinary printable output" );
888930 return target->DumpPrintableRepresentation (s, val_obj_display,
889931 custom_format);
890932 } else {
@@ -2227,6 +2269,16 @@ static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry,
22272269 if (error.Fail ())
22282270 return error;
22292271
2272+ llvm::StringRef entry_string (entry.string );
2273+ if (entry_string.contains (' :' )) {
2274+ auto [_, llvm_format] = entry_string.split (' :' );
2275+ if (!llvm_format.empty () && !LLVMFormatPattern.match (llvm_format)) {
2276+ error.SetErrorStringWithFormat (" invalid llvm format: '%s'" ,
2277+ llvm_format.data ());
2278+ return error;
2279+ }
2280+ }
2281+
22302282 if (verify_is_thread_id) {
22312283 if (entry.type != Entry::Type::ThreadID &&
22322284 entry.type != Entry::Type::ThreadProtocolID) {
0 commit comments