-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[LLDB] Add formatters for MSVC STL std::unique_ptr #148248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-lldb Author: nerix (Nerixyz) ChangesThis PR adds a summary and synthetic children for As with libc++, the deleter is only shown if it's non-empty. Tested both the shared_ptr and unique_ptr tests on Windows. Full diff: https://github.com/llvm/llvm-project/pull/148248.diff 4 Files Affected:
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()
|
Michael137
approved these changes
Jul 14, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR adds a summary and synthetic children for
std::unique_ptr
from MSVC's STL (NatVis).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.