Skip to content

[lldb][DataFormatters] Change ExtractIndexFromString to return std::optional #138297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

charles-zablit
Copy link
Contributor

This PR is in continuation of #136693.

It upgrades ExtractIndexFromString to use llvm::Expected.

@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-lldb

Author: Charles Zablit (charles-zablit)

Changes

This PR is in continuation of #136693.

It upgrades ExtractIndexFromString to use llvm::Expected.


Patch is 28.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138297.diff

21 Files Affected:

  • (modified) lldb/include/lldb/DataFormatters/FormattersHelpers.h (+1-1)
  • (modified) lldb/source/DataFormatters/FormattersHelpers.cpp (+6-5)
  • (modified) lldb/source/DataFormatters/VectorType.cpp (+8-4)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp (+12-7)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/ObjC/NSArray.cpp (+16-8)
  • (modified) lldb/source/Plugins/Language/ObjC/NSDictionary.cpp (+41-21)
  • (modified) lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp (+8-4)
  • (modified) lldb/source/Plugins/Language/ObjC/NSSet.cpp (+24-12)
diff --git a/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/lldb/include/lldb/DataFormatters/FormattersHelpers.h
index a98042fd40f93..82aae705e2a59 100644
--- a/lldb/include/lldb/DataFormatters/FormattersHelpers.h
+++ b/lldb/include/lldb/DataFormatters/FormattersHelpers.h
@@ -53,7 +53,7 @@ void AddFilter(TypeCategoryImpl::SharedPointer category_sp,
                llvm::StringRef type_name,
                ScriptedSyntheticChildren::Flags flags, bool regex = false);
 
-size_t ExtractIndexFromString(const char *item_name);
+llvm::Expected<size_t> ExtractIndexFromString(const char *item_name);
 
 Address GetArrayAddressOrPointerValue(ValueObject &valobj);
 
diff --git a/lldb/source/DataFormatters/FormattersHelpers.cpp b/lldb/source/DataFormatters/FormattersHelpers.cpp
index 085ed3d0a2f29..5e29794c291be 100644
--- a/lldb/source/DataFormatters/FormattersHelpers.cpp
+++ b/lldb/source/DataFormatters/FormattersHelpers.cpp
@@ -97,18 +97,19 @@ void lldb_private::formatters::AddFilter(
   category_sp->AddTypeFilter(type_name, match_type, filter_sp);
 }
 
-size_t lldb_private::formatters::ExtractIndexFromString(const char *item_name) {
+llvm::Expected<size_t>
+lldb_private::formatters::ExtractIndexFromString(const char *item_name) {
   if (!item_name || !*item_name)
-    return UINT32_MAX;
+    return llvm::createStringError("String has no item named '%s'", item_name);
   if (*item_name != '[')
-    return UINT32_MAX;
+    return llvm::createStringError("String has no item named '%s'", item_name);
   item_name++;
   char *endptr = nullptr;
   unsigned long int idx = ::strtoul(item_name, &endptr, 0);
   if (idx == 0 && endptr == item_name)
-    return UINT32_MAX;
+    return llvm::createStringError("String has no item named '%s'", item_name);
   if (idx == ULONG_MAX)
-    return UINT32_MAX;
+    return llvm::createStringError("String has no item named '%s'", item_name);
   return idx;
 }
 
diff --git a/lldb/source/DataFormatters/VectorType.cpp b/lldb/source/DataFormatters/VectorType.cpp
index eab2612d1e941..3fa616b9d9b14 100644
--- a/lldb/source/DataFormatters/VectorType.cpp
+++ b/lldb/source/DataFormatters/VectorType.cpp
@@ -270,10 +270,14 @@ class VectorTypeSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
   }
 
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    const char *item_name = name.GetCString();
-    uint32_t idx = ExtractIndexFromString(item_name);
-    if (idx == UINT32_MAX ||
-        (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()))
+    auto idx_or_err = ExtractIndexFromString(name.AsCString());
+    if (!idx_or_err) {
+      llvm::consumeError(idx_or_err.takeError());
+      return llvm::createStringError("Type has no child named '%s'",
+                                     name.AsCString());
+    }
+    uint32_t idx = *idx_or_err;
+    if (idx >= CalculateNumChildrenIgnoringErrors())
       return llvm::createStringError("Type has no child named '%s'",
                                      name.AsCString());
     return idx;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
