[Lldb-commits] [lldb] [LLDB] Add type summaries for MSVC STL strings (PR #143177)

via lldb-commits lldb-commits at lists.llvm.org
Tue Jun 17 13:58:02 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: nerix (Nerixyz)

<details>
<summary>Changes</summary>

This PR adds type summaries for `std::{string,wstring,u8string,u16string,u32string}` from the MSVC STL.

See https://github.com/llvm/llvm-project/issues/24834 for the MSVC STL issue.

The following changes were made:

- Added a new type summary kind `CXXCompositeSummaryFormat`. It holds a list of child summaries paired with a validator function that checks if a `ValueObject` can be formatted by a child. This feels like it should be done in another PR, but there aren't any tests for it other than the STL formatters (since it's only in C++ it can't be used in Python).
	- As part of this, the formatter data (callback/format string) from `CXXFunctionSummaryFormat` and `StringSummaryFormat` was extracted to `CXXFunctionSummaryData` and `StringSummaryData` respectively. This allows the composite format to use the same data and `FormatObject` of said data.
- `dotest.py` now detects if the MSVC STL is available. It does so by looking at the target triple, which is an additional argument passed from Lit. It specifically checks for `windows-msvc` to not match on `windows-gnu` (i.e. MinGW/Cygwin).
- (The main part): Added support for summarizing `std::(w)string` from MSVC's STL. Because the type names from the libstdc++ (pre C++ 11) string types are the same as on MSVC's STL, `CXXCompositeSummaryFormat` is used with two entries, one for MSVC's STL and one for libstdc++.
  With MSVC's STL, `std::u{8,16,32}string` is also handled. These aren't handled for libstdc++, so I put them in `LoadMsvcStlFormatters`.

---

Patch is 53.05 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/143177.diff


21 Files Affected:

- (modified) lldb/include/lldb/DataFormatters/StringPrinter.h (+15) 
- (modified) lldb/include/lldb/DataFormatters/TypeSummary.h (+91-11) 
- (modified) lldb/include/lldb/DataFormatters/ValueObjectPrinter.h (+1-1) 
- (modified) lldb/packages/Python/lldbsuite/test/configuration.py (+2) 
- (modified) lldb/packages/Python/lldbsuite/test/dotest.py (+23) 
- (modified) lldb/packages/Python/lldbsuite/test/dotest_args.py (+6) 
- (modified) lldb/packages/Python/lldbsuite/test/test_categories.py (+1) 
- (modified) lldb/source/API/SBTypeSummary.cpp (+10-1) 
- (modified) lldb/source/Commands/CommandObjectType.cpp (+4-3) 
- (modified) lldb/source/DataFormatters/TypeSummary.cpp (+112-31) 
- (modified) lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt (+1) 
- (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+115-31) 
- (added) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp (+140) 
- (added) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h (+33) 
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/Makefile (+4) 
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/TestDataFormatterStdString.py (+118) 
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/main.cpp (+40) 
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/Makefile (+4) 
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/TestDataFormatterStdU8String.py (+31) 
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/main.cpp (+14) 
- (modified) lldb/test/API/lit.cfg.py (+3) 


``````````diff
diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h b/lldb/include/lldb/DataFormatters/StringPrinter.h
index 4169f53e63f38..4ebe712be60e1 100644
--- a/lldb/include/lldb/DataFormatters/StringPrinter.h
+++ b/lldb/include/lldb/DataFormatters/StringPrinter.h
@@ -152,6 +152,21 @@ class StringPrinter {
   template <StringElementType element_type>
   static bool
   ReadBufferAndDumpToStream(const ReadBufferAndDumpToStreamOptions &options);
+
+  template <StringElementType element_type>
+  static constexpr uint64_t ElementByteSize() {
+    switch (element_type) {
+    case StringElementType::ASCII:
+    case StringElementType::UTF8:
+      return 1;
+    case StringElementType::UTF16:
+      return 2;
+    case StringElementType::UTF32:
+      return 3;
+    default:
+      return 0;
+    }
+  }
 };
 
 } // namespace formatters
diff --git a/lldb/include/lldb/DataFormatters/TypeSummary.h b/lldb/include/lldb/DataFormatters/TypeSummary.h
index 589f68c2ce314..ea32b31c0b2ae 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,
+    eComposite,
+    eInternal
+  };
 
   virtual ~TypeSummaryImpl() = default;
 
@@ -292,18 +299,29 @@ class TypeSummaryImpl {
   const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete;
 };
 
