mib created this revision.
mib added reviewers: friss, davide, jingham.
mib added a project: LLDB.
Herald added a subscriber: lldb-commits.

This patch improves data formatting for CFDictionaryRef and CFSetRef.
It uses the same data-formatter as NSCFDictionaries and NSCFSets introduced
previously (D78396 <https://reviews.llvm.org/D78396>) but did require some 
adjustments in Core::ValueObject.

Since the "Ref" types are opaque pointers to the actual CF containers, if the
value object has a synthetic value, lldb will create an empty record type to
create the new ValueObjectChild needed to dereference the original ValueObject.
This allows the "Ref" types to behaves the same as CF containers when used with
the `frame variable` command, the SBAPI or in Xcode's variable inspector.

rdar://53104287

Signed-off-by: Med Ismail Bennani <medismail.benn...@gmail.com>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79554

Files:
  lldb/source/Core/ValueObject.cpp
  lldb/source/Plugins/Language/ObjC/NSSet.cpp
  lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
  lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m

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
@@ -482,8 +482,7 @@
       CFDictionaryCreate(nil, (void *)cfKeys, (void *)cfValues, 2, nil, nil));
   NSDictionary *nscfDictionary = CFBridgingRelease(
       CFDictionaryCreate(nil, (void *)cfKeys, (void *)cfValues, 4, nil, nil));
-  CFDictionaryRef cfDictionaryRef =
-      CFDictionaryCreate(nil, (void *)cfKeys, (void *)cfValues, 3, nil, nil);
+  CFDictionaryRef cfDictionaryRef = (__bridge CFDictionaryRef)nsDictionary;
 
   NSAttributedString *attrString =
       [[NSAttributedString alloc] initWithString:@"hello world from foo"
@@ -542,6 +541,7 @@
   [nsmutableset addObject:str4];
   NSSet *nscfSet =
       CFBridgingRelease(CFSetCreate(nil, (void *)cfValues, 2, nil));
+  CFSetRef cfSetRef = (__bridge CFSetRef)nscfSet;
 
   CFDataRef data_ref =
       CFDataCreate(kCFAllocatorDefault, [immutableData bytes], 5);
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
@@ -32,7 +32,7 @@
                 '(NSDictionary *) nscfDictionary = ',
                 ' 4 key/value pairs',
                 '(CFDictionaryRef) cfDictionaryRef = ',
-                ' 3 key/value pairs',
+                ' 2 key/value pairs',
                 '(NSDictionary *) newMutableDictionary = ',
                 ' 21 key/value pairs',
                 '(CFArrayRef) cfarray_ref = ',
@@ -55,12 +55,25 @@
                 'value = 0x.* @"quux"',
                 ])
 
+                
+        self.expect(
+            'frame variable -d run-target *cfDictionaryRef',
+            patterns=[
+                '\(CFDictionaryRef\) \*cfDictionaryRef =',
+                'key = 0x.* @"foo"',
+                'value = 0x.* @"foo"',
+                'key = 0x.* @"bar"',
+                'value = 0x.* @"bar"',
+                ])
+
 
         self.expect(
-          'frame var nscfSet',
+          'frame var nscfSet cfSetRef',
           substrs=[
           '(NSSet *) nscfSet = ',
           '2 elements',
+          '(CFSetRef) cfSetRef = ',
+          '2 elements',
           ])
 
         self.expect(
@@ -70,6 +83,14 @@
               '\[0\] = 0x.* @".*"',
               '\[1\] = 0x.* @".*"',
                     ])
+                    
+        self.expect(
+          'frame variable -d run-target *cfSetRef',
+          patterns=[
+              '\(CFSetRef\) \*cfSetRef =',
+              '\[0\] = 0x.* @".*"',
+              '\[1\] = 0x.* @".*"',
+                    ])
 
         self.expect(
             'frame variable iset1 iset2 imset',
Index: lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -610,6 +610,10 @@
                   lldb_private::formatters::NSSetSyntheticFrontEndCreator,
                   "__NSCFSet synthetic children", ConstString("__NSCFSet"),
                   ScriptedSyntheticChildren::Flags());
+  AddCXXSynthetic(objc_category_sp,
+                  lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+                  "CFSetRef synthetic children", ConstString("CFSetRef"),
+                  ScriptedSyntheticChildren::Flags());
 
   AddCXXSynthetic(
       objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator,
Index: lldb/source/Plugins/Language/ObjC/NSSet.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -282,6 +282,7 @@
   static const ConstString g_OrderedSetI("__NSOrderedSetI");
   static const ConstString g_SetM("__NSSetM");
   static const ConstString g_SetCF("__NSCFSet");
+  static const ConstString g_SetCFRef("CFSetRef");
 
   if (class_name.IsEmpty())
     return false;
@@ -306,7 +307,7 @@
     }
     if (error.Fail())
       return false;
-  } else if (class_name == g_SetCF) {
+  } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
     ExecutionContext exe_ctx(process_sp);
     CFBasicHash cfbh;
     if (!cfbh.Update(valobj_addr, exe_ctx))
@@ -367,6 +368,7 @@
   static const ConstString g_OrderedSetI("__NSOrderedSetI");
   static const ConstString g_SetM("__NSSetM");
   static const ConstString g_SetCF("__NSCFSet");
+  static const ConstString g_SetCFRef("CFSetRef");
 
   if (class_name.IsEmpty())
     return nullptr;
@@ -386,7 +388,7 @@
     } else {
       return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
     }
-  } else if (class_name == g_SetCF) {
+  } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
     return (new NSCFSetSyntheticFrontEnd(valobj_sp));
   } else {
     auto &map(NSSet_Additionals::GetAdditionalSynthetics());
Index: lldb/source/Core/ValueObject.cpp
===================================================================
--- lldb/source/Core/ValueObject.cpp
+++ lldb/source/Core/ValueObject.cpp
@@ -49,6 +49,8 @@
 #include "lldb/Utility/StreamString.h"
 #include "lldb/lldb-private-types.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
 #include "llvm/Support/Compiler.h"
 
 #include <algorithm>
@@ -660,6 +662,7 @@
   uint32_t child_bitfield_bit_offset = 0;
   bool child_is_base_class = false;
   bool child_is_deref_of_parent = false;
+  CompilerType compiler_type = GetCompilerType();
   uint64_t language_flags = 0;
 
   const bool transparent_pointers = !synthetic_array_member;
@@ -667,7 +670,7 @@
 
   ExecutionContext exe_ctx(GetExecutionContextRef());
 
-  child_compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex(
+  child_compiler_type = compiler_type.GetChildCompilerTypeAtIndex(
       &exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
       ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset,
       child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class,
@@ -687,6 +690,11 @@
         language_flags);
   }
 
+  if (!valobj && synthetic_array_member)
+    valobj = GetSyntheticValue()
+                 ->GetChildAtIndex(synthetic_index, synthetic_array_member)
+                 .get();
+
   return valobj;
 }
 
@@ -2830,6 +2838,47 @@
           child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid,
           language_flags);
     }
+
+    // In case of C opaque pointers, create an empty struct type and try to
+    // recreate a new ValueObjectChild using it.
+    if (!m_deref_valobj) {
+      if (llvm::isa<TypeSystemClang>(compiler_type.GetTypeSystem())) {
+        if (HasSyntheticValue()) {
+          TargetSP target_sp = GetTargetSP();
+          TypeSystemClang *target_ast_context =
+              TypeSystemClang::GetScratch(*target_sp.get());
+
+          if (target_ast_context) {
+            ConstString g___lldb_opaque_ptr_type(
+                compiler_type.GetTypeName().AsCString());
+
+            child_compiler_type = target_ast_context->CreateRecordType(
+                nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
+                g___lldb_opaque_ptr_type.GetCString(), clang::TTK_Struct,
+                lldb::eLanguageTypeC);
+
+            if (child_compiler_type) {
+              TypeSystemClang::StartTagDeclarationDefinition(
+                  child_compiler_type);
+              TypeSystemClang::CompleteTagDeclarationDefinition(
+                  child_compiler_type);
+
+              ConstString child_name;
+              if (!child_name_str.empty())
+                child_name.SetCString(child_name_str.c_str());
+
+              m_deref_valobj = new ValueObjectChild(
+                  *this, child_compiler_type, child_name, child_byte_size,
+                  child_byte_offset, child_bitfield_bit_size,
+                  child_bitfield_bit_offset, child_is_base_class,
+                  child_is_deref_of_parent, eAddressTypeInvalid,
+                  language_flags);
+            }
+          }
+        }
+      }
+    }
+
   } else if (HasSyntheticValue()) {
     m_deref_valobj =
         GetSyntheticValue()
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to