NSSet.cpp revision 292932
1362679Sdim//===-- NSSet.cpp -----------------------------------------------*- C++ -*-===//
2362679Sdim//
3362679Sdim//                     The LLVM Compiler Infrastructure
4362679Sdim//
5362679Sdim// This file is distributed under the University of Illinois Open Source
6362679Sdim// License. See LICENSE.TXT for details.
7362679Sdim//
8362679Sdim//===----------------------------------------------------------------------===//
9362679Sdim
10362679Sdim// C Includes
11362679Sdim// C++ Includes
12362679Sdim// Other libraries and framework includes
13362679Sdim// Project includes
14362679Sdim#include "NSSet.h"
15362679Sdim
16362679Sdim#include "lldb/Core/DataBufferHeap.h"
17362679Sdim#include "lldb/Core/Error.h"
18362679Sdim#include "lldb/Core/Stream.h"
19362679Sdim#include "lldb/Core/ValueObject.h"
20362679Sdim#include "lldb/Core/ValueObjectConstResult.h"
21362679Sdim#include "lldb/DataFormatters/FormattersHelpers.h"
22362679Sdim#include "lldb/Host/Endian.h"
23362679Sdim#include "lldb/Symbol/ClangASTContext.h"
24362679Sdim#include "lldb/Target/Language.h"
25362679Sdim#include "lldb/Target/ObjCLanguageRuntime.h"
26362679Sdim#include "lldb/Target/Target.h"
27362679Sdim
28362679Sdimusing namespace lldb;
29362679Sdimusing namespace lldb_private;
30362679Sdimusing namespace lldb_private::formatters;
31362679Sdim
32362679Sdimstd::map<ConstString, CXXFunctionSummaryFormat::Callback>&
33362679SdimNSSet_Additionals::GetAdditionalSummaries ()
34362679Sdim{
35362679Sdim    static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
36362679Sdim    return g_map;
37362679Sdim}
38362679Sdim
39362679Sdimstd::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>&
40362679SdimNSSet_Additionals::GetAdditionalSynthetics ()
41362679Sdim{
42362679Sdim    static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> g_map;
43362679Sdim    return g_map;
44362679Sdim}
45362679Sdim
46362679Sdimnamespace lldb_private {
47362679Sdim    namespace formatters {
48362679Sdim        class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd
49362679Sdim        {
50362679Sdim        public:
51362679Sdim            NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
52362679Sdim
53362679Sdim            ~NSSetISyntheticFrontEnd() override;
54362679Sdim
55362679Sdim            size_t
56362679Sdim            CalculateNumChildren() override;
57362679Sdim
58362679Sdim            lldb::ValueObjectSP
59362679Sdim            GetChildAtIndex(size_t idx) override;
60362679Sdim
61362679Sdim            bool
62362679Sdim            Update() override;
63362679Sdim
64362679Sdim            bool
65362679Sdim            MightHaveChildren() override;
66362679Sdim
67362679Sdim            size_t
68362679Sdim            GetIndexOfChildWithName(const ConstString &name) override;
69362679Sdim
70362679Sdim        private:
71362679Sdim            struct DataDescriptor_32
72362679Sdim            {
73362679Sdim                uint32_t _used : 26;
74362679Sdim                uint32_t _szidx : 6;
75362679Sdim            };
76362679Sdim
77362679Sdim            struct DataDescriptor_64
78362679Sdim            {
79362679Sdim                uint64_t _used : 58;
80362679Sdim                uint32_t _szidx : 6;
81362679Sdim            };
82362679Sdim
83362679Sdim            struct SetItemDescriptor
84362679Sdim            {
85362679Sdim                lldb::addr_t item_ptr;
86362679Sdim                lldb::ValueObjectSP valobj_sp;
87362679Sdim            };
88362679Sdim
89362679Sdim            ExecutionContextRef m_exe_ctx_ref;
90362679Sdim            uint8_t m_ptr_size;
91362679Sdim            DataDescriptor_32 *m_data_32;
92362679Sdim            DataDescriptor_64 *m_data_64;
93362679Sdim            lldb::addr_t m_data_ptr;
94362679Sdim            std::vector<SetItemDescriptor> m_children;
95362679Sdim        };
96362679Sdim
97362679Sdim        class NSOrderedSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd
98362679Sdim        {
99362679Sdim        public:
100362679Sdim            NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
101362679Sdim
102362679Sdim            ~NSOrderedSetSyntheticFrontEnd() override = default;
103362679Sdim
104362679Sdim            size_t
105362679Sdim            CalculateNumChildren() override;
106362679Sdim
107362679Sdim            lldb::ValueObjectSP
108362679Sdim            GetChildAtIndex(size_t idx) override;
109362679Sdim
110362679Sdim            bool
111362679Sdim            Update() override;
112362679Sdim
113362679Sdim            bool
114362679Sdim            MightHaveChildren() override;
115362679Sdim
116362679Sdim            size_t
117362679Sdim            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
201template<bool cf_style>
202bool
203lldb_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
303SyntheticChildrenFrontEnd* 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
356lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
357SyntheticChildrenFrontEnd(*valobj_sp.get()),
358m_exe_ctx_ref(),
359m_ptr_size(8),
360m_data_32(NULL),
361m_data_64(NULL)
362{
363    if (valobj_sp)
364        Update();
365}
366
367lldb_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
375size_t
376lldb_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
385size_t
386lldb_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
393bool
394lldb_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
437bool
438lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren ()
439{
440    return true;
441}
442
443lldb::ValueObjectSP
444lldb_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
523lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
524SyntheticChildrenFrontEnd(*valobj_sp.get()),
525m_exe_ctx_ref(),
526m_ptr_size(8),
527m_data_32(NULL),
528m_data_64(NULL)
529{
530    if (valobj_sp)
531        Update ();
532}
533
534lldb_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
542size_t
543lldb_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
552size_t
553lldb_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
560bool
561lldb_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
603bool
604lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren ()
605{
606    return true;
607}
608
609lldb::ValueObjectSP
610lldb_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
691lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
692SyntheticChildrenFrontEnd(*valobj_sp.get()),
693m_count(UINT32_MAX),
694m_children()
695{}
696
697size_t
698lldb_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
708lldb::ValueObjectSP
709lldb_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
732bool
733lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::Update()
734{
735    return false;
736}
737
738bool
739lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::MightHaveChildren ()
740{
741    return true;
742}
743
744size_t
745lldb_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
754template bool
755lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
756
757template bool
758lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
759