JDevlieghere created this revision.
JDevlieghere added reviewers: friss, jingham.
JDevlieghere requested review of this revision.

Upstream support for NSConstantArray, NSConstantIntegerNumber, 
NSConstant{Float,Double}Number and NSConstantDictionary. We would've upstreamed 
this earlier but testing it requires `-fno-constant-nsnumber-literals`, 
`-fno-constant-nsarray-literals` and `-fno-constant-nsdictionary-literals` 
which haven't been upstreamed yet. As a temporary workaround use the system 
compiler (`xcrun clang`) for the constant variant of the tests.

I'm just upstreaming this. The patch and the tests were all authored by Fred 
Riss.


https://reviews.llvm.org/D107660

Files:
  lldb/source/Plugins/Language/ObjC/Cocoa.cpp
  lldb/source/Plugins/Language/ObjC/NSArray.cpp
  lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
  lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/ObjCDataFormatterTestCase.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSBundle.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSData.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSDate.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSNumber.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSURL.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjNSException.py
  lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m
  
lldb/test/API/functionalities/data-formatter/nsdictionarysynth/TestNSDictionarySynthetic.py
  lldb/test/API/functionalities/data-formatter/nssetsynth/TestNSSetSynthetic.py
  lldb/test/API/functionalities/data-formatter/poarray/TestPrintObjectArray.py
  lldb/test/API/lang/objc/orderedset/TestOrderedSet.py
  
lldb/test/API/lang/objc/single-entry-dictionary/TestObjCSingleEntryDictionary.py

Index: lldb/test/API/lang/objc/single-entry-dictionary/TestObjCSingleEntryDictionary.py
===================================================================
--- lldb/test/API/lang/objc/single-entry-dictionary/TestObjCSingleEntryDictionary.py
+++ lldb/test/API/lang/objc/single-entry-dictionary/TestObjCSingleEntryDictionary.py
@@ -21,9 +21,27 @@
         # Find the line number to break inside main().
         self.line = line_number('main.m', '// break here')
 
+    @skipUnlessDarwin
     @expectedFailureAll(oslist=['watchos'], bugnumber="rdar://problem/34642736") # bug in NSDictionary formatting on watchos
     def test_single_entry_dict(self):
         self.build()
+        self.run_tests()
+
+    @skipUnlessDarwin
+    @expectedFailureAll(oslist=['watchos'], bugnumber="rdar://problem/34642736") # bug in NSDictionary formatting on watchos
+    def test_single_entry_dict_no_const(self):
+        disable_constant_classes = {
+            'CC':
+            'xcrun clang',  # FIXME: Remove when flags are available upstream.
+            'CFLAGS_EXTRAS':
+            '-fno-constant-nsnumber-literals ' +
+            '-fno-constant-nsarray-literals ' +
+            '-fno-constant-nsdictionary-literals'
+        }
+        self.build(dictionary=disable_constant_classes)
+        self.run_tests()
+
+    def run_tests(self):
         exe = self.getBuildArtifact("a.out")
         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
Index: lldb/test/API/lang/objc/orderedset/TestOrderedSet.py
===================================================================
--- lldb/test/API/lang/objc/orderedset/TestOrderedSet.py
+++ lldb/test/API/lang/objc/orderedset/TestOrderedSet.py
@@ -8,6 +8,22 @@
 
   def test_ordered_set(self):
     self.build()
+    self.run_tests()
+
+  @skipUnlessDarwin
+  def test_ordered_set_no_const(self):
+    disable_constant_classes = {
+        'CC':
+        'xcrun clang',  # FIXME: Remove when flags are available upstream.
+        'CFLAGS_EXTRAS':
+        '-fno-constant-nsnumber-literals ' +
+        '-fno-constant-nsarray-literals ' +
+        '-fno-constant-nsdictionary-literals'
+    }
+    self.build(dictionary=disable_constant_classes)
+    self.run_tests()
+
+  def run_tests(self):
     src_file = "main.m"
     src_file_spec = lldb.SBFileSpec(src_file)
     (target, process, thread, main_breakpoint) = lldbutil.run_to_source_breakpoint(self,
Index: lldb/test/API/functionalities/data-formatter/poarray/TestPrintObjectArray.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/poarray/TestPrintObjectArray.py
+++ lldb/test/API/functionalities/data-formatter/poarray/TestPrintObjectArray.py
@@ -20,6 +20,20 @@
         self.build()
         self.printarray_data_formatter_commands()
 
+    @skipUnlessDarwin
+    def test_print_array_no_const(self):
+        """Test that expr -O -Z works"""
+        disable_constant_classes = {
+            'CC':
+            'xcrun clang',  # FIXME: Remove when flags are available upstream.
+            'CFLAGS_EXTRAS':
+            '-fno-constant-nsnumber-literals ' +
+            '-fno-constant-nsarray-literals ' +
+            '-fno-constant-nsdictionary-literals'
+        }
+        self.build(dictionary=disable_constant_classes)
+        self.printarray_data_formatter_commands()
+
     def setUp(self):
         # Call super's setUp().
         TestBase.setUp(self)
Index: lldb/test/API/functionalities/data-formatter/nssetsynth/TestNSSetSynthetic.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/nssetsynth/TestNSSetSynthetic.py
+++ lldb/test/API/functionalities/data-formatter/nssetsynth/TestNSSetSynthetic.py
@@ -24,6 +24,23 @@
     def test_rdar12529957_with_run_command(self):
         """Test that NSSet reports its synthetic children properly."""
         self.build()
+        self.run_tests()
+
+    @skipUnlessDarwin
+    def test_rdar12529957_with_run_command(self):
+        """Test that NSSet reports its synthetic children properly."""
+        disable_constant_classes = {
+            'CC':
+            'xcrun clang',  # FIXME: Remove when flags are available upstream.
+            'CFLAGS_EXTRAS':
+            '-fno-constant-nsnumber-literals ' +
+            '-fno-constant-nsarray-literals ' +
+            '-fno-constant-nsdictionary-literals'
+        }
+        self.build(dictionary=disable_constant_classes)
+        self.run_tests()
+
+    def run_tests(self):
         self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
 
         lldbutil.run_break_set_by_file_and_line(
Index: lldb/test/API/functionalities/data-formatter/nsdictionarysynth/TestNSDictionarySynthetic.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/nsdictionarysynth/TestNSDictionarySynthetic.py
+++ lldb/test/API/functionalities/data-formatter/nsdictionarysynth/TestNSDictionarySynthetic.py
@@ -24,6 +24,23 @@
     def test_rdar11988289_with_run_command(self):
         """Test that NSDictionary reports its synthetic children properly."""
         self.build()
+        self.run_tests()
+
+    @skipUnlessDarwin
+    def test_rdar11988289_with_run_command_no_const(self):
+        """Test that NSDictionary reports its synthetic children properly."""
+        disable_constant_classes = {
+            'CC':
+            'xcrun clang',  # FIXME: Remove when flags are available upstream.
+            'CFLAGS_EXTRAS':
+            '-fno-constant-nsnumber-literals ' +
+            '-fno-constant-nsarray-literals ' +
+            '-fno-constant-nsdictionary-literals'
+        }
+        self.build(dictionary=disable_constant_classes)
+        self.run_tests()
+
+    def run_tests(self):
         self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
 
         lldbutil.run_break_set_by_file_and_line(
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m
@@ -154,6 +154,14 @@
   NSNumber *num_at2 = @-12;
   NSNumber *num_at3 = @12.5;
   NSNumber *num_at4 = @-12.5;
+  NSNumber *num_at5 = @'a';
+  NSNumber *num_at6 = @42.123f;
+  NSNumber *num_at7 = @43.123;
+  NSNumber *num_at8 = @12345ll;
+  NSNumber *num_at9 = @0xF1234567890abcdeull;
+  NSNumber *num_at9b = @-1070935975400915746;
+  NSNumber *num_at10 = @YES;
+  NSNumber *num_at11 = @NO;
 
   NSDecimalNumber *decimal_number =
       [NSDecimalNumber decimalNumberWithMantissa:123456
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjNSException.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjNSException.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjNSException.py
@@ -16,7 +16,12 @@
 
     def test_nsexception_with_run_command(self):
         """Test formatters for NSException."""
-        self.appkit_tester_impl(self.nsexception_data_formatter_commands)
+        self.appkit_tester_impl(self.nsexception_data_formatter_commands, True)
+
+    @skipUnlessDarwin
+    def test_nsexception_with_run_command_no_const(self):
+        """Test formatters for NSException."""
+        self.appkit_tester_impl(self.nsexception_data_formatter_commands, False)
 
     def nsexception_data_formatter_commands(self):
         self.expect(
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSURL.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSURL.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSURL.py
@@ -16,7 +16,12 @@
 
     def test_nsurl_with_run_command(self):
         """Test formatters for NSURL."""
-        self.appkit_tester_impl(self.nsurl_data_formatter_commands)
+        self.appkit_tester_impl(self.nsurl_data_formatter_commands, True)
+
+    @skipUnlessDarwin
+    def test_nsurl_with_run_command_no_const(self):
+        """Test formatters for NSURL."""
+        self.appkit_tester_impl(self.nsurl_data_formatter_commands, False)
 
     def nsurl_data_formatter_commands(self):
         self.expect(
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSNumber.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSNumber.py
@@ -0,0 +1,67 @@
+# encoding: utf-8
+"""
+Test lldb data formatter subsystem.
+"""
+
+from __future__ import print_function
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+from ObjCDataFormatterTestCase import ObjCDataFormatterTestCase
+
+
+class ObjCDataFormatterNSNumber(ObjCDataFormatterTestCase):
+
+    @skipUnlessDarwin
+    def test_nsnumber_with_run_command(self):
+        """Test formatters for  NS container classes."""
+        self.appkit_tester_impl(self.nscontainers_data_formatter_commands, True)
+
+    @skipUnlessDarwin
+    def test_nsnumber_with_run_command_no_const(self):
+        """Test formatters for  NS container classes."""
+        self.appkit_tester_impl(self.nscontainers_data_formatter_commands, False)
+
+    def nscontainers_data_formatter_commands(self):
+        self.expect(
+            'frame variable newArray nsDictionary newDictionary nscfDictionary cfDictionaryRef newMutableDictionary cfarray_ref mutable_array_ref',
+            substrs=[
+                '(NSArray *) newArray = ', '@"50 elements"',
+                '(NSDictionary *) nsDictionary = ', ' 2 key/value pairs',
+                '(NSDictionary *) newDictionary = ', ' 12 key/value pairs',
+                '(CFDictionaryRef) cfDictionaryRef = ', ' 2 key/value pairs',
+                '(NSDictionary *) newMutableDictionary = ', ' 21 key/value pairs',
+                '(CFArrayRef) cfarray_ref = ', '@"3 elements"',
+                '(CFMutableArrayRef) mutable_array_ref = ', '@"11 elements"'
+            ])
+
+        numbers = [ ("num1", "(int)5"),
+                    ("num2", "(float)3.140000"),
+                    ("num3", "(double)3.14"),
+                    ("num4", "(int128_t)18446744073709551614"),
+                    ("num5", "(char)65"),
+                    ("num6", "(long)255"),
+                    ("num7", "(long)2000000"),
+                    ("num8_Y", "YES"),
+                    ("num8_N", "NO"),
+                    ("num9", "(short)-31616"),
+                    ("num_at1", "(int)12"),
+                    ("num_at2", "(int)-12"),
+                    ("num_at3", "(double)12.5"),
+                    ("num_at4", "(double)-12.5"),
+                    ("num_at5", "(char)97"),
+                    ("num_at6", "(float)42.123"),
+                    ("num_at7", "(double)43.123"),
+                    ("num_at8", "(long)12345"),
+                    ("num_at9", "17375808098308635870"),
+                    ("num_at9b", "-1070935975400915746"),
+                    ("num_at10", "YES"),
+                    ("num_at11", "NO"),
+        ]
+
+        for var, res in numbers:
+            self.expect('frame variable ' + var, substrs=[res])
+
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py
@@ -16,7 +16,12 @@
 
     def test_nserror_with_run_command(self):
         """Test formatters for NSError."""
-        self.appkit_tester_impl(self.nserror_data_formatter_commands)
+        self.appkit_tester_impl(self.nserror_data_formatter_commands, True)
+
+    @skipUnlessDarwin
+    def test_nserror_with_run_command_no_const(self):
+        """Test formatters for NSError."""
+        self.appkit_tester_impl(self.nserror_data_formatter_commands, False)
 
     def nserror_data_formatter_commands(self):
         self.expect(
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSDate.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSDate.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSDate.py
@@ -17,7 +17,7 @@
 
     def test_nsdate_with_run_command(self):
         """Test formatters for  NSDate."""
-        self.appkit_tester_impl(self.nsdate_data_formatter_commands)
+        self.appkit_tester_impl(self.nsdate_data_formatter_commands, False)
 
     def nsdate_data_formatter_commands(self):
         self.expect(
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSData.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSData.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSData.py
@@ -16,7 +16,12 @@
 
     def test_nsdata_with_run_command(self):
         """Test formatters for  NSData."""
-        self.appkit_tester_impl(self.nsdata_data_formatter_commands)
+        self.appkit_tester_impl(self.nsdata_data_formatter_commands, True)
+
+    @skipUnlessDarwin
+    def test_nsdata_with_run_command_no_const(self):
+        """Test formatters for  NSData."""
+        self.appkit_tester_impl(self.nsdata_data_formatter_commands, False)
 
     def nsdata_data_formatter_commands(self):
         self.expect(
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
@@ -16,7 +16,7 @@
 
     def test_nscontainers_with_run_command(self):
         """Test formatters for  NS container classes."""
-        self.appkit_tester_impl(self.nscontainers_data_formatter_commands)
+        self.appkit_tester_impl(self.nscontainers_data_formatter_commands, False)
 
     def nscontainers_data_formatter_commands(self):
         self.expect(
@@ -46,7 +46,7 @@
 
         self.expect('frame var -d run-target copyDictionary[10]',
                     substrs=['@"bar9"', '@"foo"'])
-        
+
         self.expect(
             'frame variable -d run-target *nscfDictionary',
             patterns=[
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSBundle.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSBundle.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSBundle.py
@@ -16,7 +16,12 @@
 
     def test_nsbundle_with_run_command(self):
         """Test formatters for NSBundle."""
-        self.appkit_tester_impl(self.nsbundle_data_formatter_commands)
+        self.appkit_tester_impl(self.nsbundle_data_formatter_commands, True)
+
+    @skipUnlessDarwin
+    def test_nsbundle_with_run_command_no_sonct(self):
+        """Test formatters for NSBundle."""
+        self.appkit_tester_impl(self.nsbundle_data_formatter_commands, False)
 
     def nsbundle_data_formatter_commands(self):
         self.expect(
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/ObjCDataFormatterTestCase.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/ObjCDataFormatterTestCase.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/ObjCDataFormatterTestCase.py
@@ -14,8 +14,19 @@
 
    mydir = TestBase.compute_mydir(__file__)
 
-   def appkit_tester_impl(self, commands):
-      self.build()
+   def appkit_tester_impl(self, commands, use_constant_classes):
+      disable_constant_classes = {
+          'CC':
+          'xcrun clang', # FIXME: Remove when flags are available upstream.
+          'CFLAGS_EXTRAS':
+          '-fno-constant-nsnumber-literals ' +
+          '-fno-constant-nsarray-literals ' +
+          '-fno-constant-nsdictionary-literals'
+      }
+      if use_constant_classes:
+         self.build()
+      else:
+         self.build(dictionary=disable_constant_classes)
       self.appkit_common_data_formatters_command()
       commands()
 
Index: lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -403,6 +403,9 @@
   AddCXXSummary(
       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
       "NSArray summary provider", ConstString("NSArray"), appkit_flags);
+  AddCXXSummary(
+      objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
+      "NSArray summary provider", ConstString("NSConstantArray"), appkit_flags);
   AddCXXSummary(
       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
       "NSArray summary provider", ConstString("NSMutableArray"), appkit_flags);
@@ -437,6 +440,10 @@
                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
                 "NSDictionary summary provider", ConstString("NSDictionary"),
                 appkit_flags);
+  AddCXXSummary(objc_category_sp,
+                lldb_private::formatters::NSDictionarySummaryProvider<false>,
+                "NSDictionary summary provider",
+                ConstString("NSConstantDictionary"), appkit_flags);
   AddCXXSummary(objc_category_sp,
                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
                 "NSDictionary summary provider",
@@ -543,6 +550,10 @@
                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
                   "NSArray synthetic children", ConstString("NSArray"),
                   ScriptedSyntheticChildren::Flags());
+  AddCXXSynthetic(objc_category_sp,
+                  lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+                  "NSArray synthetic children", ConstString("NSConstantArray"),
+                  ScriptedSyntheticChildren::Flags());
   AddCXXSynthetic(objc_category_sp,
                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
                   "NSArray synthetic children", ConstString("NSMutableArray"),
@@ -570,6 +581,11 @@
       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
       "NSDictionary synthetic children", ConstString("__NSDictionaryM"),
       ScriptedSyntheticChildren::Flags());
+  AddCXXSynthetic(
+      objc_category_sp,
+      lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+      "NSDictionary synthetic children", ConstString("NSConstantDictionary"),
+      ScriptedSyntheticChildren::Flags());
   AddCXXSynthetic(
       objc_category_sp,
       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
@@ -791,6 +807,18 @@
   AddCXXSummary(
       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
       "NSNumber summary provider", ConstString("NSNumber"), appkit_flags);
+  AddCXXSummary(objc_category_sp,
+                lldb_private::formatters::NSNumberSummaryProvider,
+                "NSNumber summary provider",
+                ConstString("NSConstantIntegerNumber"), appkit_flags);
+  AddCXXSummary(objc_category_sp,
+                lldb_private::formatters::NSNumberSummaryProvider,
+                "NSNumber summary provider",
+                ConstString("NSConstantDoubleNumber"), appkit_flags);
+  AddCXXSummary(objc_category_sp,
+                lldb_private::formatters::NSNumberSummaryProvider,
+                "NSNumber summary provider",
+                ConstString("NSConstantFloatNumber"), appkit_flags);
   AddCXXSummary(
       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
       "CFNumberRef summary provider", ConstString("CFNumberRef"), appkit_flags);
Index: lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -142,6 +142,38 @@
   std::vector<DictionaryItemDescriptor> m_children;
 };
 
+class NSConstantDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+  NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+  size_t CalculateNumChildren() override;
+
+  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+  bool Update() override;
+
+  bool MightHaveChildren() override;
+
+  size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+  ExecutionContextRef m_exe_ctx_ref;
+  CompilerType m_pair_type;
+  uint8_t m_ptr_size = 8;
+  lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
+  unsigned int m_size = 0;
+  lldb::addr_t m_keys_ptr = LLDB_INVALID_ADDRESS;
+  lldb::addr_t m_objects_ptr = LLDB_INVALID_ADDRESS;
+
+  struct DictionaryItemDescriptor {
+    lldb::addr_t key_ptr;
+    lldb::addr_t val_ptr;
+    lldb::ValueObjectSP valobj_sp;
+  };
+
+  std::vector<DictionaryItemDescriptor> m_children;
+};
+
 class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
 public:
   NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -225,24 +257,24 @@
   CompilerType m_pair_type;
   std::vector<DictionaryItemDescriptor> m_children;
 };
-  
+
 namespace Foundation1100 {
   class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
   public:
     NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
-    
+
     ~NSDictionaryMSyntheticFrontEnd() override;
-    
+
     size_t CalculateNumChildren() override;
-    
+
     lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
-    
+
     bool Update() override;
-    
+
     bool MightHaveChildren() override;
-    
+
     size_t GetIndexOfChildWithName(ConstString name) override;
-    
+
   private:
     struct DataDescriptor_32 {
       uint32_t _used : 26;
@@ -252,7 +284,7 @@
       uint32_t _objs_addr;
       uint32_t _keys_addr;
     };
-    
+
     struct DataDescriptor_64 {
       uint64_t _used : 58;
       uint32_t _kvo : 1;
@@ -261,13 +293,13 @@
       uint64_t _objs_addr;
       uint64_t _keys_addr;
     };
-    
+
     struct DictionaryItemDescriptor {
       lldb::addr_t key_ptr;
       lldb::addr_t val_ptr;
       lldb::ValueObjectSP valobj_sp;
     };
-    
+
     ExecutionContextRef m_exe_ctx_ref;
     uint8_t m_ptr_size;
     lldb::ByteOrder m_order;
@@ -277,7 +309,7 @@
     std::vector<DictionaryItemDescriptor> m_children;
   };
 }
-  
+
 namespace Foundation1428 {
   namespace {
     struct DataDescriptor_32 {
@@ -287,7 +319,7 @@
       uint32_t _buffer;
       uint64_t GetSize() { return _size; }
     };
-    
+
     struct DataDescriptor_64 {
       uint64_t _used : 58;
       uint32_t _kvo : 1;
@@ -300,7 +332,7 @@
   using NSDictionaryMSyntheticFrontEnd =
     GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
 }
-  
+
 namespace Foundation1437 {
   namespace {
     static const uint64_t NSDictionaryCapacities[] = {
@@ -310,10 +342,10 @@
         6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
         111638519, 180634607, 292272623, 472907251
     };
-    
+
     static const size_t NSDictionaryNumSizeBuckets =
         sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
-    
+
     struct DataDescriptor_32 {
       uint32_t _buffer;
       uint32_t _muts;
@@ -326,7 +358,7 @@
             0 : NSDictionaryCapacities[_szidx];
       }
     };
-    
+
     struct DataDescriptor_64 {
       uint64_t _buffer;
       uint32_t _muts;
@@ -340,10 +372,10 @@
       }
     };
   }
-  
+
   using NSDictionaryMSyntheticFrontEnd =
     GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
-  
+
   template <typename DD>
   uint64_t
   __NSDictionaryMSize_Impl(lldb_private::Process &process,
@@ -358,7 +390,7 @@
     }
     return descriptor._used;
   }
-  
+
   uint64_t
   __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
                Status &error) {
@@ -416,6 +448,7 @@
   static const ConstString g_DictionaryCF("__CFDictionary");
   static const ConstString g_DictionaryNSCF("__NSCFDictionary");
   static const ConstString g_DictionaryCFRef("CFDictionaryRef");
+  static const ConstString g_ConstantDictionary("NSConstantDictionary");
 
   if (class_name.IsEmpty())
     return false;
@@ -428,8 +461,14 @@
       return false;
 
     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
-  } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy 
-             || class_name == g_DictionaryMFrozen) {
+  } else if (class_name == g_ConstantDictionary) {
+    Status error;
+    value = process_sp->ReadUnsignedIntegerFromMemory(
+        valobj_addr + 2 * ptr_size, ptr_size, 0, error);
+    if (error.Fail())
+      return false;
+  } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
+             class_name == g_DictionaryMFrozen) {
     AppleObjCRuntime *apple_runtime =
     llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
     Status error;
@@ -447,8 +486,7 @@
     value = 1;
   } else if (class_name == g_Dictionary0) {
     value = 0;
-  } else if (class_name == g_DictionaryCF ||
-             class_name == g_DictionaryNSCF ||
+  } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
              class_name == g_DictionaryCFRef) {
     ExecutionContext exe_ctx(process_sp);
     CFBasicHash cfbh;
@@ -517,12 +555,15 @@
   static const ConstString g_DictionaryCF("__CFDictionary");
   static const ConstString g_DictionaryNSCF("__NSCFDictionary");
   static const ConstString g_DictionaryCFRef("CFDictionaryRef");
+  static const ConstString g_ConstantDictionary("NSConstantDictionary");
 
   if (class_name.IsEmpty())
     return nullptr;
 
   if (class_name == g_DictionaryI) {
     return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
+  } else if (class_name == g_ConstantDictionary) {
+    return (new NSConstantDictionarySyntheticFrontEnd(valobj_sp));
   } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {
     if (runtime->GetFoundationVersion() >= 1437) {
       return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
@@ -532,11 +573,10 @@
       return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
     }
   } else if (class_name == g_DictionaryMLegacy) {
-      return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
+    return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
   } else if (class_name == g_Dictionary1) {
     return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
-  } else if (class_name == g_DictionaryCF ||
-             class_name == g_DictionaryNSCF ||
+  } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
              class_name == g_DictionaryCFRef) {
     return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
   } else {
@@ -830,6 +870,120 @@
   return dict_item.valobj_sp;
 }
 
+lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
+    NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+    : SyntheticChildrenFrontEnd(*valobj_sp) {}
+
+size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
+    GetIndexOfChildWithName(ConstString name) {
+  const char *item_name = name.GetCString();
+  uint32_t idx = ExtractIndexFromString(item_name);
+  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+    return UINT32_MAX;
+  return idx;
+}
+
+size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
+    CalculateNumChildren() {
+  return m_size;
+}
+
+bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() {
+  ValueObjectSP valobj_sp = m_backend.GetSP();
+  if (!valobj_sp)
+    return false;
+  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+  Status error;
+  error.Clear();
+  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+  if (!process_sp)
+    return false;
+  m_ptr_size = process_sp->GetAddressByteSize();
+  m_order = process_sp->GetByteOrder();
+  uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);
+  m_size = process_sp->ReadUnsignedIntegerFromMemory(
+      valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error);
+  if (error.Fail())
+    return false;
+  m_keys_ptr = process_sp->ReadUnsignedIntegerFromMemory(
+      valobj_addr + 3 * m_ptr_size, m_ptr_size, 0, error);
+  if (error.Fail())
+    return false;
+  m_objects_ptr = process_sp->ReadUnsignedIntegerFromMemory(
+      valobj_addr + 4 * m_ptr_size, m_ptr_size, 0, error);
+  return !error.Fail();
+}
+
+bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
+    MightHaveChildren() {
+  return true;
+}
+
+lldb::ValueObjectSP lldb_private::formatters::
+    NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(size_t idx) {
+  uint32_t num_children = CalculateNumChildren();
+
+  if (idx >= num_children)
+    return lldb::ValueObjectSP();
+
+  if (m_children.empty()) {
+    // do the scan phase
+    lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+    ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+    if (!process_sp)
+      return lldb::ValueObjectSP();
+
+    for (unsigned int child = 0; child < num_children; ++child) {
+      Status error;
+      key_at_idx = process_sp->ReadPointerFromMemory(
+          m_keys_ptr + child * m_ptr_size, error);
+      if (error.Fail())
+        return lldb::ValueObjectSP();
+      val_at_idx = process_sp->ReadPointerFromMemory(
+          m_objects_ptr + child * m_ptr_size, error);
+      if (error.Fail())
+        return lldb::ValueObjectSP();
+      DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
+                                             lldb::ValueObjectSP()};
+      m_children.push_back(descriptor);
+    }
+  }
+
+  if (idx >= m_children.size()) // should never happen
+    return lldb::ValueObjectSP();
+
+  DictionaryItemDescriptor &dict_item = m_children[idx];
+  if (!dict_item.valobj_sp) {
+    if (!m_pair_type.IsValid()) {
+      TargetSP target_sp(m_backend.GetTargetSP());
+      if (!target_sp)
+        return ValueObjectSP();
+      m_pair_type = GetLLDBNSPairType(target_sp);
+    }
+    if (!m_pair_type.IsValid())
+      return ValueObjectSP();
+
+    DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+    if (m_ptr_size == 8) {
+      uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+      *data_ptr = dict_item.key_ptr;
+      *(data_ptr + 1) = dict_item.val_ptr;
+    } else {
+      uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+      *data_ptr = dict_item.key_ptr;
+      *(data_ptr + 1) = dict_item.val_ptr;
+    }
+
+    StreamString idx_name;
+    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+    DataExtractor data(buffer_sp, m_order, m_ptr_size);
+    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+                                                    m_exe_ctx_ref, m_pair_type);
+  }
+  return dict_item.valobj_sp;
+}
+
 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
     NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
     : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
Index: lldb/source/Plugins/Language/ObjC/NSArray.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/NSArray.cpp
+++ lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -280,6 +280,22 @@
     }
 }
 
