llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: nerix (Nerixyz) <details> <summary>Changes</summary> `std::span` didn't have a formatter for MSVC's STL yet. The type is quite useful in C++ 20, so this PR adds a formatter for it. Since the formatter is new, I made it work with both DWARF and PDB from the start. --- Full diff: https://github.com/llvm/llvm-project/pull/173053.diff 5 Files Affected: - (modified) lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt (+1) - (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+17-9) - (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h (+6) - (added) lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp (+133) - (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py (+24-5) ``````````diff diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index c52d3bdb31284..79c0cc14ec644 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -38,6 +38,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN MsvcStlAtomic.cpp MsvcStlDeque.cpp MsvcStlSmartPointer.cpp + MsvcStlSpan.cpp MsvcStlTree.cpp MsvcStlTuple.cpp MsvcStlUnordered.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index dd3b84e47dec3..c51d71de145a4 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1416,10 +1416,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider"))); - AddCXXSynthetic(cpp_category_sp, LibStdcppSpanSyntheticFrontEndCreator, - "libstdc++ std::span synthetic children", "^std::span<.+>$", - stl_deref_flags, true); - stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); @@ -1510,11 +1506,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { lldb_private::formatters::StdlibCoroutineHandleSummaryProvider, "libstdc++ std::coroutine_handle summary provider", libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true); - - AddCXXSummary(cpp_category_sp, - lldb_private::formatters::ContainerSizeSummaryProvider, - "libstdc++ std::span summary provider", "^std::span<.+>$", - stl_summary_flags, true); } static lldb_private::SyntheticChildrenFrontEnd * @@ -1671,6 +1662,17 @@ GenericDequeSyntheticFrontEndCreator(CXXSyntheticChildren *children, "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider", *valobj_sp); } +static SyntheticChildrenFrontEnd * +GenericSpanSyntheticFrontEndCreator(CXXSyntheticChildren *children, + ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + + if (IsMsvcStlSpan(*valobj_sp)) + return MsvcStlSpanSyntheticFrontEndCreator(children, valobj_sp); + return LibStdcppSpanSyntheticFrontEndCreator(children, valobj_sp); +} + /// Load formatters that are formatting types from more than one STL static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) @@ -1759,6 +1761,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic(cpp_category_sp, GenericDequeSyntheticFrontEndCreator, "std::deque container synthetic children", "^std::deque<.+>(( )?&)?$", stl_deref_flags, true); + AddCXXSynthetic(cpp_category_sp, GenericSpanSyntheticFrontEndCreator, + "std::span container synthetic children", + "^std::span<.+>$", stl_deref_flags, true); AddCXXSynthetic(cpp_category_sp, GenericMapLikeSyntheticFrontEndCreator, "std::(multi)?map/set synthetic children", @@ -1811,6 +1816,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider, "MSVC STL/libstd++ std::deque summary provider", "^std::deque<.+>(( )?&)?$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider, + "MSVC STL/libstd++ std::span summary provider", + "^std::span<.+>$", 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 e818b88e202ef..58e155b45d781 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h @@ -119,6 +119,12 @@ SyntheticChildrenFrontEnd * MsvcStlDequeSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp); +// MSVC STL std::span<> +bool IsMsvcStlSpan(ValueObject &valobj); +SyntheticChildrenFrontEnd * +MsvcStlSpanSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); + } // namespace formatters } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp new file mode 100644 index 0000000000000..8d1cfdb8986a0 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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 "MsvcStl.h" + +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/ValueObject/ValueObject.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private::formatters { + +class MsvcStlSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + MsvcStlSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~MsvcStlSpanSyntheticFrontEnd() override = default; + + llvm::Expected<uint32_t> CalculateNumChildren() override { + return m_num_elements; + } + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override; + +private: + ValueObject *m_start = nullptr; ///< First element of span. Held, not owned. + CompilerType m_element_type{}; ///< Type of span elements. + size_t m_num_elements = 0; ///< Number of elements in span. + uint32_t m_element_size = 0; ///< Size in bytes of each span element. +}; + +lldb_private::formatters::MsvcStlSpanSyntheticFrontEnd:: + MsvcStlSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) { + if (valobj_sp) + Update(); +} + +lldb::ValueObjectSP +lldb_private::formatters::MsvcStlSpanSyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (!m_start) + return {}; + + uint64_t offset = idx * m_element_size; + offset = offset + m_start->GetValueAsUnsigned(0); + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return CreateValueObjectFromAddress(name.GetString(), offset, + m_backend.GetExecutionContextRef(), + m_element_type); +} + +lldb::ChildCacheState +lldb_private::formatters::MsvcStlSpanSyntheticFrontEnd::Update() { + m_start = nullptr; + m_element_type = CompilerType(); + m_num_elements = 0; + m_element_size = 0; + + ValueObjectSP data_sp = m_backend.GetChildMemberWithName("_Mydata"); + if (!data_sp) + return lldb::ChildCacheState::eRefetch; + + m_element_type = data_sp->GetCompilerType().GetPointeeType(); + + // Get element size. + llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr); + if (!size_or_err) { + LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(), + "{0}"); + return lldb::ChildCacheState::eRefetch; + } + + m_element_size = *size_or_err; + + // Get data. + if (m_element_size > 0) + m_start = data_sp.get(); + + // Get number of elements. + if (auto size_sp = m_backend.GetChildMemberWithName("_Mysize")) + m_num_elements = size_sp->GetValueAsUnsigned(0); + else if (auto field = m_backend.GetCompilerType() + .GetDirectBaseClassAtIndex(0, nullptr) // _Span_extent_type + .GetStaticFieldWithName("_Mysize")) + m_num_elements = field.GetConstantValue().ULongLong(0); + + return lldb::ChildCacheState::eRefetch; +} + +llvm::Expected<size_t> +lldb_private::formatters::MsvcStlSpanSyntheticFrontEnd::GetIndexOfChildWithName( + ConstString name) { + if (!m_start) + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); + + auto optional_idx = formatters::ExtractIndexFromString(name.GetCString()); + if (!optional_idx) + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); + return *optional_idx; +} + +bool IsMsvcStlSpan(ValueObject &valobj) { + if (auto valobj_sp = valobj.GetNonSyntheticValue()) + return valobj_sp->GetChildMemberWithName("_Mydata") != nullptr; + return false; +} + +lldb_private::SyntheticChildrenFrontEnd * +MsvcStlSpanSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + return new MsvcStlSpanSyntheticFrontEnd(valobj_sp); +} + +} // namespace lldb_private::formatters diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py index f586fb3d698c1..4cf447e49c848 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py @@ -9,6 +9,8 @@ class StdSpanDataFormatterTestCase(TestBase): + TEST_WITH_PDB_DEBUG_INFO = True + def findVariable(self, name): var = self.frame().FindVariable(name) self.assertTrue(var.IsValid()) @@ -89,21 +91,26 @@ def do_test(self): ) # check access to synthetic children for dynamic spans + dynamic_string_span = ( + "std::span<std::basic_string<char, std::char_traits<char>, std::allocator<char>>, -1>" + if self.getDebugInfo() == "pdb" + else "dynamic_string_span" + ) self.runCmd( - 'type summary add --summary-string "item 0 is ${var[0]}" dynamic_string_span' + f'type summary add --summary-string "item 0 is ${{var[0]}}" "{dynamic_string_span}"' ) self.expect_var_path("strings_span", summary='item 0 is "smart"') self.runCmd( - 'type summary add --summary-string "item 0 is ${svar[0]}" dynamic_string_span' + f'type summary add --summary-string "item 0 is ${{svar[0]}}" "{dynamic_string_span}"' ) self.expect_var_path("strings_span", summary='item 0 is "smart"') - self.runCmd("type summary delete dynamic_string_span") + self.runCmd(f'type summary delete "{dynamic_string_span}"') # test summaries based on synthetic children self.runCmd( - 'type summary add --summary-string "span has ${svar%#} items" -e dynamic_string_span' + f'type summary add --summary-string "span has ${{svar%#}} items" -e "{dynamic_string_span}"' ) self.expect_var_path("strings_span", summary="span has 2 items") @@ -127,7 +134,7 @@ def do_test(self): result_children=expectedStringSpanChildren, ) - self.runCmd("type summary delete dynamic_string_span") + self.runCmd(f'type summary delete "{dynamic_string_span}"') lldbutil.continue_to_breakpoint(process, bkpt) @@ -191,3 +198,15 @@ def test_libstdcxx(self): def test_ref_and_ptr_libstdcxx(self): self.build(dictionary={"USE_LIBSTDCPP": 1}) self.do_test_ref_and_ptr() + + @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() + + @add_test_categories(["msvcstl"]) + def test_ref_and_ptr_msvcstl(self): + # No flags, because the "msvcstl" category checks that the MSVC STL is used by default. + self.build() + self.do_test_ref_and_ptr() `````````` </details> https://github.com/llvm/llvm-project/pull/173053 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
