Skip to content

Commit 3aacd74

Browse files
authored
[lldb][TypeSystemClang] Allow arrays to be dereferenced in C/C++. (#135843)
Add a function `GetDereferencedType` to `CompilerType` and allow `TypeSystemClang` to dereference arrays.
1 parent f1043b1 commit 3aacd74

File tree

8 files changed

+89
-60
lines changed

8 files changed

+89
-60
lines changed

lldb/include/lldb/Symbol/CompilerType.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,11 @@ class CompilerType {
433433

434434
CompilerDecl GetStaticFieldWithName(llvm::StringRef name) const;
435435

436+
llvm::Expected<CompilerType>
437+
GetDereferencedType(ExecutionContext *exe_ctx, std::string &deref_name,
438+
uint32_t &deref_byte_size, int32_t &deref_byte_offset,
439+
ValueObject *valobj, uint64_t &language_flags) const;
440+
436441
llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex(
437442
ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers,
438443
bool omit_empty_base_classes, bool ignore_array_bounds,

lldb/include/lldb/Symbol/TypeSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,12 @@ class TypeSystem : public PluginInterface,
364364
return CompilerDecl();
365365
}
366366

367+
virtual llvm::Expected<CompilerType>
368+
GetDereferencedType(lldb::opaque_compiler_type_t type,
369+
ExecutionContext *exe_ctx, std::string &deref_name,
370+
uint32_t &deref_byte_size, int32_t &deref_byte_offset,
371+
ValueObject *valobj, uint64_t &language_flags) = 0;
372+
367373
virtual llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex(
368374
lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
369375
bool transparent_pointers, bool omit_empty_base_classes,

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6184,6 +6184,24 @@ uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) {
61846184
return 0;
61856185
}
61866186

6187+
llvm::Expected<CompilerType> TypeSystemClang::GetDereferencedType(
6188+
lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
6189+
std::string &deref_name, uint32_t &deref_byte_size,
6190+
int32_t &deref_byte_offset, ValueObject *valobj, uint64_t &language_flags) {
6191+
bool type_valid = IsPointerOrReferenceType(type, nullptr) ||
6192+
IsArrayType(type, nullptr, nullptr, nullptr);
6193+
if (!type_valid)
6194+
return llvm::createStringError("not a pointer, reference or array type");
6195+
uint32_t child_bitfield_bit_size = 0;
6196+
uint32_t child_bitfield_bit_offset = 0;
6197+
bool child_is_base_class;
6198+
bool child_is_deref_of_parent;
6199+
return GetChildCompilerTypeAtIndex(
6200+
type, exe_ctx, 0, false, true, false, deref_name, deref_byte_size,
6201+
deref_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset,
6202+
child_is_base_class, child_is_deref_of_parent, valobj, language_flags);
6203+
}
6204+
61876205
llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
61886206
lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
61896207
bool transparent_pointers, bool omit_empty_base_classes,

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,12 @@ class TypeSystemClang : public TypeSystem {
889889

890890
static uint32_t GetNumPointeeChildren(clang::QualType type);
891891

892+
llvm::Expected<CompilerType>
893+
GetDereferencedType(lldb::opaque_compiler_type_t type,
894+
ExecutionContext *exe_ctx, std::string &deref_name,
895+
uint32_t &deref_byte_size, int32_t &deref_byte_offset,
896+
ValueObject *valobj, uint64_t &language_flags) override;
897+
892898
llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex(
893899
lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
894900
bool transparent_pointers, bool omit_empty_base_classes,

lldb/source/Symbol/CompilerType.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,18 @@ CompilerDecl CompilerType::GetStaticFieldWithName(llvm::StringRef name) const {
893893
return CompilerDecl();
894894
}
895895

896+
llvm::Expected<CompilerType> CompilerType::GetDereferencedType(
897+
ExecutionContext *exe_ctx, std::string &deref_name,
898+
uint32_t &deref_byte_size, int32_t &deref_byte_offset, ValueObject *valobj,
899+
uint64_t &language_flags) const {
900+
if (IsValid())
901+
if (auto type_system_sp = GetTypeSystem())
902+
return type_system_sp->GetDereferencedType(
903+
m_type, exe_ctx, deref_name, deref_byte_size, deref_byte_offset,
904+
valobj, language_flags);
905+
return CompilerType();
906+
}
907+
896908
llvm::Expected<CompilerType> CompilerType::GetChildCompilerTypeAtIndex(
897909
ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers,
898910
bool omit_empty_base_classes, bool ignore_array_bounds,

lldb/source/ValueObject/ValueObject.cpp

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,74 +2794,60 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
27942794
if (m_deref_valobj)
27952795
return m_deref_valobj->GetSP();
27962796

2797-
const bool is_pointer_or_reference_type = IsPointerOrReferenceType();
2798-
if (is_pointer_or_reference_type) {
2799-
bool omit_empty_base_classes = true;
2800-
bool ignore_array_bounds = false;
2801-
2802-
std::string child_name_str;
2803-
uint32_t child_byte_size = 0;
2804-
int32_t child_byte_offset = 0;
2805-
uint32_t child_bitfield_bit_size = 0;
2806-
uint32_t child_bitfield_bit_offset = 0;
2807-
bool child_is_base_class = false;
2808-
bool child_is_deref_of_parent = false;
2809-
const bool transparent_pointers = false;
2810-
CompilerType compiler_type = GetCompilerType();
2811-
uint64_t language_flags = 0;
2797+
std::string deref_name_str;
2798+
uint32_t deref_byte_size = 0;
2799+
int32_t deref_byte_offset = 0;
2800+
CompilerType compiler_type = GetCompilerType();
2801+
uint64_t language_flags = 0;
28122802

2813-
ExecutionContext exe_ctx(GetExecutionContextRef());
2803+
ExecutionContext exe_ctx(GetExecutionContextRef());
28142804

2815-
CompilerType child_compiler_type;
2816-
auto child_compiler_type_or_err = compiler_type.GetChildCompilerTypeAtIndex(
2817-
&exe_ctx, 0, transparent_pointers, omit_empty_base_classes,
2818-
ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset,
2819-
child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class,
2820-
child_is_deref_of_parent, this, language_flags);
2821-
if (!child_compiler_type_or_err)
2822-
LLDB_LOG_ERROR(GetLog(LLDBLog::Types),
2823-
child_compiler_type_or_err.takeError(),
2824-
"could not find child: {0}");
2825-
else
2826-
child_compiler_type = *child_compiler_type_or_err;
2827-
2828-
if (child_compiler_type && child_byte_size) {
2829-
ConstString child_name;
2830-
if (!child_name_str.empty())
2831-
child_name.SetCString(child_name_str.c_str());
2832-
2833-
m_deref_valobj = new ValueObjectChild(
2834-
*this, child_compiler_type, child_name, child_byte_size,
2835-
child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset,
2836-
child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid,
2837-
language_flags);
2805+
CompilerType deref_compiler_type;
2806+
auto deref_compiler_type_or_err = compiler_type.GetDereferencedType(
2807+
&exe_ctx, deref_name_str, deref_byte_size, deref_byte_offset, this,
2808+
language_flags);
2809+
2810+
std::string deref_error;
2811+
if (deref_compiler_type_or_err) {
2812+
deref_compiler_type = *deref_compiler_type_or_err;
2813+
if (deref_compiler_type && deref_byte_size) {
2814+
ConstString deref_name;
2815+
if (!deref_name_str.empty())
2816+
deref_name.SetCString(deref_name_str.c_str());
2817+
2818+
m_deref_valobj =
2819+
new ValueObjectChild(*this, deref_compiler_type, deref_name,
2820+
deref_byte_size, deref_byte_offset, 0, 0, false,
2821+
true, eAddressTypeInvalid, language_flags);
28382822
}
28392823

2840-
// In case of incomplete child compiler type, use the pointee type and try
2824+
// In case of incomplete deref compiler type, use the pointee type and try
28412825
// to recreate a new ValueObjectChild using it.
28422826
if (!m_deref_valobj) {
28432827
// FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g.
28442828
// `std::vector<int> &`). Remove ObjC restriction once that's resolved.
28452829
if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) &&
28462830
HasSyntheticValue()) {
2847-
child_compiler_type = compiler_type.GetPointeeType();
2831+
deref_compiler_type = compiler_type.GetPointeeType();
28482832

2849-
if (child_compiler_type) {
2850-
ConstString child_name;
2851-
if (!child_name_str.empty())
2852-
child_name.SetCString(child_name_str.c_str());
2833+
if (deref_compiler_type) {
2834+
ConstString deref_name;
2835+
if (!deref_name_str.empty())
2836+
deref_name.SetCString(deref_name_str.c_str());
28532837

28542838
m_deref_valobj = new ValueObjectChild(
2855-
*this, child_compiler_type, child_name, child_byte_size,
2856-
child_byte_offset, child_bitfield_bit_size,
2857-
child_bitfield_bit_offset, child_is_base_class,
2858-
child_is_deref_of_parent, eAddressTypeInvalid, language_flags);
2839+
*this, deref_compiler_type, deref_name, deref_byte_size,
2840+
deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid,
2841+
language_flags);
28592842
}
28602843
}
28612844
}
2862-
2863-
} else if (IsSynthetic()) {
2864-
m_deref_valobj = GetChildMemberWithName("$$dereference$$").get();
2845+
} else {
2846+
deref_error = llvm::toString(deref_compiler_type_or_err.takeError());
2847+
LLDB_LOG(GetLog(LLDBLog::Types), "could not find child: {0}", deref_error);
2848+
if (IsSynthetic()) {
2849+
m_deref_valobj = GetChildMemberWithName("$$dereference$$").get();
2850+
}
28652851
}
28662852

28672853
if (m_deref_valobj) {
@@ -2871,13 +2857,13 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
28712857
StreamString strm;
28722858
GetExpressionPath(strm);
28732859

2874-
if (is_pointer_or_reference_type)
2860+
if (deref_error.empty())
28752861
error = Status::FromErrorStringWithFormat(
28762862
"dereference failed: (%s) %s",
28772863
GetTypeName().AsCString("<invalid type>"), strm.GetData());
28782864
else
28792865
error = Status::FromErrorStringWithFormat(
2880-
"not a pointer or reference type: (%s) %s",
2866+
"dereference failed: %s: (%s) %s", deref_error.c_str(),
28812867
GetTypeName().AsCString("<invalid type>"), strm.GetData());
28822868
return ValueObjectSP();
28832869
}

lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@ def test_dereference(self):
3333
self.expect_var_path("*offset_pref", True, type="int *")
3434
self.expect_var_path("**pp_int0", value="0")
3535
self.expect_var_path("&**pp_int0", type="int *")
36-
self.expect(
37-
"frame var '*array'",
38-
error=True,
39-
substrs=["not a pointer or reference type"],
40-
)
36+
self.expect_var_path("*array", value="0")
4137
self.expect(
4238
"frame var '&*p_null'",
4339
error=True,

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def cleanup():
8888
self.expect(
8989
"frame variable *number_not_engaged",
9090
error=True,
91-
substrs=["not a pointer or reference type"],
91+
substrs=["dereference failed: not a pointer, reference or array type"],
9292
)
9393

9494
@add_test_categories(["libc++"])

0 commit comments

Comments
 (0)