+namespace ConstantArray {
+
+struct ConstantArray32 {
+  uint64_t used;
+  uint32_t list;
+};
+
+struct ConstantArray64 {
+  uint64_t used;
+  uint64_t list;
+};
+
+using NSConstantArraySyntheticFrontEnd =
+    GenericNSArrayISyntheticFrontEnd<ConstantArray32, ConstantArray64, false>;
+} // namespace ConstantArray
+
 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
 public:
   NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -356,6 +372,7 @@
   static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
   static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
   static const ConstString g_NSCallStackArray("_NSCallStackArray");
+  static const ConstString g_NSConstantArray("NSConstantArray");
 
   if (class_name.IsEmpty())
     return false;
@@ -366,6 +383,12 @@
                                                       ptr_size, 0, error);
     if (error.Fail())
       return false;
+  } else if (class_name == g_NSConstantArray) {
+    Status error;
+    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 8,
+                                                      0, error);
+    if (error.Fail())
+      return false;
   } else if (class_name == g_NSArrayM) {
     AppleObjCRuntime *apple_runtime =
     llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
@@ -803,6 +826,7 @@
   ConstString class_name(descriptor->GetClassName());
 
   static const ConstString g_NSArrayI("__NSArrayI");
+  static const ConstString g_NSConstantArray("NSConstantArray");
   static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
   static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
   static const ConstString g_NSArrayM("__NSArrayM");
@@ -823,6 +847,8 @@
     return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
   } else if (class_name == g_NSArrayI_Transfer) {
       return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
+  } else if (class_name == g_NSConstantArray) {
+    return new ConstantArray::NSConstantArraySyntheticFrontEnd(valobj_sp);
   } else if (class_name == g_NSFrozenArrayM) {
     return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
   } else if (class_name == g_NSArray0) {
Index: lldb/source/Plugins/Language/ObjC/Cocoa.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/Cocoa.cpp
+++ lldb/source/Plugins/Language/ObjC/Cocoa.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Cocoa.h"
+#include "objc/runtime.h"
 
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/Mangled.h"
@@ -456,6 +457,72 @@
   if (class_name == "NSDecimalNumber")
     return NSDecimalNumberSummaryProvider(valobj, stream, options);
 
+  if (class_name == "NSConstantIntegerNumber") {
+    Status error;
+    int64_t value = process_sp->ReadSignedIntegerFromMemory(
+        valobj_addr + 2 * ptr_size, 8, 0, error);
+    if (error.Fail())
+      return false;
+    uint64_t encoding_addr = process_sp->ReadUnsignedIntegerFromMemory(
+        valobj_addr + ptr_size, ptr_size, 0, error);
+    if (error.Fail())
+      return false;
+    char encoding =
+        process_sp->ReadUnsignedIntegerFromMemory(encoding_addr, 1, 0, error);
+    if (error.Fail())
+      return false;
+
+    switch (encoding) {
+    case _C_CHR:
+      NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
+      return true;
+    case _C_SHT:
+      NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage());
+      return true;
+    case _C_INT:
+      NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
+      return true;
+    case _C_LNG:
+    case _C_LNG_LNG:
+      NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
+      return true;
+
+    case _C_UCHR:
+    case _C_USHT:
+    case _C_UINT:
+    case _C_ULNG:
+    case _C_ULNG_LNG:
+      stream.Printf("%" PRIu64, value);
+      return true;
+    }
+
+    return false;
+  }
+
+  if (class_name == "NSConstantFloatNumber") {
+    Status error;
+    uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
+        valobj_addr + ptr_size, 4, 0, error);
+    if (error.Fail())
+      return false;
+    float flt_value = 0.0f;
+    memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
+    NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
+    return true;
+  }
+
+  if (class_name == "NSConstantDoubleNumber") {
+    Status error;
+    uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
+        valobj_addr + ptr_size, 8, 0, error);
+    if (error.Fail())
+      return false;
+    double dbl_value = 0.0;
+    memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
+    NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
+    return true;
+  }
+
   if (class_name == "NSNumber" || class_name == "__NSCFNumber") {
     int64_t value = 0;
     uint64_t i_bits = 0;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to