1 //===-- NSArray.cpp ---------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 // Other libraries and framework includes
13 #include "clang/AST/ASTContext.h"
18 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 #include "lldb/Expression/FunctionCaller.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 #include "lldb/Utility/DataBufferHeap.h"
28 #include "lldb/Utility/Endian.h"
29 #include "lldb/Utility/Status.h"
30 #include "lldb/Utility/Stream.h"
33 using namespace lldb_private;
34 using namespace lldb_private::formatters;
36 namespace lldb_private {
37 namespace formatters {
38 std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
39 NSArray_Additionals::GetAdditionalSummaries() {
40 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
44 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
45 NSArray_Additionals::GetAdditionalSynthetics() {
46 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
51 class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {
53 NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);
55 ~NSArrayMSyntheticFrontEndBase() override = default;
57 size_t CalculateNumChildren() override;
59 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
61 bool Update() override = 0;
63 bool MightHaveChildren() override;
65 size_t GetIndexOfChildWithName(const ConstString &name) override;
68 virtual lldb::addr_t GetDataAddress() = 0;
70 virtual uint64_t GetUsedCount() = 0;
72 virtual uint64_t GetOffset() = 0;
74 virtual uint64_t GetSize() = 0;
76 ExecutionContextRef m_exe_ctx_ref;
78 CompilerType m_id_type;
81 template <typename D32, typename D64>
82 class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {
84 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
86 ~GenericNSArrayMSyntheticFrontEnd() override;
88 bool Update() override;
91 lldb::addr_t GetDataAddress() override;
93 uint64_t GetUsedCount() override;
95 uint64_t GetOffset() override;
97 uint64_t GetSize() override;
104 namespace Foundation109 {
105 struct DataDescriptor_32 {
110 uint32_t _offset : 30;
115 struct DataDescriptor_64 {
120 uint64_t _offset : 62;
125 using NSArrayMSyntheticFrontEnd =
126 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
129 namespace Foundation1010 {
130 struct DataDescriptor_32 {
139 struct DataDescriptor_64 {
148 using NSArrayMSyntheticFrontEnd =
149 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
152 namespace Foundation1428 {
153 struct DataDescriptor_32 {
160 struct DataDescriptor_64 {
167 using NSArrayMSyntheticFrontEnd =
168 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
171 namespace Foundation1437 {
172 template <typename PtrType>
173 struct DataDescriptor {
188 using NSArrayMSyntheticFrontEnd =
189 GenericNSArrayMSyntheticFrontEnd<
190 DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;
192 template <typename DD>
194 __NSArrayMSize_Impl(lldb_private::Process &process,
195 lldb::addr_t valobj_addr, Status &error) {
196 const lldb::addr_t start_of_descriptor =
197 valobj_addr + process.GetAddressByteSize();
198 DD descriptor = DD();
199 process.ReadMemory(start_of_descriptor, &descriptor,
200 sizeof(descriptor), error);
204 return descriptor._used;
208 __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
210 if (process.GetAddressByteSize() == 4) {
211 return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,
214 return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,
221 template <typename D32, typename D64, bool Inline>
222 class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
224 GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
226 ~GenericNSArrayISyntheticFrontEnd() override;
228 size_t CalculateNumChildren() override;
230 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
232 bool Update() override;
234 bool MightHaveChildren() override;
236 size_t GetIndexOfChildWithName(const ConstString &name) override;
239 ExecutionContextRef m_exe_ctx_ref;
244 CompilerType m_id_type;
247 namespace Foundation1300 {
258 using NSArrayISyntheticFrontEnd =
259 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
262 namespace Foundation1430 {
263 using NSArrayISyntheticFrontEnd =
264 Foundation1428::NSArrayMSyntheticFrontEnd;
267 namespace Foundation1436 {
270 uint32_t list; // in Inline cases, this is the first element
275 uint64_t list; // in Inline cases, this is the first element
278 using NSArrayI_TransferSyntheticFrontEnd =
279 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;
281 using NSArrayISyntheticFrontEnd =
282 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
284 using NSFrozenArrayMSyntheticFrontEnd =
285 Foundation1437::NSArrayMSyntheticFrontEnd;
288 __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
290 return Foundation1437::__NSArrayMSize(process, valobj_addr, error);
294 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
296 NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
298 ~NSArray0SyntheticFrontEnd() override = default;
300 size_t CalculateNumChildren() override;
302 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
304 bool Update() override;
306 bool MightHaveChildren() override;
308 size_t GetIndexOfChildWithName(const ConstString &name) override;
311 class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
313 NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
315 ~NSArray1SyntheticFrontEnd() override = default;
317 size_t CalculateNumChildren() override;
319 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
321 bool Update() override;
323 bool MightHaveChildren() override;
325 size_t GetIndexOfChildWithName(const ConstString &name) override;
327 } // namespace formatters
328 } // namespace lldb_private
330 bool lldb_private::formatters::NSArraySummaryProvider(
331 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
332 static ConstString g_TypeHint("NSArray");
334 ProcessSP process_sp = valobj.GetProcessSP();
338 ObjCLanguageRuntime *runtime =
339 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
340 lldb::eLanguageTypeObjC);
345 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
346 runtime->GetClassDescriptor(valobj));
348 if (!descriptor || !descriptor->IsValid())
351 uint32_t ptr_size = process_sp->GetAddressByteSize();
353 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
360 ConstString class_name(descriptor->GetClassName());
362 static const ConstString g_NSArrayI("__NSArrayI");
363 static const ConstString g_NSArrayM("__NSArrayM");
364 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
365 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
366 static const ConstString g_NSArray0("__NSArray0");
367 static const ConstString g_NSArray1("__NSSingleObjectArrayI");
368 static const ConstString g_NSArrayCF("__NSCFArray");
369 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
370 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
372 if (class_name.IsEmpty())
375 if (class_name == g_NSArrayI) {
377 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
381 } else if (class_name == g_NSArrayM) {
382 AppleObjCRuntime *apple_runtime =
383 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
385 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
386 value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);
388 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
393 } else if (class_name == g_NSArrayI_Transfer) {
395 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
399 } else if (class_name == g_NSFrozenArrayM) {
401 value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);
404 } else if (class_name == g_NSArrayMLegacy) {
406 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
410 } else if (class_name == g_NSArrayMImmutable) {
412 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
416 } else if (class_name == g_NSArray0) {
418 } else if (class_name == g_NSArray1) {
420 } else if (class_name == g_NSArrayCF) {
422 value = process_sp->ReadUnsignedIntegerFromMemory(
423 valobj_addr + 2 * ptr_size, ptr_size, 0, error);
427 auto &map(NSArray_Additionals::GetAdditionalSummaries());
428 auto iter = map.find(class_name), end = map.end();
430 return iter->second(valobj, stream, options);
435 std::string prefix, suffix;
436 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
437 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
444 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
445 value == 1 ? "" : "s", suffix.c_str());
449 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontEndBase(
450 lldb::ValueObjectSP valobj_sp)
451 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
454 clang::ASTContext *ast = valobj_sp->GetExecutionContextRef()
456 ->GetScratchClangASTContext()
459 m_id_type = CompilerType(ast, ast->ObjCBuiltinIdTy);
460 if (valobj_sp->GetProcessSP())
461 m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
465 template <typename D32, typename D64>
466 lldb_private::formatters::
467 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
468 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
469 : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),
470 m_data_64(nullptr) {}
473 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {
474 return GetUsedCount();
478 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
480 if (idx >= CalculateNumChildren())
481 return lldb::ValueObjectSP();
482 lldb::addr_t object_at_idx = GetDataAddress();
483 size_t pyhs_idx = idx;
484 pyhs_idx += GetOffset();
485 if (GetSize() <= pyhs_idx)
486 pyhs_idx -= GetSize();
487 object_at_idx += (pyhs_idx * m_ptr_size);
488 StreamString idx_name;
489 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
490 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
491 m_exe_ctx_ref, m_id_type);
494 template <typename D32, typename D64>
496 lldb_private::formatters::
497 GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
498 ValueObjectSP valobj_sp = m_backend.GetSP();
506 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
509 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
512 m_ptr_size = process_sp->GetAddressByteSize();
513 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
514 if (m_ptr_size == 4) {
515 m_data_32 = new D32();
516 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
519 m_data_64 = new D64();
520 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
529 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() {
534 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName(
535 const ConstString &name) {
536 const char *item_name = name.GetCString();
537 uint32_t idx = ExtractIndexFromString(item_name);
538 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
543 template <typename D32, typename D64>
544 lldb_private::formatters::
545 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
546 ~GenericNSArrayMSyntheticFrontEnd() {
553 template <typename D32, typename D64>
555 lldb_private::formatters::
556 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
557 GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {
558 if (!m_data_32 && !m_data_64)
559 return LLDB_INVALID_ADDRESS;
560 return m_data_32 ? m_data_32->_data : m_data_64->_data;
563 template <typename D32, typename D64>
565 lldb_private::formatters::
566 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
567 GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {
568 if (!m_data_32 && !m_data_64)
570 return m_data_32 ? m_data_32->_used : m_data_64->_used;
573 template <typename D32, typename D64>
575 lldb_private::formatters::
576 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
577 GenericNSArrayMSyntheticFrontEnd::GetOffset() {
578 if (!m_data_32 && !m_data_64)
580 return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
583 template <typename D32, typename D64>
585 lldb_private::formatters::
586 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
587 GenericNSArrayMSyntheticFrontEnd::GetSize() {
588 if (!m_data_32 && !m_data_64)
590 return m_data_32 ? m_data_32->_size : m_data_64->_size;
593 template <typename D32, typename D64, bool Inline>
594 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
595 GenericNSArrayISyntheticFrontEnd(
596 lldb::ValueObjectSP valobj_sp)
597 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
598 m_data_32(nullptr), m_data_64(nullptr) {
600 CompilerType type = valobj_sp->GetCompilerType();
602 ClangASTContext *ast = valobj_sp->GetExecutionContextRef()
604 ->GetScratchClangASTContext();
606 m_id_type = CompilerType(ast->getASTContext(),
607 ast->getASTContext()->ObjCBuiltinIdTy);
612 template <typename D32, typename D64, bool Inline>
613 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
614 ~GenericNSArrayISyntheticFrontEnd() {
621 template <typename D32, typename D64, bool Inline>
623 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
624 GetIndexOfChildWithName(const ConstString &name) {
625 const char *item_name = name.GetCString();
626 uint32_t idx = ExtractIndexFromString(item_name);
627 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
632 template <typename D32, typename D64, bool Inline>
634 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
635 CalculateNumChildren() {
636 return m_data_32 ? m_data_32->used : m_data_64->used;
639 template <typename D32, typename D64, bool Inline>
641 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
643 ValueObjectSP valobj_sp = m_backend.GetSP();
651 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
654 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
657 m_ptr_size = process_sp->GetAddressByteSize();
658 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
659 if (m_ptr_size == 4) {
660 m_data_32 = new D32();
661 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
664 m_data_64 = new D64();
665 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
673 template <typename D32, typename D64, bool Inline>
675 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
676 MightHaveChildren() {
680 template <typename D32, typename D64, bool Inline>
682 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
683 GetChildAtIndex(size_t idx) {
684 if (idx >= CalculateNumChildren())
685 return lldb::ValueObjectSP();
686 lldb::addr_t object_at_idx;
688 object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;
689 object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header
690 object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer
692 object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
694 object_at_idx += (idx * m_ptr_size);
696 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
698 return lldb::ValueObjectSP();
701 return lldb::ValueObjectSP();
702 StreamString idx_name;
703 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
704 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
705 m_exe_ctx_ref, m_id_type);
708 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
709 lldb::ValueObjectSP valobj_sp)
710 : SyntheticChildrenFrontEnd(*valobj_sp) {}
713 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
714 const ConstString &name) {
719 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
723 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
727 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
732 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
734 return lldb::ValueObjectSP();
737 lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
738 lldb::ValueObjectSP valobj_sp)
739 : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
742 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
743 const ConstString &name) {
744 static const ConstString g_zero("[0]");
753 lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
757 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
761 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
766 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
768 static const ConstString g_zero("[0]");
771 CompilerType id_type(
772 m_backend.GetTargetSP()->GetScratchClangASTContext()->GetBasicType(
773 lldb::eBasicTypeObjCID));
774 return m_backend.GetSyntheticChildAtOffset(
775 m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, g_zero);
777 return lldb::ValueObjectSP();
780 SyntheticChildrenFrontEnd *
781 lldb_private::formatters::NSArraySyntheticFrontEndCreator(
782 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
786 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
789 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
790 process_sp->GetObjCLanguageRuntime());
794 CompilerType valobj_type(valobj_sp->GetCompilerType());
795 Flags flags(valobj_type.GetTypeInfo());
797 if (flags.IsClear(eTypeIsPointer)) {
799 valobj_sp = valobj_sp->AddressOf(error);
800 if (error.Fail() || !valobj_sp)
804 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
805 runtime->GetClassDescriptor(*valobj_sp));
807 if (!descriptor || !descriptor->IsValid())
810 ConstString class_name(descriptor->GetClassName());
812 static const ConstString g_NSArrayI("__NSArrayI");
813 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
814 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
815 static const ConstString g_NSArrayM("__NSArrayM");
816 static const ConstString g_NSArray0("__NSArray0");
817 static const ConstString g_NSArray1("__NSSingleObjectArrayI");
818 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
819 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
821 if (class_name.IsEmpty())
824 if (class_name == g_NSArrayI) {
825 if (runtime->GetFoundationVersion() >= 1436)
826 return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));
827 if (runtime->GetFoundationVersion() >= 1430)
828 return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));
830 return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
831 } else if (class_name == g_NSArrayI_Transfer) {
832 return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
833 } else if (class_name == g_NSArray0) {
834 } else if (class_name == g_NSFrozenArrayM) {
835 return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
836 } else if (class_name == g_NSArray0) {
837 return (new NSArray0SyntheticFrontEnd(valobj_sp));
838 } else if (class_name == g_NSArray1) {
839 return (new NSArray1SyntheticFrontEnd(valobj_sp));
840 } else if (class_name == g_NSArrayM) {
841 if (runtime->GetFoundationVersion() >= 1437)
842 return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));
843 if (runtime->GetFoundationVersion() >= 1428)
844 return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));
845 if (runtime->GetFoundationVersion() >= 1100)
846 return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
848 return (new Foundation109::NSArrayMSyntheticFrontEnd(valobj_sp));
850 auto &map(NSArray_Additionals::GetAdditionalSynthetics());
851 auto iter = map.find(class_name), end = map.end();
853 return iter->second(synth, valobj_sp);