https://github.com/kastiglione updated 
https://github.com/llvm/llvm-project/pull/174885

>From fa0ff222350da4d7841abcad9e232b0bfffdd9d2 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Wed, 7 Jan 2026 15:04:59 -0800
Subject: [PATCH 1/3] [lldb] Automatic indexing for synthetic children of
 collections

Synthetic providers for collection types use a child name format of "[N]".

This changes the Python-SWIG bridge to automatically convert child names in this
convention to the index embedded in the string. With this change, collections 
will only
need to implement `get_child_index` for non-collection children. Some examples 
are
"hidden" children (properties), or to implement `$$dereference$$` support.

The automatic conversion applies to N values that are less than the number of 
children
reported by the synthetic provider.
---
 lldb/bindings/python/python-wrapper.swig        | 17 +++++++++++++++--
 .../TestFrameVarDILArraySubscript.py            | 10 +++++++++-
 .../ArraySubscript/myArraySynthProvider.py      | 11 -----------
 3 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/lldb/bindings/python/python-wrapper.swig 
b/lldb/bindings/python/python-wrapper.swig
index 0ba152166522b..41551dc095bed 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -315,6 +315,19 @@ PyObject 
*lldb_private::python::SWIGBridge::LLDBSwigPython_GetChildAtIndex(PyObj
   return result.release();
 }
 
+static uint32_t ParseIndex(PyObject *implementor, llvm::StringRef name) {
+  unsigned long long retval;
+  if (name.consume_front("[") && !name.consumeInteger(10, retval) && name == 
"]") {
+    // Lazily calculate the number of children (capped to one past the given 
index).
+    uint32_t max = retval + 1;
+    size_t num_children =
+      
lldb_private::python::SWIGBridge::LLDBSwigPython_CalculateNumChildren(implementor,
 max);
+    if (retval < num_children)
+      return (uint32_t)retval;
+  }
+  return UINT32_MAX;
+}
+
 uint32_t 
lldb_private::python::SWIGBridge::LLDBSwigPython_GetIndexOfChildWithName(
     PyObject * implementor, const char *child_name) {
   PyErr_Cleaner py_err_cleaner(true);
@@ -323,7 +336,7 @@ uint32_t 
lldb_private::python::SWIGBridge::LLDBSwigPython_GetIndexOfChildWithNam
   auto pfunc = self.ResolveName<PythonCallable>("get_child_index");
 
   if (!pfunc.IsAllocated())
-    return UINT32_MAX;
+    return ParseIndex(implementor, child_name);
 
   llvm::Expected<PythonObject> result = pfunc.Call(PythonString(child_name));
 
@@ -332,7 +345,7 @@ uint32_t 
lldb_private::python::SWIGBridge::LLDBSwigPython_GetIndexOfChildWithNam
 
   if (PyErr_Occurred()) {
     PyErr_Clear(); // FIXME print this? do something else
-    return UINT32_MAX;
+    return ParseIndex(implementor, child_name);
   }
 
   if (retval >= 0)
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 33d2e3c4fc2b2..5c34fb32abdbf 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
@@ -89,7 +89,7 @@ def test_subscript(self):
 
     def test_subscript_synthetic(self):
         self.build()
-        lldbutil.run_to_source_breakpoint(
+        _, process, _, _ = lldbutil.run_to_source_breakpoint(
             self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
         )
 
@@ -108,3 +108,11 @@ def test_subscript_synthetic(self):
             "frame var 'ma_ptr[0]'",
             substrs=["(myArray) ma_ptr[0] = ([0] = 7, [1] = 8, [2] = 9, [3] = 
10)"],
         )
+
+        frame = process.selected_thread.selected_frame
+        my_array = frame.var("ma")
+        for i in range(my_array.num_children):
+            idx = my_array.GetIndexOfChildWithName(f"[{i}]")
+            self.assertEqual(idx, i)
+        idx = my_array.GetIndexOfChildWithName(f"[{my_array.num_children + 
1}]")
+        self.assertEqual(idx, lldb.UINT32_MAX)
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 167899bd3907c..0d9e518b6fb9b 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
@@ -20,14 +20,3 @@ def get_child_at_index(self, index):
         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 61b52d8b8663bf4dc5ce356551ac6255f0a058df Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Wed, 11 Feb 2026 13:26:25 -0800
