https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/184926
>From b1ef0ccaa846e61ae3b57595efbf86a71e419b5b Mon Sep 17 00:00:00 2001 From: Adrian Prantl <[email protected]> Date: Thu, 5 Mar 2026 17:12:56 -0800 Subject: [PATCH 1/2] [LLDB] Allow one-line summaries in the presence of synthetic child providers This is driven by the Swift language. In Swift many data types such as Int, and String are structs, and LLDB provides summary formatters and synthetic child providers for them. For String, for example, a summary formatter pulls out the string data from the implementation, while a synthetic child provider hides the implementation details from users, so strings don't expand their children. rdar://171646109 --- lldb/source/DataFormatters/FormatManager.cpp | 2 +- .../synth_oneline_summaries/Makefile | 3 +++ .../MyStringFormatter.py | 12 +++++++++++ .../TestSyntheticOneLineSummaries.py | 21 +++++++++++++++++++ .../synth_oneline_summaries/main.c | 16 ++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/MyStringFormatter.py create mode 100644 lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/TestSyntheticOneLineSummaries.py create mode 100644 lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/main.c diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 6d3faa5742d63..301b924a5625d 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -526,7 +526,7 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { if (!synth_sp->MightHaveChildren() && synth_sp->DoesProvideSyntheticValue()) is_synth_val = true; - else + else if (synth_sp->MightHaveChildren()) return false; } diff --git a/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/Makefile b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/MyStringFormatter.py b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/MyStringFormatter.py new file mode 100644 index 0000000000000..938194ee78146 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/MyStringFormatter.py @@ -0,0 +1,12 @@ +import lldb + + +class MyStringSynthProvider: + def __init__(self, valobj, dict): + self.valobj = valobj + + def num_children(self, max_num_children): + return 0 + + def has_children(self): + return False diff --git a/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/TestSyntheticOneLineSummaries.py b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/TestSyntheticOneLineSummaries.py new file mode 100644 index 0000000000000..4cada6efcca85 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/TestSyntheticOneLineSummaries.py @@ -0,0 +1,21 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class SyntheticOneLineSummariesTestCase(TestBase): + def test(self): + """Test that the presence of a synthetic child provider doesn't prevent one-line-summaries.""" + self.build() + lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) + + # set up the synthetic children provider + self.runCmd("script from MyStringFormatter import *") + self.runCmd("type synth add -l MyStringSynthProvider MyString") + self.runCmd('type summary add --summary-string "${var.guts}" MyString') + + self.expect( + "frame variable s", + substrs=['a = "hello", b = "world"'], + ) diff --git a/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/main.c b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/main.c new file mode 100644 index 0000000000000..947be634f5b9b --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/synth_oneline_summaries/main.c @@ -0,0 +1,16 @@ +struct MyString { + const char *guts; +}; + +struct S { + struct MyString a; + struct MyString b; +}; +void stop() {} +int main() { + struct S s; + s.a.guts = "hello"; + s.b.guts = "world"; + stop(); // break here + return 0; +} >From 7051eaaca2c7b71ca8aadcd167598bbf58bc2920 Mon Sep 17 00:00:00 2001 From: Adrian Prantl <[email protected]> Date: Fri, 6 Mar 2026 08:21:17 -0800 Subject: [PATCH 2/2] [LLDB] Reformat comments --- lldb/source/DataFormatters/FormatManager.cpp | 57 ++++++++++---------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 301b924a5625d..aa03f458e034a 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -458,11 +458,11 @@ lldb::Format FormatManager::GetSingleItemFormat(lldb::Format vector_format) { bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { TargetSP target_sp = valobj.GetTargetSP(); - // if settings say no oneline whatsoever + // If settings say no oneline whatsoever then don't oneline. if (target_sp && !target_sp->GetDebugger().GetAutoOneLineSummaries()) - return false; // then don't oneline + return false; - // if this object has a summary, then ask the summary + // If this object has a summary, then ask the summary. if (valobj.GetSummaryFormat().get() != nullptr) return valobj.GetSummaryFormat()->IsOneLiner(); @@ -474,12 +474,12 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { llvm::consumeError(num_children.takeError()); return true; } - // no children, no party + // No children, no party. if (*num_children == 0) return false; - // ask the type if it has any opinion about this eLazyBoolCalculate == no - // opinion; other values should be self explanatory + // Ask the type if it has any opinion about this: + // eLazyBoolCalculate == no opinion CompilerType compiler_type(valobj.GetCompilerType()); if (compiler_type.IsValid()) { switch (compiler_type.ShouldPrintAsOneLiner(&valobj)) { @@ -497,35 +497,36 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { for (size_t idx = 0; idx < *num_children; idx++) { bool is_synth_val = false; ValueObjectSP child_sp(valobj.GetChildAtIndex(idx)); - // something is wrong here - bail out + // Something is wrong here - bail out. if (!child_sp) return false; - // also ask the child's type if it has any opinion + // Also ask the child's type if it has any opinion. CompilerType child_compiler_type(child_sp->GetCompilerType()); if (child_compiler_type.IsValid()) { switch (child_compiler_type.ShouldPrintAsOneLiner(child_sp.get())) { case eLazyBoolYes: - // an opinion of yes is only binding for the child, so keep going + // An opinion of yes is only binding for the child, so keep going, case eLazyBoolCalculate: break; case eLazyBoolNo: - // but if the child says no, then it's a veto on the whole thing + // but if the child says no, then it's a veto on the whole thing. return false; } } - // if we decided to define synthetic children for a type, we probably care - // enough to show them, but avoid nesting children in children + // If we decided to define synthetic children for a type, we probably care + // enough to show them, but avoid nesting children in children. if (child_sp->GetSyntheticChildren().get() != nullptr) { ValueObjectSP synth_sp(child_sp->GetSyntheticValue()); - // wait.. wat? just get out of here.. + // Bail out if there was an error. if (!synth_sp) return false; - // but if we only have them to provide a value, keep going + // If we only have them to provide a value, keep going. if (!synth_sp->MightHaveChildren() && synth_sp->DoesProvideSyntheticValue()) is_synth_val = true; + // If there are synthetic children, the user probably wants to see them. else if (synth_sp->MightHaveChildren()) return false; } @@ -533,30 +534,30 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { total_children_name_len += child_sp->GetName().GetLength(); // 50 itself is a "randomly" chosen number - the idea is that - // overly long structs should not get this treatment + // overly long structs should not get this treatment. // FIXME: maybe make this a user-tweakable setting? if (total_children_name_len > 50) return false; - // if a summary is there.. + // If a summary is there... if (child_sp->GetSummaryFormat()) { - // and it wants children, then bail out + // and it wants children, then bail out. if (child_sp->GetSummaryFormat()->DoesPrintChildren(child_sp.get())) return false; } - // if this child has children.. + // If this child has children, if (child_sp->HasChildren()) { - // ...and no summary... - // (if it had a summary and the summary wanted children, we would have - // bailed out anyway - // so this only makes us bail out if this has no summary and we would - // then print children) - if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do - // that if not a - // synthetic valued - // child - return false; // then bail out + // and no summary... + // + // Note that if it had a summary and the summary + // wanted children, we would have bailed out anyway so this only + // makes us bail out if this has no summary and we would then + // print children. + if (!child_sp->GetSummaryFormat() && !is_synth_val) + // But again only do that if not a synthetic valued child then + // bail out. + return false; } } return true; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
