Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

kuilpd
Copy link
Contributor

@kuilpd kuilpd commented Apr 15, 2025

Add a function IsValidDereferenceType to TypeSystem.
TypeSystemClang now allows arrays to be dereferenced.

@kuilpd kuilpd requested review from labath and jimingham April 15, 2025 19:48
@kuilpd
Copy link
Contributor Author

kuilpd commented Apr 15, 2025

@labath @jimingham
This is just one way to allow C/C++ to dereference arrays and let other languages decide on which types they allow to dereference.
I tried making a GetDereferencedType function in TypeSystem, but it doesn't really need to do anything right now, everything is handled in GetChildCompilerTypeAtIndex anyway.
Also, you raised a problem that if a user has defined a synthetic child provider for the array type, then after converting array to a pointer that provider will not be used. Allowing the array to be dereferenced will do the same because of where the check for a synthetic child is in ValueObject::Dereference. I'm really not sure how to avoid that.

@labath
Copy link
Collaborator

labath commented Apr 23, 2025

@labath @jimingham This is just one way to allow C/C++ to dereference arrays and let other languages decide on which types they allow to dereference. I tried making a GetDereferencedType function in TypeSystem, but it doesn't really need to do anything right now, everything is handled in GetChildCompilerTypeAtIndex anyway.

I think something like GetDereferencedType would still look better. Maybe the clang implementation of that function could internally defer to GetChildCompilerTypeAtIndex ?

Also, you raised a problem that if a user has defined a synthetic child provider for the array type, then after converting array to a pointer that provider will not be used. Allowing the array to be dereferenced will do the same because of where the check for a synthetic child is in ValueObject::Dereference. I'm really not sure how to avoid that.

I'm not worried about that with a patch like this since the problem remains contained within ValueObject::Dereference, and you're not changing the existing logic. If we wanted to implement something like this, I suspect we would want to first check with the synthetic child provider to see if it provides a dereference operation, and only then fall back to the "normal" type system logic. But that's yet another patch.

@kuilpd
Copy link
Contributor Author

kuilpd commented Apr 23, 2025

I think something like GetDereferencedType would still look better. Maybe the clang implementation of that function could internally defer to GetChildCompilerTypeAtIndex ?

The problem I encountered is that Dereference has 2 separate checks: the first one checks if the type is a pointer or a reference, the second is done if the first one succeeds and checks if a child with a type is actually found by GetChildCompilerTypeAtIndex. By putting the first type check inside the GetDereferencedType that replaces GetChildCompilerTypeAtIndex there is no good way to tell just from the returned value whether it's the type check that failed or the type search. I added a separate argument that returns the type validity to be able to check it separately.

I'm not worried about that with a patch like this since the problem remains contained within ValueObject::Dereference, and you're not changing the existing logic. If we wanted to implement something like this, I suspect we would want to first check with the synthetic child provider to see if it provides a dereference operation, and only then fall back to the "normal" type system logic. But that's yet another patch.

I think the change in logic is allowing an array type pass the type check and calling GetChildCompilerTypeAtIndex instead of checking for $$dereference$$ synthetic value for the array type.

@labath
Copy link
Collaborator

labath commented Apr 24, 2025

The problem I encountered is that Dereference has 2 separate checks: the first one checks if the type is a pointer or a reference, the second is done if the first one succeeds and checks if a child with a type is actually found by GetChildCompilerTypeAtIndex

Why does it need to do that? Is it so to control which error message gets printed? If so, I think we could tweak that text so that we don't need that. The string "not a pointer or reference type" is not correct anymore anyway since we don't know what is the criteria that a type system will use to determine if something is dereferencable. Maybe the type system should return an llvm::Error/Expected, and then caller figures out how (and whether) to print that?

Also, could we reduce the number of arguments to that function? I'd hope that we don't need all of them since this is a very specific operation. E.g, I think the caller should be able to assume that the returned object is a "dereference" (whatever that means) of the parent instead of passing that via child_is_deref_of_parent.

I think the change in logic is allowing an array type pass the type check and calling GetChildCompilerTypeAtIndex instead of checking for $$dereference$$ synthetic value for the array type.