Subject: [PATCH 2/3] Move default subscript parsing into ValueObjectSynthetic

---
 lldb/bindings/python/python-wrapper.swig      | 17 +---
 .../lldb/DataFormatters/TypeSynthetic.h       |  5 +-
 lldb/source/DataFormatters/VectorType.cpp     | 13 ---
 .../Language/CPlusPlus/GenericBitset.cpp      |  9 --
 .../Language/CPlusPlus/GenericList.cpp        |  8 --
 .../Language/CPlusPlus/GenericOptional.cpp    |  8 +-
 .../Plugins/Language/CPlusPlus/LibCxxMap.cpp  | 12 ---
 .../Language/CPlusPlus/LibCxxTuple.cpp        |  9 --
 .../Language/CPlusPlus/LibCxxUnorderedMap.cpp | 13 ---
 .../Language/CPlusPlus/LibCxxVariant.cpp      |  9 --
 .../Language/CPlusPlus/LibStdcppTuple.cpp     | 12 ---
 .../Language/CPlusPlus/MsvcStlTree.cpp        | 13 ---
 .../Language/CPlusPlus/MsvcStlTuple.cpp       |  9 --
 .../Language/CPlusPlus/MsvcStlVariant.cpp     |  9 --
 lldb/source/Plugins/Language/ObjC/NSArray.cpp | 34 --------
 .../Plugins/Language/ObjC/NSDictionary.cpp    | 83 -------------------
 .../Plugins/Language/ObjC/NSIndexPath.cpp     | 13 ---
 lldb/source/Plugins/Language/ObjC/NSSet.cpp   | 51 ------------
 .../ValueObject/ValueObjectSynthetic.cpp      | 35 ++++++--
 .../TestFrameVarDILArraySubscript.py          | 10 +--
 .../ArraySubscript/myArraySynthProvider.py    | 11 +++
 .../synthetic_subscript/Makefile              |  2 +
 .../TestSyntheticSubscript.py                 | 23 +++++
 .../data-formatter/synthetic_subscript/main.c | 12 +++
 .../synthetic_subscript/thing_formatter.py    | 15 ++++
 25 files changed, 102 insertions(+), 333 deletions(-)
 create mode 100644 
lldb/test/API/functionalities/data-formatter/synthetic_subscript/Makefile
 create mode 100644 
lldb/test/API/functionalities/data-formatter/synthetic_subscript/TestSyntheticSubscript.py
 create mode 100644 
lldb/test/API/functionalities/data-formatter/synthetic_subscript/main.c
 create mode 100644 
lldb/test/API/functionalities/data-formatter/synthetic_subscript/thing_formatter.py

diff --git a/lldb/bindings/python/python-wrapper.swig 
b/lldb/bindings/python/python-wrapper.swig
index 41551dc095bed..0ba152166522b 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -315,19 +315,6 @@ PyObject 
*lldb_private::python::SWIGBridge::LLDBSwigPython_GetChildAtIndex(PyObj
   return result.release();
 }
 
-static uint32_t ParseIndex(PyObject *implementor, llvm::StringRef name) {
-  unsigned long long retval;
-  if (name.consume_front("[") && !name.consumeInteger(10, retval) && name == 
"]") {
-    // Lazily calculate the number of children (capped to one past the given 
index).
-    uint32_t max = retval + 1;
-    size_t num_children =
-      
lldb_private::python::SWIGBridge::LLDBSwigPython_CalculateNumChildren(implementor,
 max);
-    if (retval < num_children)
-      return (uint32_t)retval;
-  }
-  return UINT32_MAX;
-}
-
 uint32_t 