-// simple string-based summaries, using ${var to show data
-struct StringSummaryFormat : public TypeSummaryImpl {
+struct StringSummaryData {
   std::string m_format_str;
   FormatEntity::Entry m_format;
   Status m_error;
 
+  StringSummaryData(const char *f);
+  void SetFormat(const char *f);
+
+  bool FormatObject(ValueObject *valobj, std::string &dest,
+                    const TypeSummaryOptions &options,
+                    const TypeSummaryImpl &summary);
+};
+
+// simple string-based summaries, using ${var to show data
+struct StringSummaryFormat : public TypeSummaryImpl {
+  StringSummaryData m_data;
+
   StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f,
                       uint32_t ptr_match_depth = 1);
 
   ~StringSummaryFormat() override = default;
 
-  const char *GetSummaryString() const { return m_format_str.c_str(); }
+  const char *GetSummaryString() const { return m_data.m_format_str.c_str(); }
 
   void SetSummaryString(const char *f);
 
@@ -323,15 +341,23 @@ struct StringSummaryFormat : public TypeSummaryImpl {
   const StringSummaryFormat &operator=(const StringSummaryFormat &) = delete;
 };
 
-// summaries implemented via a C++ function
-struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
+struct CXXFunctionSummaryData {
   // we should convert these to SBValue and SBStream if we ever cross the
   // boundary towards the external world
-  typedef std::function<bool(ValueObject &, Stream &,
-                             const TypeSummaryOptions &)>
-      Callback;
+  using Callback =
+      std::function<bool(ValueObject &, Stream &, const TypeSummaryOptions &)>;
 
   Callback m_impl;
+
+  bool FormatObject(ValueObject *valobj, std::string &dest,
+                    const TypeSummaryOptions &options,
+                    const TypeSummaryImpl &summary);
+};
+
+// summaries implemented via a C++ function
+struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
+  using Callback = CXXFunctionSummaryData::Callback;
+  CXXFunctionSummaryData m_data;
   std::string m_description;
 
   CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl,
@@ -340,11 +366,13 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
 
   ~CXXFunctionSummaryFormat() override = default;
 
-  Callback GetBackendFunction() const { return m_impl; }
+  Callback GetBackendFunction() const { return m_data.m_impl; }
 
   const char *GetTextualInfo() const { return m_description.c_str(); }
 
-  void SetBackendFunction(Callback cb_func) { m_impl = std::move(cb_func); }
+  void SetBackendFunction(Callback cb_func) {
+    m_data.m_impl = std::move(cb_func);
+  }
 
   void SetTextualInfo(const char *descr) {
     if (descr)
@@ -372,6 +400,58 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
   operator=(const CXXFunctionSummaryFormat &) = delete;
 };
 
+/// A summary that supports multiple type layouts for the same type name.
+///
+/// This summary maintains a list of child summaries, each paired with a
+/// validator function. An associated validator is used to determine which child
+/// is appropriate for formatting a given ValueObject.
+struct CXXCompositeSummaryFormat : public TypeSummaryImpl {
+  using Validator = bool(ValueObject &valobj);
+  using ChildData = std::variant<CXXFunctionSummaryData, StringSummaryData>;
+  using Child = std::pair<Validator *, ChildData>;
+  using Children = llvm::SmallVector<Child, 2>;
+
+  Children m_children;
+  std::string m_description;
+
+  CXXCompositeSummaryFormat(const TypeSummaryImpl::Flags &flags,
+                            const char *description, Children impls = {},
+                            uint32_t ptr_match_depth = 1);
+
+  ~CXXCompositeSummaryFormat() override = default;
+
+  const char *GetTextualInfo() const { return m_description.c_str(); }
+
+  CXXCompositeSummaryFormat *Append(Validator *validator, ChildData impl);
+
+  void SetTextualInfo(const char *descr) {
+    if (descr)
+      m_description.assign(descr);
+    else
+      m_description.clear();
+  }
+
+  Children CopyChildren() const;
+
+  bool FormatObject(ValueObject *valobj, std::string &dest,
+                    const TypeSummaryOptions &options) override;
+
+  std::string GetDescription() override;
+
+  static bool classof(const TypeSummaryImpl *S) {
+    return S->GetKind() == Kind::eComposite;
+  }
+
+  std::string GetName() override;
+
+  using SharedPointer = std::shared_ptr<CXXCompositeSummaryFormat>;
+
+private:
+  CXXCompositeSummaryFormat(const CXXCompositeSummaryFormat &) = delete;
+  const CXXCompositeSummaryFormat &
+  operator=(const CXXCompositeSummaryFormat &) = delete;
+};
+
 // Python-based summaries, running script code to show data
 struct ScriptSummaryFormat : public TypeSummaryImpl {
   std::string m_function_name;
diff --git a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
index f9deb6ebf8d6d..1f20c3180d37a 100644
--- a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
+++ b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
@@ -165,7 +165,7 @@ class ValueObjectPrinter {
   std::string m_error;
   bool m_val_summary_ok;
 
-  friend struct StringSummaryFormat;
+  friend struct StringSummaryData;
 
   ValueObjectPrinter(const ValueObjectPrinter &) = delete;
   const ValueObjectPrinter &operator=(const ValueObjectPrinter &) = delete;
diff --git a/lldb/packages/Python/lldbsuite/test/configuration.py b/lldb/packages/Python/lldbsuite/test/configuration.py
index b2d91fd211477..4ec892bef69f9 100644
--- a/lldb/packages/Python/lldbsuite/test/configuration.py
+++ b/lldb/packages/Python/lldbsuite/test/configuration.py
@@ -134,6 +134,8 @@
 libcxx_include_target_dir = None
 libcxx_library_dir = None
 
+target_triple = None
+
 # A plugin whose tests will be enabled, like intel-pt.
 enabled_plugins = []
 
diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py
index d7f274ac4f60e..dd6fbdf8daed4 100644
--- a/lldb/packages/Python/lldbsuite/test/dotest.py
+++ b/lldb/packages/Python/lldbsuite/test/dotest.py
@@ -299,6 +299,8 @@ def parseOptionsAndInitTestdirs():
     configuration.libcxx_library_dir = args.libcxx_library_dir
     configuration.cmake_build_type = args.cmake_build_type.lower()
 
+    configuration.target_triple = args.target_triple
+
     if args.channels:
         lldbtest_config.channels = args.channels
 
@@ -831,6 +833,26 @@ def checkLibstdcxxSupport():
     configuration.skip_categories.append("libstdcxx")
 
 
+def canRunMsvcStlTests():
+    if "windows-msvc" in configuration.target_triple:
+        return True, "MSVC STL is present on *windows-msvc*"
+    return (
+        False,
+        f"Don't know how to build with MSVC's STL on {configuration.target_triple}",
+    )
+
+
+def checkMsvcStlSupport():
+    result, reason = canRunMsvcStlTests()
+    if result:
+        return  # msvcstl supported
+    if "msvcstl" in configuration.categories_list:
+        return  # msvcstl category explicitly requested, let it run.
+    if configuration.verbose:
+        print(f"msvcstl tests will not be run because: {reason}")
+    configuration.skip_categories.append("msvcstl")
+
+
 def canRunWatchpointTests():
     from lldbsuite.test import lldbplatformutil
 
@@ -1044,6 +1066,7 @@ def run_suite():
 
     checkLibcxxSupport()
     checkLibstdcxxSupport()
+    checkMsvcStlSupport()
     checkWatchpointSupport()
     checkDebugInfoSupport()
     checkDebugServerSupport()
diff --git a/lldb/packages/Python/lldbsuite/test/dotest_args.py b/lldb/packages/Python/lldbsuite/test/dotest_args.py
index e9c21388bc213..f47cfc7db357e 100644
--- a/lldb/packages/Python/lldbsuite/test/dotest_args.py
+++ b/lldb/packages/Python/lldbsuite/test/dotest_args.py
@@ -116,6 +116,12 @@ def create_parser():
             "The location of llvm tools used for testing (yaml2obj, FileCheck, etc.)."
         ),
     )
+    group.add_argument(
+        "--target-triple",
+        help=textwrap.dedent(
+            "The target triple the tests will run on (e.g. x86_64-pc-windows-msvc)."
+        ),
+    )
 
     # Test filtering options
     group = parser.add_argument_group("Test filtering options")
diff --git a/lldb/packages/Python/lldbsuite/test/test_categories.py b/lldb/packages/Python/lldbsuite/test/test_categories.py
index b585f695adeab..1f6e8a78e0c0d 100644
--- a/lldb/packages/Python/lldbsuite/test/test_categories.py
+++ b/lldb/packages/Python/lldbsuite/test/test_categories.py
@@ -33,6 +33,7 @@
     "lldb-server": "Tests related to lldb-server",
     "lldb-dap": "Tests for the Debug Adapter Protocol with lldb-dap",
     "llgs": "Tests for the gdb-server functionality of lldb-server",
+    "msvcstl": "Test for MSVC STL data formatters",
     "pexpect": "Tests requiring the pexpect library to be available",
     "objc": "Tests related to the Objective-C programming language support",
     "pyapi": "Tests related to the Python API",
diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp
index 58ec068ab9600..b62e786f522d4 100644
--- a/lldb/source/API/SBTypeSummary.cpp
+++ b/lldb/source/API/SBTypeSummary.cpp
@@ -370,6 +370,9 @@ bool SBTypeSummary::IsEqualTo(lldb::SBTypeSummary &rhs) {
     if (IsSummaryString() != rhs.IsSummaryString())
       return false;
     return GetOptions() == rhs.GetOptions();
+  case TypeSummaryImpl::Kind::eComposite:
+    return llvm::dyn_cast<CXXCompositeSummaryFormat>(m_opaque_sp.get()) ==
+           llvm::dyn_cast<CXXCompositeSummaryFormat>(rhs.m_opaque_sp.get());
   case TypeSummaryImpl::Kind::eInternal:
     return (m_opaque_sp.get() == rhs.m_opaque_sp.get());
   }
@@ -406,7 +409,7 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
   if (CXXFunctionSummaryFormat *current_summary_ptr =
           llvm::dyn_cast<CXXFunctionSummaryFormat>(m_opaque_sp.get())) {
     new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(
-        GetOptions(), current_summary_ptr->m_impl,
+        GetOptions(), current_summary_ptr->m_data.m_impl,
         current_summary_ptr->m_description.c_str()));
   } else if (ScriptSummaryFormat *current_summary_ptr =
                  llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
@@ -417,6 +420,12 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
                  llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get())) {
     new_sp = TypeSummaryImplSP(new StringSummaryFormat(
         GetOptions(), current_summary_ptr->GetSummaryString()));
+  } else if (CXXCompositeSummaryFormat *current_summary_ptr =
+                 llvm::dyn_cast<CXXCompositeSummaryFormat>(m_opaque_sp.get())) {
+    new_sp = TypeSummaryImplSP(new CXXCompositeSummaryFormat(
+        GetOptions(), current_summary_ptr->GetTextualInfo(),
+        current_summary_ptr->CopyChildren(),
+        current_summary_ptr->GetPtrMatchDepth()));
   }
 
   SetSP(new_sp);
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp
index 19cd3ff2972e9..bd6138a860caa 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -1397,9 +1397,10 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
     result.AppendError("summary creation failed");
     return false;
   }