I see. I'm still not worried about that because it means the array gets the same treatment as pointers. I think it's reasonable (though probably not very useful) that if a user registers a data formatter for Foo*, they should be able to provide a custom dereference operation that's different than "dereferencing the pointer". It doesn't work now, but if we ever wanted to make that possible, I don't think we'd need to (or should) treat pointers and arrays differently.

@kuilpd
Copy link
Contributor Author

kuilpd commented Apr 24, 2025

Why does it need to do that? Is it so to control which error message gets printed? If so, I think we could tweak that text so that we don't need that. The string "not a pointer or reference type" is not correct anymore anyway since we don't know what is the criteria that a type system will use to determine if something is dereferencable. Maybe the type system should return an llvm::Error/Expected, and then caller figures out how (and whether) to print that?

From what I could understand, if we try to find a $$dereference$$ when GetDereferencedType fails for any reason, it ends up calling ValueObject::Dereference again and goes into infinite recursion. It needs to attempt dereferencing on valid types and not try to find $$dereference$$ when dereferencing fails. I'm not sure exactly what the cases are, but some tests fail this way with this logic, for example TestStlIncompleteTypes. Synthetic values just have to be checked only on invalid types.

GetChildCompilerTypeAtIndex can also return a StringError, so we can't rely on that either. I'd rather not check the exact string error message, better to have a separate flag.

@kuilpd kuilpd force-pushed the lldb-dereference-in-typesystem branch from e5d6984 to 0d5348a Compare April 24, 2025 16:50
@kuilpd kuilpd marked this pull request as ready for review April 24, 2025 16:50
@kuilpd kuilpd requested a review from JDevlieghere as a code owner April 24, 2025 16:50
@llvmbot llvmbot added the lldb label Apr 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 24, 2025

@llvm/pr-subscribers-lldb

Author: Ilia Kuklin (kuilpd)

Changes

Add a function IsValidDereferenceType to TypeSystem.
TypeSystemClang now allows arrays to be dereferenced.


Full diff: https://github.com/llvm/llvm-project/pull/135843.diff

7 Files Affected:

  • (modified) lldb/include/lldb/Symbol/CompilerType.h (+8)
  • (modified) lldb/include/lldb/Symbol/TypeSystem.h (+7)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+17)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+7)
  • (modified) lldb/source/Symbol/CompilerType.cpp (+15)
  • (modified) lldb/source/ValueObject/ValueObject.cpp (+31-33)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py (+1-1)
diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index 671b5314c24a2..f02a415afd12c 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -433,6 +433,14 @@ class CompilerType {
 
   CompilerDecl GetStaticFieldWithName(llvm::StringRef name) const;
 
+  llvm::Expected<CompilerType>
+  GetDereferencedType(ExecutionContext *exe_ctx, std::string &child_name,
+                      uint32_t &child_byte_size, int32_t &child_byte_offset,
+                      uint32_t &child_bitfield_bit_size,
+                      uint32_t &child_bitfield_bit_offset,
+                      bool &child_is_base_class, ValueObject *valobj,
+                      uint64_t &language_flags, bool &type_valid) 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 9e9edc09a0846..7c58805342993 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -364,6 +364,13 @@ class TypeSystem : public PluginInterface,
     return CompilerDecl();
   }
 
+  virtual llvm::Expected<CompilerType> GetDereferencedType(
+      lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
+      std::string &child_name, uint32_t &child_byte_size,
+      int32_t &child_byte_offset, uint32_t &child_bitfield_bit_size,
+      uint32_t &child_bitfield_bit_offset, bool &child_is_base_class,
+      ValueObject *valobj, uint64_t &language_flags, bool &type_valid) = 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 59292f4b24af3..5c1b98509892e 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -6201,6 +6201,23 @@ 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 &child_name, uint32_t &child_byte_size,
+    int32_t &child_byte_offset, uint32_t &child_bitfield_bit_size,
+    uint32_t &child_bitfield_bit_offset, bool &child_is_base_class,
+    ValueObject *valobj, uint64_t &language_flags, bool &type_valid) {
+  type_valid = IsPointerOrReferenceType(type, nullptr) ||
+               IsArrayType(type, nullptr, nullptr, nullptr);
+  if (!type_valid)
+    return llvm::createStringError("not a pointer, reference or array type");
+  bool child_is_deref_of_parent;
+  return GetChildCompilerTypeAtIndex(
+      type, exe_ctx, 0, false, true, false, 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, 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 442f88a5b79ae..ab74027cc75c4 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -889,6 +889,13 @@ 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 &child_name, uint32_t &child_byte_size,
+      int32_t &child_byte_offset, uint32_t &child_bitfield_bit_size,
+      uint32_t &child_bitfield_bit_offset, bool &child_is_base_class,
+      ValueObject *valobj, uint64_t &language_flags, bool &type_valid) 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 8e89d006d08d3..998822708fe21 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -893,6 +893,21 @@ CompilerDecl CompilerType::GetStaticFieldWithName(llvm::StringRef name) const {
   return CompilerDecl();
 }
 
+llvm::Expected<CompilerType> CompilerType::GetDereferencedType(
+    ExecutionContext *exe_ctx, std::string &child_name,
+    uint32_t &child_byte_size, int32_t &child_byte_offset,
+    uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
+    bool &child_is_base_class, ValueObject *valobj, uint64_t &language_flags,
+    bool &type_valid) const {
+  if (IsValid())
+    if (auto type_system_sp = GetTypeSystem())
+      return type_system_sp->GetDereferencedType(
+          m_type, exe_ctx, child_name, child_byte_size, child_byte_offset,
+          child_bitfield_bit_size, child_bitfield_bit_offset,
+          child_is_base_class, valobj, language_flags, type_valid);
+  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 8741cb7343166..b023dbf118d78 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -2850,37 +2850,37 @@ 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 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;
+  CompilerType compiler_type = GetCompilerType();
+  uint64_t language_flags = 0;
+  bool is_valid_dereference_type = false;
 
-    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)
+  CompilerType child_compiler_type;
+  auto child_compiler_type_or_err = compiler_type.GetDereferencedType(
+      &exe_ctx, child_name_str, child_byte_size, child_byte_offset,
+      child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class,
+      this, language_flags, is_valid_dereference_type);
+
+  std::string deref_error;
+  if (!child_compiler_type_or_err) {
+    auto err = child_compiler_type_or_err.takeError();
+    if (err.isA<llvm::StringError>()) {
+      deref_error = llvm::toString(std::move(err));
       LLDB_LOG_ERROR(GetLog(LLDBLog::Types),
-                     child_compiler_type_or_err.takeError(),
+                     llvm::createStringError(deref_error),
                      "could not find child: {0}");
-    else
-      child_compiler_type = *child_compiler_type_or_err;
+    }
+  } else
+    child_compiler_type = *child_compiler_type_or_err;
 
+  if (is_valid_dereference_type) {
     if (child_compiler_type && child_byte_size) {
       ConstString child_name;
       if (!child_name_str.empty())
@@ -2889,8 +2889,7 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
       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);
+          child_is_base_class, true, eAddressTypeInvalid, language_flags);
     }
 
     // In case of incomplete child compiler type, use the pointee type and try
@@ -2910,12 +2909,11 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
           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);
+              child_bitfield_bit_offset, child_is_base_class, true,
+              eAddressTypeInvalid, language_flags);
         }
       }
     }
-
   } else if (HasSyntheticValue()) {
     m_deref_valobj =
         GetSyntheticValue()->GetChildMemberWithName("$$dereference$$").get();
@@ -2930,13 +2928,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/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..8f36edea7d727 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"],
         )
 
     @add_test_categories(["libc++"])

@labath
Copy link
Collaborator

labath commented Apr 25, 2025

Why does it need to do that? Is it so to control which error message gets printed? If so, I think we could tweak that text so that we don't need that. The string "not a pointer or reference type" is not correct anymore anyway since we don't know what is the criteria that a type system will use to determine if something is dereferencable. Maybe the type system should return an llvm::Error/Expected, and then caller figures out how (and whether) to print that?

From what I could understand, if we try to find a $$dereference$$ when GetDereferencedType fails for any reason, it ends up calling ValueObject::Dereference again and goes into infinite recursion. It needs to attempt dereferencing on valid types and not try to find $$dereference$$ when dereferencing fails. I'm not sure exactly what the cases are, but some tests fail this way with this logic, for example TestStlIncompleteTypes. Synthetic values just have to be checked only on invalid types.

Thank you for looking into this. I can see how something like this might happen, but that's not the conclusion I would draw from this, at least not without more data. I think we need to know how exactly is that recursion happening (e.g., the call stack). Since there is python code involved, it could be there's a bug there. The data formatters we write for tests aren't exactly battle-tested, and it's certainly possible to cause an infinite recursion with a bad data formatter.

It's also possible that the implementation of Dereference is just too persistent. I think it's doing too much. I've created #137311 which I think is a better way to approach dereferencing (BTW, I think you'll need to do something similar in the new frame var implementation). You could try whether patching that in causes the recursion to go away.

(Also, to avoid any confusion, I want to add that I don't consider this to be a requirement for merging #134428. I'm just waiting on that PR as you haven't responded to all of my comments.)

@kuilpd
Copy link
Contributor Author

kuilpd commented Apr 25, 2025

It's also possible that the implementation of Dereference is just too persistent. I think it's doing too much. I've created #137311 which I think is a better way to approach dereferencing (BTW, I think you'll need to do something similar in the new frame var implementation). You could try whether patching that in causes the recursion to go away.

This seems to fix the issue, I was able to remove the type check and rely just on the success of GetDereferencedType.
I will wait until you merge that patch before updating and applying this one.

@kuilpd kuilpd force-pushed the lldb-dereference-in-typesystem branch from 0d5348a to a0ebf36 Compare April 30, 2025 16:14
Comment on lines 2800 to 2802
uint32_t child_bitfield_bit_size = 0;
uint32_t child_bitfield_bit_offset = 0;
bool child_is_base_class = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think child_is_base_class should go away as well, and maybe the bitfield fields as well (in principle I can imagine a pointer to a bitfield, but I don't think any current language has those).

@@ -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"],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the full error message here? Would be nice to check that it's reasonable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a thought that a message might be different since it comes from TypeSystem, but now I realize it's C++ test and we know exactly which type system.

Comment on lines 2851 to 2857
auto err = child_compiler_type_or_err.takeError();
if (err.isA<llvm::StringError>()) {
deref_error = llvm::toString(std::move(err));
LLDB_LOG_ERROR(GetLog(LLDBLog::Types),
llvm::createStringError(deref_error),
"could not find child: {0}");
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any error can be converted to a string.

Suggested change
auto err = child_compiler_type_or_err.takeError();
if (err.isA<llvm::StringError>()) {
deref_error = llvm::toString(std::move(err));
LLDB_LOG_ERROR(GetLog(LLDBLog::Types),
llvm::createStringError(deref_error),
"could not find child: {0}");
}
deref_error = llvm::toString(child_compiler_type_or_err.takeError());
LLDB_LOG(GetLog(LLDBLog::Types),
"could not find child: {0}", deref_error);

Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I think this is fine now. @jimingham, @adrian-prantl, do you have anything to add.

Heads-up: I believe you will need to implement this method in the Swift type system in order to keep dereferencing working.

CompilerType compiler_type = GetCompilerType();
uint64_t language_flags = 0;
std::string child_name_str;
uint32_t child_byte_size = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a tiny nit, but I find this flow harder to read because I don't understand why you use both "child" and "deref" as prefixes related to the defererenced object. I had to think a bit to realize that this distinction was without difference...

It is true that in strict lldb terms, the deference valobj is a child of the valobj it is the dereference of, but that's the least interesting aspect of it here.

For instance, it's odd that child_name_str is the name that you are going to give to m_deref_valobj, or when you assign deref_error from child_type_or_err.

@jimingham
Copy link
Collaborator

This looks fine to me as well. I had a small typographical nit which you can act on or not as you feel moved to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants