1 //===-- NSSet.cpp -----------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "NSSet.h"
15 
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/Error.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 #include "lldb/Host/Endian.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Target/Language.h"
25 #include "lldb/Target/ObjCLanguageRuntime.h"
26 #include "lldb/Target/Target.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace lldb_private::formatters;
31 
32 std::map<ConstString, CXXFunctionSummaryFormat::Callback>&
33 NSSet_Additionals::GetAdditionalSummaries ()
34 {
35     static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
36     return g_map;
37 }
38 
39 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>&
40 NSSet_Additionals::GetAdditionalSynthetics ()
41 {
42     static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> g_map;
43     return g_map;
44 }
45 
46 namespace lldb_private {
47     namespace formatters {
48         class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd
49         {
50         public:
51             NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
52 
53             ~NSSetISyntheticFrontEnd() override;
54 
55             size_t
56             CalculateNumChildren() override;
57 
58             lldb::ValueObjectSP
59             GetChildAtIndex(size_t idx) override;
60 
61             bool
62             Update() override;
63 
64             bool
65             MightHaveChildren() override;
66 
67             size_t
68             GetIndexOfChildWithName(const ConstString &name) override;
69 
70         private:
71             struct DataDescriptor_32
72             {
73                 uint32_t _used : 26;
74                 uint32_t _szidx : 6;
75             };
76 
77             struct DataDescriptor_64
78             {
79                 uint64_t _used : 58;
80                 uint32_t _szidx : 6;
81             };
82 
83             struct SetItemDescriptor
84             {
85                 lldb::addr_t item_ptr;
86                 lldb::ValueObjectSP valobj_sp;
87             };
88 
89             ExecutionContextRef m_exe_ctx_ref;
90             uint8_t m_ptr_size;
91             DataDescriptor_32 *m_data_32;
92             DataDescriptor_64 *m_data_64;
93             lldb::addr_t m_data_ptr;
94             std::vector<SetItemDescriptor> m_children;
95         };
96 
97         class NSOrderedSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd
98         {
99         public:
100             NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
101 
102             ~NSOrderedSetSyntheticFrontEnd() override = default;
103 
104             size_t
105             CalculateNumChildren() override;
106 
107             lldb::ValueObjectSP
108             GetChildAtIndex(size_t idx) override;
109 
110             bool
111             Update() override;
112 
113             bool
114             MightHaveChildren() override;
115 
116             size_t
117             GetIndexOfChildWithName(const ConstString &name) override;
118 
119         private:
120             uint32_t m_count;
121             std::map<uint32_t,lldb::ValueObjectSP> m_children;
122         };
123 
124         class NSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
125         {
126         public:
127             NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
128 
129             ~NSSetMSyntheticFrontEnd() override;
130 
131             size_t
132             CalculateNumChildren() override;
133 
134             lldb::ValueObjectSP
135             GetChildAtIndex(size_t idx) override;
136 
137             bool
138             Update() override;
139 
140             bool
141             MightHaveChildren() override;
142 
143             size_t
144             GetIndexOfChildWithName(const ConstString &name) override;
145 
146         private:
147             struct DataDescriptor_32
148             {
149                 uint32_t _used : 26;
150                 uint32_t _size;
151                 uint32_t _mutations;
152                 uint32_t _objs_addr;
153             };
154 
155             struct DataDescriptor_64
156             {
157                 uint64_t _used : 58;
158                 uint64_t _size;
159                 uint64_t _mutations;
160                 uint64_t _objs_addr;
161             };
162 
163             struct SetItemDescriptor
164             {
165                 lldb::addr_t item_ptr;
166                 lldb::ValueObjectSP valobj_sp;
167             };
168 
169             ExecutionContextRef m_exe_ctx_ref;
170             uint8_t m_ptr_size;
171             DataDescriptor_32 *m_data_32;
172             DataDescriptor_64 *m_data_64;
173             std::vector<SetItemDescriptor> m_children;
174         };
175 
176         class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
177         {
178         public:
179             NSSetCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
180 
181             ~NSSetCodeRunningSyntheticFrontEnd() override;
182 
183             size_t
184             CalculateNumChildren() override;
185 
186             lldb::ValueObjectSP
187             GetChildAtIndex(size_t idx) override;
188 
189             bool
190             Update() override;
191 
192             bool
193             MightHaveChildren() override;
194 
195             size_t
196             GetIndexOfChildWithName(const ConstString &name) override;
197         };
198     } // namespace formatters
199 } // namespace lldb_private
200 
201 template<bool cf_style>
202 bool
203 lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
204 {
205     static ConstString g_TypeHint("NSSet");
206 
207     ProcessSP process_sp = valobj.GetProcessSP();
208     if (!process_sp)
209         return false;
210 
211     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
212 
213     if (!runtime)
214         return false;
215 
216     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
217 
218     if (!descriptor.get() || !descriptor->IsValid())
219         return false;
220 
221     uint32_t ptr_size = process_sp->GetAddressByteSize();
222     bool is_64bit = (ptr_size == 8);
223 
224     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
225 
226     if (!valobj_addr)
227         return false;
228 
229     uint64_t value = 0;
230 
231     ConstString class_name_cs = descriptor->GetClassName();
232     const char* class_name = class_name_cs.GetCString();
233 
234     if (!class_name || !*class_name)
235         return false;
236 
237     if (!strcmp(class_name,"__NSSetI"))
238     {
239         Error error;
240         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
241         if (error.Fail())
242             return false;
243         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
244     }
245     else if (!strcmp(class_name,"__NSSetM"))
246     {
247         Error error;
248         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
249         if (error.Fail())
250             return false;
251         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
252     }
253     /*else if (!strcmp(class_name,"__NSCFSet"))
254      {
255      Error error;
256      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
257      if (error.Fail())
258      return false;
259      if (is_64bit)
260      value &= ~0x1fff000000000000UL;
261      }
262      else if (!strcmp(class_name,"NSCountedSet"))
263      {
264      Error error;
265      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
266      if (error.Fail())
267      return false;
268      value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : 12), 4, 0, error);
269      if (error.Fail())
270      return false;
271      if (is_64bit)
272      value &= ~0x1fff000000000000UL;
273      }*/
274     else
275     {
276         auto& map(NSSet_Additionals::GetAdditionalSummaries());
277         auto iter = map.find(class_name_cs), end = map.end();
278         if (iter != end)
279             return iter->second(valobj, stream, options);
280         if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
281             return false;
282     }
283 
284     std::string prefix,suffix;
285     if (Language* language = Language::FindPlugin(options.GetLanguage()))
286     {
287         if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
288         {
289             prefix.clear();
290             suffix.clear();
291         }
292     }
293 
294     stream.Printf("%s%" PRIu64 " %s%s%s",
295                   prefix.c_str(),
296                   value,
297                   "element",
298                   value == 1 ? "" : "s",
299                   suffix.c_str());
300     return true;
301 }
302 
303 SyntheticChildrenFrontEnd* lldb_private::formatters::NSSetSyntheticFrontEndCreator (CXXSyntheticChildren* synth, lldb::ValueObjectSP valobj_sp)
304 {
305     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
306     if (!process_sp)
307         return NULL;
308     ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
309     if (!runtime)
310         return NULL;
311 
312     CompilerType valobj_type(valobj_sp->GetCompilerType());
313     Flags flags(valobj_type.GetTypeInfo());
314 
315     if (flags.IsClear(eTypeIsPointer))
316     {
317         Error error;
318         valobj_sp = valobj_sp->AddressOf(error);
319         if (error.Fail() || !valobj_sp)
320             return NULL;
321     }
322 
323     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
324 
325     if (!descriptor.get() || !descriptor->IsValid())
326         return NULL;
327 
328     ConstString class_name_cs = descriptor->GetClassName();
329     const char* class_name = class_name_cs.GetCString();
330 
331     if (!class_name || !*class_name)
332         return NULL;
333 
334     if (!strcmp(class_name,"__NSSetI"))
335     {
336         return (new NSSetISyntheticFrontEnd(valobj_sp));
337     }
338     else if (!strcmp(class_name,"__NSSetM"))
339     {
340         return (new NSSetMSyntheticFrontEnd(valobj_sp));
341     }
342     else if ((!strcmp(class_name,"__NSOrderedSetI")) || (!strcmp(class_name,"__NSOrderedSetM")))
343     {
344         return new NSOrderedSetSyntheticFrontEnd(valobj_sp); // this runs code
345     }
346     else
347     {
348         auto& map(NSSet_Additionals::GetAdditionalSynthetics());
349         auto iter = map.find(class_name_cs), end = map.end();
350         if (iter != end)
351             return iter->second(synth, valobj_sp);
352         return /*(new NSSetCodeRunningSyntheticFrontEnd(valobj_sp))*/ NULL;
353     }
354 }
355 
356 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
357 SyntheticChildrenFrontEnd(*valobj_sp.get()),
358 m_exe_ctx_ref(),
359 m_ptr_size(8),
360 m_data_32(NULL),
361 m_data_64(NULL)
362 {
363     if (valobj_sp)
364         Update();
365 }
366 
367 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd ()
368 {
369     delete m_data_32;
370     m_data_32 = NULL;
371     delete m_data_64;
372     m_data_64 = NULL;
373 }
374 
375 size_t
376 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
377 {
378     const char* item_name = name.GetCString();
379     uint32_t idx = ExtractIndexFromString(item_name);
380     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
381         return UINT32_MAX;
382     return idx;
383 }
384 
385 size_t
386 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren ()
387 {
388     if (!m_data_32 && !m_data_64)
389         return 0;
390     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
391 }
392 
393 bool
394 lldb_private::formatters::NSSetISyntheticFrontEnd::Update()
395 {
396     m_children.clear();
397     delete m_data_32;
398     m_data_32 = NULL;
399     delete m_data_64;
400     m_data_64 = NULL;
401     m_ptr_size = 0;
402     ValueObjectSP valobj_sp = m_backend.GetSP();
403     if (!valobj_sp)
404         return false;
405     if (!valobj_sp)
406         return false;
407     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
408     Error error;
409     if (valobj_sp->IsPointerType())
410     {
411         valobj_sp = valobj_sp->Dereference(error);
412         if (error.Fail() || !valobj_sp)
413             return false;
414     }
415     error.Clear();
416     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
417     if (!process_sp)
418         return false;
419     m_ptr_size = process_sp->GetAddressByteSize();
420     uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
421     if (m_ptr_size == 4)
422     {
423         m_data_32 = new DataDescriptor_32();
424         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
425     }
426     else
427     {
428         m_data_64 = new DataDescriptor_64();
429         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
430     }
431     if (error.Fail())
432         return false;
433     m_data_ptr = data_location + m_ptr_size;
434     return false;
435 }
436 
437 bool
438 lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren ()
439 {
440     return true;
441 }
442 
443 lldb::ValueObjectSP
444 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx)
445 {
446     uint32_t num_children = CalculateNumChildren();
447 
448     if (idx >= num_children)
449         return lldb::ValueObjectSP();
450 
451     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
452     if (!process_sp)
453         return lldb::ValueObjectSP();
454 
455     if (m_children.empty())
456     {
457         // do the scan phase
458         lldb::addr_t obj_at_idx = 0;
459 
460         uint32_t tries = 0;
461         uint32_t test_idx = 0;
462 
463         while(tries < num_children)
464         {
465             obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
466             if (!process_sp)
467                 return lldb::ValueObjectSP();
468             Error error;
469             obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
470             if (error.Fail())
471                 return lldb::ValueObjectSP();
472 
473             test_idx++;
474 
475             if (!obj_at_idx)
476                 continue;
477             tries++;
478 
479             SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
480 
481             m_children.push_back(descriptor);
482         }
483     }
484 
485     if (idx >= m_children.size()) // should never happen
486         return lldb::ValueObjectSP();
487 
488     SetItemDescriptor &set_item = m_children[idx];
489     if (!set_item.valobj_sp)
490     {
491         auto ptr_size = process_sp->GetAddressByteSize();
492         DataBufferHeap buffer(ptr_size,0);
493         switch (ptr_size)
494         {
495             case 0: // architecture has no clue?? - fail
496                 return lldb::ValueObjectSP();
497             case 4:
498                 *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
499                 break;
500             case 8:
501                 *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
502                 break;
503             default:
504                 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
505         }
506         StreamString idx_name;
507         idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
508 
509         DataExtractor data(buffer.GetBytes(),
510                            buffer.GetByteSize(),
511                            process_sp->GetByteOrder(),
512                            process_sp->GetAddressByteSize());
513 
514         set_item.valobj_sp =
515         CreateValueObjectFromData(idx_name.GetData(),
516                                   data,
517                                   m_exe_ctx_ref,
518                                   m_backend.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
519     }
520     return set_item.valobj_sp;
521 }
522 
523 lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
524 SyntheticChildrenFrontEnd(*valobj_sp.get()),
525 m_exe_ctx_ref(),
526 m_ptr_size(8),
527 m_data_32(NULL),
528 m_data_64(NULL)
529 {
530     if (valobj_sp)
531         Update ();
532 }
533 
534 lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd ()
535 {
536     delete m_data_32;
537     m_data_32 = NULL;
538     delete m_data_64;
539     m_data_64 = NULL;
540 }
541 
542 size_t
543 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
544 {
545     const char* item_name = name.GetCString();
546     uint32_t idx = ExtractIndexFromString(item_name);
547     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
548         return UINT32_MAX;
549     return idx;
550 }
551 
552 size_t
553 lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren ()
554 {
555     if (!m_data_32 && !m_data_64)
556         return 0;
557     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
558 }
559 
560 bool
561 lldb_private::formatters::NSSetMSyntheticFrontEnd::Update()
562 {
563     m_children.clear();
564     ValueObjectSP valobj_sp = m_backend.GetSP();
565     m_ptr_size = 0;
566     delete m_data_32;
567     m_data_32 = NULL;
568     delete m_data_64;
569     m_data_64 = NULL;
570     if (!valobj_sp)
571         return false;
572     if (!valobj_sp)
573         return false;
574     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
575     Error error;
576     if (valobj_sp->IsPointerType())
577     {
578         valobj_sp = valobj_sp->Dereference(error);
579         if (error.Fail() || !valobj_sp)
580             return false;
581     }
582     error.Clear();
583     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
584     if (!process_sp)
585         return false;
586     m_ptr_size = process_sp->GetAddressByteSize();
587     uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
588     if (m_ptr_size == 4)
589     {
590         m_data_32 = new DataDescriptor_32();
591         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
592     }
593     else
594     {
595         m_data_64 = new DataDescriptor_64();
596         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
597     }
598     if (error.Fail())
599         return false;
600     return false;
601 }
602 
603 bool
604 lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren ()
605 {
606     return true;
607 }
608 
609 lldb::ValueObjectSP
610 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
611 {
612     lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
613 
614     uint32_t num_children = CalculateNumChildren();
615 
616     if (idx >= num_children)
617         return lldb::ValueObjectSP();
618 
619     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
620     if (!process_sp)
621         return lldb::ValueObjectSP();
622 
623     if (m_children.empty())
624     {
625         // do the scan phase
626         lldb::addr_t obj_at_idx = 0;
627 
628         uint32_t tries = 0;
629         uint32_t test_idx = 0;
630 
631         while(tries < num_children)
632         {
633             obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
634             if (!process_sp)
635                 return lldb::ValueObjectSP();
636             Error error;
637             obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
638             if (error.Fail())
639                 return lldb::ValueObjectSP();
640 
641             test_idx++;
642 
643             if (!obj_at_idx)
644                 continue;
645             tries++;
646 
647             SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
648 
649             m_children.push_back(descriptor);
650         }
651     }
652 
653     if (idx >= m_children.size()) // should never happen
654         return lldb::ValueObjectSP();
655 
656     SetItemDescriptor &set_item = m_children[idx];
657     if (!set_item.valobj_sp)
658     {
659         auto ptr_size = process_sp->GetAddressByteSize();
660         DataBufferHeap buffer(ptr_size,0);
661         switch (ptr_size)
662         {
663             case 0: // architecture has no clue?? - fail
664                 return lldb::ValueObjectSP();
665             case 4:
666                 *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
667                 break;
668             case 8:
669                 *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
670                 break;
671             default:
672                 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
673         }
674         StreamString idx_name;
675         idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
676 
677         DataExtractor data(buffer.GetBytes(),
678                            buffer.GetByteSize(),
679                            process_sp->GetByteOrder(),
680                            process_sp->GetAddressByteSize());
681 
682         set_item.valobj_sp =
683         CreateValueObjectFromData(idx_name.GetData(),
684                                   data,
685                                   m_exe_ctx_ref,
686                                   m_backend.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
687     }
688     return set_item.valobj_sp;
689 }
690 
691 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
692 SyntheticChildrenFrontEnd(*valobj_sp.get()),
693 m_count(UINT32_MAX),
694 m_children()
695 {}
696 
697 size_t
698 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::CalculateNumChildren ()
699 {
700     if (m_count != UINT32_MAX)
701         return m_count;
702     uint64_t count_temp;
703     if (ExtractValueFromObjCExpression(m_backend,"unsigned int","count",count_temp))
704         return (m_count = count_temp);
705     return (m_count = 0);
706 }
707 
708 lldb::ValueObjectSP
709 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetChildAtIndex (size_t idx)
710 {
711     auto iter = m_children.find(idx);
712     if (iter == m_children.end())
713     {
714         lldb::ValueObjectSP retval_sp;
715         if (idx <= m_count)
716         {
717             retval_sp = CallSelectorOnObject(m_backend, "id", "objectAtIndex", idx);
718             if (retval_sp)
719             {
720                 StreamString idx_name;
721                 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
722                 retval_sp->SetName(ConstString(idx_name.GetData()));
723             }
724             m_children[idx] = retval_sp;
725         }
726         return retval_sp;
727     }
728     else
729         return iter->second;
730 }
731 
732 bool
733 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::Update()
734 {
735     return false;
736 }
737 
738 bool
739 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::MightHaveChildren ()
740 {
741     return true;
742 }
743 
744 size_t
745 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
746 {
747     const char* item_name = name.GetCString();
748     uint32_t idx = ExtractIndexFromString(item_name);
749     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
750         return UINT32_MAX;
751     return idx;
752 }
753 
754 template bool
755 lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
756 
757 template bool
758 lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
759