15ffd83dbSDimitry Andric //===-- LibCxxUnorderedMap.cpp --------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "LibCxx.h" 100b57cec5SDimitry Andric 115ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 120b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h" 130b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h" 140b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h" 150b57cec5SDimitry Andric #include "lldb/Target/Target.h" 16bdd1243dSDimitry Andric #include "lldb/Utility/ConstString.h" 170b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 180b57cec5SDimitry Andric #include "lldb/Utility/Endian.h" 190b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 200b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 21bdd1243dSDimitry Andric #include "llvm/ADT/StringRef.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric using namespace lldb; 240b57cec5SDimitry Andric using namespace lldb_private; 250b57cec5SDimitry Andric using namespace lldb_private::formatters; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric namespace lldb_private { 280b57cec5SDimitry Andric namespace formatters { 290b57cec5SDimitry Andric class LibcxxStdUnorderedMapSyntheticFrontEnd 300b57cec5SDimitry Andric : public SyntheticChildrenFrontEnd { 310b57cec5SDimitry Andric public: 320b57cec5SDimitry Andric LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default; 350b57cec5SDimitry Andric 36*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> CalculateNumChildren() override; 370b57cec5SDimitry Andric 38*0fca6ea1SDimitry Andric lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 390b57cec5SDimitry Andric 40*0fca6ea1SDimitry Andric lldb::ChildCacheState Update() override; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric bool MightHaveChildren() override; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric size_t GetIndexOfChildWithName(ConstString name) override; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric private: 470b57cec5SDimitry Andric CompilerType m_element_type; 480b57cec5SDimitry Andric CompilerType m_node_type; 4981ad6265SDimitry Andric ValueObject *m_tree = nullptr; 5081ad6265SDimitry Andric size_t m_num_elements = 0; 5181ad6265SDimitry Andric ValueObject *m_next_element = nullptr; 520b57cec5SDimitry Andric std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache; 530b57cec5SDimitry Andric }; 54*0fca6ea1SDimitry Andric 55*0fca6ea1SDimitry Andric class LibCxxUnorderedMapIteratorSyntheticFrontEnd 56*0fca6ea1SDimitry Andric : public SyntheticChildrenFrontEnd { 57*0fca6ea1SDimitry Andric public: 58*0fca6ea1SDimitry Andric LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric ~LibCxxUnorderedMapIteratorSyntheticFrontEnd() override = default; 61*0fca6ea1SDimitry Andric 62*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> CalculateNumChildren() override; 63*0fca6ea1SDimitry Andric 64*0fca6ea1SDimitry Andric lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 65*0fca6ea1SDimitry Andric 66*0fca6ea1SDimitry Andric lldb::ChildCacheState Update() override; 67*0fca6ea1SDimitry Andric 68*0fca6ea1SDimitry Andric bool MightHaveChildren() override; 69*0fca6ea1SDimitry Andric 70*0fca6ea1SDimitry Andric size_t GetIndexOfChildWithName(ConstString name) override; 71*0fca6ea1SDimitry Andric 72*0fca6ea1SDimitry Andric private: 73*0fca6ea1SDimitry Andric lldb::ValueObjectSP m_pair_sp; ///< ValueObject for the key/value pair 74*0fca6ea1SDimitry Andric ///< that the iterator currently points 75*0fca6ea1SDimitry Andric ///< to. 76*0fca6ea1SDimitry Andric }; 77*0fca6ea1SDimitry Andric 780b57cec5SDimitry Andric } // namespace formatters 790b57cec5SDimitry Andric } // namespace lldb_private 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 820b57cec5SDimitry Andric LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 8381ad6265SDimitry Andric : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), 8481ad6265SDimitry Andric m_elements_cache() { 850b57cec5SDimitry Andric if (valobj_sp) 860b57cec5SDimitry Andric Update(); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 89*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters:: 90*0fca6ea1SDimitry Andric LibcxxStdUnorderedMapSyntheticFrontEnd::CalculateNumChildren() { 910b57cec5SDimitry Andric return m_num_elements; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 94bdd1243dSDimitry Andric static void consumeInlineNamespace(llvm::StringRef &name) { 95bdd1243dSDimitry Andric // Delete past an inline namespace, if any: __[a-zA-Z0-9_]+:: 96bdd1243dSDimitry Andric auto scratch = name; 97bdd1243dSDimitry Andric if (scratch.consume_front("__") && std::isalnum(scratch[0])) { 98bdd1243dSDimitry Andric scratch = scratch.drop_while([](char c) { return std::isalnum(c); }); 99bdd1243dSDimitry Andric if (scratch.consume_front("::")) { 100bdd1243dSDimitry Andric // Successfully consumed a namespace. 101bdd1243dSDimitry Andric name = scratch; 102bdd1243dSDimitry Andric } 103bdd1243dSDimitry Andric } 104bdd1243dSDimitry Andric } 105bdd1243dSDimitry Andric 106bdd1243dSDimitry Andric static bool isStdTemplate(ConstString type_name, llvm::StringRef type) { 107bdd1243dSDimitry Andric llvm::StringRef name = type_name.GetStringRef(); 108bdd1243dSDimitry Andric // The type name may be prefixed with `std::__<inline-namespace>::`. 109bdd1243dSDimitry Andric if (name.consume_front("std::")) 110bdd1243dSDimitry Andric consumeInlineNamespace(name); 1115f757f3fSDimitry Andric return name.consume_front(type) && name.starts_with("<"); 112bdd1243dSDimitry Andric } 113bdd1243dSDimitry Andric 114bdd1243dSDimitry Andric static bool isUnorderedMap(ConstString type_name) { 115bdd1243dSDimitry Andric return isStdTemplate(type_name, "unordered_map") || 116bdd1243dSDimitry Andric isStdTemplate(type_name, "unordered_multimap"); 117bdd1243dSDimitry Andric } 118bdd1243dSDimitry Andric 1190b57cec5SDimitry Andric lldb::ValueObjectSP lldb_private::formatters:: 120*0fca6ea1SDimitry Andric LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { 121*0fca6ea1SDimitry Andric if (idx >= CalculateNumChildrenIgnoringErrors()) 1220b57cec5SDimitry Andric return lldb::ValueObjectSP(); 1230b57cec5SDimitry Andric if (m_tree == nullptr) 1240b57cec5SDimitry Andric return lldb::ValueObjectSP(); 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric while (idx >= m_elements_cache.size()) { 1270b57cec5SDimitry Andric if (m_next_element == nullptr) 1280b57cec5SDimitry Andric return lldb::ValueObjectSP(); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric Status error; 1310b57cec5SDimitry Andric ValueObjectSP node_sp = m_next_element->Dereference(error); 1320b57cec5SDimitry Andric if (!node_sp || error.Fail()) 1330b57cec5SDimitry Andric return lldb::ValueObjectSP(); 1340b57cec5SDimitry Andric 13506c3fb27SDimitry Andric ValueObjectSP value_sp = node_sp->GetChildMemberWithName("__value_"); 13606c3fb27SDimitry Andric ValueObjectSP hash_sp = node_sp->GetChildMemberWithName("__hash_"); 1370b57cec5SDimitry Andric if (!hash_sp || !value_sp) { 1380b57cec5SDimitry Andric if (!m_element_type) { 13906c3fb27SDimitry Andric auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"}); 1400b57cec5SDimitry Andric if (!p1_sp) 1410b57cec5SDimitry Andric return nullptr; 1420b57cec5SDimitry Andric 143*0fca6ea1SDimitry Andric ValueObjectSP first_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp); 1440b57cec5SDimitry Andric if (!first_sp) 1450b57cec5SDimitry Andric return nullptr; 146*0fca6ea1SDimitry Andric 1470b57cec5SDimitry Andric m_element_type = first_sp->GetCompilerType(); 1480b57cec5SDimitry Andric m_element_type = m_element_type.GetTypeTemplateArgument(0); 1490b57cec5SDimitry Andric m_element_type = m_element_type.GetPointeeType(); 1500b57cec5SDimitry Andric m_node_type = m_element_type; 1510b57cec5SDimitry Andric m_element_type = m_element_type.GetTypeTemplateArgument(0); 152bdd1243dSDimitry Andric // This synthetic provider is used for both unordered_(multi)map and 153bdd1243dSDimitry Andric // unordered_(multi)set. For unordered_map, the element type has an 154bdd1243dSDimitry Andric // additional type layer, an internal struct (`__hash_value_type`) 155bdd1243dSDimitry Andric // that wraps a std::pair. Peel away the internal wrapper type - whose 156bdd1243dSDimitry Andric // structure is of no value to users, to expose the std::pair. This 157bdd1243dSDimitry Andric // matches the structure returned by the std::map synthetic provider. 158bdd1243dSDimitry Andric if (isUnorderedMap(m_backend.GetTypeName())) { 1590b57cec5SDimitry Andric std::string name; 160bdd1243dSDimitry Andric CompilerType field_type = m_element_type.GetFieldAtIndex( 161bdd1243dSDimitry Andric 0, name, nullptr, nullptr, nullptr); 162bdd1243dSDimitry Andric CompilerType actual_type = field_type.GetTypedefedType(); 163bdd1243dSDimitry Andric if (isStdTemplate(actual_type.GetTypeName(), "pair")) 164bdd1243dSDimitry Andric m_element_type = actual_type; 165bdd1243dSDimitry Andric } 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric if (!m_node_type) 1680b57cec5SDimitry Andric return nullptr; 16906c3fb27SDimitry Andric node_sp = m_next_element->Cast(m_node_type.GetPointerType()) 17006c3fb27SDimitry Andric ->Dereference(error); 17106c3fb27SDimitry Andric if (!node_sp || error.Fail()) 17206c3fb27SDimitry Andric return nullptr; 17306c3fb27SDimitry Andric 17406c3fb27SDimitry Andric hash_sp = node_sp->GetChildMemberWithName("__hash_"); 1755f757f3fSDimitry Andric if (!hash_sp) 1760b57cec5SDimitry Andric return nullptr; 1775f757f3fSDimitry Andric 1785f757f3fSDimitry Andric value_sp = node_sp->GetChildMemberWithName("__value_"); 1795f757f3fSDimitry Andric if (!value_sp) { 1805f757f3fSDimitry Andric // clang-format off 1815f757f3fSDimitry Andric // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an 1825f757f3fSDimitry Andric // anonymous union. 1835f757f3fSDimitry Andric // Child 0: __hash_node_base base class 1845f757f3fSDimitry Andric // Child 1: __hash_ 1855f757f3fSDimitry Andric // Child 2: anonymous union 1865f757f3fSDimitry Andric // clang-format on 1875f757f3fSDimitry Andric auto anon_union_sp = node_sp->GetChildAtIndex(2); 1885f757f3fSDimitry Andric if (!anon_union_sp) 1895f757f3fSDimitry Andric return nullptr; 1905f757f3fSDimitry Andric 1915f757f3fSDimitry Andric value_sp = anon_union_sp->GetChildMemberWithName("__value_"); 1925f757f3fSDimitry Andric if (!value_sp) 1935f757f3fSDimitry Andric return nullptr; 1945f757f3fSDimitry Andric } 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric m_elements_cache.push_back( 1970b57cec5SDimitry Andric {value_sp.get(), hash_sp->GetValueAsUnsigned(0)}); 19806c3fb27SDimitry Andric m_next_element = node_sp->GetChildMemberWithName("__next_").get(); 1990b57cec5SDimitry Andric if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0) 2000b57cec5SDimitry Andric m_next_element = nullptr; 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx]; 2040b57cec5SDimitry Andric if (!val_hash.first) 2050b57cec5SDimitry Andric return lldb::ValueObjectSP(); 2060b57cec5SDimitry Andric StreamString stream; 2070b57cec5SDimitry Andric stream.Printf("[%" PRIu64 "]", (uint64_t)idx); 2080b57cec5SDimitry Andric DataExtractor data; 2090b57cec5SDimitry Andric Status error; 2100b57cec5SDimitry Andric val_hash.first->GetData(data, error); 2110b57cec5SDimitry Andric if (error.Fail()) 2120b57cec5SDimitry Andric return lldb::ValueObjectSP(); 2130b57cec5SDimitry Andric const bool thread_and_frame_only_if_stopped = true; 2140b57cec5SDimitry Andric ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock( 2150b57cec5SDimitry Andric thread_and_frame_only_if_stopped); 2160b57cec5SDimitry Andric return CreateValueObjectFromData(stream.GetString(), data, exe_ctx, 217bdd1243dSDimitry Andric m_element_type); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 220*0fca6ea1SDimitry Andric lldb::ChildCacheState 221*0fca6ea1SDimitry Andric lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() { 2224824e7fdSDimitry Andric m_num_elements = 0; 2230b57cec5SDimitry Andric m_next_element = nullptr; 2240b57cec5SDimitry Andric m_elements_cache.clear(); 22506c3fb27SDimitry Andric ValueObjectSP table_sp = m_backend.GetChildMemberWithName("__table_"); 2260b57cec5SDimitry Andric if (!table_sp) 227*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 2280b57cec5SDimitry Andric 22906c3fb27SDimitry Andric ValueObjectSP p2_sp = table_sp->GetChildMemberWithName("__p2_"); 230*0fca6ea1SDimitry Andric if (!p2_sp) 231*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 2320b57cec5SDimitry Andric 233*0fca6ea1SDimitry Andric ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp); 2340b57cec5SDimitry Andric if (!num_elements_sp) 235*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 2364824e7fdSDimitry Andric 237*0fca6ea1SDimitry Andric ValueObjectSP p1_sp = table_sp->GetChildMemberWithName("__p1_"); 238*0fca6ea1SDimitry Andric if (!p1_sp) 239*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 240*0fca6ea1SDimitry Andric 241*0fca6ea1SDimitry Andric ValueObjectSP value_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp); 242*0fca6ea1SDimitry Andric if (!value_sp) 243*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 244*0fca6ea1SDimitry Andric 245*0fca6ea1SDimitry Andric m_tree = value_sp->GetChildMemberWithName("__next_").get(); 2464824e7fdSDimitry Andric if (m_tree == nullptr) 247*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 2484824e7fdSDimitry Andric 2494824e7fdSDimitry Andric m_num_elements = num_elements_sp->GetValueAsUnsigned(0); 2504824e7fdSDimitry Andric 2510b57cec5SDimitry Andric if (m_num_elements > 0) 252*0fca6ea1SDimitry Andric m_next_element = m_tree; 253*0fca6ea1SDimitry Andric 254*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 2580b57cec5SDimitry Andric MightHaveChildren() { 2590b57cec5SDimitry Andric return true; 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: 2630b57cec5SDimitry Andric GetIndexOfChildWithName(ConstString name) { 2640b57cec5SDimitry Andric return ExtractIndexFromString(name.GetCString()); 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric SyntheticChildrenFrontEnd * 2680b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator( 2690b57cec5SDimitry Andric CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 2700b57cec5SDimitry Andric return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp) 2710b57cec5SDimitry Andric : nullptr); 2720b57cec5SDimitry Andric } 273*0fca6ea1SDimitry Andric 274*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: 275*0fca6ea1SDimitry Andric LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 276*0fca6ea1SDimitry Andric : SyntheticChildrenFrontEnd(*valobj_sp) { 277*0fca6ea1SDimitry Andric if (valobj_sp) 278*0fca6ea1SDimitry Andric Update(); 279*0fca6ea1SDimitry Andric } 280*0fca6ea1SDimitry Andric 281*0fca6ea1SDimitry Andric lldb::ChildCacheState lldb_private::formatters:: 282*0fca6ea1SDimitry Andric LibCxxUnorderedMapIteratorSyntheticFrontEnd::Update() { 283*0fca6ea1SDimitry Andric m_pair_sp.reset(); 284*0fca6ea1SDimitry Andric 285*0fca6ea1SDimitry Andric ValueObjectSP valobj_sp = m_backend.GetSP(); 286*0fca6ea1SDimitry Andric if (!valobj_sp) 287*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 288*0fca6ea1SDimitry Andric 289*0fca6ea1SDimitry Andric TargetSP target_sp(valobj_sp->GetTargetSP()); 290*0fca6ea1SDimitry Andric 291*0fca6ea1SDimitry Andric if (!target_sp) 292*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 293*0fca6ea1SDimitry Andric 294*0fca6ea1SDimitry Andric // Get the unordered_map::iterator 295*0fca6ea1SDimitry Andric // m_backend is an 'unordered_map::iterator', aka a 296*0fca6ea1SDimitry Andric // '__hash_map_iterator<__hash_table::iterator>' 297*0fca6ea1SDimitry Andric // 298*0fca6ea1SDimitry Andric // __hash_map_iterator::__i_ is a __hash_table::iterator (aka 299*0fca6ea1SDimitry Andric // __hash_iterator<__node_pointer>) 300*0fca6ea1SDimitry Andric auto hash_iter_sp = valobj_sp->GetChildMemberWithName("__i_"); 301*0fca6ea1SDimitry Andric if (!hash_iter_sp) 302*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 303*0fca6ea1SDimitry Andric 304*0fca6ea1SDimitry Andric // Type is '__hash_iterator<__node_pointer>' 305*0fca6ea1SDimitry Andric auto hash_iter_type = hash_iter_sp->GetCompilerType(); 306*0fca6ea1SDimitry Andric if (!hash_iter_type.IsValid()) 307*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 308*0fca6ea1SDimitry Andric 309*0fca6ea1SDimitry Andric // Type is '__node_pointer' 310*0fca6ea1SDimitry Andric auto node_pointer_type = hash_iter_type.GetTypeTemplateArgument(0); 311*0fca6ea1SDimitry Andric if (!node_pointer_type.IsValid()) 312*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 313*0fca6ea1SDimitry Andric 314*0fca6ea1SDimitry Andric // Cast the __hash_iterator to a __node_pointer (which stores our key/value 315*0fca6ea1SDimitry Andric // pair) 316*0fca6ea1SDimitry Andric auto hash_node_sp = hash_iter_sp->Cast(node_pointer_type); 317*0fca6ea1SDimitry Andric if (!hash_node_sp) 318*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 319*0fca6ea1SDimitry Andric 320*0fca6ea1SDimitry Andric auto key_value_sp = hash_node_sp->GetChildMemberWithName("__value_"); 321*0fca6ea1SDimitry Andric if (!key_value_sp) { 322*0fca6ea1SDimitry Andric // clang-format off 323*0fca6ea1SDimitry Andric // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an 324*0fca6ea1SDimitry Andric // anonymous union. 325*0fca6ea1SDimitry Andric // Child 0: __hash_node_base base class 326*0fca6ea1SDimitry Andric // Child 1: __hash_ 327*0fca6ea1SDimitry Andric // Child 2: anonymous union 328*0fca6ea1SDimitry Andric // clang-format on 329*0fca6ea1SDimitry Andric auto anon_union_sp = hash_node_sp->GetChildAtIndex(2); 330*0fca6ea1SDimitry Andric if (!anon_union_sp) 331*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 332*0fca6ea1SDimitry Andric 333*0fca6ea1SDimitry Andric key_value_sp = anon_union_sp->GetChildMemberWithName("__value_"); 334*0fca6ea1SDimitry Andric if (!key_value_sp) 335*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 336*0fca6ea1SDimitry Andric } 337*0fca6ea1SDimitry Andric 338*0fca6ea1SDimitry Andric // Create the synthetic child, which is a pair where the key and value can be 339*0fca6ea1SDimitry Andric // retrieved by querying the synthetic frontend for 340*0fca6ea1SDimitry Andric // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second") 341*0fca6ea1SDimitry Andric // respectively. 342*0fca6ea1SDimitry Andric // 343*0fca6ea1SDimitry Andric // std::unordered_map stores the actual key/value pair in 344*0fca6ea1SDimitry Andric // __hash_value_type::__cc_ (or previously __cc). 345*0fca6ea1SDimitry Andric auto potential_child_sp = key_value_sp->Clone(ConstString("pair")); 346*0fca6ea1SDimitry Andric if (potential_child_sp) 347*0fca6ea1SDimitry Andric if (potential_child_sp->GetNumChildrenIgnoringErrors() == 1) 348*0fca6ea1SDimitry Andric if (auto child0_sp = potential_child_sp->GetChildAtIndex(0); 349*0fca6ea1SDimitry Andric child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc") 350*0fca6ea1SDimitry Andric potential_child_sp = child0_sp->Clone(ConstString("pair")); 351*0fca6ea1SDimitry Andric 352*0fca6ea1SDimitry Andric m_pair_sp = potential_child_sp; 353*0fca6ea1SDimitry Andric 354*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 355*0fca6ea1SDimitry Andric } 356*0fca6ea1SDimitry Andric 357*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters:: 358*0fca6ea1SDimitry Andric LibCxxUnorderedMapIteratorSyntheticFrontEnd::CalculateNumChildren() { 359*0fca6ea1SDimitry Andric return 2; 360*0fca6ea1SDimitry Andric } 361*0fca6ea1SDimitry Andric 362*0fca6ea1SDimitry Andric lldb::ValueObjectSP lldb_private::formatters:: 363*0fca6ea1SDimitry Andric LibCxxUnorderedMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { 364*0fca6ea1SDimitry Andric if (m_pair_sp) 365*0fca6ea1SDimitry Andric return m_pair_sp->GetChildAtIndex(idx); 366*0fca6ea1SDimitry Andric return lldb::ValueObjectSP(); 367*0fca6ea1SDimitry Andric } 368*0fca6ea1SDimitry Andric 369*0fca6ea1SDimitry Andric bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: 370*0fca6ea1SDimitry Andric MightHaveChildren() { 371*0fca6ea1SDimitry Andric return true; 372*0fca6ea1SDimitry Andric } 373*0fca6ea1SDimitry Andric 374*0fca6ea1SDimitry Andric size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: 375*0fca6ea1SDimitry Andric GetIndexOfChildWithName(ConstString name) { 376*0fca6ea1SDimitry Andric if (name == "first") 377*0fca6ea1SDimitry Andric return 0; 378*0fca6ea1SDimitry Andric if (name == "second") 379*0fca6ea1SDimitry Andric return 1; 380*0fca6ea1SDimitry Andric return UINT32_MAX; 381*0fca6ea1SDimitry Andric } 382*0fca6ea1SDimitry Andric 383*0fca6ea1SDimitry Andric SyntheticChildrenFrontEnd * 384*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEndCreator( 385*0fca6ea1SDimitry Andric CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 386*0fca6ea1SDimitry Andric return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp) 387*0fca6ea1SDimitry Andric : nullptr); 388*0fca6ea1SDimitry Andric } 389