#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;
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())
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;
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::
"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(