lldb_private::python::SWIGBridge::LLDBSwigPython_GetIndexOfChildWithName(
     PyObject * implementor, const char *child_name) {
   PyErr_Cleaner py_err_cleaner(true);
@@ -336,7 +323,7 @@ uint32_t 
lldb_private::python::SWIGBridge::LLDBSwigPython_GetIndexOfChildWithNam
   auto pfunc = self.ResolveName<PythonCallable>("get_child_index");
 
   if (!pfunc.IsAllocated())
-    return ParseIndex(implementor, child_name);
+    return UINT32_MAX;
 
   llvm::Expected<PythonObject> result = pfunc.Call(PythonString(child_name));
 
@@ -345,7 +332,7 @@ uint32_t 
lldb_private::python::SWIGBridge::LLDBSwigPython_GetIndexOfChildWithNam
 
   if (PyErr_Occurred()) {
     PyErr_Clear(); // FIXME print this? do something else
-    return ParseIndex(implementor, child_name);
+    return UINT32_MAX;
   }
 
   if (retval >= 0)
diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h 
b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index 5779c5de0703f..80d5b987d70de 100644
--- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -46,7 +46,10 @@ class SyntheticChildrenFrontEnd {
 
   virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) = 0;
 
-  virtual llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) = 0;
+  virtual llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) {
+    return llvm::createStringError("Type has no child named '%s'",
+                                   name.AsCString());
+  }
 
   /// This function is assumed to always succeed and if it fails, the front-end
   /// should know to deal with it in the correct way (most probably, by 
refusing
diff --git a/lldb/source/DataFormatters/VectorType.cpp 
b/lldb/source/DataFormatters/VectorType.cpp
index c2355fbfdcb2f..624f9de312bb3 100644
--- a/lldb/source/DataFormatters/VectorType.cpp
+++ b/lldb/source/DataFormatters/VectorType.cpp
@@ -271,19 +271,6 @@ class VectorTypeSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
     return lldb::ChildCacheState::eRefetch;
   }
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = ExtractIndexFromString(name.AsCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    uint32_t idx = *optional_idx;
-    if (idx >= CalculateNumChildrenIgnoringErrors())
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    return idx;
-  }
-
 private:
   lldb::Format m_parent_format = eFormatInvalid;
   lldb::Format m_item_format = eFormatInvalid;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
index f2521ec750875..1d522f0b4a724 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
@@ -28,15 +28,6 @@ class GenericBitsetFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    return *optional_idx;
-  }
-
   lldb::ChildCacheState Update() override;
   llvm::Expected<uint32_t> CalculateNumChildren() override {
     return m_elements.size();
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index 8c5ac31aef3f3..7dcc9a19098b5 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -124,14 +124,6 @@ template <StlType Stl> class ListIterator {
 template <StlType Stl>
 class AbstractListFrontEnd : public SyntheticChildrenFrontEnd {
 public:
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    return *optional_idx;
-  }
   lldb::ChildCacheState Update() override;
 
 protected:
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
index 7fc6eb55d4e3e..e4c261a5411f7 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
@@ -41,12 +41,8 @@ class GenericOptionalFrontend : public 
SyntheticChildrenFrontEnd {
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
     if (name == "$$dereference$$")
       return 0;
-    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    return *optional_idx;
+    return llvm::createStringError("Type has no child named '%s'",
+                                   name.AsCString());
   }
 
   llvm::Expected<uint32_t> CalculateNumChildren() override {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 85766966f1554..d00a293929e17 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -197,8 +197,6 @@ class LibcxxStdMapSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   llvm::Expected<uint32_t>
   CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair);
@@ -390,16 +388,6 @@ 
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
   return lldb::ChildCacheState::eRefetch;
 }
 
-llvm::Expected<size_t> 
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
-    GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  return *optional_idx;
-}
-
 SyntheticChildrenFrontEnd *
 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator(
     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
index ebc6d92aabe05..3e4093509b6bc 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
@@ -20,15 +20,6 @@ class TupleFrontEnd: public SyntheticChildrenFrontEnd {
     Update();
   }
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    return *optional_idx;
-  }
-
   lldb::ChildCacheState Update() override;
   llvm::Expected<uint32_t> CalculateNumChildren() override {
     return m_elements.size();
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 5588208a3ef84..25e33dbde1229 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -40,8 +40,6 @@ class LibcxxStdUnorderedMapSyntheticFrontEnd
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   CompilerType GetNodeType();
   CompilerType GetElementType(CompilerType table_type);
@@ -285,17 +283,6 @@ 
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() {
   return lldb::ChildCacheState::eRefetch;
 }
 
-llvm::Expected<size_t>
-lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
-    GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  return *optional_idx;
-}
-
 SyntheticChildrenFrontEnd *
 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator(
     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
index 30fec4e2dde0f..2855fc1e0512a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
@@ -202,15 +202,6 @@ class VariantFrontEnd : public SyntheticChildrenFrontEnd {
     Update();
   }
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    return *optional_idx;
-  }
-
   lldb::ChildCacheState Update() override;
   llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; }
   ValueObjectSP GetChildAtIndex(uint32_t idx) override;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
