https://github.com/medismailben updated 
https://github.com/llvm/llvm-project/pull/210469

>From 547ab0ba7e261272cfd76e44d536eaf67a6f683c Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <[email protected]>
Date: Fri, 17 Jul 2026 17:24:53 -0700
Subject: [PATCH] [lldb/script] Add class-based summary providers via
 ScriptedStringSummaryInterface

Add `type summary add -L <ClassName>` as a class-based alternative to the
existing function-based summary providers, purely additive: nothing about
ScriptSummaryFormat/GetScriptedSummary (the existing function-based path) is
touched.

ScriptedSummaryFormat (TypeSummary.h/.cpp) is a new TypeSummaryImpl backed by
a new Kind::eScriptedClass, parallel to ScriptSummaryFormat. Unlike every
other scripted extension in this series, its interface object cannot be
created eagerly at construction time -- SBTypeSummary::CreateWithClassName
can run before any debugger/target context exists -- so CreatePluginObject is
deferred to the first FormatObject() call and cached from then on, mirroring
how ScriptSummaryFormat already lazily resolves and caches its function
object.

SBTypeSummary::CreateWithClassName mirrors 
SBTypeSynthetic::CreateWithClassName's
existing shape. The two exhaustive switches over TypeSummaryImpl::Kind
(GetSummaryKindName, SBTypeSummary::IsEqualTo) each get a case for
eScriptedClass so the new kind does not trip a -Wswitch failure or silently
compare unequal.

Signed-off-by: Med Ismail Bennani <[email protected]>
---
 lldb/bindings/python/CMakeLists.txt           |  1 +
 lldb/docs/CMakeLists.txt                      |  1 +
 .../templates/scripted_string_summary.py      | 40 +++++++++
 lldb/include/lldb/API/SBTypeSummary.h         |  4 +
 .../include/lldb/DataFormatters/TypeSummary.h | 54 +++++++++++-
 .../ScriptedStringSummaryInterface.h          | 28 ++++++
 .../lldb/Interpreter/ScriptInterpreter.h      |  5 ++
 lldb/include/lldb/lldb-enumerations.h         |  3 +-
 lldb/include/lldb/lldb-forward.h              |  3 +
 lldb/source/API/SBTypeSummary.cpp             | 25 ++++++
 lldb/source/Commands/CommandObjectType.cpp    | 73 ++++++++++++++--
 lldb/source/DataFormatters/TypeSummary.cpp    | 75 ++++++++++++++++
 lldb/source/Interpreter/ScriptInterpreter.cpp |  4 +
 .../ScriptInterpreter/Python/CMakeLists.txt   |  1 +
 .../ScriptInterpreterPythonInterfaces.cpp     |  2 +
 .../ScriptInterpreterPythonInterfaces.h       |  1 +
 .../ScriptedStringSummaryPythonInterface.cpp  | 87 +++++++++++++++++++
 .../ScriptedStringSummaryPythonInterface.h    | 48 ++++++++++
 .../Python/ScriptInterpreterPython.cpp        |  7 ++
 .../Python/ScriptInterpreterPythonImpl.h      |  3 +
 20 files changed, 457 insertions(+), 8 deletions(-)
 create mode 100644 lldb/examples/python/templates/scripted_string_summary.py
 create mode 100644 
lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h
 create mode 100644 
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp
 create mode 100644 
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h

diff --git a/lldb/bindings/python/CMakeLists.txt 
b/lldb/bindings/python/CMakeLists.txt
index d29b143c1408c..902f20d4f0b41 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -120,6 +120,7 @@ function(finish_swig_python swig_target 
lldb_python_bindings_dir lldb_python_tar
     "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_breakpoint.py"
     "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_hook.py"
     
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_stackframe_recognizer.py"
+    "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_string_summary.py"
     )
 
   if(APPLE)
diff --git a/lldb/docs/CMakeLists.txt b/lldb/docs/CMakeLists.txt
index dd091836dc1aa..760991c5a68b5 100644
--- a/lldb/docs/CMakeLists.txt
+++ b/lldb/docs/CMakeLists.txt
@@ -33,6 +33,7 @@ if (LLDB_ENABLE_PYTHON AND SPHINX_FOUND)
       COMMAND "${CMAKE_COMMAND}" -E copy 
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_breakpoint.py" 
"${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
       COMMAND "${CMAKE_COMMAND}" -E copy 
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_hook.py" 
"${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
       COMMAND "${CMAKE_COMMAND}" -E copy 
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_stackframe_recognizer.py"
 "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
+      COMMAND "${CMAKE_COMMAND}" -E copy 
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_string_summary.py" 
"${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
       COMMENT "Copying lldb.py to pretend its a Python package.")
 
     add_dependencies(lldb-python-doc-package swig_wrapper_python)
diff --git a/lldb/examples/python/templates/scripted_string_summary.py 
b/lldb/examples/python/templates/scripted_string_summary.py
new file mode 100644
index 0000000000000..217c3bb6a8e25
--- /dev/null
+++ b/lldb/examples/python/templates/scripted_string_summary.py
@@ -0,0 +1,40 @@
+from abc import ABCMeta, abstractmethod
+
+import lldb
+
+
+class ScriptedStringSummary(metaclass=ABCMeta):
+    """
+    The base class for a scripted string summary provider.
+
+    A summary provider produces the one-line string shown next to a value in
+    `frame variable`/`expression` output. Register it with
+    `type summary add -l <ClassName> <TypeName>`.
+
+    Most of the base class methods are `@abstractmethod` that need to be
+    overwritten by the inheriting class.
+    """
+
+    def __init__(self):
+        """Construct a scripted summary provider.
+
+        Summary providers are constructed with no arguments and are shared
+        across every value they're asked to summarize.
+        """
+        pass
+
+    @abstractmethod
+    def get_summary(
+        self, valobj: lldb.SBValue, options: lldb.SBTypeSummaryOptions
+    ) -> str:
+        """Get the summary string for a value.
+
+        Args:
+            valobj (lldb.SBValue): The value to summarize.
+            options (lldb.SBTypeSummaryOptions): The options to use when
+                producing the summary.
+
+        Returns:
+            str: The summary string for `valobj`.
+        """
+        pass
diff --git a/lldb/include/lldb/API/SBTypeSummary.h 
b/lldb/include/lldb/API/SBTypeSummary.h
index b6869e53a39e7..9ca26532d8156 100644
--- a/lldb/include/lldb/API/SBTypeSummary.h
+++ b/lldb/include/lldb/API/SBTypeSummary.h
@@ -81,6 +81,10 @@ class SBTypeSummary {
   CreateWithScriptCode(const char *data,
                        uint32_t options = 0); // see lldb::eTypeOption values
 
+  static SBTypeSummary
+  CreateWithClassName(const char *data,
+                      uint32_t options = 0); // see lldb::eTypeOption values
+
 #ifndef SWIG
   static SBTypeSummary CreateWithCallback(FormatCallback cb,
                                           uint32_t options = 0,
diff --git a/lldb/include/lldb/DataFormatters/TypeSummary.h 
b/lldb/include/lldb/DataFormatters/TypeSummary.h
index a0938556e0174..4abf18c9c39a3 100644
--- a/lldb/include/lldb/DataFormatters/TypeSummary.h
+++ b/lldb/include/lldb/DataFormatters/TypeSummary.h
@@ -48,7 +48,14 @@ class TypeSummaryOptions {
 
 class TypeSummaryImpl {
 public:
-  enum class Kind { eSummaryString, eScript, eBytecode, eCallback, eInternal };
+  enum class Kind {
+    eSummaryString,
+    eScript,
+    eBytecode,
+    eCallback,
+    eInternal,
+    eScriptedClass
+  };
 
   virtual ~TypeSummaryImpl() = default;
 
@@ -423,6 +430,51 @@ struct ScriptSummaryFormat : public TypeSummaryImpl {
   const ScriptSummaryFormat &operator=(const ScriptSummaryFormat &) = delete;
 };
 
+// Python-based summaries backed by a class, running an instance's
+// `get_summary` method to show data. Unlike ScriptSummaryFormat (a bare
+// function resolved once and cached), the Python object here is itself the
+// cache: it's created lazily on the first call to FormatObject (since this
+// format can be constructed via SBTypeSummary::CreateWithClassName before
+// any debugger/target context exists) and then reused across every
+// subsequent call, for every value of the matching type.
+struct ScriptedSummaryFormat : public TypeSummaryImpl {
+  std::string m_class_name;
+  lldb::ScriptedStringSummaryInterfaceSP m_interface_sp;
+
+  ScriptedSummaryFormat(const TypeSummaryImpl::Flags &flags,
+                        const char *class_name, uint32_t ptr_match_depth = 1);
+
+  ~ScriptedSummaryFormat() override = default;
+
+  const char *GetClassName() const { return m_class_name.c_str(); }
+
+  void SetClassName(const char *class_name) {
+    if (class_name)
+      m_class_name.assign(class_name);
+    else
+      m_class_name.clear();
+    m_interface_sp.reset();
+  }
+
+  bool FormatObject(ValueObject *valobj, std::string &dest,
+                    const TypeSummaryOptions &options) override;
+
+  std::string GetDescription() override;
+
+  std::string GetName() override;
+
+  static bool classof(const TypeSummaryImpl *S) {
+    return S->GetKind() == Kind::eScriptedClass;
+  }
+
+  typedef std::shared_ptr<ScriptedSummaryFormat> SharedPointer;
+
+private:
+  ScriptedSummaryFormat(const ScriptedSummaryFormat &) = delete;
+  const ScriptedSummaryFormat &
+  operator=(const ScriptedSummaryFormat &) = delete;
+};
+
 /// A summary formatter that is defined in LLDB formmater bytecode.
 ///
 /// See `BytecodeSyntheticChildren` for the corresponding synthetic formatter.
diff --git 
a/lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h 
b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h
new file mode 100644
index 0000000000000..a0bc59d82f750
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTRINGSUMMARYINTERFACE_H
+#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTRINGSUMMARYINTERFACE_H
+
+#include "ScriptedInterface.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+class ScriptedStringSummaryInterface : virtual public ScriptedInterface {
+public:
+  virtual llvm::Expected<StructuredData::GenericSP>
+  CreatePluginObject(llvm::StringRef class_name) = 0;
+
+  virtual std::optional<std::string>
+  GetSummary(ValueObject &valobj, const TypeSummaryOptions &options) {
+    return std::nullopt;
+  }
+};
+} // namespace lldb_private
+
+#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTRINGSUMMARYINTERFACE_H
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h 
b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 0e65cb4b8ac4a..98ff3a353d405 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -586,6 +586,11 @@ class ScriptInterpreter : public PluginInterface {
     return {};
   }
 
+  virtual lldb::ScriptedStringSummaryInterfaceSP
+  CreateScriptedStringSummaryInterface() {
+    return {};
+  }
+
   virtual StructuredData::ObjectSP
   CreateStructuredDataFromScriptObject(ScriptObject obj) {
     return {};
diff --git a/lldb/include/lldb/lldb-enumerations.h 
b/lldb/include/lldb/lldb-enumerations.h
index 93c252b55de99..773152d1dc13b 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -268,7 +268,8 @@ enum ScriptedExtension {
   eScriptedExtensionScriptedThread,
   eScriptedExtensionScriptedFrame,
   eScriptedExtensionScriptedStackFrameRecognizer,
-  kLastScriptedExtension = eScriptedExtensionScriptedStackFrameRecognizer
+  eScriptedExtensionScriptedStringSummary,
+  kLastScriptedExtension = eScriptedExtensionScriptedStringSummary
 };
 
 /// Register numbering types.
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 157aa5743f016..075a033253b1c 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -199,6 +199,7 @@ class ScriptedProcessInterface;
 class ScriptedThreadInterface;
 class ScriptedThreadPlanInterface;
 class ScriptedStackFrameRecognizerInterface;
+class ScriptedStringSummaryInterface;
 class ScriptedSyntheticChildren;
 class SearchFilter;
 class Section;
@@ -438,6 +439,8 @@ typedef 
std::shared_ptr<lldb_private::ScriptedBreakpointInterface>
     ScriptedBreakpointInterfaceSP;
 typedef std::shared_ptr<lldb_private::ScriptedStackFrameRecognizerInterface>
     ScriptedStackFrameRecognizerInterfaceSP;
+typedef std::shared_ptr<lldb_private::ScriptedStringSummaryInterface>
+    ScriptedStringSummaryInterfaceSP;
 typedef std::shared_ptr<lldb_private::Section> SectionSP;
 typedef std::unique_ptr<lldb_private::SectionList> SectionListUP;
 typedef std::weak_ptr<lldb_private::Section> SectionWP;
diff --git a/lldb/source/API/SBTypeSummary.cpp 
b/lldb/source/API/SBTypeSummary.cpp
index 58ec068ab9600..a424394d2768f 100644
--- a/lldb/source/API/SBTypeSummary.cpp
+++ b/lldb/source/API/SBTypeSummary.cpp
@@ -135,6 +135,17 @@ SBTypeSummary SBTypeSummary::CreateWithScriptCode(const 
char *data,
       TypeSummaryImplSP(new ScriptSummaryFormat(options, "", data)));
 }
 
+SBTypeSummary SBTypeSummary::CreateWithClassName(const char *data,
+                                                 uint32_t options) {
+  LLDB_INSTRUMENT_VA(data, options);
+
+  if (!data || data[0] == 0)
+    return SBTypeSummary();
+
+  return SBTypeSummary(
+      TypeSummaryImplSP(new ScriptedSummaryFormat(options, data)));
+}
+
 SBTypeSummary SBTypeSummary::CreateWithCallback(FormatCallback cb,
                                                 uint32_t options,
                                                 const char *description) {
@@ -372,6 +383,16 @@ bool SBTypeSummary::IsEqualTo(lldb::SBTypeSummary &rhs) {
     return GetOptions() == rhs.GetOptions();
   case TypeSummaryImpl::Kind::eInternal:
     return (m_opaque_sp.get() == rhs.m_opaque_sp.get());
+  case TypeSummaryImpl::Kind::eScriptedClass: {
+    ScriptedSummaryFormat *lhs_ptr =
+        llvm::dyn_cast<ScriptedSummaryFormat>(m_opaque_sp.get());
+    ScriptedSummaryFormat *rhs_ptr =
+        llvm::dyn_cast<ScriptedSummaryFormat>(rhs.m_opaque_sp.get());
+    if (!lhs_ptr || !rhs_ptr)
+      return false;
+    return strcmp(lhs_ptr->GetClassName(), rhs_ptr->GetClassName()) == 0 &&
+           GetOptions() == rhs.GetOptions();
+  }
   }
 
   return false;
@@ -417,6 +438,10 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
                  llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get())) {
     new_sp = TypeSummaryImplSP(new StringSummaryFormat(
         GetOptions(), current_summary_ptr->GetSummaryString()));
+  } else if (ScriptedSummaryFormat *current_summary_ptr =
+                 llvm::dyn_cast<ScriptedSummaryFormat>(m_opaque_sp.get())) {
+    new_sp = TypeSummaryImplSP(new ScriptedSummaryFormat(
+        GetOptions(), current_summary_ptr->GetClassName()));
   }
 
   SetSP(new_sp);
diff --git a/lldb/source/Commands/CommandObjectType.cpp 
b/lldb/source/Commands/CommandObjectType.cpp
index c1dc949a7b815..985bf4709fef0 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -21,6 +21,7 @@
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionArgParser.h"
 #include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
 #include "lldb/Interpreter/OptionValueBoolean.h"
 #include "lldb/Interpreter/OptionValueLanguage.h"
 #include "lldb/Interpreter/OptionValueString.h"
@@ -123,9 +124,9 @@ const char *FormatCategoryToString(FormatCategoryItem item, 
bool long_name) {
 class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
                                     public IOHandlerDelegateMultiline {
 private:
-  class CommandOptions : public Options {
+  class CommandOptions : public OptionGroup {
   public:
-    CommandOptions(CommandInterpreter &interpreter) {}
+    CommandOptions() = default;
 
     ~CommandOptions() override = default;
 
@@ -151,12 +152,16 @@ class CommandObjectTypeSummaryAdd : public 
CommandObjectParsed,
     uint32_t m_ptr_match_depth = 1;
   };
 
+  OptionGroupOptions m_option_group;
   CommandOptions m_options;
+  OptionGroupPythonClassWithDict m_class_options;
 
-  Options *GetOptions() override { return &m_options; }
+  Options *GetOptions() override { return &m_option_group; }
 
   bool Execute_ScriptSummary(Args &command, CommandReturnObject &result);
 
+  bool Execute_PythonClassSummary(Args &command, CommandReturnObject &result);
+
   bool Execute_StringSummary(Args &command, CommandReturnObject &result);
 
 public:
@@ -1163,7 +1168,8 @@ Status 
CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
     uint32_t option_idx, llvm::StringRef option_arg,
     ExecutionContext *execution_context) {
   Status error;
-  const int short_option = m_getopt_table[option_idx].val;
+  const int short_option =
+      g_type_summary_add_options[option_idx].short_option;
   bool success;
 
   switch (short_option) {
@@ -1374,6 +1380,48 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
   return result.Succeeded();
 }
 
+bool CommandObjectTypeSummaryAdd::Execute_PythonClassSummary(
+    Args &command, CommandReturnObject &result) {
+  const size_t argc = command.GetArgumentCount();
+
+  if (argc < 1 && !m_options.m_name) {
+    result.AppendErrorWithFormat("%s takes one or more args",
+                                 m_cmd_name.c_str());
+    return false;
+  }
+
+  const std::string &class_name = m_class_options.GetName();
+  if (class_name.empty()) {
+    result.AppendError("must provide a Python class name");
+    return false;
+  }
+
+  TypeSummaryImplSP script_format = std::make_shared<ScriptedSummaryFormat>(
+      m_options.m_flags, class_name.c_str(), m_options.m_ptr_match_depth);
+
+  Status error;
+
+  for (auto &entry : command.entries()) {
+    AddSummary(ConstString(entry.ref()), script_format, m_options.m_match_type,
+               m_options.m_category, &error);
+    if (error.Fail()) {
+      result.AppendError(error.AsCString());
+      return false;
+    }
+  }
+
+  if (m_options.m_name) {
+    AddNamedSummary(m_options.m_name, script_format, &error);
+    if (error.Fail()) {
+      result.AppendError(error.AsCString());
+      result.AppendError("added to types, but not given a name");
+      return false;
+    }
+  }
+
+  return result.Succeeded();
+}
+
 #endif
 
 bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
@@ -1450,7 +1498,14 @@ CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd(
     CommandInterpreter &interpreter)
     : CommandObjectParsed(interpreter, "type summary add",
                           "Add a new summary style for a type.", nullptr),
-      IOHandlerDelegateMultiline("DONE"), m_options(interpreter) {
+      IOHandlerDelegateMultiline("DONE"),
+      m_class_options("scripted string summary", /*is_class=*/true, 'L', 'K',
+                      'V') {
+  m_option_group.Append(&m_options);
+  m_option_group.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
+                        LLDB_OPT_SET_ALL);
+  m_option_group.Finalize();
+
   AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
 
   SetHelpLong(
@@ -1553,7 +1608,13 @@ void CommandObjectTypeSummaryAdd::DoExecute(Args 
&command,
                                             CommandReturnObject &result) {
   WarnOnPotentialUnquotedUnsignedType(command, result);
 
-  if (m_options.m_is_add_script) {
+  if (!m_class_options.GetName().empty()) {
+#if LLDB_ENABLE_PYTHON
+    Execute_PythonClassSummary(command, result);
+#else
+    result.AppendError("python is disabled");
+#endif
+  } else if (m_options.m_is_add_script) {
 #if LLDB_ENABLE_PYTHON
     Execute_ScriptSummary(command, result);
 #else
diff --git a/lldb/source/DataFormatters/TypeSummary.cpp 
b/lldb/source/DataFormatters/TypeSummary.cpp
index 4f01466f85148..73ff39db19a81 100644
--- a/lldb/source/DataFormatters/TypeSummary.cpp
+++ b/lldb/source/DataFormatters/TypeSummary.cpp
@@ -16,6 +16,8 @@
 #include "lldb/Core/Debugger.h"
 #include "lldb/DataFormatters/ValueObjectPrinter.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
 #include "lldb/Symbol/CompilerType.h"
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/Target.h"
@@ -60,6 +62,8 @@ std::string TypeSummaryImpl::GetSummaryKindName() {
     return "c++";
   case Kind::eBytecode:
     return "bytecode";
+  case Kind::eScriptedClass:
+    return "python class";
   }
   llvm_unreachable("Unknown type kind name");
 }
@@ -242,6 +246,77 @@ std::string ScriptSummaryFormat::GetDescription() {
 
 std::string ScriptSummaryFormat::GetName() { return m_script_formatter_name; }
 
+ScriptedSummaryFormat::ScriptedSummaryFormat(
+    const TypeSummaryImpl::Flags &flags, const char *class_name,
+    uint32_t ptr_match_depth)
+    : TypeSummaryImpl(Kind::eScriptedClass, flags, ptr_match_depth),
+      m_class_name(class_name ? class_name : ""), m_interface_sp() {}
+
+bool ScriptedSummaryFormat::FormatObject(ValueObject *valobj,
+                                         std::string &retval,
+                                         const TypeSummaryOptions &options) {
+  if (!valobj)
+    return false;
+
+  TargetSP target_sp(valobj->GetTargetSP());
+
+  if (!target_sp) {
+    retval.assign("error: no target");
+    return false;
+  }
+
+  ScriptInterpreter *script_interpreter =
+      target_sp->GetDebugger().GetScriptInterpreter();
+
+  if (!script_interpreter) {
+    retval.assign("error: no ScriptInterpreter");
+    return false;
+  }
+
+  if (!m_interface_sp) {
+    m_interface_sp = 
script_interpreter->CreateScriptedStringSummaryInterface();
+    if (!m_interface_sp) {
+      retval.assign("error: no ScriptedStringSummaryInterface");
+      return false;
+    }
+
+    llvm::Expected<StructuredData::GenericSP> obj_or_err =
+        m_interface_sp->CreatePluginObject(m_class_name);
+    if (!obj_or_err) {
+      retval.assign(llvm::toString(obj_or_err.takeError()));
+      m_interface_sp.reset();
+      return false;
+    }
+  }
+
+  std::optional<std::string> summary =
+      m_interface_sp->GetSummary(*valobj, options);
+  if (!summary) {
+    retval.assign("error: script did not provide a summary");
+    return false;
+  }
+
+  retval = std::move(*summary);
+  return true;
+}
+
+std::string ScriptedSummaryFormat::GetDescription() {
+  StreamString sstr;
+  sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u\n  ",
+              Cascades() ? "" : " (not cascading)",
+              !DoesPrintChildren(nullptr) ? "" : " (show children)",
+              !DoesPrintValue(nullptr) ? " (hide value)" : "",
+              IsOneLiner() ? " (one-line printout)" : "",
+              SkipsPointers() ? " (skip pointers)" : "",
+              SkipsReferences() ? " (skip references)" : "",
+              HideNames(nullptr) ? " (hide member names)" : "",
+              GetPtrMatchDepth());
+  sstr.PutCString(m_class_name);
+  return std::string(sstr.GetString());
+}
+
+std::string ScriptedSummaryFormat::GetName() { return m_class_name; }
+
 BytecodeSummaryFormat::BytecodeSummaryFormat(
     const TypeSummaryImpl::Flags &flags,
     std::unique_ptr<llvm::MemoryBuffer> bytecode)
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp 
b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 4f6095d097d10..33e915951596e 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -221,6 +221,8 @@ 
ScriptInterpreter::ExtensionToString(lldb::ScriptedExtension extension) {
     return "ScriptedFrame";
   case eScriptedExtensionScriptedStackFrameRecognizer:
     return "ScriptedStackFrameRecognizer";
+  case eScriptedExtensionScriptedStringSummary:
+    return "ScriptedStringSummary";
   }
   llvm_unreachable("unhandled ScriptedExtension");
 }
@@ -241,6 +243,8 @@ ScriptInterpreter::StringToExtension(llvm::StringRef 
string) {
       .CaseLower("ScriptedFrame", eScriptedExtensionScriptedFrame)
       .CaseLower("ScriptedStackFrameRecognizer",
                  eScriptedExtensionScriptedStackFrameRecognizer)
+      .CaseLower("ScriptedStringSummary",
+                 eScriptedExtensionScriptedStringSummary)
       .Default(eScriptedExtensionInvalid);
 }
 
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt 
b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 201574da72a19..9932d31d26f30 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -33,6 +33,7 @@ set(python_plugin_sources
   Interfaces/ScriptedHookPythonInterface.cpp
   Interfaces/ScriptedBreakpointPythonInterface.cpp
   Interfaces/ScriptedStackFrameRecognizerPythonInterface.cpp
+  Interfaces/ScriptedStringSummaryPythonInterface.cpp
   Interfaces/ScriptedThreadPlanPythonInterface.cpp
   Interfaces/ScriptedThreadPythonInterface.cpp
 )
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
index 8914f6b239023..1636723a7d459 100644
--- 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
@@ -30,6 +30,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() {
   ScriptedThreadPythonInterface::Initialize();
   ScriptedFramePythonInterface::Initialize();
   ScriptedStackFrameRecognizerPythonInterface::Initialize();
+  ScriptedStringSummaryPythonInterface::Initialize();
 }
 
 void ScriptInterpreterPythonInterfaces::Terminate() {
@@ -43,4 +44,5 @@ void ScriptInterpreterPythonInterfaces::Terminate() {
   ScriptedThreadPythonInterface::Terminate();
   ScriptedFramePythonInterface::Terminate();
   ScriptedStackFrameRecognizerPythonInterface::Terminate();
+  ScriptedStringSummaryPythonInterface::Terminate();
 }
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 03d747e63a592..686614c5f2da9 100644
--- 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
@@ -20,6 +20,7 @@
 #include "ScriptedPlatformPythonInterface.h"
 #include "ScriptedProcessPythonInterface.h"
 #include "ScriptedStackFrameRecognizerPythonInterface.h"
+#include "ScriptedStringSummaryPythonInterface.h"
 #include "ScriptedThreadPlanPythonInterface.h"
 #include "ScriptedThreadPythonInterface.h"
 
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp
new file mode 100644
index 0000000000000..c3fdffdad2f05
--- /dev/null
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../lldb-python.h"
+
+#include "lldb/Core/PluginManager.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "../SWIGPythonBridge.h"
+#include "../ScriptInterpreterPythonImpl.h"
+#include "ScriptedStringSummaryPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ScriptedStringSummaryPythonInterface::ScriptedStringSummaryPythonInterface(
+    ScriptInterpreterPythonImpl &interpreter)
+    : ScriptedStringSummaryInterface(), ScriptedPythonInterface(interpreter) {}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedStringSummaryPythonInterface::CreatePluginObject(
+    llvm::StringRef class_name) {
+  if (class_name.empty())
+    return llvm::createStringError("empty class name");
+
+  return ScriptedPythonInterface::CreatePluginObject(
+      ScriptedMetadata(class_name, nullptr), nullptr);
+}
+
+std::optional<std::string> ScriptedStringSummaryPythonInterface::GetSummary(
+    ValueObject &valobj, const TypeSummaryOptions &options) {
+  if (!m_object_instance_sp)
+    return std::nullopt;
+
+  Locker py_lock(&m_interpreter,
+                 Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN,
+                 Locker::FreeLock);
+
+  PythonObject implementor(PyRefType::Borrowed,
+                           (PyObject *)m_object_instance_sp->GetValue());
+  if (!implementor.IsAllocated())
+    return std::nullopt;
+
+  llvm::Expected<PythonObject> expected_py_return = implementor.CallMethod(
+      "get_summary", SWIGBridge::ToSWIGWrapper(valobj.GetSP()),
+      SWIGBridge::ToSWIGWrapper(options));
+
+  if (!expected_py_return) {
+    llvm::consumeError(expected_py_return.takeError());
+    return std::nullopt;
+  }
+
+  PythonObject py_return = std::move(expected_py_return.get());
+  if (!py_return.IsAllocated())
+    return std::nullopt;
+
+  // Match the legacy function-based summary contract
+  // (LLDBSwigPythonCallTypeScript): the return value is converted via
+  // Python's str() regardless of its type, so `get_summary` may return any
+  // str()-convertible object, not just a literal string.
+  return py_return.Str().GetString().str();
+}
+
+void ScriptedStringSummaryPythonInterface::Initialize() {
+  const std::vector<llvm::StringRef> ci_usages = {
+      "type summary add -L <ClassName> [-K <key> -V <value> ...] <TypeName>"};
+  const std::vector<llvm::StringRef> api_usages = {
+      "SBTypeSummary.CreateWithClassName"};
+  PluginManager::RegisterPlugin(
+      GetPluginNameStatic(),
+      "Provide a summary string for a type, used by 'type summary add -l'",
+      CreateInstance, eScriptedExtensionScriptedStringSummary,
+      eScriptLanguagePython, {ci_usages, api_usages});
+}
+
+void ScriptedStringSummaryPythonInterface::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h
new file mode 100644
index 0000000000000..c54c3ad6581bc
--- /dev/null
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStringSummaryPythonInterface.h
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef 
LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTRINGSUMMARYPYTHONINTERFACE_H
+#define 
LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTRINGSUMMARYPYTHONINTERFACE_H
+
+#include "lldb/Interpreter/Interfaces/ScriptedStringSummaryInterface.h"
+
+#include "ScriptedPythonInterface.h"
+namespace lldb_private {
+
+class ScriptedStringSummaryPythonInterface
+    : public ScriptedStringSummaryInterface,
+      public ScriptedPythonInterface,
+      public PluginInterface {
+public:
+  ScriptedStringSummaryPythonInterface(
+      ScriptInterpreterPythonImpl &interpreter);
+
+  llvm::Expected<StructuredData::GenericSP>
+  CreatePluginObject(llvm::StringRef class_name) override;
+
+  llvm::SmallVector<AbstractMethodRequirement>
+  GetAbstractMethodRequirements() const override {
+    return llvm::SmallVector<AbstractMethodRequirement>({{"get_summary", 3}});
+  }
+
+  std::optional<std::string>
+  GetSummary(ValueObject &valobj, const TypeSummaryOptions &options) override;
+
+  static void Initialize();
+
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() {
+    return "ScriptedStringSummaryPythonInterface";
+  }
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+} // namespace lldb_private
+
+#endif // 
LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTRINGSUMMARYPYTHONINTERFACE_H
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp 
b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 7b1bd9d8411c5..71d607814c238 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -289,6 +289,8 @@ llvm::Expected<std::string> 
ScriptInterpreterPython::ExtensionToImportPath(
     return "lldb.plugins.scripted_process";
   case eScriptedExtensionScriptedStackFrameRecognizer:
     return "lldb.plugins.scripted_stackframe_recognizer";
+  case eScriptedExtensionScriptedStringSummary:
+    return "lldb.plugins.scripted_string_summary";
   case eScriptedExtensionInvalid:
     return llvm::createStringError("invalid extension name");
   }
@@ -2003,6 +2005,11 @@ 
ScriptInterpreterPythonImpl::CreateScriptedStackFrameRecognizerInterface() {
   return std::make_shared<ScriptedStackFrameRecognizerPythonInterface>(*this);
 }
 
+ScriptedStringSummaryInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedStringSummaryInterface() {
+  return std::make_shared<ScriptedStringSummaryPythonInterface>(*this);
+}
+
 ScriptedThreadInterfaceSP
 ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() {
   return std::make_shared<ScriptedThreadPythonInterface>(*this);
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h 
b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index d8a817198253f..570be07cc4e3b 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -86,6 +86,9 @@ class ScriptInterpreterPythonImpl : public 
ScriptInterpreterPython {
   lldb::ScriptedStackFrameRecognizerInterfaceSP
   CreateScriptedStackFrameRecognizerInterface() override;
 
+  lldb::ScriptedStringSummaryInterfaceSP
+  CreateScriptedStringSummaryInterface() override;
+
   lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
 
   lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;

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

Reply via email to