-  if (string_format->m_error.Fail()) {
-    result.AppendErrorWithFormat("syntax error: %s",
-                                 string_format->m_error.AsCString("<unknown>"));
+  if (string_format->m_data.m_error.Fail()) {
+    result.AppendErrorWithFormat(
+        "syntax error: %s",
+        string_format->m_data.m_error.AsCString("<unknown>"));
     return false;
   }
   lldb::TypeSummaryImplSP entry(string_format.release());
diff --git a/lldb/source/DataFormatters/TypeSummary.cpp b/lldb/source/DataFormatters/TypeSummary.cpp
index 6aa290698cd12..4830b2c28901a 100644
--- a/lldb/source/DataFormatters/TypeSummary.cpp
+++ b/lldb/source/DataFormatters/TypeSummary.cpp
@@ -57,21 +57,17 @@ std::string TypeSummaryImpl::GetSummaryKindName() {
     return "python";
   case Kind::eInternal:
     return "c++";
+  case Kind::eComposite:
+    return "composite";
   case Kind::eBytecode:
     return "bytecode";
   }
   llvm_unreachable("Unknown type kind name");
 }
 
-StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags,
-                                         const char *format_cstr,
-                                         uint32_t ptr_match_depth)
-    : TypeSummaryImpl(Kind::eSummaryString, flags, ptr_match_depth),
-      m_format_str() {
-  SetSummaryString(format_cstr);
-}
+StringSummaryData::StringSummaryData(const char *f) { SetFormat(f); }
 
