Index: include/lldb/API/SBValue.h =================================================================== --- include/lldb/API/SBValue.h +++ include/lldb/API/SBValue.h @@ -235,6 +235,13 @@ lldb::DynamicValueType use_dynamic, bool can_create_synthetic); + /// The return value is a tri-state value. If it is positive, then it means that there + /// is indeed a child at index idx. If it is 0, then it means that there is no child + /// at that index. If it is negative, then it means that it (whether a child exists or not + /// at that said index) could not be evaluated properly. + int32_t + HasChildAtIndex (uint32_t idx); + // Matches children of this object only and will match base classes and // member names if this is a clang typed object. uint32_t Index: include/lldb/Core/ValueObject.h =================================================================== --- include/lldb/Core/ValueObject.h +++ include/lldb/Core/ValueObject.h @@ -554,6 +554,13 @@ virtual lldb::ValueObjectSP GetChildAtIndex (size_t idx, bool can_create); + // The return value is a tri-state value. If it is positive, then it means that there + // is indeed a child at index idx. If it is 0, then it means that there is no child + // at that index. If it is negative, then it means that it (whether a child exists or not + // at that said index) could not be evaluated properly. + virtual int + HasChildAtIndex (size_t idx); + // this will always create the children if necessary lldb::ValueObjectSP GetChildAtIndexPath (const std::initializer_list &idxs, Index: include/lldb/Core/ValueObjectSyntheticFilter.h =================================================================== --- include/lldb/Core/ValueObjectSyntheticFilter.h +++ include/lldb/Core/ValueObjectSyntheticFilter.h @@ -56,6 +56,9 @@ virtual lldb::ValueObjectSP GetChildAtIndex (size_t idx, bool can_create); + + virtual int + HasChildAtIndex (size_t idx); virtual lldb::ValueObjectSP GetChildMemberWithName (const ConstString &name, bool can_create); Index: include/lldb/DataFormatters/TypeSynthetic.h =================================================================== --- include/lldb/DataFormatters/TypeSynthetic.h +++ include/lldb/DataFormatters/TypeSynthetic.h @@ -62,6 +62,12 @@ virtual lldb::ValueObjectSP GetChildAtIndex (size_t idx) = 0; + + virtual int + HasChildAtIndex (size_t idx) + { + return -1; + } virtual size_t GetIndexOfChildWithName (const ConstString &name) = 0; @@ -129,6 +135,9 @@ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; } + int + HasChildAtIndex(size_t idx) override { return 0; } + size_t GetIndexOfChildWithName(const ConstString &name) override { return UINT32_MAX; } @@ -454,6 +463,15 @@ return lldb::ValueObjectSP(); return m_backend.GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx), true); } + + int + HasChildAtIndex(size_t idx) override + { + if (idx < filter->GetCount()) + return 1; + else + return 0; + } bool Update() override { return false; } @@ -595,6 +613,9 @@ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + int + HasChildAtIndex(size_t idx) override; bool Update() override; Index: include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- include/lldb/Interpreter/ScriptInterpreter.h +++ include/lldb/Interpreter/ScriptInterpreter.h @@ -361,6 +361,12 @@ } virtual int + HasChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) + { + return -1; + } + + virtual int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name) { return UINT32_MAX; Index: scripts/Python/python-wrapper.swig =================================================================== --- scripts/Python/python-wrapper.swig +++ scripts/Python/python-wrapper.swig @@ -716,6 +716,32 @@ } SWIGEXPORT int +LLDBSwigPython_HasChildAtIndex +( + PyObject *implementor, + uint32_t idx +) +{ + PyErr_Cleaner py_err_cleaner(true); + + PyCallable pfunc = PyCallable::FindWithMemberFunction(implementor, "has_child_at_index"); + + if (!pfunc) + return -1; + + PyObject *py_return = NULL; + py_return = pfunc(idx); + + if (py_return == NULL) + return -1; + + int truth_value = PyObject_IsTrue(py_return); + Py_DECREF(py_return); + + return truth_value; +} + +SWIGEXPORT int LLDBSwigPython_GetIndexOfChildWithName ( PyObject *implementor, Index: scripts/interface/SBValue.i =================================================================== --- scripts/interface/SBValue.i +++ scripts/interface/SBValue.i @@ -238,6 +238,17 @@ GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool can_create_synthetic); + + %feature("docstring", " + //------------------------------------------------------------------ + /// The return value is a tri-state value. If it is positive, then it means that there + /// is indeed a child at index idx. If it is 0, then it means that there is no child + /// at that index. If it is negative, then it means that it (whether a child exists or not + /// at that said index) could not be evaluated properly. + //------------------------------------------------------------------ + ") HasChildAtIndex; + int32_t + HasChildAtIndex (uint32_t idx); lldb::SBValue CreateChildAtOffset (const char *name, uint32_t offset, lldb::SBType type); Index: source/API/SBValue.cpp =================================================================== --- source/API/SBValue.cpp +++ source/API/SBValue.cpp @@ -997,6 +997,18 @@ return sb_value; } +int32_t +SBValue::HasChildAtIndex (uint32_t idx) +{ + ValueLocker locker; + lldb::ValueObjectSP value_sp(GetSP(locker)); + + if (!value_sp) + return -1; + + return value_sp->HasChildAtIndex (idx); +} + uint32_t SBValue::GetIndexOfChildWithName (const char *name) { Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -145,6 +145,9 @@ LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx); extern "C" int +LLDBSwigPython_HasChildAtIndex (void *implementor, uint32_t idx); + +extern "C" int LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name); extern "C" void * @@ -336,6 +339,7 @@ LLDBSwigPythonCreateCommandObject, LLDBSwigPython_CalculateNumChildren, LLDBSwigPython_GetChildAtIndex, + LLDBSwigPython_HasChildAtIndex, LLDBSwigPython_GetIndexOfChildWithName, LLDBSWIGPython_CastPyObjectToSBValue, LLDBSWIGPython_GetValueObjectSPFromSBValue, Index: source/Core/ValueObject.cpp =================================================================== --- source/Core/ValueObject.cpp +++ source/Core/ValueObject.cpp @@ -561,6 +561,35 @@ return child_sp; } +int +ValueObject::HasChildAtIndex (size_t idx) +{ + ExecutionContext exe_ctx (GetExecutionContextRef()); + std::string child_name_str; + bool child_is_base_class, child_is_deref_of_parent; + int32_t child_byte_offset; + uint32_t child_byte_size, child_bitfield_bit_size, child_bitfield_bit_offset; + + auto compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex (&exe_ctx, + idx, + false, // transparent_pointers + true, // omit_empty_base_classes, + false, //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); + + if (compiler_type) + return 1; + else + return 0; +} + ValueObjectSP ValueObject::GetChildAtIndexPath (const std::initializer_list& idxs, size_t* index_of_error) Index: source/Core/ValueObjectSyntheticFilter.cpp =================================================================== --- source/Core/ValueObjectSyntheticFilter.cpp +++ source/Core/ValueObjectSyntheticFilter.cpp @@ -36,7 +36,13 @@ { return m_backend.GetChildAtIndex(idx, true); } - + + int + HasChildAtIndex (size_t idx) + { + return m_backend.HasChildAtIndex(idx); + } + size_t GetIndexOfChildWithName (const ConstString &name) { @@ -233,6 +239,17 @@ return valobj->GetSP(); } +int +ValueObjectSynthetic::HasChildAtIndex (size_t idx) +{ + UpdateValueIfNeeded(); + + if (m_synth_filter_ap.get() == NULL) + return -1; + + return m_synth_filter_ap->HasChildAtIndex (idx); +} + lldb::ValueObjectSP ValueObjectSynthetic::GetChildMemberWithName (const ConstString &name, bool can_create) { Index: source/DataFormatters/TypeSynthetic.cpp =================================================================== --- source/DataFormatters/TypeSynthetic.cpp +++ source/DataFormatters/TypeSynthetic.cpp @@ -190,6 +190,15 @@ return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx); } +int +ScriptedSyntheticChildren::FrontEnd::HasChildAtIndex (size_t idx) +{ + if (!m_wrapper_sp || !m_interpreter) + return -1; + + return m_interpreter->HasChildAtIndex(m_wrapper_sp, idx); +} + bool ScriptedSyntheticChildren::FrontEnd::IsValid () { Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h =================================================================== --- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -71,6 +71,7 @@ typedef size_t (*SWIGPythonCalculateNumChildren) (void *implementor); typedef void* (*SWIGPythonGetChildAtIndex) (void *implementor, uint32_t idx); + typedef int (*SWIGPythonHasChildAtIndex) (void *implementor, uint32_t idx); typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name); typedef void* (*SWIGPythonCastPyObjectToSBValue) (void* data); typedef lldb::ValueObjectSP (*SWIGPythonGetValueObjectSPFromSBValue) (void* data); @@ -200,6 +201,8 @@ lldb::ValueObjectSP GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override; + int HasChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override; + int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name) override; bool UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor) override; @@ -363,6 +366,7 @@ SWIGPythonCreateCommandObject swig_create_cmd, SWIGPythonCalculateNumChildren swig_calc_children, SWIGPythonGetChildAtIndex swig_get_child_index, + SWIGPythonHasChildAtIndex swig_has_child_at_index, SWIGPythonGetIndexOfChildWithName swig_get_index_child, SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue , SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -60,6 +60,7 @@ static ScriptInterpreterPython::SWIGPythonCreateCommandObject g_swig_create_cmd = nullptr; static ScriptInterpreterPython::SWIGPythonCalculateNumChildren g_swig_calc_children = nullptr; static ScriptInterpreterPython::SWIGPythonGetChildAtIndex g_swig_get_child_index = nullptr; +static ScriptInterpreterPython::SWIGPythonHasChildAtIndex g_swig_has_child_at_index = nullptr; static ScriptInterpreterPython::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = nullptr; static ScriptInterpreterPython::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = nullptr; static ScriptInterpreterPython::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr; @@ -2262,6 +2263,28 @@ } int +ScriptInterpreterPython::HasChildAtIndex(const StructuredData::ObjectSP &implementor_sp, uint32_t idx) +{ + if (!implementor_sp) + return -1; + + StructuredData::Generic *generic = implementor_sp->GetAsGeneric(); + if (!generic) + return -1; + void *implementor = generic->GetValue(); + if (!implementor) + return -1; + + if (!g_swig_has_child_at_index) + return -1; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + return g_swig_has_child_at_index (implementor, idx); + } +} + +int ScriptInterpreterPython::GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor_sp, const char *child_name) { if (!implementor_sp) @@ -3124,6 +3147,7 @@ SWIGPythonCreateCommandObject swig_create_cmd, SWIGPythonCalculateNumChildren swig_calc_children, SWIGPythonGetChildAtIndex swig_get_child_index, + SWIGPythonHasChildAtIndex swig_has_child_at_index, SWIGPythonGetIndexOfChildWithName swig_get_index_child, SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue , SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, @@ -3151,6 +3175,7 @@ g_swig_create_cmd = swig_create_cmd; g_swig_calc_children = swig_calc_children; g_swig_get_child_index = swig_get_child_index; + g_swig_has_child_at_index = swig_has_child_at_index; g_swig_get_index_child = swig_get_index_child; g_swig_cast_to_sbvalue = swig_cast_to_sbvalue; g_swig_get_valobj_sp_from_sbvalue = swig_get_valobj_sp_from_sbvalue;