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
