Add an LLDB data formatter for single-element NSArray and NSDictionary Cocoa containers

Fixes rdar://23715118

llvm-svn: 262254
diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
index a1bce4d..c288217 100644
--- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -227,6 +227,29 @@
             size_t
             GetIndexOfChildWithName(const ConstString &name) override;
         };
+
+        class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd
+        {
+        public:
+            NSArray1SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+            
+            ~NSArray1SyntheticFrontEnd() override = default;
+            
+            size_t
+            CalculateNumChildren() override;
+            
+            lldb::ValueObjectSP
+            GetChildAtIndex(size_t idx) override;
+            
+            bool
+            Update() override;
+            
+            bool
+            MightHaveChildren() override;
+            
+            size_t
+            GetIndexOfChildWithName(const ConstString &name) override;
+        };
     } // namespace formatters
 } // namespace lldb_private
 
@@ -258,30 +281,40 @@
     
     uint64_t value = 0;
     
-    const char* class_name = descriptor->GetClassName().GetCString();
+    ConstString class_name(descriptor->GetClassName());
     
-    if (!class_name || !*class_name)
+    static const ConstString g_NSArrayI("__NSArrayI");
+    static const ConstString g_NSArrayM("__NSArrayM");
+    static const ConstString g_NSArray0("__NSArray0");
+    static const ConstString g_NSArray1("__NSSingleObjectArrayI");
+    static const ConstString g_NSArrayCF("__NSCFArray");
+    
+    if (class_name.IsEmpty())
         return false;
     
-    if (!strcmp(class_name,"__NSArrayI"))
+    if (class_name == g_NSArrayI)
     {
         Error error;
         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
         if (error.Fail())
             return false;
     }
-    else if (!strcmp(class_name,"__NSArrayM"))
+    else if (class_name == g_NSArrayM)
     {
         Error error;
         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
         if (error.Fail())
             return false;
     }
-    else if (!strcmp(class_name,"__NSArray0"))
+    else if (class_name == g_NSArray0)
     {
         value = 0;
     }
-    else if (!strcmp(class_name,"__NSCFArray"))
+    else if (class_name == g_NSArray1)
+    {
+        value = 1;
+    }
+    else if (class_name == g_NSArrayCF)
     {
         Error error;
         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
@@ -666,6 +699,53 @@
     return lldb::ValueObjectSP();
 }
 
+lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd (*valobj_sp.get())
+{
+}
+
+size_t
+lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+    static const ConstString g_zero("[0]");
+    
+    if (name == g_zero)
+        return 0;
+    
+    return UINT32_MAX;
+}
+
+size_t
+lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren ()
+{
+    return 1;
+}
+
+bool
+lldb_private::formatters::NSArray1SyntheticFrontEnd::Update()
+{
+    return false;
+}
+
+bool
+lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren ()
+{
+    return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+    static const ConstString g_zero("[0]");
+    
+    if (idx == 0)
+    {
+        CompilerType id_type(m_backend.GetTargetSP()->GetScratchClangASTContext()->GetBasicType(lldb::eBasicTypeObjCID));
+        return m_backend.GetSyntheticChildAtOffset(m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, g_zero);
+    }
+    return lldb::ValueObjectSP();
+}
+
 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
 {
     if (!valobj_sp)
@@ -694,20 +774,29 @@
     if (!descriptor || !descriptor->IsValid())
         return nullptr;
     
-    const char* class_name = descriptor->GetClassName().GetCString();
+    ConstString class_name(descriptor->GetClassName());
     
-    if (!class_name || !*class_name)
+    static const ConstString g_NSArrayI("__NSArrayI");
+    static const ConstString g_NSArrayM("__NSArrayM");
+    static const ConstString g_NSArray0("__NSArray0");
+    static const ConstString g_NSArray1("__NSSingleObjectArrayI");
+    
+    if (class_name.IsEmpty())
         return nullptr;
     
-    if (!strcmp(class_name,"__NSArrayI"))
+    if (class_name == g_NSArrayI)
     {
         return (new NSArrayISyntheticFrontEnd(valobj_sp));
     }
-    else if (!strcmp(class_name,"__NSArray0"))
+    else if (class_name == g_NSArrayM)
     {
         return (new NSArray0SyntheticFrontEnd(valobj_sp));
     }
-    else if (!strcmp(class_name,"__NSArrayM"))
+    else if (class_name == g_NSArray1)
+    {
+        return (new NSArray1SyntheticFrontEnd(valobj_sp));
+    }
+    else if (class_name == g_NSArrayM)
     {
         if (runtime->GetFoundationVersion() >= 1100)
             return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));