-void StringSummaryFormat::SetSummaryString(const char *format_cstr) {
+void StringSummaryData::SetFormat(const char *format_cstr) {
   m_format.Clear();
   if (format_cstr && format_cstr[0]) {
     m_format_str = format_cstr;
@@ -82,8 +78,19 @@ void StringSummaryFormat::SetSummaryString(const char *format_cstr) {
   }
 }
 
-bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
-                                       const TypeSummaryOptions &options) {
+StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags,
+                                         const char *format_cstr,
+                                         uint32_t ptr_match_depth)
+    : TypeSummaryImpl(Kind::eSummaryString, flags, ptr_match_depth),
+      m_data(format_cstr) {}
+
+void StringSummaryFormat::SetSummaryString(const char *format_cstr) {
+  m_data.SetFormat(format_cstr);
+}
+
+bool StringSummaryData::FormatObject(ValueObject *valobj, std::string &retval,
+                                     const TypeSummaryOptions &options,
+                                     const TypeSummaryImpl &summary) {
   if (!valobj) {
     retval.assign("NULL ValueObject");
     return false;
@@ -96,12 +103,12 @@ bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
   if (frame)
     sc = frame->GetSymbolContext(lldb::eSymbolContextEverything);
 
-  if (IsOneLiner()) {
+  if (summary.IsOneLiner()) {
     // We've already checked the case of a NULL valobj above.  Let's put in an
     // assert here to make sure someone doesn't take that out:
     assert(valobj && "Must have a valid ValueObject to summarize");
     ValueObjectPrinter printer(*valobj, &s, DumpValueObjectOptions());
-    printer.PrintChildrenOneLiner(HideNames(valobj));
+    printer.PrintChildrenOneLiner(summary.HideNames(valobj));
     retval = std::string(s.GetString());
     return true;
   } else {
@@ -117,40 +124,52 @@ bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
   }
 }
 
+bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
+                                       const TypeSummaryOptions &options) {
+  return m_data.FormatObject(valobj, retval, options, *this);
+}
+
 std::string StringSummaryFormat::GetDescription() {
   StreamString sstr;
 
-  sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s ptr-match-depth=%u", m_format_str.c_str(),
-              m_error.Fail() ? " error: " : "",
-              m_error.Fail() ? m_error.AsCString() : "",
-              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.Printf(
+      "`%s`%s%s%s%s%s%s%s%s%s ptr-match-depth=%u", m_data.m_format_str.c_str(),
+      m_data.m_error.Fail() ? " error: " : "",
+      m_data.m_error.Fail() ? m_data.m_error.AsCString() : "",
+      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());
   return std::string(sstr.GetString());
 }
 
-std::string StringSummaryFormat::GetName() { return m_format_str; }
+std::string StringSummaryFormat::GetName() { return m_data.m_format_str; }
+
+bool CXXFunctionSummaryData::FormatObject(ValueObject *valobj,
+                                          std::string &dest,
+                                          const TypeSummaryOptions &options,
+                                          const TypeSummaryImpl &summary) {
+  dest.clear();
+  StreamString stream;
+  if (!m_impl || !m_impl(*valobj, stream, options))
+    return false;
+  dest = std::string(stream.GetString());
+  return true;
+}
 
 CXXFunctionSummaryFormat::CXXFunctionSummaryFormat(
     const TypeSummaryImpl::Flags &flags, Callback impl, const char *description,
     uint32_t ptr_match_depth)
-    : TypeSummaryImpl(Kind::eCallback, flags, ptr_match_depth), m_impl(impl),
+    : TypeSummaryImpl(Kind::eCallback, flags, ptr_match_depth), m_data{impl},
       m_description(description ? description : "") {}
 
 bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj,
                                             std::string &dest,
                                             const TypeSummaryOptions &options) {
-  dest.clear();
-  StreamString stream;
-  if (!m_impl || !m_impl(*valobj, stream, options))
-    return false;
-  dest = std::string(stream.GetString());
-  return true;
+  return m_data.FormatObject(valobj, dest, options, *this);
 }
 
 std::string CXXFunctionSummaryFormat::GetDescription() {
@@ -169,6 +188,68 @@ std::string CXXFunctionSummaryFormat::GetDescription() {
 
 std::string CXXFunctionSummaryFormat::GetName() { return m_description; }
 
+CXXCompositeSummaryFormat::CXXCompositeSummaryFormat(
+    const TypeSummaryImpl::Flags &flags, const char *description,
+    Children children, uint32_t ptr_match_depth)
+    : TypeSummaryImpl(Kind::eComposite, flags, ptr_match_depth),
+      m_children(std::move(children)) {}
+
+CXXCompositeSummaryFormat *
+CXXCompositeSummaryFormat::Append(Validator *validator, ChildData child) {
+  m_children.emplace_back(validator, std::move(child));
+  return this;
+}
+
+CXXCompositeSummaryFormat::Children
+CXXCompositeSummaryFormat::CopyChildren() const {
+  auto copy = [](const Child &entry) -> Child {
+    return {entry.first,
+            std::visit(llvm::makeVisitor(
+                           [](const CXXFunctionSummaryData &fn) -> ChildData {
+                             return fn;
+                           },
+                           [](const StringSummaryData &string) -> ChildData {
+                             return StringS...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/143177


More information about the lldb-commits mailing list