Author: Ilia Kuklin
Date: 2025-05-12T16:46:58+05:00
New Revision: 3aacd74594b1f8ab04904d277b6a106c98904b29

URL: 
https://github.com/llvm/llvm-project/commit/3aacd74594b1f8ab04904d277b6a106c98904b29
DIFF: 
https://github.com/llvm/llvm-project/commit/3aacd74594b1f8ab04904d277b6a106c98904b29.diff

LOG: [lldb][TypeSystemClang] Allow arrays to be dereferenced in C/C++. (#135843)

Add a function `GetDereferencedType` to `CompilerType` and allow
`TypeSystemClang` to dereference arrays.

Added: 
    

Modified: 
    lldb/include/lldb/Symbol/CompilerType.h
    lldb/include/lldb/Symbol/TypeSystem.h
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
    lldb/source/Symbol/CompilerType.cpp
    lldb/source/ValueObject/ValueObject.cpp
    
lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
    
lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Symbol/CompilerType.h 
b/lldb/include/lldb/Symbol/CompilerType.h
index fdbc2057ac10f..b8badfda92cf3 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -433,6 +433,11 @@ class CompilerType {
 
   CompilerDecl GetStaticFieldWithName(llvm::StringRef name) const;
 
+  llvm::Expected<CompilerType>
+  GetDereferencedType(ExecutionContext *exe_ctx, std::string &deref_name,
+                      uint32_t &deref_byte_size, int32_t &deref_byte_offset,
+                      ValueObject *valobj, uint64_t &language_flags) const;
+
   llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex(
       ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers,
       bool omit_empty_base_classes, bool ignore_array_bounds,

diff  --git a/lldb/include/lldb/Symbol/TypeSystem.h 
b/lldb/include/lldb/Symbol/TypeSystem.h
index df87fea32b72a..1f1a3ac4bc56b 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -364,6 +364,12 @@ class TypeSystem : public PluginInterface,
     return CompilerDecl();
   }
 
+  virtual llvm::Expected<CompilerType>
+  GetDereferencedType(lldb::opaque_compiler_type_t type,
+                      ExecutionContext *exe_ctx, std::string &deref_name,
+                      uint32_t &deref_byte_size, int32_t &deref_byte_offset,
+                      ValueObject *valobj, uint64_t &language_flags) = 0;
+
   virtual llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex(
       lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
       bool transparent_pointers, bool omit_empty_base_classes,

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 3b286885cc37f..d24f3726b1d25 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -6184,6 +6184,24 @@ uint32_t 
TypeSystemClang::GetNumPointeeChildren(clang::QualType type) {
   return 0;
 }
 
+llvm::Expected<CompilerType> TypeSystemClang::GetDereferencedType(
+    lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
+    std::string &deref_name, uint32_t &deref_byte_size,
+    int32_t &deref_byte_offset, ValueObject *valobj, uint64_t &language_flags) 
{
+  bool type_valid = IsPointerOrReferenceType(type, nullptr) ||
+                    IsArrayType(type, nullptr, nullptr, nullptr);
+  if (!type_valid)
+    return llvm::createStringError("not a pointer, reference or array type");
+  uint32_t child_bitfield_bit_size = 0;
+  uint32_t child_bitfield_bit_offset = 0;
+  bool child_is_base_class;
+  bool child_is_deref_of_parent;
+  return GetChildCompilerTypeAtIndex(
+      type, exe_ctx, 0, false, true, false, deref_name, deref_byte_size,
+      deref_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset,
+      child_is_base_class, child_is_deref_of_parent, valobj, language_flags);
+}
+
 llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
     lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
     bool transparent_pointers, bool omit_empty_base_classes,

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 93933846d114d..f918cb017f51b 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -889,6 +889,12 @@ class TypeSystemClang : public TypeSystem {
 
   static uint32_t GetNumPointeeChildren(clang::QualType type);
 
+  llvm::Expected<CompilerType>
+  GetDereferencedType(lldb::opaque_compiler_type_t type,
+                      ExecutionContext *exe_ctx, std::string &deref_name,
+                      uint32_t &deref_byte_size, int32_t &deref_byte_offset,
+                      ValueObject *valobj, uint64_t &language_flags) override;
+
   llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex(
       lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
       bool transparent_pointers, bool omit_empty_base_classes,

diff  --git a/lldb/source/Symbol/CompilerType.cpp 
b/lldb/source/Symbol/CompilerType.cpp
index 90c4dbf0c6206..dd81fc2361f88 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -893,6 +893,18 @@ CompilerDecl 
CompilerType::GetStaticFieldWithName(llvm::StringRef name) const {
   return CompilerDecl();
 }
 
+llvm::Expected<CompilerType> CompilerType::GetDereferencedType(
+    ExecutionContext *exe_ctx, std::string &deref_name,
+    uint32_t &deref_byte_size, int32_t &deref_byte_offset, ValueObject *valobj,
+    uint64_t &language_flags) const {
+  if (IsValid())
+    if (auto type_system_sp = GetTypeSystem())
+      return type_system_sp->GetDereferencedType(
+          m_type, exe_ctx, deref_name, deref_byte_size, deref_byte_offset,
+          valobj, language_flags);
+  return CompilerType();
+}
+
 llvm::Expected<CompilerType> CompilerType::GetChildCompilerTypeAtIndex(
     ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers,
     bool omit_empty_base_classes, bool ignore_array_bounds,

diff  --git a/lldb/source/ValueObject/ValueObject.cpp 
b/lldb/source/ValueObject/ValueObject.cpp
index e1c66763ff0b8..6f0fe9a5b83f9 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -2794,74 +2794,60 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
   if (m_deref_valobj)
     return m_deref_valobj->GetSP();
 
-  const bool is_pointer_or_reference_type = IsPointerOrReferenceType();
-  if (is_pointer_or_reference_type) {
-    bool omit_empty_base_classes = true;
-    bool ignore_array_bounds = false;
-
-    std::string child_name_str;
-    uint32_t child_byte_size = 0;
-    int32_t child_byte_offset = 0;
-    uint32_t child_bitfield_bit_size = 0;
-    uint32_t child_bitfield_bit_offset = 0;
-    bool child_is_base_class = false;
-    bool child_is_deref_of_parent = false;
-    const bool transparent_pointers = false;
-    CompilerType compiler_type = GetCompilerType();
-    uint64_t language_flags = 0;
+  std::string deref_name_str;
+  uint32_t deref_byte_size = 0;
+  int32_t deref_byte_offset = 0;
+  CompilerType compiler_type = GetCompilerType();
+  uint64_t language_flags = 0;
 
-    ExecutionContext exe_ctx(GetExecutionContextRef());
+  ExecutionContext exe_ctx(GetExecutionContextRef());
 
-    CompilerType child_compiler_type;
-    auto child_compiler_type_or_err = 
compiler_type.GetChildCompilerTypeAtIndex(
-        &exe_ctx, 0, 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,
-        child_is_deref_of_parent, this, language_flags);
-    if (!child_compiler_type_or_err)
-      LLDB_LOG_ERROR(GetLog(LLDBLog::Types),
-                     child_compiler_type_or_err.takeError(),
-                     "could not find child: {0}");
-    else
-      child_compiler_type = *child_compiler_type_or_err;
-
-    if (child_compiler_type && child_byte_size) {
-      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);
+  CompilerType deref_compiler_type;
+  auto deref_compiler_type_or_err = compiler_type.GetDereferencedType(
+      &exe_ctx, deref_name_str, deref_byte_size, deref_byte_offset, this,
+      language_flags);
+
+  std::string deref_error;
+  if (deref_compiler_type_or_err) {
+    deref_compiler_type = *deref_compiler_type_or_err;
+    if (deref_compiler_type && deref_byte_size) {
+      ConstString deref_name;
+      if (!deref_name_str.empty())
+        deref_name.SetCString(deref_name_str.c_str());
+
+      m_deref_valobj =
+          new ValueObjectChild(*this, deref_compiler_type, deref_name,
+                               deref_byte_size, deref_byte_offset, 0, 0, false,
+                               true, eAddressTypeInvalid, language_flags);
     }
 
-    // In case of incomplete child compiler type, use the pointee type and try
+    // In case of incomplete deref compiler type, use the pointee type and try
     // to recreate a new ValueObjectChild using it.
     if (!m_deref_valobj) {
       // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g.
       // `std::vector<int> &`). Remove ObjC restriction once that's resolved.
       if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) &&
           HasSyntheticValue()) {
-        child_compiler_type = compiler_type.GetPointeeType();
+        deref_compiler_type = compiler_type.GetPointeeType();
 
-        if (child_compiler_type) {
-          ConstString child_name;
-          if (!child_name_str.empty())
-            child_name.SetCString(child_name_str.c_str());
+        if (deref_compiler_type) {
+          ConstString deref_name;
+          if (!deref_name_str.empty())
+            deref_name.SetCString(deref_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);
+              *this, deref_compiler_type, deref_name, deref_byte_size,
+              deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid,
+              language_flags);
         }
       }
     }
-
-  } else if (IsSynthetic()) {
-    m_deref_valobj = GetChildMemberWithName("$$dereference$$").get();
+  } else {
+    deref_error = llvm::toString(deref_compiler_type_or_err.takeError());
+    LLDB_LOG(GetLog(LLDBLog::Types), "could not find child: {0}", deref_error);
+    if (IsSynthetic()) {
+      m_deref_valobj = GetChildMemberWithName("$$dereference$$").get();
+    }
   }
 
   if (m_deref_valobj) {
@@ -2871,13 +2857,13 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
     StreamString strm;
     GetExpressionPath(strm);
 
-    if (is_pointer_or_reference_type)
+    if (deref_error.empty())
       error = Status::FromErrorStringWithFormat(
           "dereference failed: (%s) %s",
           GetTypeName().AsCString("<invalid type>"), strm.GetData());
     else
       error = Status::FromErrorStringWithFormat(
-          "not a pointer or reference type: (%s) %s",
+          "dereference failed: %s: (%s) %s", deref_error.c_str(),
           GetTypeName().AsCString("<invalid type>"), strm.GetData());
     return ValueObjectSP();
   }

diff  --git 
a/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
index d36c5fce6d43d..6753f988c4187 100644
--- 
a/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
+++ 
b/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
@@ -33,11 +33,7 @@ def test_dereference(self):
         self.expect_var_path("*offset_pref", True, type="int *")
         self.expect_var_path("**pp_int0", value="0")
         self.expect_var_path("&**pp_int0", type="int *")
-        self.expect(
-            "frame var '*array'",
-            error=True,
-            substrs=["not a pointer or reference type"],
-        )
+        self.expect_var_path("*array", value="0")
         self.expect(
             "frame var '&*p_null'",
             error=True,

diff  --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py
index 7dc656a7ae225..99d79a9f125b1 100644
--- 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py
@@ -88,7 +88,7 @@ def cleanup():
         self.expect(
             "frame variable *number_not_engaged",
             error=True,
-            substrs=["not a pointer or reference type"],
+            substrs=["dereference failed: not a pointer, reference or array 
type"],
         )
 
     @add_test_categories(["libc++"])


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to