index 234471d5ba518..ebcac0a48bd30 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
@@ -29,11 +29,13 @@ class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {
   GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
 
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    size_t idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (idx == UINT32_MAX)
+    auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+    if (!idx_or_err) {
+      llvm::consumeError(idx_or_err.takeError());
       return llvm::createStringError("Type has no child named '%s'",
                                      name.AsCString());
-    return idx;
+    }
+    return *idx_or_err;
   }
 
   lldb::ChildCacheState Update() override;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
index 6f1b2ee3fd9e3..bfcc15ae805e7 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
@@ -39,11 +39,13 @@ class GenericOptionalFrontend : public SyntheticChildrenFrontEnd {
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
     if (name == "$$dereference$$")
       return 0;
-    size_t idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (idx == UINT32_MAX)
+    auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+    if (!idx_or_err) {
+      llvm::consumeError(idx_or_err.takeError());
       return llvm::createStringError("Type has no child named '%s'",
                                      name.AsCString());
-    return idx;
+    }
+    return *idx_or_err;
   }
 
   llvm::Expected<uint32_t> CalculateNumChildren() override {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
index e8a886dd71821..04891d7d094f3 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
@@ -108,12 +108,13 @@ lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  size_t idx = ExtractIndexFromString(name.GetCString());
-  if (idx == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return idx;
+  return *idx_or_err;
 }
 
 lldb_private::SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
index ea18c02ee6591..9d4773c56b3e3 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
@@ -107,11 +107,13 @@ class ListIterator {
 class AbstractListFrontEnd : public SyntheticChildrenFrontEnd {
 public:
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    size_t idx = ExtractIndexFromString(name.GetCString());
-    if (idx == UINT32_MAX)
+    auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+    if (!idx_or_err) {
+      llvm::consumeError(idx_or_err.takeError());
       return llvm::createStringError("Type has no child named '%s'",
                                      name.AsCString());
-    return idx;
+    }
+    return *idx_or_err;
   }
   lldb::ChildCacheState Update() override;
 
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index fec2d6f29ca54..9c3694e2448fc 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -395,12 +395,13 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
 
 llvm::Expected<size_t> lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
     GetIndexOfChildWithName(ConstString name) {
-  size_t idx = ExtractIndexFromString(name.GetCString());
-  if (idx == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return idx;
+  return *idx_or_err;
 }
 
 SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
index 41fc704d5886f..a4ded6e0d7d85 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
@@ -179,12 +179,13 @@ lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
   if (!m_base)
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
-  size_t idx = ExtractIndexFromString(name.GetCString());
-  if (idx == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return idx;
+  return *idx_or_err;
 }
 
 lldb_private::SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
index 1c4d8509374f1..309d91ae02ecb 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
@@ -150,11 +150,13 @@ lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
   if (!m_start)
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
-  size_t idx = ExtractIndexFromString(name.GetCString());
-  if (idx == UINT32_MAX)
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
-  return idx;
+  }
+  return *idx_or_err;
 }
 
 lldb_private::SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
index 43721e4b41fb8..26e8c48b4f8eb 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
@@ -133,12 +133,13 @@ llvm::Expected<size_t> lldb_private::formatters::
   if (!m_start)
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
-  size_t idx = ExtractIndexFromString(name.GetCString());
-  if (idx == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return idx;
+  return *idx_or_err;
 }
 
 lldb_private::SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
index 270aad5ea9310..235a26da50a5f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
@@ -21,11 +21,13 @@ class TupleFrontEnd: public SyntheticChildrenFrontEnd {
   }
 
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    size_t idx = formatters::ExtractIndexFromString(name.GetCString());
-    if (idx == UINT32_MAX)
+    auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+    if (!idx_or_err) {
+      llvm::consumeError(idx_or_err.takeError());
       return llvm::createStringError("Type has no child named '%s'",
                                      name.AsCString());
-    return idx;
+    }
+    return *idx_or_err;
   }
 
   lldb::ChildCacheState Update() override;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 313664e691c9f..de37aeda25168 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -294,12 +294,13 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() {
 llvm::Expected<size_t>
 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
     GetIndexOfChildWithName(ConstString name) {
-  size_t idx = ExtractIndexFromString(name.GetCString());
-  if (idx == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return idx;
+  return *idx_or_err;
 }
 
 SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
index 172df6358789e..4c87e167589da 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
@@ -129,12 +129,13 @@ lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
   if (!m_start || !m_finish)
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
-  size_t idx = ExtractIndexFromString(name.GetCString());
-  if (idx == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return idx;
+  return *idx_or_err;
 }
 
 lldb_private::SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
index 2419683a4d713..12071321189b9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
@@ -203,11 +203,13 @@ class VariantFrontEnd : public SyntheticChildrenFrontEnd {
   }
 
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    size_t index = formatters::ExtractIndexFromString(name.GetCString());
-    if (index == UINT32_MAX)
+    auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+    if (!idx_or_err) {
+      llvm::consumeError(idx_or_err.takeError());
       return llvm::createStringError("Type has no child named '%s'",
                                      name.AsCString());
-    return index;
+    }
+    return *idx_or_err;
   }
 
   lldb::ChildCacheState Update() override;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index abbf1ed935b6b..228647b8961b1 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -170,12 +170,13 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
   if (!m_start || !m_finish)
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
-  size_t index = formatters::ExtractIndexFromString(name.GetCString());
-  if (index == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return index;
+  return *idx_or_err;
 }
 
 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
@@ -273,10 +274,14 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
   if (!m_count || !m_base_data_address)
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
-  const char *item_name = name.GetCString();
-  uint32_t idx = ExtractIndexFromString(item_name);
-  if (idx == UINT32_MAX ||
-      (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()))
+  auto idx_or_err = ExtractIndexFromString(name.AsCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
+    return llvm::createStringError("Type has no child named '%s'",
+                                   name.AsCString());
+  }
+  uint32_t idx = *idx_or_err;
+  if (idx >= CalculateNumChildrenIgnoringErrors())
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   return idx;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
index cae5aa379b245..4f05dc1934958 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
@@ -98,12 +98,13 @@ LibStdcppTupleSyntheticFrontEnd::CalculateNumChildren() {
 
 llvm::Expected<size_t>
 LibStdcppTupleSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
-  size_t index = formatters::ExtractIndexFromString(name.GetCString());
-  if (index == UINT32_MAX) {
+  auto idx_or_err = formatters::ExtractIndexFromString(name.GetCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   }
-  return index;
+  return *idx_or_err;
 }
 
 SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
index 5e72bd5a6bab6..465639a21d943 100644
--- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -528,10 +528,14 @@ lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
 
 llvm::Expected<size_t> lldb_private::formatters::NSArrayMSyntheticFrontEndBase::
     GetIndexOfChildWithName(ConstString name) {
-  const char *item_name = name.GetCString();
-  size_t idx = ExtractIndexFromString(item_name);
-  if (idx == UINT32_MAX ||
-      (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()))
+  auto idx_or_err = ExtractIndexFromString(name.AsCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
+    return llvm::createStringError("Type has no child named '%s'",
+                                   name.AsCString());
+  }
+  uint32_t idx = *idx_or_err;
+  if (idx >= CalculateNumChildrenIgnoringErrors())
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   return idx;
@@ -616,10 +620,14 @@ template <typename D32, typename D64, bool Inline>
 llvm::Expected<size_t>
 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<
     D32, D64, Inline>::GetIndexOfChildWithName(ConstString name) {
-  const char *item_name = name.GetCString();
-  uint32_t idx = ExtractIndexFromString(item_name);
-  if (idx == UINT32_MAX ||
-      (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()))
+  auto idx_or_err = ExtractIndexFromString(name.AsCString());
+  if (!idx_or_err) {
+    llvm::consumeError(idx_or_err.takeError());
+    return llvm::createStringError("Type has no child named '%s'",
+                                   name.AsCString());
+  }
+  uint32_t idx = *idx_or_err;
+  if (idx >= CalculateNumChildrenIgnoringErrors())
     return llvm::createStringError("Type has no child named '%s'",
                                    name.AsCString());
   return idx;
diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
index b04b4610a0bf4..babf638a54ee6 100644
--- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -587,10 +587,14 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
 
 llvm::Expected<size_t> lldb_private::formatters::
     NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
-  const char *item_name = name.GetCString();
-  uint32_t idx = ExtractIndexFromString(item_name);
-  if (idx == UINT32_MAX ||
-      (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()))
+  auto idx_or_err = ExtractIndexFromString(name.AsCString());
+  if (!idx_or_err) {
+    llvm::c...
[truncated]

Copy link
Member

@bulbazord bulbazord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of this PR (big fan of llvm::Expected) but the way this is implemented contains an anti-pattern IMO. Specifically, all callers consume the error from ExtractIndexFromString only to then create a similar but different error string afterwards. It would be great if the callers could just propagate the error from ExtractIndexFromString instead of doing this dance.

Perhaps ExtractIndexFromString could return the error string Type has no child named '%s' and the function could be named something more descriptive? Something like ExtractIndexOfChildFromString?

@Michael137
Copy link
Member

Michael137 commented May 2, 2025

I like the idea of this PR (big fan of llvm::Expected) but the way this is implemented contains an anti-pattern IMO. Specifically, all callers consume the error from ExtractIndexFromString only to then create a similar but different error string afterwards. It would be great if the callers could just propagate the error from ExtractIndexFromString instead of doing this dance.

Perhaps ExtractIndexFromString could return the error string Type has no child named '%s' and the function could be named something more descriptive? Something like ExtractIndexOfChildFromString?

+1

This is what I was afraid of when we discussed what kind of error we want to put into these Expected objects (#136693 (comment)). We now have this unwritten rule that forces us to consume the more detailed error at random places (e.g., in this case we created this artificial boundary where we can't bubble up detailed errors from the formatters, which forces us to consume the error from lower levels). What we really want is to consume this error just when we're about to present it to the user, so we can swap it for something more user-friendly. @adrian-prantl suggested that we create an Error object that holds both a generic/user-presentable message and the detailed message. I agree with @bulbazord that we should bubble the error up for now until we have such an object

@@ -97,18 +97,19 @@ void lldb_private::formatters::AddFilter(
category_sp->AddTypeFilter(type_name, match_type, filter_sp);
}

size_t lldb_private::formatters::ExtractIndexFromString(const char *item_name) {
llvm::Expected<size_t>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here I would just return a std::optional<>, since all of the StringErrors just say "this failed" without any specific other information, and that's something the caller can also piece together.

auto idx_or_err = ExtractIndexFromString(name.AsCString());
if (!idx_or_err) {
llvm::consumeError(idx_or_err.takeError());
return llvm::createStringError("Type has no child named '%s'",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment above. I would probably just return optional from ExtractIndexFromString, since the error message isn't that useful. But if it were useful, I wanted to point out that we also have llvm::joinErrors()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up switching to std::optional following the different discussions. The error message are not very descriptive, and not finding an index did not mean there was an error, but rather that the name was not found in the string.

@Michael137 Michael137 changed the title [lldb] Upgrade ExtractIndexFromString to use llvm::Expected [lldb][DataFormatters] Change ExtractIndexFromString to return std::optional May 7, 2025
@Michael137 Michael137 merged commit 0d47a45 into llvm:main May 8, 2025
10 checks passed
charles-zablit added a commit to charles-zablit/llvm-project that referenced this pull request May 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants