diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 75d20a4378f09..0f788ff602b70 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -160,31 +160,26 @@ class LLDB_API SBValue { /// members (empty base classes are omitted), and all members of the /// current class will then follow the base classes. /// - /// Pointers differ depending on what they point to. If the pointer - /// points to a simple type, the child at index zero - /// is the only child value available, unless \a synthetic_allowed - /// is \b true, in which case the pointer will be used as an array - /// and can create 'synthetic' child values using positive or - /// negative indexes. If the pointer points to an aggregate type - /// (an array, class, union, struct), then the pointee is - /// transparently skipped and any children are going to be the indexes - /// of the child values within the aggregate type. For example if - /// we have a 'Point' type and we have a SBValue that contains a - /// pointer to a 'Point' type, then the child at index zero will be - /// the 'x' member, and the child at index 1 will be the 'y' member - /// (the child at index zero won't be a 'Point' instance). + /// For array and pointers the behavior of the function depends on the value + /// of the \a treat_as_array argument. If \b false, the function returns + /// members of the array as given by the array bounds. If the value is a + /// pointer to a simple type, the child at index zero is the only child + /// value available. If the pointer points to an aggregate type (an array, + /// class, union, etc.), then the pointee is transparently skipped and any + /// children are going to be the indexes of the child values within the + /// aggregate type. For example if we have a 'Point' type and we have a + /// SBValue that contains a pointer to a 'Point' type, then the child at + /// index zero will be the 'x' member, and the child at index 1 will be the + /// 'y' member (the child at index zero won't be a 'Point' instance). If \a + /// treat_as_array is \b true, pointer values will be used as a (C) array and + /// and the function will create 'synthetic' child values using positive or + /// negative indexes. In case of arrays, the function will return values + /// which are outside of the array bounds. /// /// If you actually need an SBValue that represents the type pointed /// to by a SBValue for which GetType().IsPointeeType() returns true, /// regardless of the pointee type, you can do that with SBValue::Dereference. /// - /// Arrays have a preset number of children that can be accessed by - /// index and will returns invalid child values for indexes that are - /// out of bounds unless the \a synthetic_allowed is \b true. In this - /// case the array can create 'synthetic' child values for indexes - /// that aren't in the array bounds using positive or negative - /// indexes. - /// /// \param[in] idx /// The index of the child value to get /// @@ -193,7 +188,7 @@ class LLDB_API SBValue { /// and also if the target can be run to figure out the dynamic /// type of the child value. /// - /// \param[in] can_create_synthetic + /// \param[in] treat_as_array /// If \b true, then allow child values to be created by index /// for pointers and arrays for indexes that normally wouldn't /// be allowed. @@ -202,7 +197,7 @@ class LLDB_API SBValue { /// A new SBValue object that represents the child member value. lldb::SBValue GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic); + bool treat_as_array); // Matches children of this object only and will match base classes and // member names if this is a clang typed object. diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index e5cdc8f311450..88c86a5482910 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -666,7 +666,6 @@ lldb::SBValue SBValue::CreateBoolValue(const char *name, bool value) { SBValue SBValue::GetChildAtIndex(uint32_t idx) { LLDB_INSTRUMENT_VA(this, idx); - const bool can_create_synthetic = false; lldb::DynamicValueType use_dynamic = eNoDynamicValues; TargetSP target_sp; if (m_opaque_sp) @@ -675,24 +674,24 @@ SBValue SBValue::GetChildAtIndex(uint32_t idx) { if (target_sp) use_dynamic = target_sp->GetPreferDynamicValue(); - return GetChildAtIndex(idx, use_dynamic, can_create_synthetic); + return GetChildAtIndex(idx, use_dynamic, /*treat_as_array=*/false); } SBValue SBValue::GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic) { - LLDB_INSTRUMENT_VA(this, idx, use_dynamic, can_create_synthetic); - - lldb::ValueObjectSP child_sp; - + bool treat_as_array) { + LLDB_INSTRUMENT_VA(this, idx, use_dynamic, treat_as_array); ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); + + lldb::ValueObjectSP child_sp; if (value_sp) { const bool can_create = true; - child_sp = value_sp->GetChildAtIndex(idx); - if (can_create_synthetic && !child_sp) { + if (treat_as_array && + (value_sp->IsPointerType() || value_sp->IsArrayType())) child_sp = value_sp->GetSyntheticArrayMember(idx, can_create); - } + else + child_sp = value_sp->GetChildAtIndex(idx); } SBValue sb_value; diff --git a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py index 2fd1e0ce9c6a3..8b36308de63da 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py +++ b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py @@ -21,3 +21,31 @@ def test_str(self): has_formatted = self.frame().FindVariable("has_foo") self.expect(str(formatted), exe=False, substrs=["synth_child"]) self.expect(str(has_formatted), exe=False, substrs=["synth_child"]) + + def test_synth_arr(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.cpp") + ) + point_arr = self.frame().FindVariable("point_arr") + point_ptr = self.frame().FindVariable("point_ptr") + for v in [point_arr, point_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck( + name=f"[{i}]", + type="Point", + children=[ + ValueCheck(name="x", value=str(2 * i + 1)), + ValueCheck(name="y", value=str(2 * i + 2)), + ], + ) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") + + int_arr = self.frame().FindVariable("int_arr") + int_ptr = self.frame().FindVariable("int_ptr") + for v in [int_arr, int_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck(name=f"[{i}]", type="int", value=str(i + 1)) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") diff --git a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp index 52c6474d7a1b2..d9b65f017a30a 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp +++ b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp @@ -6,8 +6,17 @@ struct HasFoo { Foo f; }; +struct Point { + int x; + int y; +}; + int main() { Foo foo; HasFoo has_foo; + Point point_arr[] = {{1, 2}, {3, 4}, {5, 6}}; + int int_arr[] = {1, 2, 3, 4, 5, 6}; + Point *point_ptr = point_arr; + int *int_ptr = int_arr; return 0; // break here }