Author: Dave Lee Date: 2022-09-02T08:53:46-07:00 New Revision: a2ec18ee043f7c8caa0e9e329721182b9f1a5dcd
URL: https://github.com/llvm/llvm-project/commit/a2ec18ee043f7c8caa0e9e329721182b9f1a5dcd DIFF: https://github.com/llvm/llvm-project/commit/a2ec18ee043f7c8caa0e9e329721182b9f1a5dcd.diff LOG: [lldb] From unordered_map synthetic provider, return std::pair children Change the behavior of the libc++ `unordered_map` synthetic provider to present children as `std::pair` values, just like `std::map` does. The synthetic provider for libc++ `std::unordered_map` has returned children that expose a level of internal structure (over top of the key/value pair). For example, given an unordered map initialized with `{{1,2}, {3, 4}}`, the output is: ``` (std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const int, int> > >) map = size=2 { [0] = { __cc = (first = 3, second = 4) } [1] = { __cc = (first = 1, second = 2) } } ``` It's not ideal/necessary to have the numbered children embdedded in the `__cc` field. Note: the numbered children have type `std::__hash_node<std::__hash_value_type<Key, T>, void *>::__node_value_type`, and the `__cc` fields have type `std::__hash_value_type<Key, T>::value_type`. Compare this output to `std::map`: ``` (std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >) map = size=2 { [0] = (first = 1, second = 2) [1] = (first = 3, second = 4) ``` Where the numbered children have type `std::pair<const Key, T>`. This changes the behavior of the synthetic provider for `unordered_map` to also present children as `pairs`, just like `std::map`. It appears the synthetic provider implementation for `unordered_map` was meant to provide this behavior, but was maybe incomplete (see d22a94377f7554a7e9df050f6dfc3ee42384e3fe). It has both an `m_node_type` and an `m_element_type`, but uses only the former. The latter is exactly the type needed for the children pairs. With this existing code, it's not much of a change to make this work. Differential Revision: https://reviews.llvm.org/D117383 Added: Modified: lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py Removed: ################################################################################ diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index 85c04ea728f56..90e6e124090e9 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -13,10 +13,12 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; @@ -65,6 +67,19 @@ size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: return m_num_elements; } +static bool isStdTemplate(ConstString type_name, llvm::StringRef type) { + llvm::StringRef name = type_name.GetStringRef(); + // The type name may or may not be prefixed with `std::` or `std::__1::`. + if (name.consume_front("std::")) + name.consume_front("__1::"); + return name.consume_front(type) && name.startswith("<"); +} + +static bool isUnorderedMap(ConstString type_name) { + return isStdTemplate(type_name, "unordered_map") || + isStdTemplate(type_name, "unordered_multimap"); +} + lldb::ValueObjectSP lldb_private::formatters:: LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) { if (idx >= CalculateNumChildren()) @@ -118,10 +133,20 @@ lldb::ValueObjectSP lldb_private::formatters:: m_element_type = m_element_type.GetPointeeType(); m_node_type = m_element_type; m_element_type = m_element_type.GetTypeTemplateArgument(0); - std::string name; - m_element_type = - m_element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr); - m_element_type = m_element_type.GetTypedefedType(); + // This synthetic provider is used for both unordered_(multi)map and + // unordered_(multi)set. For unordered_map, the element type has an + // additional type layer, an internal struct (`__hash_value_type`) + // that wraps a std::pair. Peel away the internal wrapper type - whose + // structure is of no value to users, to expose the std::pair. This + // matches the structure returned by the std::map synthetic provider. + if (isUnorderedMap(m_backend.GetTypeName())) { + std::string name; + CompilerType field_type = m_element_type.GetFieldAtIndex( + 0, name, nullptr, nullptr, nullptr); + CompilerType actual_type = field_type.GetTypedefedType(); + if (isStdTemplate(actual_type.GetTypeName(), "pair")) + m_element_type = actual_type; + } } if (!m_node_type) return nullptr; @@ -153,7 +178,7 @@ lldb::ValueObjectSP lldb_private::formatters:: ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock( thread_and_frame_only_if_stopped); return CreateValueObjectFromData(stream.GetString(), data, exe_ctx, - val_hash.first->GetCompilerType()); + m_element_type); } bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py index 6bb14417ea2d4..7730e780bd478 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py @@ -47,12 +47,17 @@ def cleanup(): "corrupt_map", ['%s::unordered_map' % ns, 'size=0 {}']) + must_not_contain__cc = r'(?s)^(?!.*\b__cc = )' + self.look_for_content_and_continue( - "map", ['%s::unordered_map' % - ns, 'size=5 {', 'hello', 'world', 'this', 'is', 'me']) + "map", ['%s::unordered_map' % ns, + must_not_contain__cc, + 'size=5 {', 'hello', 'world', 'this', 'is', 'me']) self.look_for_content_and_continue( - "mmap", ['%s::unordered_multimap' % ns, 'size=6 {', 'first = 3', 'second = "this"', + "mmap", ['%s::unordered_multimap' % ns, + must_not_contain__cc, + 'size=6 {', 'first = 3', 'second = "this"', 'first = 2', 'second = "hello"']) self.look_for_content_and_continue( _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits