[Lldb-commits] [lldb] fd0ecac - [lldb] Surface GetIndexOfChildWithName errors instead of dropping them (#224059)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Sep 17 08:57:16 PDT 2026
Author: Charles Zablit
Date: 2026-09-17T16:57:10+01:00
New Revision: fd0ecaccdc131ae3e541be4d1eb83d85758bf104
URL: https://github.com/llvm/llvm-project/commit/fd0ecaccdc131ae3e541be4d1eb83d85758bf104
DIFF: https://github.com/llvm/llvm-project/commit/fd0ecaccdc131ae3e541be4d1eb83d85758bf104.diff
LOG: [lldb] Surface GetIndexOfChildWithName errors instead of dropping them (#224059)
`ValueObjectSynthetic::GetChildMemberWithName` and
`SBValue::GetIndexOfChildWithName` called `llvm::consumeError` on the
`llvm::Expected` returned by `GetIndexOfChildWithName` and reported the
failure as a null `ValueObjectSP` / `UINT32_MAX`, so the reason a lookup
failed never reached anyone. Log them instead: `LLDBLog::DataFormatters`
from ValueObject and formatter code, `LLDBLog::API` at the SB boundary.
That is the convention `BlockPointer.cpp` and `LibCxx.cpp` already
follow.
Also, in `ValueObjectSynthetic::GetIndexOfChildWithName`:
- A front-end with `TypeOptions::eTypeOptionCustomSubscripting` that
failed to find the child left `index` at its `SIZE_MAX` initializer,
dropped the front-end's error unread, then cached `SIZE_MAX` in
`m_name_toindex` and returned it as a valid index. Return the
front-end's error instead.
- Call `GetNumChildren(max)` rather than
`GetNumChildrenIgnoringErrors(max)` for the `"[N]"` subscript bounds
check and propagate the error, so a child count that fails to compute is
no longer reported as a subscript that is out of range.
- Return early on a cache hit rather than falling through a chain of
else-if branches that retested `found_index`.
Lower-cases the two `"Type has no child named"` messages in
`TypeSynthetic.h` for consistency with every other instance of that
string.
Follow-up to the review on #136693.
rdar://150281004
rdar://150281080
Added:
Modified:
lldb/include/lldb/DataFormatters/TypeSynthetic.h
lldb/include/lldb/ValueObject/ValueObject.h
lldb/source/API/SBValue.cpp
lldb/source/ValueObject/ValueObjectSynthetic.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index 6eb06ba8dda7f..07d3f68f4849e 100644
--- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -53,7 +53,7 @@ class SyntheticChildrenFrontEnd {
/// subscripting behavior - for example a sparse array, disable automatic
/// subscripting with TypeOptions::eTypeOptionCustomSubscripting.
virtual llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) {
- return llvm::createStringErrorV("Type has no child named '{0}'", name);
+ return llvm::createStringErrorV("type has no child named '{0}'", name);
}
/// This function is assumed to always succeed and if it fails, the front-end
@@ -121,7 +121,7 @@ class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd {
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return nullptr; }
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
- return llvm::createStringErrorV("Type has no child named '{0}'", name);
+ return llvm::createStringErrorV("type has no child named '{0}'", name);
}
lldb::ChildCacheState Update() override {
diff --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h
index de69cf3882fd6..c336213c84e25 100644
--- a/lldb/include/lldb/ValueObject/ValueObject.h
+++ b/lldb/include/lldb/ValueObject/ValueObject.h
@@ -496,6 +496,11 @@ class ValueObject {
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name,
bool can_create = true);
+ /// Return the index of the child named \c name.
+ ///
+ /// The error is for LLDB developers, not for the user: a missing child is the
+ /// ordinary negative answer to a lookup. Callers that cannot propagate it
+ /// should log it rather than call \c llvm::consumeError.
virtual llvm::Expected<size_t> GetIndexOfChildWithName(llvm::StringRef name);
llvm::Expected<uint32_t> GetNumChildren(uint32_t max = UINT32_MAX);
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 449cafb85ef64..d2e2dc7e9646d 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -646,7 +646,7 @@ uint32_t SBValue::GetIndexOfChildWithName(const char *name) {
if (auto idx_or_err = value_sp->GetIndexOfChildWithName(name))
return *idx_or_err;
else
- llvm::consumeError(idx_or_err.takeError());
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), idx_or_err.takeError(), "{0}");
}
return UINT32_MAX;
}
diff --git a/lldb/source/ValueObject/ValueObjectSynthetic.cpp b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
index 74a3cfa4cc0f5..385ef0ca7c2a4 100644
--- a/lldb/source/ValueObject/ValueObjectSynthetic.cpp
+++ b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
@@ -332,7 +332,8 @@ ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name,
auto index_or_err = GetIndexOfChildWithName(name);
if (!index_or_err) {
- llvm::consumeError(index_or_err.takeError());
+ LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), index_or_err.takeError(),
+ "{0}");
return lldb::ValueObjectSP();
}
@@ -345,45 +346,48 @@ ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {
ConstString name(name_ref);
- std::optional<uint32_t> found_index = std::nullopt;
{
std::lock_guard<std::mutex> guard(m_child_mutex);
auto name_to_index = m_name_toindex.find(name.GetCString());
if (name_to_index != m_name_toindex.end())
- found_index = name_to_index->second;
+ return name_to_index->second;
}
- if (!found_index && m_synth_filter_up != nullptr) {
- size_t index = SIZE_MAX;
- if (auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name)) {
- index = *index_or_err;
- } else if (!m_synth_sp->CustomSubscripting()) {
- // Provide automatic support for subscript child names ("[N]").
- auto maybe_index = formatters::ExtractIndexFromString(name.GetCString());
- if (!maybe_index)
- // The child name was not of the form "[N]", return the original error.
- return index_or_err.takeError();
-
- // Subscripting succeeded, ignore the original error.
- llvm::consumeError(index_or_err.takeError());
- index = *maybe_index;
-
- // Prevent unnecessary work by limiting max to one past the index.
- uint32_t max = index + 1;
- auto num_children = GetNumChildrenIgnoringErrors(max);
- if (index >= num_children)
- return llvm::createStringErrorV("subscript index out of range: {0}",
- index);
- }
- std::lock_guard<std::mutex> guard(m_child_mutex);
- m_name_toindex[name.GetCString()] = index;
- return index;
- } else if (!found_index && m_synth_filter_up == nullptr) {
+ if (!m_synth_filter_up)
return llvm::createStringErrorV("type has no child named '{0}'", name);
- } else if (found_index)
- return *found_index;
- return llvm::createStringErrorV("type has no child named '{0}'", name);
+ size_t index;
+ auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name);
+ if (index_or_err) {
+ index = *index_or_err;
+ } else {
+ // The front-end does its own subscripting, so its answer is final.
+ if (m_synth_sp->CustomSubscripting())
+ return index_or_err.takeError();
+
+ // Provide automatic support for subscript child names ("[N]").
+ auto maybe_index = formatters::ExtractIndexFromString(name.GetCString());
+ if (!maybe_index)
+ // The child name was not of the form "[N]", return the original error.
+ return index_or_err.takeError();
+
+ // Subscripting succeeded, ignore the original error.
+ llvm::consumeError(index_or_err.takeError());
+ index = *maybe_index;
+
+ // Prevent unnecessary work by limiting max to one past the index.
+ uint32_t max = index + 1;
+ auto num_children = GetNumChildren(max);
+ if (!num_children)
+ return num_children.takeError();
+ if (index >= *num_children)
+ return llvm::createStringErrorV("subscript index out of range: {0}",
+ index);
+ }
+
+ std::lock_guard<std::mutex> guard(m_child_mutex);
+ m_name_toindex[name.GetCString()] = index;
+ return index;
}
bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
More information about the lldb-commits
mailing list