xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- LibCxxMap.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"
160b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
170b57cec5SDimitry Andric #include "lldb/Utility/Endian.h"
180b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
190b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
20*0fca6ea1SDimitry Andric #include "lldb/lldb-enumerations.h"
21*0fca6ea1SDimitry Andric #include "lldb/lldb-forward.h"
22*0fca6ea1SDimitry Andric #include <cstdint>
23*0fca6ea1SDimitry Andric #include <locale>
24*0fca6ea1SDimitry Andric #include <optional>
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace lldb;
270b57cec5SDimitry Andric using namespace lldb_private;
280b57cec5SDimitry Andric using namespace lldb_private::formatters;
290b57cec5SDimitry Andric 
30*0fca6ea1SDimitry Andric // The flattened layout of the std::__tree_iterator::__ptr_ looks
31*0fca6ea1SDimitry Andric // as follows:
32*0fca6ea1SDimitry Andric //
33*0fca6ea1SDimitry Andric // The following shows the contiguous block of memory:
34*0fca6ea1SDimitry Andric //
35*0fca6ea1SDimitry Andric //        +-----------------------------+ class __tree_end_node
36*0fca6ea1SDimitry Andric // __ptr_ | pointer __left_;            |
37*0fca6ea1SDimitry Andric //        +-----------------------------+ class __tree_node_base
38*0fca6ea1SDimitry Andric //        | pointer __right_;           |
39*0fca6ea1SDimitry Andric //        | __parent_pointer __parent_; |
40*0fca6ea1SDimitry Andric //        | bool __is_black_;           |
41*0fca6ea1SDimitry Andric //        +-----------------------------+ class __tree_node
42*0fca6ea1SDimitry Andric //        | __node_value_type __value_; | <<< our key/value pair
43*0fca6ea1SDimitry Andric //        +-----------------------------+
44*0fca6ea1SDimitry Andric //
45*0fca6ea1SDimitry Andric // where __ptr_ has type __iter_pointer.
46*0fca6ea1SDimitry Andric 
470b57cec5SDimitry Andric class MapEntry {
480b57cec5SDimitry Andric public:
490b57cec5SDimitry Andric   MapEntry() = default;
500b57cec5SDimitry Andric   explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
510b57cec5SDimitry Andric   explicit MapEntry(ValueObject *entry)
520b57cec5SDimitry Andric       : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   ValueObjectSP left() const {
550b57cec5SDimitry Andric     if (!m_entry_sp)
560b57cec5SDimitry Andric       return m_entry_sp;
570b57cec5SDimitry Andric     return m_entry_sp->GetSyntheticChildAtOffset(
580b57cec5SDimitry Andric         0, m_entry_sp->GetCompilerType(), true);
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   ValueObjectSP right() const {
620b57cec5SDimitry Andric     if (!m_entry_sp)
630b57cec5SDimitry Andric       return m_entry_sp;
640b57cec5SDimitry Andric     return m_entry_sp->GetSyntheticChildAtOffset(
650b57cec5SDimitry Andric         m_entry_sp->GetProcessSP()->GetAddressByteSize(),
660b57cec5SDimitry Andric         m_entry_sp->GetCompilerType(), true);
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   ValueObjectSP parent() const {
700b57cec5SDimitry Andric     if (!m_entry_sp)
710b57cec5SDimitry Andric       return m_entry_sp;
720b57cec5SDimitry Andric     return m_entry_sp->GetSyntheticChildAtOffset(
730b57cec5SDimitry Andric         2 * m_entry_sp->GetProcessSP()->GetAddressByteSize(),
740b57cec5SDimitry Andric         m_entry_sp->GetCompilerType(), true);
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   uint64_t value() const {
780b57cec5SDimitry Andric     if (!m_entry_sp)
790b57cec5SDimitry Andric       return 0;
800b57cec5SDimitry Andric     return m_entry_sp->GetValueAsUnsigned(0);
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   bool error() const {
840b57cec5SDimitry Andric     if (!m_entry_sp)
850b57cec5SDimitry Andric       return true;
860b57cec5SDimitry Andric     return m_entry_sp->GetError().Fail();
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   bool null() const { return (value() == 0); }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   ValueObjectSP GetEntry() const { return m_entry_sp; }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   bool operator==(const MapEntry &rhs) const {
960b57cec5SDimitry Andric     return (rhs.m_entry_sp.get() == m_entry_sp.get());
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric private:
1000b57cec5SDimitry Andric   ValueObjectSP m_entry_sp;
1010b57cec5SDimitry Andric };
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric class MapIterator {
1040b57cec5SDimitry Andric public:
1050b57cec5SDimitry Andric   MapIterator(ValueObject *entry, size_t depth = 0)
1060b57cec5SDimitry Andric       : m_entry(entry), m_max_depth(depth), m_error(false) {}
1070b57cec5SDimitry Andric 
108*0fca6ea1SDimitry Andric   MapIterator() = default;
109480093f4SDimitry Andric 
1100b57cec5SDimitry Andric   ValueObjectSP value() { return m_entry.GetEntry(); }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   ValueObjectSP advance(size_t count) {
1130b57cec5SDimitry Andric     ValueObjectSP fail;
1140b57cec5SDimitry Andric     if (m_error)
1150b57cec5SDimitry Andric       return fail;
1160b57cec5SDimitry Andric     size_t steps = 0;
1170b57cec5SDimitry Andric     while (count > 0) {
1180b57cec5SDimitry Andric       next();
1190b57cec5SDimitry Andric       count--, steps++;
1200b57cec5SDimitry Andric       if (m_error || m_entry.null() || (steps > m_max_depth))
1210b57cec5SDimitry Andric         return fail;
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric     return m_entry.GetEntry();
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric 
126*0fca6ea1SDimitry Andric private:
127*0fca6ea1SDimitry Andric   /// Mimicks libc++'s __tree_next algorithm, which libc++ uses
128*0fca6ea1SDimitry Andric   /// in its __tree_iteartor::operator++.
1290b57cec5SDimitry Andric   void next() {
1300b57cec5SDimitry Andric     if (m_entry.null())
1310b57cec5SDimitry Andric       return;
1320b57cec5SDimitry Andric     MapEntry right(m_entry.right());
1330b57cec5SDimitry Andric     if (!right.null()) {
1340b57cec5SDimitry Andric       m_entry = tree_min(std::move(right));
1350b57cec5SDimitry Andric       return;
1360b57cec5SDimitry Andric     }
1370b57cec5SDimitry Andric     size_t steps = 0;
1380b57cec5SDimitry Andric     while (!is_left_child(m_entry)) {
1390b57cec5SDimitry Andric       if (m_entry.error()) {
1400b57cec5SDimitry Andric         m_error = true;
1410b57cec5SDimitry Andric         return;
1420b57cec5SDimitry Andric       }
1430b57cec5SDimitry Andric       m_entry.SetEntry(m_entry.parent());
1440b57cec5SDimitry Andric       steps++;
1450b57cec5SDimitry Andric       if (steps > m_max_depth) {
1460b57cec5SDimitry Andric         m_entry = MapEntry();
1470b57cec5SDimitry Andric         return;
1480b57cec5SDimitry Andric       }
1490b57cec5SDimitry Andric     }
1500b57cec5SDimitry Andric     m_entry = MapEntry(m_entry.parent());
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
153*0fca6ea1SDimitry Andric   /// Mimicks libc++'s __tree_min algorithm.
154fe6060f1SDimitry Andric   MapEntry tree_min(MapEntry x) {
1550b57cec5SDimitry Andric     if (x.null())
1560b57cec5SDimitry Andric       return MapEntry();
1570b57cec5SDimitry Andric     MapEntry left(x.left());
1580b57cec5SDimitry Andric     size_t steps = 0;
1590b57cec5SDimitry Andric     while (!left.null()) {
1600b57cec5SDimitry Andric       if (left.error()) {
1610b57cec5SDimitry Andric         m_error = true;
1620b57cec5SDimitry Andric         return MapEntry();
1630b57cec5SDimitry Andric       }
1640b57cec5SDimitry Andric       x = left;
1650b57cec5SDimitry Andric       left.SetEntry(x.left());
1660b57cec5SDimitry Andric       steps++;
1670b57cec5SDimitry Andric       if (steps > m_max_depth)
1680b57cec5SDimitry Andric         return MapEntry();
1690b57cec5SDimitry Andric     }
1700b57cec5SDimitry Andric     return x;
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   bool is_left_child(const MapEntry &x) {
1740b57cec5SDimitry Andric     if (x.null())
1750b57cec5SDimitry Andric       return false;
1760b57cec5SDimitry Andric     MapEntry rhs(x.parent());
1770b57cec5SDimitry Andric     rhs.SetEntry(rhs.left());
1780b57cec5SDimitry Andric     return x.value() == rhs.value();
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   MapEntry m_entry;
182fcaf7f86SDimitry Andric   size_t m_max_depth = 0;
183fcaf7f86SDimitry Andric   bool m_error = false;
1840b57cec5SDimitry Andric };
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric namespace lldb_private {
1870b57cec5SDimitry Andric namespace formatters {
1880b57cec5SDimitry Andric class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
1890b57cec5SDimitry Andric public:
1900b57cec5SDimitry Andric   LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   ~LibcxxStdMapSyntheticFrontEnd() override = default;
1930b57cec5SDimitry Andric 
194*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
1950b57cec5SDimitry Andric 
196*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
1970b57cec5SDimitry Andric 
198*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   bool MightHaveChildren() override;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric private:
205*0fca6ea1SDimitry Andric   /// Returns the ValueObject for the __tree_node type that
206*0fca6ea1SDimitry Andric   /// holds the key/value pair of the node at index \ref idx.
207*0fca6ea1SDimitry Andric   ///
208*0fca6ea1SDimitry Andric   /// \param[in] idx The child index that we're looking to get
209*0fca6ea1SDimitry Andric   ///                the key/value pair for.
210*0fca6ea1SDimitry Andric   ///
211*0fca6ea1SDimitry Andric   /// \param[in] max_depth The maximum search depth after which
212*0fca6ea1SDimitry Andric   ///                      we stop trying to find the key/value
213*0fca6ea1SDimitry Andric   ///                      pair for.
214*0fca6ea1SDimitry Andric   ///
215*0fca6ea1SDimitry Andric   /// \returns On success, returns the ValueObjectSP corresponding
216*0fca6ea1SDimitry Andric   ///          to the __tree_node's __value_ member (which holds
217*0fca6ea1SDimitry Andric   ///          the key/value pair the formatter wants to display).
218*0fca6ea1SDimitry Andric   ///          On failure, will return nullptr.
219*0fca6ea1SDimitry Andric   ValueObjectSP GetKeyValuePair(size_t idx, size_t max_depth);
2200b57cec5SDimitry Andric 
22181ad6265SDimitry Andric   ValueObject *m_tree = nullptr;
22281ad6265SDimitry Andric   ValueObject *m_root_node = nullptr;
223*0fca6ea1SDimitry Andric   CompilerType m_node_ptr_type;
22481ad6265SDimitry Andric   size_t m_count = UINT32_MAX;
2250b57cec5SDimitry Andric   std::map<size_t, MapIterator> m_iterators;
2260b57cec5SDimitry Andric };
227*0fca6ea1SDimitry Andric 
228*0fca6ea1SDimitry Andric class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
229*0fca6ea1SDimitry Andric public:
230*0fca6ea1SDimitry Andric   LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
231*0fca6ea1SDimitry Andric 
232*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
233*0fca6ea1SDimitry Andric 
234*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
235*0fca6ea1SDimitry Andric 
236*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
237*0fca6ea1SDimitry Andric 
238*0fca6ea1SDimitry Andric   bool MightHaveChildren() override;
239*0fca6ea1SDimitry Andric 
240*0fca6ea1SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
241*0fca6ea1SDimitry Andric 
242*0fca6ea1SDimitry Andric   ~LibCxxMapIteratorSyntheticFrontEnd() override = default;
243*0fca6ea1SDimitry Andric 
244*0fca6ea1SDimitry Andric private:
245*0fca6ea1SDimitry Andric   ValueObjectSP m_pair_sp = nullptr;
246*0fca6ea1SDimitry Andric };
2470b57cec5SDimitry Andric } // namespace formatters
2480b57cec5SDimitry Andric } // namespace lldb_private
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
2510b57cec5SDimitry Andric     LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
252*0fca6ea1SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp) {
2530b57cec5SDimitry Andric   if (valobj_sp)
2540b57cec5SDimitry Andric     Update();
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric 
257*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters::
258*0fca6ea1SDimitry Andric     LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren() {
2590b57cec5SDimitry Andric   if (m_count != UINT32_MAX)
2600b57cec5SDimitry Andric     return m_count;
261*0fca6ea1SDimitry Andric 
2620b57cec5SDimitry Andric   if (m_tree == nullptr)
2630b57cec5SDimitry Andric     return 0;
264*0fca6ea1SDimitry Andric 
265*0fca6ea1SDimitry Andric   ValueObjectSP size_node(m_tree->GetChildMemberWithName("__pair3_"));
266*0fca6ea1SDimitry Andric   if (!size_node)
2670b57cec5SDimitry Andric     return 0;
2680b57cec5SDimitry Andric 
269*0fca6ea1SDimitry Andric   size_node = GetFirstValueOfLibCXXCompressedPair(*size_node);
2700b57cec5SDimitry Andric 
271*0fca6ea1SDimitry Andric   if (!size_node)
2720b57cec5SDimitry Andric     return 0;
273*0fca6ea1SDimitry Andric 
274*0fca6ea1SDimitry Andric   m_count = size_node->GetValueAsUnsigned(0);
2750b57cec5SDimitry Andric   return m_count;
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric 
278*0fca6ea1SDimitry Andric ValueObjectSP
279*0fca6ea1SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetKeyValuePair(
280*0fca6ea1SDimitry Andric     size_t idx, size_t max_depth) {
281*0fca6ea1SDimitry Andric   MapIterator iterator(m_root_node, max_depth);
282*0fca6ea1SDimitry Andric 
283*0fca6ea1SDimitry Andric   size_t advance_by = idx;
284*0fca6ea1SDimitry Andric   if (idx > 0) {
285*0fca6ea1SDimitry Andric     // If we have already created the iterator for the previous
286*0fca6ea1SDimitry Andric     // index, we can start from there and advance by 1.
287*0fca6ea1SDimitry Andric     auto cached_iterator = m_iterators.find(idx - 1);
288*0fca6ea1SDimitry Andric     if (cached_iterator != m_iterators.end()) {
289*0fca6ea1SDimitry Andric       iterator = cached_iterator->second;
290*0fca6ea1SDimitry Andric       advance_by = 1;
2910b57cec5SDimitry Andric     }
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric 
294*0fca6ea1SDimitry Andric   ValueObjectSP iterated_sp(iterator.advance(advance_by));
295*0fca6ea1SDimitry Andric   if (!iterated_sp)
296*0fca6ea1SDimitry Andric     // this tree is garbage - stop
297*0fca6ea1SDimitry Andric     return nullptr;
298*0fca6ea1SDimitry Andric 
299*0fca6ea1SDimitry Andric   if (!m_node_ptr_type.IsValid())
300*0fca6ea1SDimitry Andric     return nullptr;
301*0fca6ea1SDimitry Andric 
302*0fca6ea1SDimitry Andric   // iterated_sp is a __iter_pointer at this point.
303*0fca6ea1SDimitry Andric   // We can cast it to a __node_pointer (which is what libc++ does).
304*0fca6ea1SDimitry Andric   auto value_type_sp = iterated_sp->Cast(m_node_ptr_type);
305*0fca6ea1SDimitry Andric   if (!value_type_sp)
306*0fca6ea1SDimitry Andric     return nullptr;
307*0fca6ea1SDimitry Andric 
308*0fca6ea1SDimitry Andric   // Finally, get the key/value pair.
309*0fca6ea1SDimitry Andric   value_type_sp = value_type_sp->GetChildMemberWithName("__value_");
310*0fca6ea1SDimitry Andric   if (!value_type_sp)
311*0fca6ea1SDimitry Andric     return nullptr;
312*0fca6ea1SDimitry Andric 
313*0fca6ea1SDimitry Andric   m_iterators[idx] = iterator;
314*0fca6ea1SDimitry Andric 
315*0fca6ea1SDimitry Andric   return value_type_sp;
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric lldb::ValueObjectSP
3190b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
320*0fca6ea1SDimitry Andric     uint32_t idx) {
321bdd1243dSDimitry Andric   static ConstString g_cc_("__cc_"), g_cc("__cc");
32281ad6265SDimitry Andric   static ConstString g_nc("__nc");
323*0fca6ea1SDimitry Andric   uint32_t num_children = CalculateNumChildrenIgnoringErrors();
324*0fca6ea1SDimitry Andric   if (idx >= num_children)
325*0fca6ea1SDimitry Andric     return nullptr;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   if (m_tree == nullptr || m_root_node == nullptr)
328*0fca6ea1SDimitry Andric     return nullptr;
3290b57cec5SDimitry Andric 
330*0fca6ea1SDimitry Andric   ValueObjectSP key_val_sp = GetKeyValuePair(idx, /*max_depth=*/num_children);
331*0fca6ea1SDimitry Andric   if (!key_val_sp) {
332*0fca6ea1SDimitry Andric     // this will stop all future searches until an Update() happens
333*0fca6ea1SDimitry Andric     m_tree = nullptr;
334*0fca6ea1SDimitry Andric     return nullptr;
3350b57cec5SDimitry Andric   }
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   // at this point we have a valid
3380b57cec5SDimitry Andric   // we need to copy current_sp into a new object otherwise we will end up with
3390b57cec5SDimitry Andric   // all items named __value_
3400b57cec5SDimitry Andric   StreamString name;
3410b57cec5SDimitry Andric   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
342*0fca6ea1SDimitry Andric   auto potential_child_sp = key_val_sp->Clone(ConstString(name.GetString()));
3430b57cec5SDimitry Andric   if (potential_child_sp) {
344*0fca6ea1SDimitry Andric     switch (potential_child_sp->GetNumChildrenIgnoringErrors()) {
3450b57cec5SDimitry Andric     case 1: {
34606c3fb27SDimitry Andric       auto child0_sp = potential_child_sp->GetChildAtIndex(0);
347bdd1243dSDimitry Andric       if (child0_sp &&
348bdd1243dSDimitry Andric           (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc))
3490b57cec5SDimitry Andric         potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
3500b57cec5SDimitry Andric       break;
3510b57cec5SDimitry Andric     }
3520b57cec5SDimitry Andric     case 2: {
35306c3fb27SDimitry Andric       auto child0_sp = potential_child_sp->GetChildAtIndex(0);
35406c3fb27SDimitry Andric       auto child1_sp = potential_child_sp->GetChildAtIndex(1);
355bdd1243dSDimitry Andric       if (child0_sp &&
356bdd1243dSDimitry Andric           (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc) &&
357bdd1243dSDimitry Andric           child1_sp && child1_sp->GetName() == g_nc)
3580b57cec5SDimitry Andric         potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
3590b57cec5SDimitry Andric       break;
3600b57cec5SDimitry Andric     }
3610b57cec5SDimitry Andric     }
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric   return potential_child_sp;
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric 
366*0fca6ea1SDimitry Andric lldb::ChildCacheState
367*0fca6ea1SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
3680b57cec5SDimitry Andric   m_count = UINT32_MAX;
3690b57cec5SDimitry Andric   m_tree = m_root_node = nullptr;
3700b57cec5SDimitry Andric   m_iterators.clear();
37106c3fb27SDimitry Andric   m_tree = m_backend.GetChildMemberWithName("__tree_").get();
3720b57cec5SDimitry Andric   if (!m_tree)
373*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
37406c3fb27SDimitry Andric   m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get();
375*0fca6ea1SDimitry Andric   m_node_ptr_type =
376*0fca6ea1SDimitry Andric       m_tree->GetCompilerType().GetDirectNestedTypeWithName("__node_pointer");
377*0fca6ea1SDimitry Andric 
378*0fca6ea1SDimitry Andric   return lldb::ChildCacheState::eRefetch;
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
3820b57cec5SDimitry Andric     MightHaveChildren() {
3830b57cec5SDimitry Andric   return true;
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
3870b57cec5SDimitry Andric     GetIndexOfChildWithName(ConstString name) {
3880b57cec5SDimitry Andric   return ExtractIndexFromString(name.GetCString());
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric SyntheticChildrenFrontEnd *
3920b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator(
3930b57cec5SDimitry Andric     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
3940b57cec5SDimitry Andric   return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr);
3950b57cec5SDimitry Andric }
396*0fca6ea1SDimitry Andric 
397*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
398*0fca6ea1SDimitry Andric     LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
399*0fca6ea1SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp) {
400*0fca6ea1SDimitry Andric   if (valobj_sp)
401*0fca6ea1SDimitry Andric     Update();
402*0fca6ea1SDimitry Andric }
403*0fca6ea1SDimitry Andric 
404*0fca6ea1SDimitry Andric lldb::ChildCacheState
405*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
406*0fca6ea1SDimitry Andric   m_pair_sp.reset();
407*0fca6ea1SDimitry Andric 
408*0fca6ea1SDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
409*0fca6ea1SDimitry Andric   if (!valobj_sp)
410*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
411*0fca6ea1SDimitry Andric 
412*0fca6ea1SDimitry Andric   TargetSP target_sp(valobj_sp->GetTargetSP());
413*0fca6ea1SDimitry Andric   if (!target_sp)
414*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
415*0fca6ea1SDimitry Andric 
416*0fca6ea1SDimitry Andric   // m_backend is a std::map::iterator
417*0fca6ea1SDimitry Andric   // ...which is a __map_iterator<__tree_iterator<..., __node_pointer, ...>>
418*0fca6ea1SDimitry Andric   //
419*0fca6ea1SDimitry Andric   // Then, __map_iterator::__i_ is a __tree_iterator
420*0fca6ea1SDimitry Andric   auto tree_iter_sp = valobj_sp->GetChildMemberWithName("__i_");
421*0fca6ea1SDimitry Andric   if (!tree_iter_sp)
422*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
423*0fca6ea1SDimitry Andric 
424*0fca6ea1SDimitry Andric   // Type is __tree_iterator::__node_pointer
425*0fca6ea1SDimitry Andric   // (We could alternatively also get this from the template argument)
426*0fca6ea1SDimitry Andric   auto node_pointer_type =
427*0fca6ea1SDimitry Andric       tree_iter_sp->GetCompilerType().GetDirectNestedTypeWithName(
428*0fca6ea1SDimitry Andric           "__node_pointer");
429*0fca6ea1SDimitry Andric   if (!node_pointer_type.IsValid())
430*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
431*0fca6ea1SDimitry Andric 
432*0fca6ea1SDimitry Andric   // __ptr_ is a __tree_iterator::__iter_pointer
433*0fca6ea1SDimitry Andric   auto iter_pointer_sp = tree_iter_sp->GetChildMemberWithName("__ptr_");
434*0fca6ea1SDimitry Andric   if (!iter_pointer_sp)
435*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
436*0fca6ea1SDimitry Andric 
437*0fca6ea1SDimitry Andric   // Cast the __iter_pointer to a __node_pointer (which stores our key/value
438*0fca6ea1SDimitry Andric   // pair)
439*0fca6ea1SDimitry Andric   auto node_pointer_sp = iter_pointer_sp->Cast(node_pointer_type);
440*0fca6ea1SDimitry Andric   if (!node_pointer_sp)
441*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
442*0fca6ea1SDimitry Andric 
443*0fca6ea1SDimitry Andric   auto key_value_sp = node_pointer_sp->GetChildMemberWithName("__value_");
444*0fca6ea1SDimitry Andric   if (!key_value_sp)
445*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
446*0fca6ea1SDimitry Andric 
447*0fca6ea1SDimitry Andric   // Create the synthetic child, which is a pair where the key and value can be
448*0fca6ea1SDimitry Andric   // retrieved by querying the synthetic frontend for
449*0fca6ea1SDimitry Andric   // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second")
450*0fca6ea1SDimitry Andric   // respectively.
451*0fca6ea1SDimitry Andric   //
452*0fca6ea1SDimitry Andric   // std::map stores the actual key/value pair in value_type::__cc_ (or
453*0fca6ea1SDimitry Andric   // previously __cc).
454*0fca6ea1SDimitry Andric   key_value_sp = key_value_sp->Clone(ConstString("pair"));
455*0fca6ea1SDimitry Andric   if (key_value_sp->GetNumChildrenIgnoringErrors() == 1) {
456*0fca6ea1SDimitry Andric     auto child0_sp = key_value_sp->GetChildAtIndex(0);
457*0fca6ea1SDimitry Andric     if (child0_sp &&
458*0fca6ea1SDimitry Andric         (child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc"))
459*0fca6ea1SDimitry Andric       key_value_sp = child0_sp->Clone(ConstString("pair"));
460*0fca6ea1SDimitry Andric   }
461*0fca6ea1SDimitry Andric 
462*0fca6ea1SDimitry Andric   m_pair_sp = key_value_sp;
463*0fca6ea1SDimitry Andric 
464*0fca6ea1SDimitry Andric   return lldb::ChildCacheState::eRefetch;
465*0fca6ea1SDimitry Andric }
466*0fca6ea1SDimitry Andric 
467*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters::
468*0fca6ea1SDimitry Andric     LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
469*0fca6ea1SDimitry Andric   return 2;
470*0fca6ea1SDimitry Andric }
471*0fca6ea1SDimitry Andric 
472*0fca6ea1SDimitry Andric lldb::ValueObjectSP
473*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex(
474*0fca6ea1SDimitry Andric     uint32_t idx) {
475*0fca6ea1SDimitry Andric   if (!m_pair_sp)
476*0fca6ea1SDimitry Andric     return nullptr;
477*0fca6ea1SDimitry Andric 
478*0fca6ea1SDimitry Andric   return m_pair_sp->GetChildAtIndex(idx);
479*0fca6ea1SDimitry Andric }
480*0fca6ea1SDimitry Andric 
481*0fca6ea1SDimitry Andric bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
482*0fca6ea1SDimitry Andric     MightHaveChildren() {
483*0fca6ea1SDimitry Andric   return true;
484*0fca6ea1SDimitry Andric }
485*0fca6ea1SDimitry Andric 
486*0fca6ea1SDimitry Andric size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
487*0fca6ea1SDimitry Andric     GetIndexOfChildWithName(ConstString name) {
488*0fca6ea1SDimitry Andric   if (!m_pair_sp)
489*0fca6ea1SDimitry Andric     return UINT32_MAX;
490*0fca6ea1SDimitry Andric 
491*0fca6ea1SDimitry Andric   return m_pair_sp->GetIndexOfChildWithName(name);
492*0fca6ea1SDimitry Andric }
493*0fca6ea1SDimitry Andric 
494*0fca6ea1SDimitry Andric SyntheticChildrenFrontEnd *
495*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
496*0fca6ea1SDimitry Andric     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
497*0fca6ea1SDimitry Andric   return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
498*0fca6ea1SDimitry Andric                     : nullptr);
499*0fca6ea1SDimitry Andric }
500