From 0d51e89d663bfd85f3b503452d9c6221be0f7fb7 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Thu, 31 Jul 2025 15:07:25 -0700 Subject: [PATCH 1/5] [LLDB] Update DIL handling of array subscripting. This updates the DIL code for handling array subscripting to more closely match and handle all the cases from the original 'frame var' implementation. Also updates the DIL array subscripting test. This particularly fixes some issues with handling synthetic children, objc pointers, and accessing specific bits within scalar data types. --- lldb/source/ValueObject/DILEval.cpp | 155 ++++++++++++++---- .../TestFrameVarDILArraySubscript.py | 16 +- 2 files changed, 135 insertions(+), 36 deletions(-) diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 6f28434c646cd..527fd46cab1cc 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -323,6 +323,7 @@ Interpreter::Visit(const MemberOfNode *node) { m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); } + llvm::Expected Interpreter::Visit(const ArraySubscriptNode *node) { auto lhs_or_err = Evaluate(node->GetBase()); @@ -330,40 +331,136 @@ Interpreter::Visit(const ArraySubscriptNode *node) { return lhs_or_err; lldb::ValueObjectSP base = *lhs_or_err; - // Check to see if 'base' has a synthetic value; if so, try using that. + StreamString var_expr_path_strm; uint64_t child_idx = node->GetIndex(); - if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) { - llvm::Expected num_children = - synthetic->GetNumChildren(child_idx + 1); - if (!num_children) - return llvm::make_error( - m_expr, toString(num_children.takeError()), node->GetLocation()); - if (child_idx >= *num_children) { - std::string message = llvm::formatv( - "array index {0} is not valid for \"({1}) {2}\"", child_idx, - base->GetTypeName().AsCString(""), - base->GetName().AsCString()); - return llvm::make_error(m_expr, message, + lldb::ValueObjectSP child_valobj_sp; + bool is_incomplete_array = false; + CompilerType base_type = base->GetCompilerType().GetNonReferenceType(); + base->GetExpressionPath(var_expr_path_strm); + if (base_type.IsPointerType()) { + bool is_objc_pointer = true; + if (base->GetCompilerType().GetMinimumLanguage() != lldb::eLanguageTypeObjC) + is_objc_pointer = false; + else if (!base_type.IsPointerType()) + is_objc_pointer = false; + + if (is_objc_pointer && !m_use_synthetic) { + std::string errMsg = + llvm::formatv("\"(({0}) {1}\" is an Objective-C pointer, and cannot " + "be subscripted", + base->GetTypeName().AsCString(""), + base->GetName()); + return llvm::make_error(m_expr, errMsg, + node->GetLocation()); + } else if (is_objc_pointer) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (!synthetic || synthetic == base) { + std::string errMsg = + llvm::formatv("\"({0}) {1}\" is not an array type", + base->GetTypeName().AsCString(""), + base->GetName()); + return llvm::make_error(m_expr, errMsg, + node->GetLocation()); + } else if (static_cast(child_idx) >= + synthetic->GetNumChildrenIgnoringErrors()) { + std::string errMsg = + llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", + child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + return llvm::make_error(m_expr, errMsg, + node->GetLocation()); + } else { + child_valobj_sp = synthetic->GetChildAtIndex(child_idx); + if (!child_valobj_sp) { + std::string errMsg = + llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", + child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + return llvm::make_error(m_expr, errMsg, + node->GetLocation()); + } + } + } else { // it's not an objc pointer + child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); + if (!child_valobj_sp) { + std::string errMsg = + llvm::formatv("failed to use pointer as array for index {0} for " + "\"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + if (base_type.IsPointerToVoid()) + errMsg = "subscript of pointer to incomplete type 'void'"; + return llvm::make_error(m_expr, errMsg, + node->GetLocation()); + } + } + } else if (base_type.IsArrayType( + nullptr, nullptr, &is_incomplete_array)) { + child_valobj_sp = base->GetChildAtIndex(child_idx); + if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic)) + child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); + if (!child_valobj_sp) { + std::string errMsg = + llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", + child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + return llvm::make_error(m_expr, errMsg, node->GetLocation()); } - if (lldb::ValueObjectSP child_valobj_sp = - synthetic->GetChildAtIndex(child_idx)) - return child_valobj_sp; + } else if (base_type.IsScalarType()) { + child_valobj_sp = + base->GetSyntheticBitFieldChild(child_idx, child_idx, true); + if (!child_valobj_sp) { + std::string errMsg = + llvm::formatv("bitfield range {0}-{1} is not valid for \"({2}) {3}\"", + child_idx, child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + return llvm::make_error(m_expr, errMsg, + node->GetLocation(), 1); + } + } else { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (!m_use_synthetic || !synthetic || synthetic == base) { + std::string errMsg = + llvm::formatv("\"{0}\" is not an array type", + base->GetTypeName().AsCString("")); + return llvm::make_error(m_expr, errMsg, + node->GetLocation(), 1); + } else if (static_cast(child_idx) >= + synthetic->GetNumChildrenIgnoringErrors()) { + std::string errMsg = + llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", + child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + return llvm::make_error(m_expr, errMsg, + node->GetLocation(), 1); + } else { + child_valobj_sp = synthetic->GetChildAtIndex(child_idx); + if (!child_valobj_sp) { + std::string errMsg = + llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", + child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + return llvm::make_error(m_expr, errMsg, + node->GetLocation(), 1); + } + } } - auto base_type = base->GetCompilerType().GetNonReferenceType(); - if (!base_type.IsPointerType() && !base_type.IsArrayType()) - return llvm::make_error( - m_expr, "subscripted value is not an array or pointer", - node->GetLocation()); - if (base_type.IsPointerToVoid()) - return llvm::make_error( - m_expr, "subscript of pointer to incomplete type 'void'", - node->GetLocation()); - - if (base_type.IsArrayType()) { - if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx)) - return child_valobj_sp; + if (child_valobj_sp) { + if (m_use_dynamic != lldb::eNoDynamicValues) { + lldb::ValueObjectSP dynamic_value_sp( + child_valobj_sp->GetDynamicValue(m_use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; + } + return child_valobj_sp; } int64_t signed_child_idx = node->GetIndex(); diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py index 0f56057189395..769bed2acb02c 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py @@ -69,17 +69,19 @@ def test_subscript(self): substrs=["expected 'r_square', got: <'.'"], ) - # Base should be a "pointer to T" and index should be of an integral type. - self.expect( - "frame var 'idx_1[0]'", - error=True, - substrs=["subscripted value is not an array or pointer"], - ) + + # Test accessing bits in scalar types. + self.expect_var_path("idx_1[0]", value="1") + self.expect_var_path("idx_1[1]", value="0") + + # Bit acess not valid for a reference. self.expect( "frame var 'idx_1_ref[0]'", error=True, - substrs=["subscripted value is not an array or pointer"], + substrs=["bitfield range 0-0 is not valid"], ) + + # Base should be a "pointer to T" and index should be of an integral type. self.expect( "frame var 'int_arr[int_ptr]'", error=True, From 0f706e8d85fd9868bf656b02c8f9c09da6e6f58d Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Wed, 6 Aug 2025 22:58:40 -0700 Subject: [PATCH 2/5] Address reviewer comments: - Remove code testing for objc pointers - No else-after-return - Rename errMsg err_msg - Add child_idx+1 argument to calls to GetNumChildrenIgnoringErrors - Fix typo. --- lldb/source/ValueObject/DILEval.cpp | 106 +++++------------- .../TestFrameVarDILArraySubscript.py | 2 +- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 527fd46cab1cc..d75d221cb7299 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -338,63 +338,17 @@ Interpreter::Visit(const ArraySubscriptNode *node) { CompilerType base_type = base->GetCompilerType().GetNonReferenceType(); base->GetExpressionPath(var_expr_path_strm); if (base_type.IsPointerType()) { - bool is_objc_pointer = true; - if (base->GetCompilerType().GetMinimumLanguage() != lldb::eLanguageTypeObjC) - is_objc_pointer = false; - else if (!base_type.IsPointerType()) - is_objc_pointer = false; - - if (is_objc_pointer && !m_use_synthetic) { - std::string errMsg = - llvm::formatv("\"(({0}) {1}\" is an Objective-C pointer, and cannot " - "be subscripted", + child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); + if (!child_valobj_sp) { + std::string err_msg = + llvm::formatv("failed to use pointer as array for index {0} for " + "\"({1}) {2}\"", child_idx, base->GetTypeName().AsCString(""), - base->GetName()); - return llvm::make_error(m_expr, errMsg, + var_expr_path_strm.GetData()); + if (base_type.IsPointerToVoid()) + err_msg = "subscript of pointer to incomplete type 'void'"; + return llvm::make_error(m_expr, err_msg, node->GetLocation()); - } else if (is_objc_pointer) { - lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); - if (!synthetic || synthetic == base) { - std::string errMsg = - llvm::formatv("\"({0}) {1}\" is not an array type", - base->GetTypeName().AsCString(""), - base->GetName()); - return llvm::make_error(m_expr, errMsg, - node->GetLocation()); - } else if (static_cast(child_idx) >= - synthetic->GetNumChildrenIgnoringErrors()) { - std::string errMsg = - llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", - child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, errMsg, - node->GetLocation()); - } else { - child_valobj_sp = synthetic->GetChildAtIndex(child_idx); - if (!child_valobj_sp) { - std::string errMsg = - llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", - child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, errMsg, - node->GetLocation()); - } - } - } else { // it's not an objc pointer - child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); - if (!child_valobj_sp) { - std::string errMsg = - llvm::formatv("failed to use pointer as array for index {0} for " - "\"({1}) {2}\"", child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); - if (base_type.IsPointerToVoid()) - errMsg = "subscript of pointer to incomplete type 'void'"; - return llvm::make_error(m_expr, errMsg, - node->GetLocation()); - } } } else if (base_type.IsArrayType( nullptr, nullptr, &is_incomplete_array)) { @@ -402,54 +356,54 @@ Interpreter::Visit(const ArraySubscriptNode *node) { if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic)) child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); if (!child_valobj_sp) { - std::string errMsg = + std::string err_msg = llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", child_idx, base->GetTypeName().AsCString(""), var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, errMsg, + return llvm::make_error(m_expr, err_msg, node->GetLocation()); } } else if (base_type.IsScalarType()) { child_valobj_sp = base->GetSyntheticBitFieldChild(child_idx, child_idx, true); if (!child_valobj_sp) { - std::string errMsg = + std::string err_msg = llvm::formatv("bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx, child_idx, base->GetTypeName().AsCString(""), var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, errMsg, + return llvm::make_error(m_expr, err_msg, node->GetLocation(), 1); } } else { lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); if (!m_use_synthetic || !synthetic || synthetic == base) { - std::string errMsg = + std::string err_msg = llvm::formatv("\"{0}\" is not an array type", base->GetTypeName().AsCString("")); - return llvm::make_error(m_expr, errMsg, + return llvm::make_error(m_expr, err_msg, node->GetLocation(), 1); - } else if (static_cast(child_idx) >= - synthetic->GetNumChildrenIgnoringErrors()) { - std::string errMsg = + } + if (static_cast(child_idx) >= + synthetic->GetNumChildrenIgnoringErrors(child_idx+1)) { + std::string err_msg = llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", child_idx, base->GetTypeName().AsCString(""), var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, errMsg, + return llvm::make_error(m_expr, err_msg, + node->GetLocation(), 1); + } + child_valobj_sp = synthetic->GetChildAtIndex(child_idx); + if (!child_valobj_sp) { + std::string err_msg = + llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", + child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); + return llvm::make_error(m_expr, err_msg, node->GetLocation(), 1); - } else { - child_valobj_sp = synthetic->GetChildAtIndex(child_idx); - if (!child_valobj_sp) { - std::string errMsg = - llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", - child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, errMsg, - node->GetLocation(), 1); - } } } diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py index 769bed2acb02c..1a3a52883955c 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py @@ -74,7 +74,7 @@ def test_subscript(self): self.expect_var_path("idx_1[0]", value="1") self.expect_var_path("idx_1[1]", value="0") - # Bit acess not valid for a reference. + # Bit adcess not valid for a reference. self.expect( "frame var 'idx_1_ref[0]'", error=True, From a394c684eaf5df27c90c6facd6d7e1548e32d9d2 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Wed, 6 Aug 2025 23:15:01 -0700 Subject: [PATCH 3/5] Fix clang-format issues. --- lldb/source/ValueObject/DILEval.cpp | 52 ++++++++----------- .../TestFrameVarDILArraySubscript.py | 1 - 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index d75d221cb7299..18cc1bfc6554b 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -323,7 +323,6 @@ Interpreter::Visit(const MemberOfNode *node) { m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); } - llvm::Expected Interpreter::Visit(const ArraySubscriptNode *node) { auto lhs_or_err = Evaluate(node->GetBase()); @@ -340,27 +339,25 @@ Interpreter::Visit(const ArraySubscriptNode *node) { if (base_type.IsPointerType()) { child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); if (!child_valobj_sp) { - std::string err_msg = - llvm::formatv("failed to use pointer as array for index {0} for " - "\"({1}) {2}\"", child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); + std::string err_msg = llvm::formatv( + "failed to use pointer as array for index {0} for " + "\"({1}) {2}\"", + child_idx, base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); if (base_type.IsPointerToVoid()) err_msg = "subscript of pointer to incomplete type 'void'"; return llvm::make_error(m_expr, err_msg, node->GetLocation()); } - } else if (base_type.IsArrayType( - nullptr, nullptr, &is_incomplete_array)) { + } else if (base_type.IsArrayType(nullptr, nullptr, &is_incomplete_array)) { child_valobj_sp = base->GetChildAtIndex(child_idx); if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic)) child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); if (!child_valobj_sp) { - std::string err_msg = - llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", - child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); return llvm::make_error(m_expr, err_msg, node->GetLocation()); } @@ -368,11 +365,10 @@ Interpreter::Visit(const ArraySubscriptNode *node) { child_valobj_sp = base->GetSyntheticBitFieldChild(child_idx, child_idx, true); if (!child_valobj_sp) { - std::string err_msg = - llvm::formatv("bitfield range {0}-{1} is not valid for \"({2}) {3}\"", - child_idx, child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); + std::string err_msg = llvm::formatv( + "bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx, + child_idx, base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); return llvm::make_error(m_expr, err_msg, node->GetLocation(), 1); } @@ -386,22 +382,20 @@ Interpreter::Visit(const ArraySubscriptNode *node) { node->GetLocation(), 1); } if (static_cast(child_idx) >= - synthetic->GetNumChildrenIgnoringErrors(child_idx+1)) { - std::string err_msg = - llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", - child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); + synthetic->GetNumChildrenIgnoringErrors(child_idx + 1)) { + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); return llvm::make_error(m_expr, err_msg, node->GetLocation(), 1); } child_valobj_sp = synthetic->GetChildAtIndex(child_idx); if (!child_valobj_sp) { - std::string err_msg = - llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", - child_idx, - base->GetTypeName().AsCString(""), - var_expr_path_strm.GetData()); + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString(""), + var_expr_path_strm.GetData()); return llvm::make_error(m_expr, err_msg, node->GetLocation(), 1); } diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py index 1a3a52883955c..1a59fd3bca9f2 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py @@ -69,7 +69,6 @@ def test_subscript(self): substrs=["expected 'r_square', got: <'.'"], ) - # Test accessing bits in scalar types. self.expect_var_path("idx_1[0]", value="1") self.expect_var_path("idx_1[1]", value="0") From fe70937cf480ab623b75315537c020726ae48f02 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Tue, 12 Aug 2025 21:49:28 -0700 Subject: [PATCH 4/5] Add std::move for err_msg strings and dynamic value. Add test case for GetSyntheticArrayMember. --- lldb/source/ValueObject/DILEval.cpp | 18 +++++------ .../TestFrameVarDILArraySubscript.py | 6 ++++ .../var-dil/basics/ArraySubscript/main.cpp | 9 ++++++ .../ArraySubscript/myArraySynthProvider.py | 32 +++++++++++++++++++ 4 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 18cc1bfc6554b..89a117e79da51 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -346,7 +346,7 @@ Interpreter::Visit(const ArraySubscriptNode *node) { var_expr_path_strm.GetData()); if (base_type.IsPointerToVoid()) err_msg = "subscript of pointer to incomplete type 'void'"; - return llvm::make_error(m_expr, err_msg, + return llvm::make_error(m_expr, std::move(err_msg), node->GetLocation()); } } else if (base_type.IsArrayType(nullptr, nullptr, &is_incomplete_array)) { @@ -358,7 +358,7 @@ Interpreter::Visit(const ArraySubscriptNode *node) { "array index {0} is not valid for \"({1}) {2}\"", child_idx, base->GetTypeName().AsCString(""), var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, err_msg, + return llvm::make_error(m_expr, std::move(err_msg), node->GetLocation()); } } else if (base_type.IsScalarType()) { @@ -369,7 +369,7 @@ Interpreter::Visit(const ArraySubscriptNode *node) { "bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx, child_idx, base->GetTypeName().AsCString(""), var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, err_msg, + return llvm::make_error(m_expr, std::move(err_msg), node->GetLocation(), 1); } } else { @@ -378,7 +378,7 @@ Interpreter::Visit(const ArraySubscriptNode *node) { std::string err_msg = llvm::formatv("\"{0}\" is not an array type", base->GetTypeName().AsCString("")); - return llvm::make_error(m_expr, err_msg, + return llvm::make_error(m_expr, std::move(err_msg), node->GetLocation(), 1); } if (static_cast(child_idx) >= @@ -387,7 +387,7 @@ Interpreter::Visit(const ArraySubscriptNode *node) { "array index {0} is not valid for \"({1}) {2}\"", child_idx, base->GetTypeName().AsCString(""), var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, err_msg, + return llvm::make_error(m_expr, std::move(err_msg), node->GetLocation(), 1); } child_valobj_sp = synthetic->GetChildAtIndex(child_idx); @@ -396,17 +396,15 @@ Interpreter::Visit(const ArraySubscriptNode *node) { "array index {0} is not valid for \"({1}) {2}\"", child_idx, base->GetTypeName().AsCString(""), var_expr_path_strm.GetData()); - return llvm::make_error(m_expr, err_msg, + return llvm::make_error(m_expr, std::move(err_msg), node->GetLocation(), 1); } } if (child_valobj_sp) { if (m_use_dynamic != lldb::eNoDynamicValues) { - lldb::ValueObjectSP dynamic_value_sp( - child_valobj_sp->GetDynamicValue(m_use_dynamic)); - if (dynamic_value_sp) - child_valobj_sp = dynamic_value_sp; + if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic)) + child_valobj_sp = std::move(dynamic_sp); } return child_valobj_sp; } diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py index 1a59fd3bca9f2..e3cfb878dd415 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py @@ -106,6 +106,8 @@ def test_subscript_synthetic(self): ) self.runCmd("settings set target.experimental.use-DIL true") + self.runCmd("script from myArraySynthProvider import *") + self.runCmd("type synth add -l myArraySynthProvider myArray") # Test synthetic value subscription self.expect_var_path("vector[1]", value="2") @@ -114,3 +116,7 @@ def test_subscript_synthetic(self): error=True, substrs=["array index 100 is not valid"], ) + self.expect( + "frame var 'ma_ptr[0]'", + substrs=["(myArray) ma_ptr[0] = ([0] = 7, [1] = 8, [2] = 9, [3] = 10)"], + ) diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp index a9a3612dfae5a..03ad3e872ca76 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp @@ -1,5 +1,11 @@ #include +class myArray { +public: + int m_array[4] = {7, 8, 9, 10}; + int m_arr_size = 4; +}; + int main(int argc, char **argv) { int int_arr[] = {1, 2, 3}; int *int_ptr = int_arr; @@ -29,5 +35,8 @@ int main(int argc, char **argv) { std::vector vector = {1, 2, 3}; + myArray ma; + myArray *ma_ptr = &ma; + return 0; // Set a breakpoint here } diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py new file mode 100644 index 0000000000000..be6b54a032eeb --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py @@ -0,0 +1,32 @@ +import lldb + +class myArraySynthProvider: + def __init__(self, valobj, dict): + self.valobj = valobj + + def num_children(self): + size_valobj = self.valobj.GetChildMemberWithName("m_arr_size") + if size_valobj: + return size_valobj.GetValueAsUnsigned(0) + return 0 + + def get_child_at_index(self, index): + size_valobj = self.valobj.GetChildMemberWithName("m_arr_size") + arr = self.valobj.GetChildMemberWithName("m_array") + if not size_valobj or not arr: + return None + max_idx = size_valobj.GetValueAsUnsigned(0) + if index >= max_idx: + return None + return arr.GetChildAtIndex(index) + + def get_child_index(self, name): + if name == "[0]": + return 0 + if name == "[1]": + return + if name == "[2]": + return 2 + if name == "[3]": + return 3 + return -1 From 0f8331c8de0923e7374eb038fc4200deb11fac3f Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Tue, 12 Aug 2025 21:58:37 -0700 Subject: [PATCH 5/5] Fix clang format issues. --- .../ArraySubscript/myArraySynthProvider.py | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py index be6b54a032eeb..167899bd3907c 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/myArraySynthProvider.py @@ -1,32 +1,33 @@ import lldb + class myArraySynthProvider: - def __init__(self, valobj, dict): - self.valobj = valobj + def __init__(self, valobj, dict): + self.valobj = valobj - def num_children(self): - size_valobj = self.valobj.GetChildMemberWithName("m_arr_size") - if size_valobj: - return size_valobj.GetValueAsUnsigned(0) - return 0 + def num_children(self): + size_valobj = self.valobj.GetChildMemberWithName("m_arr_size") + if size_valobj: + return size_valobj.GetValueAsUnsigned(0) + return 0 - def get_child_at_index(self, index): - size_valobj = self.valobj.GetChildMemberWithName("m_arr_size") - arr = self.valobj.GetChildMemberWithName("m_array") - if not size_valobj or not arr: - return None - max_idx = size_valobj.GetValueAsUnsigned(0) - if index >= max_idx: - return None - return arr.GetChildAtIndex(index) + def get_child_at_index(self, index): + size_valobj = self.valobj.GetChildMemberWithName("m_arr_size") + arr = self.valobj.GetChildMemberWithName("m_array") + if not size_valobj or not arr: + return None + max_idx = size_valobj.GetValueAsUnsigned(0) + if index >= max_idx: + return None + return arr.GetChildAtIndex(index) - def get_child_index(self, name): - if name == "[0]": - return 0 - if name == "[1]": - return - if name == "[2]": - return 2 - if name == "[3]": - return 3 - return -1 + def get_child_index(self, name): + if name == "[0]": + return 0 + if name == "[1]": + return + if name == "[2]": + return 2 + if name == "[3]": + return 3 + return -1