https://github.com/kastiglione updated 
https://github.com/llvm/llvm-project/pull/195351

>From e5d73eaaaef661f373a3959b34a5b78d9862e0c8 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Fri, 1 May 2026 13:45:19 -0700
Subject: [PATCH 1/7] [lldb] Add lldb.summary and lldb.synthetic decorators

---
 lldb/bindings/python/python-extensions.swig   | 44 +++++++++++++++++++
 lldb/bindings/python/python-wrapper.swig      | 21 +++++++--
 .../decorator-formatters/Makefile             |  2 +
 .../TestDecoratorFormatters.py                | 31 +++++++++++++
 .../decorator-formatters/formatters.py        | 29 ++++++++++++
 .../decorator-formatters/main.cpp             | 15 +++++++
 6 files changed, 138 insertions(+), 4 deletions(-)
 create mode 100644 
lldb/test/API/functionalities/data-formatter/decorator-formatters/Makefile
 create mode 100644 
lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
 create mode 100644 
lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
 create mode 100644 
lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp

diff --git a/lldb/bindings/python/python-extensions.swig 
b/lldb/bindings/python/python-extensions.swig
index 40fa76872ee96..7f5cf520223f0 100644
--- a/lldb/bindings/python/python-extensions.swig
+++ b/lldb/bindings/python/python-extensions.swig
@@ -606,3 +606,47 @@ def is_numeric_type(basic_type):
     return (False,False)
 
 %}
+
+%pythoncode %{
+
+def _type_spec(type_name, regex):
+    type_spec = f"'{type_name}'"
+    if regex:
+        type_spec = f"-x {type_spec}"
+    return type_spec
+
+def summary(type_name, regex=False):
+    """A decorator that registers a function as an LLDB type summary provider.
+
+    @lldb.summary("MyType")
+    def MyTypeSummary(valobj, internal_dict):
+        return "summary string"
+    """
+    type_spec = _type_spec(type_name, regex)
+    def decorator(func):
+        qualified = f"{func.__module__}.{func.__qualname__}"
+        func._lldb_register_command = f"type summary add -F {qualified} 
{type_spec}"
+        return func
+    return decorator
+
+def synthetic(type_name, regex=False):
+    """A decorator that registers a class as an LLDB synthetic child provider.
+
+    @lldb.synthetic("MyType")
+    class MyTypeSynthetic:
+        def __init__(self, valobj, internal_dict):
+            ...
+    """
+    type_spec = _type_spec(type_name, regex)
+    def decorator(cls):
+        qualified = f"{cls.__module__}.{cls.__qualname__}"
+        cls._lldb_register_command = f"type synthetic add -l {qualified} 
{type_spec}"
+        return cls
+    return decorator
+
+def _register_lldb_decorators(module, debugger):
+    for obj in vars(module).values():
+        if cmd := getattr(obj, '_lldb_register_command', None):
+            debugger.HandleCommand(cmd)
+
+%}
diff --git a/lldb/bindings/python/python-wrapper.swig 
b/lldb/bindings/python/python-wrapper.swig
index 72f90f1b23c29..db19604ca51c4 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -1007,10 +1007,23 @@ bool 
lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit(
 
   // This method is optional and need not exist.  So if we don't find it,
   // it's actually a success, not a failure.
-  if (!pfunc.IsAllocated())
-    return true;
-
-  pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), dict);
+  if (pfunc.IsAllocated())
+    pfunc(SWIGBridge::ToSWIGWrapper(debugger), dict);
+
+  // Scan the module for @lldb.summary and @lldb.synthetic decorators.
+  auto lldb_module =
+      unwrapIgnoringErrors(PythonModule::Import("lldb"));
+  if (lldb_module.IsAllocated()) {
+    auto register_func =
+        lldb_module.ResolveName<PythonCallable>("_register_lldb_decorators");
+    if (register_func.IsAllocated()) {
+      auto user_module =
+          unwrapIgnoringErrors(PythonModule::Import(python_module_name));
+      if (user_module.IsAllocated())
+        register_func(std::move(user_module),
+                       SWIGBridge::ToSWIGWrapper(std::move(debugger)));
+    }
+  }
 
   return true;
 }
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/Makefile 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/Makefile
new file mode 100644
index 0000000000000..3d0b98f13f3d7
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/decorator-formatters/Makefile
@@ -0,0 +1,2 @@
+CXX_SOURCES := main.cpp
+include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
new file mode 100644
index 0000000000000..14c5584d02f81
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
@@ -0,0 +1,31 @@
+"""
+Test @lldb.summary and @lldb.synthetic decorators lead to automatic formatter
+registration, when using `command script import`.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_summary(self):
+        self.build()
+        self.runCmd("command script import formatters.py")
+        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.cpp")
+        )
+        frame = thread.selected_frame
+        p = frame.var("p")
+        self.assertEqual(p.summary, "(1, 2)")
+
+    def test_synthetic(self):
+        self.build()
+        self.runCmd("command script import formatters.py")
+        lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.cpp")
+        )
+        self.expect("v c", substrs=["[0] = 10", "[1] = 20", "[2] = 30"])
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
new file mode 100644
index 0000000000000..f45f96a27f3ae
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
@@ -0,0 +1,29 @@
+import lldb
+
+
[email protected]("Pair")
+def pair_summary(valobj, _):
+    first = valobj.GetChildMemberWithName("first").GetValueAsSigned()
+    second = valobj.GetChildMemberWithName("second").GetValueAsSigned()
+    return f"({first}, {second})"
+
+
[email protected]("Container")
+class ContainerSyntheticProvider:
+    valobj: lldb.SBValue
+    count: int
+    items: lldb.SBValue
+
+    def __init__(self, valobj: lldb.SBValue, _) -> None:
+        self.valobj = valobj
+
+    def update(self) -> bool:
+        self.count = 
self.valobj.GetChildMemberWithName("size").GetValueAsSigned()
+        self.items = self.valobj.GetChildMemberWithName("items")
+        return True
+
+    def num_children(self) -> int:
+        return self.count
+
+    def get_child_at_index(self, index: int) -> lldb.SBValue:
+        return self.items.GetChildAtIndex(index)
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp
new file mode 100644
index 0000000000000..ccd43df0aafaa
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp
@@ -0,0 +1,15 @@
+struct Pair {
+  int first;
+  int second;
+};
+
+struct Container {
+  int items[3];
+  int size;
+};
+
+int main() {
+  Pair p = {1, 2};
+  Container c = {{10, 20, 30}, 3};
+  return 0; // break here
+}

>From 307fe8533c96fea2a2bab2c97dbee7a45a298776 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 7 May 2026 15:46:11 -0700
Subject: [PATCH 2/7] Refactor to call HandleCommand immediately, via
 CommandInterpreter

---
 lldb/bindings/python/python-extensions.swig | 94 ++++++++++++---------
 lldb/bindings/python/python-wrapper.swig    | 21 +----
 2 files changed, 58 insertions(+), 57 deletions(-)

diff --git a/lldb/bindings/python/python-extensions.swig 
b/lldb/bindings/python/python-extensions.swig
index 7f5cf520223f0..a1a923714a3f9 100644
--- a/lldb/bindings/python/python-extensions.swig
+++ b/lldb/bindings/python/python-extensions.swig
@@ -282,6 +282,60 @@ def command(command_name=None, doc=None):
 
     return callable
 
+
+def _add_formatter(kind: str, type_name: str, options: dict):
+    import shlex
+
+    type_name = shlex.quote(type_name)
+
+    flag_list = []
+    # Convert `option=True` to "--option", all other cases convert to 
"--option value".
+    for key, value in options.values():
+        flag = key.replace("_", "-")
+        if value is True:
+            flag_list.append(f"--{flag}")
+        else:
+            flag_list.extend((f"--{flag}", value))
+
+    def decorator(obj):
+        qualified = f"{obj.__module__}.{obj.__qualname__}"
+        if isinstance(obj, type):
+            flag_list.extend(("--python-class", qualified))
+        elif callable(obj):
+            flag_list.extend(("--python-function", qualified))
+
+        result = SBCommandReturnObject()
+        flags = " ".join(flag_list)
+        interp = debugger.GetCommandInterpreter()
+        interp.HandleCommand(f"type {kind} add {flags} {type_name}", result)
+        if not result.Succeeded():
+            raise RuntimeError(result.GetError())
+        return obj
+
+    return decorator
+
+
+def summary(type_name, **kwargs):
+    """A decorator that registers a function as an LLDB type summary provider.
+
+    @lldb.summary("MyType")
+    def MyTypeSummary(valobj, _):
+        return "summary string"
+    """
+    return _add_formatter("summary", type_name, kwargs)
+
+
+def synthetic(type_name, **kwargs):
+    """A decorator that registers a class as an LLDB synthetic child provider.
+
+    @lldb.synthetic("MyType")
+    class MyTypeSynthetic:
+        def __init__(self, valobj, _):
+            ...
+    """
+    return _add_formatter("synthetic", type_name, kwargs)
+
+
 class declaration(object):
     '''A class that represents a source declaration location with file, line 
and column.'''
     def __init__(self, file, line, col):
@@ -609,44 +663,4 @@ def is_numeric_type(basic_type):
 
 %pythoncode %{
 
-def _type_spec(type_name, regex):
-    type_spec = f"'{type_name}'"
-    if regex:
-        type_spec = f"-x {type_spec}"
-    return type_spec
-
-def summary(type_name, regex=False):
-    """A decorator that registers a function as an LLDB type summary provider.
-
-    @lldb.summary("MyType")
-    def MyTypeSummary(valobj, internal_dict):
-        return "summary string"
-    """
-    type_spec = _type_spec(type_name, regex)
-    def decorator(func):
-        qualified = f"{func.__module__}.{func.__qualname__}"
-        func._lldb_register_command = f"type summary add -F {qualified} 
{type_spec}"
-        return func
-    return decorator
-
-def synthetic(type_name, regex=False):
-    """A decorator that registers a class as an LLDB synthetic child provider.
-
-    @lldb.synthetic("MyType")
-    class MyTypeSynthetic:
-        def __init__(self, valobj, internal_dict):
-            ...
-    """
-    type_spec = _type_spec(type_name, regex)
-    def decorator(cls):
-        qualified = f"{cls.__module__}.{cls.__qualname__}"
-        cls._lldb_register_command = f"type synthetic add -l {qualified} 
{type_spec}"
-        return cls
-    return decorator
-
-def _register_lldb_decorators(module, debugger):
-    for obj in vars(module).values():
-        if cmd := getattr(obj, '_lldb_register_command', None):
-            debugger.HandleCommand(cmd)
-
 %}
diff --git a/lldb/bindings/python/python-wrapper.swig 
b/lldb/bindings/python/python-wrapper.swig
index db19604ca51c4..72f90f1b23c29 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -1007,23 +1007,10 @@ bool 
lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit(
 
   // This method is optional and need not exist.  So if we don't find it,
   // it's actually a success, not a failure.
-  if (pfunc.IsAllocated())
-    pfunc(SWIGBridge::ToSWIGWrapper(debugger), dict);
-
-  // Scan the module for @lldb.summary and @lldb.synthetic decorators.
-  auto lldb_module =
-      unwrapIgnoringErrors(PythonModule::Import("lldb"));
-  if (lldb_module.IsAllocated()) {
-    auto register_func =
-        lldb_module.ResolveName<PythonCallable>("_register_lldb_decorators");
-    if (register_func.IsAllocated()) {
-      auto user_module =
-          unwrapIgnoringErrors(PythonModule::Import(python_module_name));
-      if (user_module.IsAllocated())
-        register_func(std::move(user_module),
-                       SWIGBridge::ToSWIGWrapper(std::move(debugger)));
-    }
-  }
+  if (!pfunc.IsAllocated())
+    return true;
+
+  pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), dict);
 
   return true;
 }

>From e4fdea0de86d0073bc26728aa5d53159f4c13563 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 7 May 2026 15:48:18 -0700
Subject: [PATCH 3/7] refined comment

---
 lldb/bindings/python/python-extensions.swig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/bindings/python/python-extensions.swig 
b/lldb/bindings/python/python-extensions.swig
index a1a923714a3f9..a8a1968e6e384 100644
--- a/lldb/bindings/python/python-extensions.swig
+++ b/lldb/bindings/python/python-extensions.swig
@@ -288,8 +288,8 @@ def _add_formatter(kind: str, type_name: str, options: 
dict):
 
     type_name = shlex.quote(type_name)
 
+    # Convert `option=True` to "--option", all others to "--option value".
     flag_list = []
-    # Convert `option=True` to "--option", all other cases convert to 
"--option value".
     for key, value in options.values():
         flag = key.replace("_", "-")
         if value is True:

>From 7c911c615f96a0c4ede53751fbd292977fd3aadf Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 7 May 2026 16:07:56 -0700
Subject: [PATCH 4/7] Add regex tests; Fixes and cleanups

---
 lldb/bindings/python/python-extensions.swig   |  6 +---
 .../TestDecoratorFormatters.py                |  9 +++--
 .../decorator-formatters/formatters.py        | 35 +++++++++++++++----
 .../decorator-formatters/main.cpp             | 14 ++++----
 4 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/lldb/bindings/python/python-extensions.swig 
b/lldb/bindings/python/python-extensions.swig
index a8a1968e6e384..8f1008ab641dd 100644
--- a/lldb/bindings/python/python-extensions.swig
+++ b/lldb/bindings/python/python-extensions.swig
@@ -290,7 +290,7 @@ def _add_formatter(kind: str, type_name: str, options: 
dict):
 
     # Convert `option=True` to "--option", all others to "--option value".
     flag_list = []
-    for key, value in options.values():
+    for key, value in options.items():
         flag = key.replace("_", "-")
         if value is True:
             flag_list.append(f"--{flag}")
@@ -660,7 +660,3 @@ def is_numeric_type(basic_type):
     return (False,False)
 
 %}
-
-%pythoncode %{
-
-%}
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
index 14c5584d02f81..eb8e5a214431e 100644
--- 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
+++ 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
@@ -19,8 +19,10 @@ def test_summary(self):
             self, "break here", lldb.SBFileSpec("main.cpp")
         )
         frame = thread.selected_frame
-        p = frame.var("p")
-        self.assertEqual(p.summary, "(1, 2)")
+        ic = frame.var("ic")
+        self.assertEqual(ic.summary, "size=2")
+        fc = frame.var("fc")
+        self.assertEqual(fc.summary, "size=2")
 
     def test_synthetic(self):
         self.build()
@@ -28,4 +30,5 @@ def test_synthetic(self):
         lldbutil.run_to_source_breakpoint(
             self, "break here", lldb.SBFileSpec("main.cpp")
         )
-        self.expect("v c", substrs=["[0] = 10", "[1] = 20", "[2] = 30"])
+        self.expect("v ic", substrs=["[0] = 10", "[1] = 20"])
+        self.expect("v fc", substrs=["[0] = 10.5", "[1] = 20.25"])
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
index f45f96a27f3ae..ee9c8443f5a03 100644
--- 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
+++ 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/formatters.py
@@ -1,15 +1,26 @@
 import lldb
 
 
[email protected]("Pair")
-def pair_summary(valobj, _):
-    first = valobj.GetChildMemberWithName("first").GetValueAsSigned()
-    second = valobj.GetChildMemberWithName("second").GetValueAsSigned()
-    return f"({first}, {second})"
+def _summary(valobj: lldb.SBValue) -> str:
+    size = (
+        valobj.GetNonSyntheticValue()
+        .GetChildMemberWithName("size")
+        .GetValueAsUnsigned()
+    )
+    return f"size={size}"
 
 
[email protected]("Container")
-class ContainerSyntheticProvider:
[email protected]("IntContainer", expand=True)
+def IntContainerSummary(valobj: lldb.SBValue, _):
+    return _summary(valobj)
+
+
[email protected]("^Container<.+>$", regex=True, expand=True)
+def ContainerSummary(valobj, _):
+    return _summary(valobj)
+
+
+class _ContainerSyntheticBase:
     valobj: lldb.SBValue
     count: int
     items: lldb.SBValue
@@ -27,3 +38,13 @@ def num_children(self) -> int:
 
     def get_child_at_index(self, index: int) -> lldb.SBValue:
         return self.items.GetChildAtIndex(index)
+
+
[email protected]("IntContainer")
+class IntContainerSynthetic(_ContainerSyntheticBase):
+    pass
+
+
[email protected]("^Container<.+>$", regex=True)
+class ContainerSynthetic(_ContainerSyntheticBase):
+    pass
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp
index ccd43df0aafaa..35bf7253d929b 100644
--- a/lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/decorator-formatters/main.cpp
@@ -1,15 +1,15 @@
-struct Pair {
-  int first;
-  int second;
+struct IntContainer {
+  int items[3];
+  int size;
 };
 
-struct Container {
-  int items[3];
+template <typename T> struct Container {
+  T items[3];
   int size;
 };
 
 int main() {
-  Pair p = {1, 2};
-  Container c = {{10, 20, 30}, 3};
+  IntContainer ic = {{10, 20, 0}, 2};
+  Container<float> fc = {{10.5, 20.25, 0}, 2};
   return 0; // break here
 }

>From e4495e9a6377948ffa8c89f6c964d919c30211eb Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 7 May 2026 16:11:48 -0700
Subject: [PATCH 5/7] Grep test friendly

---
 lldb/bindings/python/python-extensions.swig | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lldb/bindings/python/python-extensions.swig 
b/lldb/bindings/python/python-extensions.swig
index 8f1008ab641dd..8d6d825b65b3c 100644
--- a/lldb/bindings/python/python-extensions.swig
+++ b/lldb/bindings/python/python-extensions.swig
@@ -283,7 +283,7 @@ def command(command_name=None, doc=None):
     return callable
 
 
-def _add_formatter(kind: str, type_name: str, options: dict):
+def _add_formatter(cmd: str, type_name: str, options: dict):
     import shlex
 
     type_name = shlex.quote(type_name)
@@ -307,7 +307,7 @@ def _add_formatter(kind: str, type_name: str, options: 
dict):
         result = SBCommandReturnObject()
         flags = " ".join(flag_list)
         interp = debugger.GetCommandInterpreter()
-        interp.HandleCommand(f"type {kind} add {flags} {type_name}", result)
+        interp.HandleCommand(f"{cmd} {flags} {type_name}", result)
         if not result.Succeeded():
             raise RuntimeError(result.GetError())
         return obj
@@ -322,7 +322,7 @@ def summary(type_name, **kwargs):
     def MyTypeSummary(valobj, _):
         return "summary string"
     """
-    return _add_formatter("summary", type_name, kwargs)
+    return _add_formatter("type summary add", type_name, kwargs)
 
 
 def synthetic(type_name, **kwargs):
@@ -333,7 +333,7 @@ def synthetic(type_name, **kwargs):
         def __init__(self, valobj, _):
             ...
     """
-    return _add_formatter("synthetic", type_name, kwargs)
+    return _add_formatter("type synthetic add", type_name, kwargs)
 
 
 class declaration(object):

>From 61d9c1d00f48fb4c47561db772e896187268fb22 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 7 May 2026 16:25:49 -0700
Subject: [PATCH 6/7] Document formatter decorators

---
 lldb/docs/use/variable.rst | 102 +++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst
index 82bb3c7ba1e11..3261edbc49797 100644
--- a/lldb/docs/use/variable.rst
+++ b/lldb/docs/use/variable.rst
@@ -882,6 +882,10 @@ you to input a Python script as a summary:
   LLDB will emit a warning if it is unable to find the function you passed, but
   will still register the binding.
 
+- using the ``@lldb.summary`` decorator on a function definition. This combines
+  the definition and registration into a single step. See
+  :ref:`decorator-formatters` for details.
+
 Regular Expression Typenames
 ----------------------------
 
@@ -1146,6 +1150,10 @@ children provider in LLDB:
       y = "Hello world"
    }
 
+As an alternative to the two-step import-then-register pattern above, you can
+use the ``@lldb.synthetic`` decorator to combine both steps. See
+:ref:`decorator-formatters` for details.
+
 LLDB has synthetic children providers for a core subset of STL classes, both in
 the version provided by libstdcpp and by libcxx, as well as for several
 Foundation classes.
@@ -1212,6 +1220,100 @@ or other special provisions and the expression command 
chooses to ignore
 synthetic children in the interest of equivalency with code you asked to have
 compiled from source.
 
+.. _decorator-formatters:
+
+Decorator-Based Formatter Registration
+---------------------------------------
+
+Beginning in version 23, LLDB provides Python decorators that combine the
+definition and registration of formatters into a single step. When a module
+using these decorators is loaded via ``command script import``, the formatters
+are automatically registered.
+
+``@lldb.summary``
++++++++++++++++++
+
+The ``@lldb.summary`` decorator registers a Python function as a type summary
+provider:
+
+.. code-block:: python
+
+   import lldb
+
+   @lldb.summary("Person")
+   def PersonSummary(valobj: lldb.SBValue, _) -> str:
+       name = valobj.GetChildMemberWithName("name").GetSummary()
+       age = valobj.GetChildMemberWithName("age").GetValueAsUnsigned()
+       return f"name={name}, age={age}"
+
+This is equivalent to defining the function and then running:
+
+::
+
+   (lldb) type summary add --python-function module.PersonSummary Person
+
+``@lldb.synthetic``
++++++++++++++++++++
+
+The ``@lldb.synthetic`` decorator registers a Python class as a synthetic child
+provider:
+
+.. code-block:: python
+
+   import lldb
+
+   @lldb.synthetic("Person")
+   class PersonChildren:
+       def __init__(self, valobj: lldb.SBValue, _) -> None:
+           self.valobj = valobj
+
+       def update(self) -> bool:
+           self.name = self.valobj.GetChildMemberWithName("name")
+           self.age = self.valobj.GetChildMemberWithName("age")
+           return True
+
+       def num_children(self) -> int:
+           return 2
+
+       def get_child_at_index(self, index) -> lldb.SBValue:
+           if index == 0:
+               return self.name
+           if index == 1:
+               return self.age
+           return lldb.SBValue()
+
+This is equivalent to defining the class and then running:
+
+::
+
+   (lldb) type synthetic add --python-class module.PersonChildren Person
+
+Passing Options
++++++++++++++++
+
+Both decorators accept keyword arguments that map to command-line flags of the
+corresponding ``type summary add`` or ``type synthetic add`` commands.
+Underscores in keyword names are converted to hyphens. A value of ``True``
+produces a bare flag; any other value is passed as the flag's argument.
+
+For example, to register a summary for a regex type pattern with the expand
+flag:
+
+.. code-block:: python
+
+   @lldb.summary("^std::vector<.+>$", regex=True, expand=True)
+   def VectorSummary(valobj, internal_dict):
+       ...
+
+This is equivalent to:
+
+::
+
+   (lldb) type summary add --python-function module.VectorSummary --regex 
--expand "^std::vector<.+>$"
+
+Other commonly used options include ``category`` to place the formatter in a
+specific category.
+
 Filters
 -------
 

>From f0111b60aa754760a2b6f936c445c716fd05e148 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 7 May 2026 20:13:24 -0700
Subject: [PATCH 7/7] Test failure

---
 .../decorator-formatters/TestDecoratorFormatters.py         | 3 +++
 .../data-formatter/decorator-formatters/broken_formatter.py | 6 ++++++
 2 files changed, 9 insertions(+)
 create mode 100644 
lldb/test/API/functionalities/data-formatter/decorator-formatters/broken_formatter.py

diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
index eb8e5a214431e..5972442ec4c23 100644
--- 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
+++ 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/TestDecoratorFormatters.py
@@ -32,3 +32,6 @@ def test_synthetic(self):
         )
         self.expect("v ic", substrs=["[0] = 10", "[1] = 20"])
         self.expect("v fc", substrs=["[0] = 10.5", "[1] = 20.25"])
+
+    def test_failure(self):
+        self.expect("command script import broken_formatter.py", error=True)
diff --git 
a/lldb/test/API/functionalities/data-formatter/decorator-formatters/broken_formatter.py
 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/broken_formatter.py
new file mode 100644
index 0000000000000..64f60973fde54
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/decorator-formatters/broken_formatter.py
@@ -0,0 +1,6 @@
+import lldb
+
+
[email protected]("Ignored", invalid=True)
+def IgnoredSummary(valobj: lldb.SBValue, _) -> str:
+    return "nope"

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to