From bbf5b55615b403dce4972e2b02b9a228d7a05f8c Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Thu, 23 Apr 2026 10:27:33 -0700 Subject: [PATCH 1/3] [lldb] Add print-braces setting for ValueObject printing --- .../DataFormatters/DumpValueObjectOptions.h | 3 +++ .../OptionGroupValueObjectDisplay.h | 2 +- lldb/include/lldb/Target/Target.h | 2 ++ .../DataFormatters/DumpValueObjectOptions.cpp | 8 +++++++- .../DataFormatters/ValueObjectPrinter.cpp | 17 ++++++++++------ .../OptionGroupValueObjectDisplay.cpp | 3 +++ lldb/source/Target/Target.cpp | 6 ++++++ lldb/source/Target/TargetProperties.td | 3 +++ .../data-formatter/print-braces/Makefile | 2 ++ .../print-braces/TestPrintBraces.py | 20 +++++++++++++++++++ .../data-formatter/print-braces/main.c | 14 +++++++++++++ 11 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/print-braces/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py create mode 100644 lldb/test/API/functionalities/data-formatter/print-braces/main.c diff --git a/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h b/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h index 70166f33cfc45..4f3aeae3ad520 100644 --- a/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h +++ b/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h @@ -125,6 +125,8 @@ class DumpValueObjectOptions { DumpValueObjectOptions &SetRevealEmptyAggregates(bool reveal = true); + DumpValueObjectOptions &SetPrintBraces(bool print = true); + DumpValueObjectOptions &SetExpandPointerTypeFlags(unsigned flags); DumpValueObjectOptions &SetElementCount(uint32_t element_count = 0); @@ -162,6 +164,7 @@ class DumpValueObjectOptions { bool m_allow_oneliner_mode : 1; bool m_hide_pointer_value : 1; bool m_reveal_empty_aggregates : 1; + bool m_print_braces : 1; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h b/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h index 4fd552a6700b8..fe0251b12d364 100644 --- a/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h +++ b/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h @@ -44,7 +44,7 @@ class OptionGroupValueObjectDisplay : public OptionGroup { bool show_types : 1, show_location : 1, flat_output : 1, use_object_desc : 1, use_synth : 1, be_raw : 1, ignore_cap : 1, run_validator : 1, - max_depth_is_default : 1; + max_depth_is_default : 1, print_braces : 1; uint32_t no_summary_depth; uint32_t max_depth; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 913e10eaf3479..0c2f61135953a 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -202,6 +202,8 @@ class TargetProperties : public Properties { /// otherwise false. std::pair GetMaximumDepthOfChildrenToDisplay() const; + bool GetPrintBraces() const; + uint32_t GetMaximumSizeOfStringSummary() const; uint32_t GetMaximumMemReadSize() const; diff --git a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp index e1df9522256fa..60158e7eec628 100644 --- a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp +++ b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp @@ -21,7 +21,8 @@ DumpValueObjectOptions::DumpValueObjectOptions() m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false), m_hide_value(false), m_run_validator(false), m_use_type_display_name(true), m_allow_oneliner_mode(true), - m_hide_pointer_value(false), m_reveal_empty_aggregates(true) {} + m_hide_pointer_value(false), m_reveal_empty_aggregates(true), + m_print_braces(true) {} DumpValueObjectOptions::DumpValueObjectOptions(ValueObject &valobj) : DumpValueObjectOptions() { @@ -210,6 +211,11 @@ DumpValueObjectOptions::SetRevealEmptyAggregates(bool reveal) { return *this; } +DumpValueObjectOptions &DumpValueObjectOptions::SetPrintBraces(bool print) { + m_print_braces = print; + return *this; +} + DumpValueObjectOptions & DumpValueObjectOptions::SetExpandPointerTypeFlags(unsigned flags) { m_expand_ptr_type_flags = flags; diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp index 002638024c64b..4142ce383bb11 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -583,12 +583,16 @@ void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed, m_stream->EOL(); } else { if (ShouldPrintValueObject()) { - if (IsRef()) { - m_stream->PutCString(": "); - } else if (value_printed || summary_printed || ShouldShowName()) { - m_stream->PutChar(' '); + if (m_options.m_print_braces) { + if (IsRef()) { + m_stream->PutCString(": "); + } else if (value_printed || summary_printed || ShouldShowName()) { + m_stream->PutChar(' '); + } + + m_stream->PutChar('{'); } - m_stream->PutCString("{\n"); + m_stream->EOL(); } m_stream->IndentMore(); } @@ -667,7 +671,8 @@ void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) { m_stream->Indent("...\n"); } m_stream->IndentLess(); - m_stream->Indent("}\n"); + if (m_options.m_print_braces) + m_stream->Indent("}\n"); } } diff --git a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp index 1939d79fec6a9..df75ba2681aa9 100644 --- a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -172,6 +172,7 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting( be_raw = false; ignore_cap = false; run_validator = false; + print_braces = true; TargetSP target_sp = execution_context ? execution_context->GetTargetSP() : TargetSP(); @@ -180,6 +181,7 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting( auto max_depth_config = target_sp->GetMaximumDepthOfChildrenToDisplay(); max_depth = std::get(max_depth_config); max_depth_is_default = std::get(max_depth_config); + print_braces = target_sp->GetPrintBraces(); } else { // If we don't have any targets, then dynamic values won't do us much good. use_dynamic = lldb::eNoDynamicValues; @@ -203,6 +205,7 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions( .SetUseSyntheticValue(use_synth) .SetFlatOutput(flat_output) .SetIgnoreCap(ignore_cap) + .SetPrintBraces(print_braces) .SetFormat(format) .SetSummary(summary_sp); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 27ddc4e7e5092..fbd156e40f4cd 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -5004,6 +5004,12 @@ TargetProperties::GetMaximumDepthOfChildrenToDisplay() const { return {option_value->GetCurrentValue(), is_default}; } +bool TargetProperties::GetPrintBraces() const { + const uint32_t idx = ePropertyPrintBraces; + return GetPropertyAtIndexAs( + idx, g_target_properties[idx].default_uint_value != 0); +} + uint32_t TargetProperties::GetMaximumSizeOfStringSummary() const { const uint32_t idx = ePropertyMaxSummaryLength; return GetPropertyAtIndexAs( diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 223a12e059258..a694fe4145188 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -101,6 +101,9 @@ let Definition = "target", Path = "target" in { def MaxChildrenDepth: Property<"max-children-depth", "UInt64">, DefaultUnsignedValue<5>, Desc<"Maximum depth to expand children.">; + def PrintBraces: Property<"print-braces", "Boolean">, + DefaultTrue, + Desc<"Print curly braces around structures when displaying variable values.">; def MaxSummaryLength: Property<"max-string-summary-length", "UInt64">, DefaultUnsignedValue<1024>, Desc<"Maximum number of characters to show when using %s in summary strings.">; diff --git a/lldb/test/API/functionalities/data-formatter/print-braces/Makefile b/lldb/test/API/functionalities/data-formatter/print-braces/Makefile new file mode 100644 index 0000000000000..c9319d6e6888a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/print-braces/Makefile @@ -0,0 +1,2 @@ +C_SOURCES := main.c +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py b/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py new file mode 100644 index 0000000000000..866d562ab7f0a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py @@ -0,0 +1,20 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestPrintBraces(TestBase): + def test_default_has_braces(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) + self.expect("frame variable s", substrs=["{", "}"]) + + def test_no_braces(self): + self.build() + self.runCmd("settings set target.print-braces false") + lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) + self.expect( + "frame variable s", matching=False, substrs=["{", "}"] + ) + self.expect("frame variable s", substrs=["x = 1", "y = 2", "z = 3"]) diff --git a/lldb/test/API/functionalities/data-formatter/print-braces/main.c b/lldb/test/API/functionalities/data-formatter/print-braces/main.c new file mode 100644 index 0000000000000..52345c7a1503a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/print-braces/main.c @@ -0,0 +1,14 @@ +struct Inner { + int x; + int y; +}; + +struct Outer { + struct Inner inner; + int z; +}; + +int main(void) { + struct Outer s = {{1, 2}, 3}; + return s.z; // break here +} From 05d24d3fd66453559f2a93c644528a134f1087a2 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Thu, 23 Apr 2026 10:59:59 -0700 Subject: [PATCH 2/3] formatting --- .../data-formatter/print-braces/TestPrintBraces.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py b/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py index 866d562ab7f0a..6e937daeb3a5b 100644 --- a/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py +++ b/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py @@ -14,7 +14,5 @@ def test_no_braces(self): self.build() self.runCmd("settings set target.print-braces false") lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) - self.expect( - "frame variable s", matching=False, substrs=["{", "}"] - ) + self.expect("frame variable s", matching=False, substrs=["{", "}"]) self.expect("frame variable s", substrs=["x = 1", "y = 2", "z = 3"]) From 1ad2d88941a1f4f29d33a4b7184e1f653613a122 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Thu, 23 Apr 2026 11:13:20 -0700 Subject: [PATCH 3/3] Move property to debugger, not target --- lldb/include/lldb/Core/Debugger.h | 2 ++ lldb/include/lldb/Target/Target.h | 2 -- lldb/source/Core/CoreProperties.td | 4 ++++ lldb/source/Core/Debugger.cpp | 6 ++++++ lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp | 2 +- lldb/source/Target/Target.cpp | 6 ------ lldb/source/Target/TargetProperties.td | 3 --- .../data-formatter/print-braces/TestPrintBraces.py | 2 +- 8 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index e53e916d78cc1..6da60a1200d45 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -382,6 +382,8 @@ class Debugger : public std::enable_shared_from_this, bool GetAutoOneLineSummaries() const; + bool GetPrintBraces() const; + bool GetAutoIndent() const; bool SetAutoIndent(bool b); diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 0c2f61135953a..913e10eaf3479 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -202,8 +202,6 @@ class TargetProperties : public Properties { /// otherwise false. std::pair GetMaximumDepthOfChildrenToDisplay() const; - bool GetPrintBraces() const; - uint32_t GetMaximumSizeOfStringSummary() const; uint32_t GetMaximumMemReadSize() const; diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 8cea0931868aa..01ae8734b2c2c 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -240,6 +240,10 @@ let Definition = "debugger", Path = "" in { Global, DefaultTrue, Desc<"If true, LLDB will automatically display small structs in one-liner format (default: true).">; + def PrintBraces: Property<"print-braces", "Boolean">, + Global, + DefaultTrue, + Desc<"Print curly braces around structures when displaying variable values.">; def AutoIndent: Property<"auto-indent", "Boolean">, Global, DefaultTrue, diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 48e03881fa3b5..d7177a00bba73 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -723,6 +723,12 @@ bool Debugger::GetAutoOneLineSummaries() const { idx, g_debugger_properties[idx].default_uint_value != 0); } +bool Debugger::GetPrintBraces() const { + const uint32_t idx = ePropertyPrintBraces; + return GetPropertyAtIndexAs( + idx, g_debugger_properties[idx].default_uint_value != 0); +} + bool Debugger::GetEscapeNonPrintables() const { const uint32_t idx = ePropertyEscapeNonPrintables; return GetPropertyAtIndexAs( diff --git a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp index df75ba2681aa9..5064437eaf07a 100644 --- a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -181,7 +181,7 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting( auto max_depth_config = target_sp->GetMaximumDepthOfChildrenToDisplay(); max_depth = std::get(max_depth_config); max_depth_is_default = std::get(max_depth_config); - print_braces = target_sp->GetPrintBraces(); + print_braces = target_sp->GetDebugger().GetPrintBraces(); } else { // If we don't have any targets, then dynamic values won't do us much good. use_dynamic = lldb::eNoDynamicValues; diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index fbd156e40f4cd..27ddc4e7e5092 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -5004,12 +5004,6 @@ TargetProperties::GetMaximumDepthOfChildrenToDisplay() const { return {option_value->GetCurrentValue(), is_default}; } -bool TargetProperties::GetPrintBraces() const { - const uint32_t idx = ePropertyPrintBraces; - return GetPropertyAtIndexAs( - idx, g_target_properties[idx].default_uint_value != 0); -} - uint32_t TargetProperties::GetMaximumSizeOfStringSummary() const { const uint32_t idx = ePropertyMaxSummaryLength; return GetPropertyAtIndexAs( diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index a694fe4145188..223a12e059258 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -101,9 +101,6 @@ let Definition = "target", Path = "target" in { def MaxChildrenDepth: Property<"max-children-depth", "UInt64">, DefaultUnsignedValue<5>, Desc<"Maximum depth to expand children.">; - def PrintBraces: Property<"print-braces", "Boolean">, - DefaultTrue, - Desc<"Print curly braces around structures when displaying variable values.">; def MaxSummaryLength: Property<"max-string-summary-length", "UInt64">, DefaultUnsignedValue<1024>, Desc<"Maximum number of characters to show when using %s in summary strings.">; diff --git a/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py b/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py index 6e937daeb3a5b..6adfebfb9b695 100644 --- a/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py +++ b/lldb/test/API/functionalities/data-formatter/print-braces/TestPrintBraces.py @@ -12,7 +12,7 @@ def test_default_has_braces(self): def test_no_braces(self): self.build() - self.runCmd("settings set target.print-braces false") + self.runCmd("settings set print-braces false") lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) self.expect("frame variable s", matching=False, substrs=["{", "}"]) self.expect("frame variable s", substrs=["x = 1", "y = 2", "z = 3"])