index cf72265bfbad3..d4fcd32c6b54b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
@@ -32,8 +32,6 @@ class LibStdcppTupleSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   // The lifetime of a ValueObject and all its derivative ValueObjects
   // (children, clones, etc.) is managed by a ClusterManager. These
@@ -96,16 +94,6 @@ LibStdcppTupleSyntheticFrontEnd::CalculateNumChildren() {
   return m_members.size();
 }
 
-llvm::Expected<size_t>
-LibStdcppTupleSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  return *optional_idx;
-}
-
 SyntheticChildrenFrontEnd *
 lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator(
     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTree.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTree.cpp
index ddf6c27a3e003..80dc0a7bf055f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTree.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTree.cpp
@@ -187,8 +187,6 @@ class MsvcStlTreeSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   /// Returns the ValueObject for the _Tree_node at index \ref idx.
   ///
@@ -335,17 +333,6 @@ 
lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd::Update() {
   return lldb::ChildCacheState::eRefetch;
 }
 
-llvm::Expected<size_t>
-lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd::GetIndexOfChildWithName(
-    ConstString name) {
-  auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  return *optional_idx;
-}
-
 lldb::ChildCacheState MsvcStlTreeIterSyntheticFrontEnd::Update() {
   m_inner_sp = nullptr;
   auto node_sp = m_backend.GetChildMemberWithName("_Ptr");
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTuple.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTuple.cpp
index fe20b4c141a65..fd133550e00b7 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTuple.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTuple.cpp
@@ -20,15 +20,6 @@ class TupleFrontEnd : public SyntheticChildrenFrontEnd {
     Update();
   }
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    return *optional_idx;
-  }
-
   lldb::ChildCacheState Update() override;
   llvm::Expected<uint32_t> CalculateNumChildren() override {
     return m_elements.size();
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
index 3e7647be48bb0..53b99d7a48170 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
@@ -141,15 +141,6 @@ class VariantFrontEnd : public SyntheticChildrenFrontEnd {
     Update();
   }
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    return *optional_idx;
-  }
-
   lldb::ChildCacheState Update() override;
   llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; }
   ValueObjectSP GetChildAtIndex(uint32_t idx) override;
diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp 
b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
index 25376e064879d..b1dc9ff7e48bf 100644
--- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -56,8 +56,6 @@ class NSArrayMSyntheticFrontEndBase : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override = 0;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 protected:
   virtual lldb::addr_t GetDataAddress() = 0;
 
@@ -218,8 +216,6 @@ class GenericNSArrayISyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   ExecutionContextRef m_exe_ctx_ref;
   uint8_t m_ptr_size = 8;
@@ -526,20 +522,6 @@ 
lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
                          : lldb::ChildCacheState::eRefetch;
 }
 
-llvm::Expected<size_t> 
lldb_private::formatters::NSArrayMSyntheticFrontEndBase::
-    GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 template <typename D32, typename D64>
 lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::
     GenericNSArrayMSyntheticFrontEnd::~GenericNSArrayMSyntheticFrontEnd() {
@@ -615,22 +597,6 @@ 
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
   m_data_64 = nullptr;
 }
 
-template <typename D32, typename D64, bool Inline>
-llvm::Expected<size_t>
-lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<
-    D32, D64, Inline>::GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 template <typename D32, typename D64, bool Inline>
 llvm::Expected<uint32_t>
 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<
diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp 
b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
index 24e84899e683c..ffe6852a67f9d 100644
--- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -110,8 +110,6 @@ class NSDictionaryISyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   struct DataDescriptor_32 {
     uint32_t _used : 26;
@@ -149,8 +147,6 @@ class NSConstantDictionarySyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   ExecutionContextRef m_exe_ctx_ref;
   CompilerType m_pair_type;
@@ -179,8 +175,6 @@ class NSCFDictionarySyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   struct DictionaryItemDescriptor {
     lldb::addr_t key_ptr;
@@ -229,8 +223,6 @@ class GenericNSDictionaryMSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   struct DictionaryItemDescriptor {
     lldb::addr_t key_ptr;
@@ -260,8 +252,6 @@ namespace Foundation1100 {
 
     lldb::ChildCacheState Update() override;
 
-    llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
   private:
     struct DataDescriptor_32 {
       uint32_t _used : 26;
@@ -586,20 +576,6 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
   m_data_64 = nullptr;
 }
 
-llvm::Expected<size_t> lldb_private::formatters::
-    NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 llvm::Expected<uint32_t> lldb_private::formatters::
     NSDictionaryISyntheticFrontEnd::CalculateNumChildren() {
   if (!m_data_32 && !m_data_64)
@@ -724,20 +700,6 @@ lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
       m_pair_type() {}
 
-llvm::Expected<size_t> lldb_private::formatters::
-    NSCFDictionarySyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) 
{
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 llvm::Expected<uint32_t> lldb_private::formatters::
     NSCFDictionarySyntheticFrontEnd::CalculateNumChildren() {
   if (!m_hashtable.IsValid())
@@ -860,21 +822,6 @@ 
lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
     NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
     : SyntheticChildrenFrontEnd(*valobj_sp) {}
 
-llvm::Expected<size_t>
-lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
-    GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 llvm::Expected<uint32_t> lldb_private::formatters::
     NSConstantDictionarySyntheticFrontEnd::CalculateNumChildren() {
   return m_size;
@@ -1064,22 +1011,6 @@ 
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
   m_data_64 = nullptr;
 }
 
-template <typename D32, typename D64>
-llvm::Expected<size_t>
-lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
-    D32, D64>::GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 template <typename D32, typename D64>
 llvm::Expected<uint32_t>
 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
@@ -1228,20 +1159,6 @@ lldb_private::formatters::Foundation1100::
   m_data_64 = nullptr;
 }
 
-llvm::Expected<size_t> lldb_private::formatters::Foundation1100::
-    NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 llvm::Expected<uint32_t> lldb_private::formatters::Foundation1100::
     NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
   if (!m_data_32 && !m_data_64)
diff --git a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp 
b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
index b5360195e91d2..23f711931f956 100644
--- a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
@@ -126,19 +126,6 @@ class NSIndexPathSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    auto optional_idx = ExtractIndexFromString(name.AsCString());
-    if (!optional_idx) {
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    }
-    uint32_t idx = *optional_idx;
-    if (idx >= CalculateNumChildrenIgnoringErrors())
-      return llvm::createStringError("Type has no child named '%s'",
-                                     name.AsCString());
-    return idx;
-  }
-
   lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
 
 protected:
diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp 
b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
index 150b233507128..44af668759f96 100644
--- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -52,8 +52,6 @@ class NSSetISyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   struct DataDescriptor_32 {
     uint32_t _used : 26;
@@ -88,8 +86,6 @@ class NSCFSetSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
   struct SetItemDescriptor {
     lldb::addr_t item_ptr;
@@ -119,8 +115,6 @@ class GenericNSSetMSyntheticFrontEnd : public 
SyntheticChildrenFrontEnd {
 
   lldb::ChildCacheState Update() override;
 
-  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
 private:
 
   struct SetItemDescriptor {
@@ -386,21 +380,6 @@ 
lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
   m_data_64 = nullptr;
 }
 
-llvm::Expected<size_t>
-lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
-    ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 llvm::Expected<uint32_t>
 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
   if (!m_data_32 && !m_data_64)
@@ -522,21 +501,6 @@ 
lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(
     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
       m_pair_type() {}
 
-llvm::Expected<size_t>
-lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(
-    ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 llvm::Expected<uint32_t>
 lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {
   if (!m_hashtable.IsValid())
@@ -661,21 +625,6 @@ 
lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::
   m_data_64 = nullptr;
 }
 
-template <typename D32, typename D64>
-llvm::Expected<size_t> 
lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
-    D32, D64>::GetIndexOfChildWithName(ConstString name) {
-  auto optional_idx = ExtractIndexFromString(name.AsCString());
-  if (!optional_idx) {
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  }
-  uint32_t idx = *optional_idx;
-  if (idx >= CalculateNumChildrenIgnoringErrors())
-    return llvm::createStringError("Type has no child named '%s'",
-                                   name.AsCString());
-  return idx;
-}
-
 template <typename D32, typename D64>
 llvm::Expected<uint32_t>
 lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
diff --git a/lldb/source/ValueObject/ValueObjectSynthetic.cpp 
b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
index 44e53bd5fd82e..af342c66fabed 100644
--- a/lldb/source/ValueObject/ValueObjectSynthetic.cpp
+++ b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
@@ -9,6 +9,7 @@
 #include "lldb/ValueObject/ValueObjectSynthetic.h"
 
 #include "lldb/Core/Value.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
 #include "lldb/DataFormatters/TypeSynthetic.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Utility/ConstString.h"
@@ -18,6 +19,7 @@
 #include "lldb/ValueObject/ValueObject.h"
 
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
 #include <optional>
 
 namespace lldb_private {
@@ -329,6 +331,21 @@ 
ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name,
   return GetChildAtIndex(*index_or_err, can_create);
 }
 
+static std::optional<uint32_t> ParseSubscriptIndex(ValueObjectSynthetic 
&valobj,
+                                                   llvm::StringRef name) {
+  auto maybe_index = formatters::ExtractIndexFromString(name.data());
+  if (!maybe_index)
+    return std::nullopt;
+
+  auto idx = *maybe_index;
+  // Prevent unnecessary work by limiting max to one past the index.
+  uint32_t max = idx + 1;
+  auto num_children = valobj.GetNumChildrenIgnoringErrors(max);
+  if (idx >= num_children)
+    return std::nullopt;
+  return idx;
+}
+
 llvm::Expected<size_t>
 ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {
   UpdateValueIfNeeded();
@@ -344,12 +361,20 @@ 
ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {
   }
 
   if (!found_index && m_synth_filter_up != nullptr) {
-    auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name);
-    if (!index_or_err)
-      return index_or_err.takeError();
+    size_t index = SIZE_MAX;
+    if (auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name)) {
+      index = *index_or_err;
+    } else {
+      // Provide automatic support for subscript child names ("[N]").
+      auto maybe_subscript = ParseSubscriptIndex(*this, name);
+      if (!maybe_subscript)
+        return index_or_err.takeError();
+      index = *maybe_subscript;
+      llvm::consumeError(index_or_err.takeError());
+    }
     std::lock_guard<std::mutex> guard(m_child_mutex);
-    m_name_toindex[name.GetCString()] = *index_or_err;
-    return *index_or_err;
+    m_name_toindex[name.GetCString()] = index;
+    return index;
   } else if (!found_index && m_synth_filter_up == nullptr) {
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
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 5c34fb32abdbf..33d2e3c4fc2b2 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
@@ -89,7 +89,7 @@ def test_subscript(self):
 
     def test_subscript_synthetic(self):
         self.build()
-        _, process, _, _ = lldbutil.run_to_source_breakpoint(
+        lldbutil.run_to_source_breakpoint(
             self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
         )
 
@@ -108,11 +108,3 @@ def test_subscript_synthetic(self):
             "frame var 'ma_ptr[0]'",
             substrs=["(myArray) ma_ptr[0] = ([0] = 7, [1] = 8, [2] = 9, [3] = 
10)"],
         )
-
-        frame = process.selected_thread.selected_frame
-        my_array = frame.var("ma")
-        for i in range(my_array.num_children):
-            idx = my_array.GetIndexOfChildWithName(f"[{i}]")
-            self.assertEqual(idx, i)
-        idx = my_array.GetIndexOfChildWithName(f"[{my_array.num_children + 
1}]")
-        self.assertEqual(idx, lldb.UINT32_MAX)
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 0d9e518b6fb9b..7549128d9b640 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
@@ -20,3 +20,14 @@ def get_child_at_index(self, index):
         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 1
+        if name == "[2]":
+            return 2
+        if name == "[3]":
+            return 3
+        return -1
diff --git 
a/lldb/test/API/functionalities/data-formatter/synthetic_subscript/Makefile 
b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/Makefile
new file mode 100644
index 0000000000000..c9319d6e6888a
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := main.c
+include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/data-formatter/synthetic_subscript/TestSyntheticSubscript.py
 
b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/TestSyntheticSubscript.py
new file mode 100644
index 0000000000000..be34b0f1f72d8
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/TestSyntheticSubscript.py
@@ -0,0 +1,23 @@
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        _, process, _, _ = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.c")
+        )
+        self.runCmd("command script import thing_formatter.py")
+        frame = process.selected_thread.selected_frame
+        x = frame.var("x")
+        names = ("zero", "one")
+        for i in range(x.num_children):
+            idx = x.GetIndexOfChildWithName(f"[{i}]")
+            self.assertEqual(idx, i)
+            child = x.GetChildAtIndex(idx)
+            self.assertEqual(child.name, names[idx])
+        idx = x.GetIndexOfChildWithName(f"[{x.num_children + 1}]")
+        self.assertEqual(idx, lldb.UINT32_MAX)
diff --git 
a/lldb/test/API/functionalities/data-formatter/synthetic_subscript/main.c 
b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/main.c
new file mode 100644
index 0000000000000..ca0da120a7c0c
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/main.c
@@ -0,0 +1,12 @@
+struct Thing {
+  int zero;
+  int one;
+};
+
+int main() {
+  struct Thing x;
+  x.zero = 1;
+  x.one = 2;
+  __builtin_printf("break here\n");
+  return 0;
+}
diff --git 
a/lldb/test/API/functionalities/data-formatter/synthetic_subscript/thing_formatter.py
 
b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/thing_formatter.py
new file mode 100644
index 0000000000000..0027f0ba0be68
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/synthetic_subscript/thing_formatter.py
@@ -0,0 +1,15 @@
+class ThingSynthetic:
+    def __init__(self, valobj, _) -> None:
+        self.valobj = valobj
+
+    def num_children(self):
+        return self.valobj.num_children
+
+    def get_child_at_index(self, idx):
+        return self.valobj.GetChildAtIndex(idx)
+
+    # Use default implementation of get_child_index.
+
+
+def __lldb_init_module(dbg, _):
+    dbg.HandleCommand(f"type synthetic add -l {__name__}.ThingSynthetic Thing")

>From 5931bdee706a49b3f67e166399ae30f313279246 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 12 Feb 2026 09:46:23 -0800
Subject: [PATCH 3/3] Rename a local var

---
 lldb/source/ValueObject/ValueObjectSynthetic.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lldb/source/ValueObject/ValueObjectSynthetic.cpp 
b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
index af342c66fabed..9e0026c11c233 100644
--- a/lldb/source/ValueObject/ValueObjectSynthetic.cpp
+++ b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
@@ -366,10 +366,10 @@ 
ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {
       index = *index_or_err;
     } else {
       // Provide automatic support for subscript child names ("[N]").
-      auto maybe_subscript = ParseSubscriptIndex(*this, name);
-      if (!maybe_subscript)
+      auto maybe_index = ParseSubscriptIndex(*this, name);
+      if (!maybe_index)
         return index_or_err.takeError();
-      index = *maybe_subscript;
+      index = *maybe_index;
       llvm::consumeError(index_or_err.takeError());
     }
     std::lock_guard<std::mutex> guard(m_child_mutex);

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to