[Lldb-commits] [lldb] [LLDB] Add formatters for MSVC STL std::unique_ptr (PR #148248)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Jul 11 07:34:35 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: nerix (Nerixyz)
<details>
<summary>Changes</summary>
This PR adds a summary and synthetic children for `std::unique_ptr` from MSVC's STL ([NatVis](https://github.com/microsoft/STL/blob/313964b78a8fd5a52e7965e13781f735bcce13c5/stl/debugger/STL.natvis#L285-L303)).
As with libc++, the deleter is only shown if it's non-empty.
Tested both the shared_ptr and unique_ptr tests on Windows.
Towards #<!-- -->24834.
---
Full diff: https://github.com/llvm/llvm-project/pull/148248.diff
4 Files Affected:
- (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+27-4)
- (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h (+8)
- (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp (+115)
- (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py (+11)
``````````diff
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 2db3e6f0ca315..9a869f3ea0289 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1566,10 +1566,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::optional synthetic child", "^std::optional<.+>(( )?&)?$",
stl_deref_flags, true);
- AddCXXSummary(cpp_category_sp,
- lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
- "libstdc++ std::unique_ptr summary provider",
- "^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
"libstdc++ std::coroutine_handle summary provider",
@@ -1599,6 +1595,24 @@ GenericSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
return LibStdcppSmartPointerSummaryProvider(valobj, stream, options);
}
+static lldb_private::SyntheticChildrenFrontEnd *
+GenericUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *children,
+ lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+
+ if (IsMsvcStlUniquePtr(*valobj_sp))
+ return MsvcStlUniquePtrSyntheticFrontEndCreator(valobj_sp);
+ return LibStdcppUniquePtrSyntheticFrontEndCreator(children, valobj_sp);
+}
+
+static bool GenericUniquePtrSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options) {
+ if (IsMsvcStlUniquePtr(valobj))
+ return MsvcStlUniquePtrSummaryProvider(valobj, stream, options);
+ return LibStdcppUniquePointerSummaryProvider(valobj, stream, options);
+}
+
/// Load formatters that are formatting types from more than one STL
static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
@@ -1642,12 +1656,18 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
},
"MSVC STL/libstdc++ std::wstring summary provider"));
+ stl_summary_flags.SetDontShowChildren(false);
+ stl_summary_flags.SetSkipPointers(false);
+
AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
"std::shared_ptr synthetic children",
"^std::shared_ptr<.+>(( )?&)?$", stl_synth_flags, true);
AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
"std::weak_ptr synthetic children",
"^std::weak_ptr<.+>(( )?&)?$", stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, GenericUniquePtrSyntheticFrontEndCreator,
+ "std::unique_ptr synthetic children",
+ "^std::unique_ptr<.+>(( )?&)?$", stl_synth_flags, true);
AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
"MSVC STL/libstdc++ std::shared_ptr summary provider",
@@ -1655,6 +1675,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
"MSVC STL/libstdc++ std::weak_ptr summary provider",
"^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp, GenericUniquePtrSummaryProvider,
+ "MSVC STL/libstdc++ std::unique_ptr summary provider",
+ "^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true);
}
static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
index edf3f4e8a5387..fe75bf275f8e2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
@@ -37,6 +37,14 @@ bool MsvcStlSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
lldb_private::SyntheticChildrenFrontEnd *
MsvcStlSmartPointerSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp);
+// MSVC STL std::unique_ptr<>
+bool IsMsvcStlUniquePtr(ValueObject &valobj);
+bool MsvcStlUniquePtrSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+lldb_private::SyntheticChildrenFrontEnd *
+MsvcStlUniquePtrSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp);
+
} // namespace formatters
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp
index b1aecc4b6611a..6f66540f3cba9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp
@@ -84,6 +84,23 @@ class MsvcStlSmartPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
ValueObject *m_ptr_obj = nullptr;
};
+class MsvcStlUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ lldb::ValueObjectSP m_value_ptr_sp;
+ lldb::ValueObjectSP m_deleter_sp;
+};
+
} // namespace formatters
} // namespace lldb_private
@@ -163,3 +180,101 @@ lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEndCreator(
lldb::ValueObjectSP valobj_sp) {
return new MsvcStlSmartPointerSyntheticFrontEnd(valobj_sp);
}
+
+bool lldb_private::formatters::IsMsvcStlUniquePtr(ValueObject &valobj) {
+ if (auto valobj_sp = valobj.GetNonSyntheticValue())
+ return valobj_sp->GetChildMemberWithName("_Mypair") != nullptr;
+
+ return false;
+}
+
+bool lldb_private::formatters::MsvcStlUniquePtrSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+
+ ValueObjectSP ptr_sp(valobj_sp->GetChildAtNamePath({"_Mypair", "_Myval2"}));
+ if (!ptr_sp)
+ return false;
+
+ DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
+
+ return true;
+}
+
+lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::
+ MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ MsvcStlUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
+ if (m_value_ptr_sp)
+ return m_deleter_sp ? 2 : 1;
+ return 0;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_value_ptr_sp)
+ return lldb::ValueObjectSP();
+
+ if (idx == 0)
+ return m_value_ptr_sp;
+
+ if (idx == 1)
+ return m_deleter_sp;
+
+ if (idx == 2) {
+ Status status;
+ auto value_sp = m_value_ptr_sp->Dereference(status);
+ if (status.Success()) {
+ return value_sp;
+ }
+ }
+
+ return lldb::ValueObjectSP();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP pair_sp = valobj_sp->GetChildMemberWithName("_Mypair");
+ if (!pair_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ if (auto value_ptr_sp = pair_sp->GetChildMemberWithName("_Myval2"))
+ m_value_ptr_sp = value_ptr_sp->Clone(ConstString("pointer"));
+
+ // Only present if the deleter is non-empty
+ if (auto deleter_sp = pair_sp->GetChildMemberWithName("_Myval1"))
+ m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+llvm::Expected<size_t>
+lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (name == "pointer")
+ return 0;
+ if (name == "deleter")
+ return 1;
+ if (name == "obj" || name == "object" || name == "$$dereference$$")
+ return 2;
+ return llvm::createStringError("Type has no child named '%s'",
+ name.AsCString());
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEndCreator(
+ lldb::ValueObjectSP valobj_sp) {
+ return new MsvcStlUniquePtrSyntheticFrontEnd(valobj_sp);
+}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
index 1b204c7d6ef02..0b68b1b532bb0 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
@@ -102,6 +102,12 @@ def test_libcxx(self):
self.build(dictionary={"USE_LIBCPP": 1})
self.do_test()
+ @add_test_categories(["msvcstl"])
+ def test_msvcstl(self):
+ # No flags, because the "msvcstl" category checks that the MSVC STL is used by default.
+ self.build()
+ self.do_test()
+
def do_test_recursive_unique_ptr(self):
# Tests that LLDB can handle when we have a loop in the unique_ptr
# reference chain and that it correctly handles the different options
@@ -155,3 +161,8 @@ def test_recursive_unique_ptr_libstdcxx(self):
def test_recursive_unique_ptr_libcxx(self):
self.build(dictionary={"USE_LIBCPP": 1})
self.do_test_recursive_unique_ptr()
+
+ @add_test_categories(["msvcstl"])
+ def test_recursive_unique_ptr_msvcstl(self):
+ self.build()
+ self.do_test_recursive_unique_ptr()
``````````
</details>
https://github.com/llvm/llvm-project/pull/148248
More information about the lldb-commits
mailing list