Skip to content

Report back errors in GetNumChildren() #84265

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

Merged
merged 1 commit into from
Mar 11, 2024

Conversation

adrian-prantl
Copy link
Collaborator

This is a proof-of-concept patch that illustrates how to use the
Expected return values to surface rich error messages all the way up
to the ValueObjectPrinter.

This is the final patch in the series that includes #83501 and #84219

@llvmbot
Copy link
Member

llvmbot commented Mar 7, 2024

@llvm/pr-subscribers-lldb

Author: Adrian Prantl (adrian-prantl)

Changes

This is a proof-of-concept patch that illustrates how to use the
Expected return values to surface rich error messages all the way up
to the ValueObjectPrinter.

This is the final patch in the series that includes #83501 and #84219


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

76 Files Affected:

  • (modified) lldb/include/lldb/Core/ValueObject.h (+6-5)
  • (modified) lldb/include/lldb/Core/ValueObjectCast.h (+1-1)
  • (modified) lldb/include/lldb/Core/ValueObjectChild.h (+1-1)
  • (modified) lldb/include/lldb/Core/ValueObjectConstResult.h (+1-1)
  • (modified) lldb/include/lldb/Core/ValueObjectDynamicValue.h (+1-1)
  • (modified) lldb/include/lldb/Core/ValueObjectMemory.h (+1-1)
  • (modified) lldb/include/lldb/Core/ValueObjectRegister.h (+2-2)
  • (modified) lldb/include/lldb/Core/ValueObjectSyntheticFilter.h (+2-2)
  • (modified) lldb/include/lldb/Core/ValueObjectVTable.h (+1-1)
  • (modified) lldb/include/lldb/Core/ValueObjectVariable.h (+1-1)
  • (modified) lldb/include/lldb/DataFormatters/TypeSynthetic.h (+15-11)
  • (modified) lldb/include/lldb/DataFormatters/ValueObjectPrinter.h (+1-1)
  • (modified) lldb/include/lldb/DataFormatters/VectorIterator.h (+2-2)
  • (modified) lldb/include/lldb/Symbol/CompilerType.h (+3-2)
  • (modified) lldb/include/lldb/Symbol/Type.h (+1-1)
  • (modified) lldb/include/lldb/Symbol/TypeSystem.h (+4-3)
  • (modified) lldb/include/lldb/Target/StackFrameRecognizer.h (+2-1)
  • (modified) lldb/source/API/SBValue.cpp (+2-1)
  • (modified) lldb/source/Core/FormatEntity.cpp (+2-1)
  • (modified) lldb/source/Core/IOHandlerCursesGUI.cpp (+2-1)
  • (modified) lldb/source/Core/ValueObject.cpp (+21-10)
  • (modified) lldb/source/Core/ValueObjectCast.cpp (+4-2)
  • (modified) lldb/source/Core/ValueObjectChild.cpp (+4-2)
  • (modified) lldb/source/Core/ValueObjectConstResult.cpp (+5-2)
  • (modified) lldb/source/Core/ValueObjectDynamicValue.cpp (+5-2)
  • (modified) lldb/source/Core/ValueObjectMemory.cpp (+7-3)
  • (modified) lldb/source/Core/ValueObjectRegister.cpp (+9-4)
  • (modified) lldb/source/Core/ValueObjectSyntheticFilter.cpp (+22-15)
  • (modified) lldb/source/Core/ValueObjectVTable.cpp (+4-2)
  • (modified) lldb/source/Core/ValueObjectVariable.cpp (+7-3)
  • (modified) lldb/source/DataFormatters/FormatManager.cpp (+8-3)
  • (modified) lldb/source/DataFormatters/TypeSynthetic.cpp (+5-3)
  • (modified) lldb/source/DataFormatters/ValueObjectPrinter.cpp (+20-5)
  • (modified) lldb/source/DataFormatters/VectorType.cpp (+10-5)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (+2-1)
  • (modified) lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp (+3-1)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp (+4-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp (+4-4)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/Coroutines.h (+2-2)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp (+10-5)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp (+13-13)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxx.h (+8-8)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp (+5-5)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp (+5-5)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp (+10-10)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp (+11-9)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp (+2-2)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp (+2-2)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp (+5-5)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp (+5-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp (+6-6)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp (+5-5)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp (+3-3)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp (+12-11)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp (+17-10)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp (+8-5)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp (+5-4)
  • (modified) lldb/source/Plugins/Language/ObjC/Cocoa.cpp (+2-2)
  • (modified) lldb/source/Plugins/Language/ObjC/NSArray.cpp (+25-23)
  • (modified) lldb/source/Plugins/Language/ObjC/NSDictionary.cpp (+54-44)
  • (modified) lldb/source/Plugins/Language/ObjC/NSError.cpp (+2-2)
  • (modified) lldb/source/Plugins/Language/ObjC/NSException.cpp (+2-4)
  • (modified) lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp (+6-3)
  • (modified) lldb/source/Plugins/Language/ObjC/NSSet.cpp (+30-23)
  • (modified) lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp (+4-1)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+25-12)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+4-3)
  • (modified) lldb/source/Symbol/CompilerType.cpp (+5-3)
  • (modified) lldb/source/Symbol/Type.cpp (+1-1)
  • (modified) lldb/source/Symbol/Variable.cpp (+3-1)
  • (modified) lldb/source/Target/StackFrame.cpp (+8-5)
  • (added) lldb/test/API/functionalities/valobj_errors/Makefile (+9)
  • (added) lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py (+15)
  • (added) lldb/test/API/functionalities/valobj_errors/hidden.c (+3)
  • (added) lldb/test/API/functionalities/valobj_errors/main.c (+9)
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 4c0b0b2dae6cd4..652bbef0516eca 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -465,7 +465,7 @@ class ValueObject {
   /// Returns a unique id for this ValueObject.
   lldb::user_id_t GetID() const { return m_id.GetID(); }
 
-  virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx,
+  virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx,
                                               bool can_create = true);
 
   // The method always creates missing children in the path, if necessary.
@@ -476,7 +476,7 @@ class ValueObject {
 
   virtual size_t GetIndexOfChildWithName(llvm::StringRef name);
 
-  size_t GetNumChildren(uint32_t max = UINT32_MAX);
+  llvm::Expected<uint32_t> GetNumChildren(uint32_t max = UINT32_MAX);
 
   const Value &GetValue() const { return m_value; }
 
@@ -791,7 +791,7 @@ class ValueObject {
       return (m_children.find(idx) != m_children.end());
     }
 
-    ValueObject *GetChildAtIndex(size_t idx) {
+    ValueObject *GetChildAtIndex(uint32_t idx) {
       std::lock_guard<std::recursive_mutex> guard(m_mutex);
       const auto iter = m_children.find(idx);
       return ((iter == m_children.end()) ? nullptr : iter->second);
@@ -958,9 +958,10 @@ class ValueObject {
                                           int32_t synthetic_index);
 
   /// Should only be called by ValueObject::GetNumChildren().
-  virtual size_t CalculateNumChildren(uint32_t max = UINT32_MAX) = 0;
+  virtual llvm::Expected<uint32_t>
+  CalculateNumChildren(uint32_t max = UINT32_MAX) = 0;
 
-  void SetNumChildren(size_t num_children);
+  void SetNumChildren(uint32_t num_children);
 
   void SetValueDidChange(bool value_changed) {
     m_flags.m_value_did_change = value_changed;
diff --git a/lldb/include/lldb/Core/ValueObjectCast.h b/lldb/include/lldb/Core/ValueObjectCast.h
index fe053c12d9c343..ba25e166f32688 100644
--- a/lldb/include/lldb/Core/ValueObjectCast.h
+++ b/lldb/include/lldb/Core/ValueObjectCast.h
@@ -33,7 +33,7 @@ class ValueObjectCast : public ValueObject {
 
   std::optional<uint64_t> GetByteSize() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   lldb::ValueType GetValueType() const override;
 
diff --git a/lldb/include/lldb/Core/ValueObjectChild.h b/lldb/include/lldb/Core/ValueObjectChild.h
index 46b14e6840f0dc..1f88e607cb5737 100644
--- a/lldb/include/lldb/Core/ValueObjectChild.h
+++ b/lldb/include/lldb/Core/ValueObjectChild.h
@@ -39,7 +39,7 @@ class ValueObjectChild : public ValueObject {
 
   lldb::ValueType GetValueType() const override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   ConstString GetTypeName() override;
 
diff --git a/lldb/include/lldb/Core/ValueObjectConstResult.h b/lldb/include/lldb/Core/ValueObjectConstResult.h
index d61df859bebce4..37dc0867f26c9e 100644
--- a/lldb/include/lldb/Core/ValueObjectConstResult.h
+++ b/lldb/include/lldb/Core/ValueObjectConstResult.h
@@ -67,7 +67,7 @@ class ValueObjectConstResult : public ValueObject {
 
   lldb::ValueType GetValueType() const override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   ConstString GetTypeName() override;
 
diff --git a/lldb/include/lldb/Core/ValueObjectDynamicValue.h b/lldb/include/lldb/Core/ValueObjectDynamicValue.h
index 2758b4e5bb564d..82c20eee0cd42d 100644
--- a/lldb/include/lldb/Core/ValueObjectDynamicValue.h
+++ b/lldb/include/lldb/Core/ValueObjectDynamicValue.h
@@ -43,7 +43,7 @@ class ValueObjectDynamicValue : public ValueObject {
 
   ConstString GetDisplayTypeName() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   lldb::ValueType GetValueType() const override;
 
diff --git a/lldb/include/lldb/Core/ValueObjectMemory.h b/lldb/include/lldb/Core/ValueObjectMemory.h
index 3c01df388d2e6d..a8fb0353d601b2 100644
--- a/lldb/include/lldb/Core/ValueObjectMemory.h
+++ b/lldb/include/lldb/Core/ValueObjectMemory.h
@@ -47,7 +47,7 @@ class ValueObjectMemory : public ValueObject {
 
   ConstString GetDisplayTypeName() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   lldb::ValueType GetValueType() const override;
 
diff --git a/lldb/include/lldb/Core/ValueObjectRegister.h b/lldb/include/lldb/Core/ValueObjectRegister.h
index 2e47eee3d7f793..fec8566ba33d90 100644
--- a/lldb/include/lldb/Core/ValueObjectRegister.h
+++ b/lldb/include/lldb/Core/ValueObjectRegister.h
@@ -47,7 +47,7 @@ class ValueObjectRegisterSet : public ValueObject {
 
   ConstString GetQualifiedTypeName() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member,
                                   int32_t synthetic_index) override;
@@ -95,7 +95,7 @@ class ValueObjectRegister : public ValueObject {
 
   ConstString GetTypeName() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   bool SetValueFromCString(const char *value_str, Status &error) override;
 
diff --git a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
index 67596232eafd1e..ca6d6c728005db 100644
--- a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
+++ b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -47,11 +47,11 @@ class ValueObjectSynthetic : public ValueObject {
 
   bool MightHaveChildren() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   lldb::ValueType GetValueType() const override;
 
-  lldb::ValueObjectSP GetChildAtIndex(size_t idx,
+  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx,
                                       bool can_create = true) override;
 
   lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name,
diff --git a/lldb/include/lldb/Core/ValueObjectVTable.h b/lldb/include/lldb/Core/ValueObjectVTable.h
index 217ff8d0d334ce..4662f395a4dde9 100644
--- a/lldb/include/lldb/Core/ValueObjectVTable.h
+++ b/lldb/include/lldb/Core/ValueObjectVTable.h
@@ -64,7 +64,7 @@ class ValueObjectVTable : public ValueObject {
 
   std::optional<uint64_t> GetByteSize() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member,
                                   int32_t synthetic_index) override;
diff --git a/lldb/include/lldb/Core/ValueObjectVariable.h b/lldb/include/lldb/Core/ValueObjectVariable.h
index bba28ce567b2a0..db3847f14a0b5a 100644
--- a/lldb/include/lldb/Core/ValueObjectVariable.h
+++ b/lldb/include/lldb/Core/ValueObjectVariable.h
@@ -46,7 +46,7 @@ class ValueObjectVariable : public ValueObject {
 
   ConstString GetDisplayTypeName() override;
 
-  size_t CalculateNumChildren(uint32_t max) override;
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
   lldb::ValueType GetValueType() const override;
 
diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index 23cc054b399a67..1c47b32c0ecc54 100644
--- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -38,14 +38,16 @@ class SyntheticChildrenFrontEnd {
 
   virtual ~SyntheticChildrenFrontEnd() = default;
 
-  virtual size_t CalculateNumChildren() = 0;
+  virtual llvm::Expected<uint32_t> CalculateNumChildren() = 0;
 
-  virtual size_t CalculateNumChildren(uint32_t max) {
+  virtual llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) {
     auto count = CalculateNumChildren();
-    return count <= max ? count : max;
+    if (!count)
+      return count;
+    return *count <= max ? *count : max;
   }
 
-  virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx) = 0;
+  virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) = 0;
 
   virtual size_t GetIndexOfChildWithName(ConstString name) = 0;
 
@@ -109,9 +111,9 @@ class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd {
 
   ~SyntheticValueProviderFrontEnd() override = default;
 
-  size_t CalculateNumChildren() override { return 0; }
+  llvm::Expected<uint32_t> CalculateNumChildren() override { return 0; }
 
-  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; }
+  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return nullptr; }
 
   size_t GetIndexOfChildWithName(ConstString name) override {
     return UINT32_MAX;
@@ -322,9 +324,11 @@ class TypeFilterImpl : public SyntheticChildren {
 
     ~FrontEnd() override = default;
 
-    size_t CalculateNumChildren() override { return filter->GetCount(); }
+    llvm::Expected<uint32_t> CalculateNumChildren() override {
+      return filter->GetCount();
+    }
 
-    lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
+    lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
       if (idx >= filter->GetCount())
         return lldb::ValueObjectSP();
       return m_backend.GetSyntheticExpressionPathChild(
@@ -426,11 +430,11 @@ class ScriptedSyntheticChildren : public SyntheticChildren {
 
     bool IsValid();
 
-    size_t CalculateNumChildren() override;
+    llvm::Expected<uint32_t> CalculateNumChildren() override;
 
-    size_t CalculateNumChildren(uint32_t max) override;
+    llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override;
 
-    lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+    lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
 
     lldb::ChildCacheState Update() override;
 
diff --git a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
index fe46321c3186cf..32b101a2f9843c 100644
--- a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
+++ b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
@@ -127,7 +127,7 @@ class ValueObjectPrinter {
   void PrintChild(lldb::ValueObjectSP child_sp,
                   const DumpValueObjectOptions::PointerDepth &curr_ptr_depth);
 
-  uint32_t GetMaxNumChildrenToPrint(bool &print_dotdotdot);
+  llvm::Expected<uint32_t> GetMaxNumChildrenToPrint(bool &print_dotdotdot);
 
   void
   PrintChildren(bool value_printed, bool summary_printed,
diff --git a/lldb/include/lldb/DataFormatters/VectorIterator.h b/lldb/include/lldb/DataFormatters/VectorIterator.h
index 5f774bb72c3a3a..70bcf50ca1b1d2 100644
--- a/lldb/include/lldb/DataFormatters/VectorIterator.h
+++ b/lldb/include/lldb/DataFormatters/VectorIterator.h
@@ -24,9 +24,9 @@ class VectorIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
   VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,
                                   llvm::ArrayRef<ConstString> item_names);
 
-  size_t CalculateNumChildren() override;
+  llvm::Expected<uint32_t> CalculateNumChildren() override;
 
-  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
 
   lldb::ChildCacheState Update() override;
 
diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index 414c44275aaafc..c1dce4ccbf79c2 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -386,8 +386,9 @@ class CompilerType {
 
   std::optional<size_t> GetTypeBitAlign(ExecutionContextScope *exe_scope) const;
 
-  uint32_t GetNumChildren(bool omit_empty_base_classes,
-                          const ExecutionContext *exe_ctx) const;
+  llvm::Expected<uint32_t>
+  GetNumChildren(bool omit_empty_base_classes,
+                 const ExecutionContext *exe_ctx) const;
 
   lldb::BasicType GetBasicTypeEnumeration() const;
 
diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h
index acd1a769f13cd6..b5eac5fa732d67 100644
--- a/lldb/include/lldb/Symbol/Type.h
+++ b/lldb/include/lldb/Symbol/Type.h
@@ -440,7 +440,7 @@ class Type : public std::enable_shared_from_this<Type>, public UserID {
 
   std::optional<uint64_t> GetByteSize(ExecutionContextScope *exe_scope);
 
-  uint32_t GetNumChildren(bool omit_empty_base_classes);
+  llvm::Expected<uint32_t> GetNumChildren(bool omit_empty_base_classes);
 
   bool IsAggregateType();
 
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index 63829131556e87..f647fcbf1636ea 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -300,9 +300,10 @@ class TypeSystem : public PluginInterface,
 
   virtual lldb::Format GetFormat(lldb::opaque_compiler_type_t type) = 0;
 
-  virtual uint32_t GetNumChildren(lldb::opaque_compiler_type_t type,
-                                  bool omit_empty_base_classes,
-                                  const ExecutionContext *exe_ctx) = 0;
+  virtual llvm::Expected<uint32_t>
+  GetNumChildren(lldb::opaque_compiler_type_t type,
+                 bool omit_empty_base_classes,
+                 const ExecutionContext *exe_ctx) = 0;
 
   virtual CompilerType GetBuiltinTypeByName(ConstString name);
 
diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h
index 419f0c0aac1f86..5e8e12b2a4e961 100644
--- a/lldb/include/lldb/Target/StackFrameRecognizer.h
+++ b/lldb/include/lldb/Target/StackFrameRecognizer.h
@@ -164,7 +164,8 @@ class ValueObjectRecognizerSynthesizedValue : public ValueObject {
     m_value = m_parent->GetValue();
     return true;
   }
-  size_t CalculateNumChildren(uint32_t max = UINT32_MAX) override {
+  llvm::Expected<uint32_t>
+  CalculateNumChildren(uint32_t max = UINT32_MAX) override {
     return m_parent->GetNumChildren(max);
   }
   CompilerType GetCompilerTypeImpl() override {
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 89d26a1fbe2824..6668f642ab2ef5 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -947,7 +947,8 @@ uint32_t SBValue::GetNumChildren(uint32_t max) {
   ValueLocker locker;
   lldb::ValueObjectSP value_sp(GetSP(locker));
   if (value_sp)
-    num_children = value_sp->GetNumChildren(max);
+    num_children =
+        llvm::expectedToStdOptional(value_sp->GetNumChildren(max)).value_or(0);
 
   return num_children;
 }
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index fa5eadc6ff4e9a..5e8cd2e1dda39f 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -926,7 +926,8 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
     s.PutChar('[');
 
     if (index_higher < 0)
-      index_higher = valobj->GetNumChildren() - 1;
+      index_higher =
+          llvm::expectedToStdOptional(valobj->GetNumChildren()).value_or(0) - 1;
 
     uint32_t max_num_children =
         target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp
index 620e68a28510ef..dcb83aa692a1c1 100644
--- a/lldb/source/Core/IOHandlerCursesGUI.cpp
+++ b/lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -4519,7 +4519,8 @@ struct Row {
       calculated_children = true;
       ValueObjectSP valobj = value.GetSP();
       if (valobj) {
-        const size_t num_children = valobj->GetNumChildren();
+        const size_t num_children =
+            llvm::expectedToStdOptional(valobj->GetNumChildren()).value_or(0);
         for (size_t i = 0; i < num_children; ++i) {
           children.push_back(Row(valobj->GetChildAtIndex(i), this));
         }
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 840b100c70ddaa..03fb3c86d89394 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -372,12 +372,12 @@ bool ValueObject::IsLogicalTrue(Status &error) {
   return ret;
 }
 
-ValueObjectSP ValueObject::GetChildAtIndex(size_t idx, bool can_create) {
+ValueObjectSP ValueObject::GetChildAtIndex(uint32_t idx, bool can_create) {
   ValueObjectSP child_sp;
   // We may need to update our value if we are dynamic
   if (IsPossibleDynamicType())
     UpdateValueIfNeeded(false);
-  if (idx < GetNumChildren()) {
+  if (idx < llvm::expectedToStdOptional(GetNumChildren()).value_or(0)) {
     // Check if we have already made the child value object?
     if (can_create && !m_children.HasChildAtIndex(idx)) {
       // No we haven't created the child at this index, so lets have our
@@ -440,7 +440,7 @@ ValueObjectSP ValueObject::GetChildMemberWithName(llvm::StringRef name,
   return child_sp;
 }
 
-size_t ValueObject::GetNumChildren(uint32_t max) {
+llvm::Expected<uint32_t> ValueObject::GetNumChildren(uint32_t max) {
   UpdateValueIfNeeded();
 
   if (max < UINT32_MAX) {
@@ -452,7 +452,11 @@ size_t ValueObject::GetNumChildren(uint32_t max) {
   }
 
   if (!m_flags.m_children_count_valid) {
-    SetNumChildren(CalculateNumChildren());
+    auto num_children_or_err = CalculateNumChildren();
+    if (num_children_or_err)
+      SetNumChildren(*num_children_or_err);
+    else
+      return num_children_or_err;
   }
   return m_children.GetChildrenCount();
 }
@@ -464,13 +468,14 @@ bool ValueObject::MightHaveChildren() {
     if (type_info & (eTypeHasChildren | eTypeIsPointer | eTypeIsReference))
       has_children = true;
   } else {
-    has_children = GetNumChildren() > 0;
+    has_children =
+        llvm::expectedToStdOptional(GetNumChildren()).value_or(0) > 0;
   }
   return has_children;
 }
 
 // Should only be called by ValueObject::GetNumChildren()
-void ValueObject::SetNumChildren(size_t num_children) {
+void ValueObject::SetNumChildren(uint32_t num_children) {
   m_flags.m_children_count_valid = true;
   m_children.SetChildrenCount(num_children);
 }
@@ -1176,7 +1181,8 @@ bool ValueObject::DumpPrintableRepresentation(
       if (flags.Test(eTypeIsArray)) {
         if ((custom_format == eFormatBytes) ||
             (custom_format == eFormatBytesWithASCII)) {
-          const size_t count = GetNumChildren();
+          const size_t count =
+              llvm::expectedToStdOptional(GetNumChildren()).value_or(0);
 
           s << '[';
           for (size_t low = 0; low < count; low++) {
@@ -1215,7 +1221,8 @@ bool ValueObject::DumpPrintableRepresentation(
                                                      // format should be printed
                                                      // directly
         {
-          const size_t count = GetNumChildren();
+          const size_t count =
+              llvm::expectedToStdOptional(GetNumChildren()).value_or(0);
 
           Format format = FormatManager::GetSingleItemFormat(custom_format);
 
@@ -1294,7 +1301,9 @@ bool ValueObject::DumpPrintableRepresentation(
       break;
 
     case eValueObjectRepresentationStyleChildrenCount:
-      strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren());
+      strm.Printf(
+          "%" PRIu64 "",
+          (uint64_t)llvm::expectedToStdOptional(GetNumChildren()).value_or(0));
       str = strm.GetString();
       break;
 
@@ -2320,7 +2329,9 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl(
             child_valobj_sp = root->GetSyntheticArrayMember(index, true);
           if (!child_valobj_sp)
             if (root->HasSyntheticValue() &&
-                root->GetSyntheticValue()->GetNumChildren() > index)
+                llvm::expectedToStdOptional(
+                    root->GetSyntheticValue()->GetNumChildren())
+                        .value_or(0) > index)
               child_valobj_sp =
                   root->GetSyntheticValue()->GetChildAtIndex(index);
           if (child_valobj_sp) {
diff --git a/lldb/source/Core/ValueObjectCast.cpp b/lldb/source/Core/ValueObjectCast.cpp
index 0882d4b3677619..c8e31641514170 100644
--- a/lldb/source/Core/ValueObjectCast.cpp
+++ b/lldb/source/Core/ValueObjectCast.cpp
@@ -41,11 +41,13 @@ ValueObjectCast::~ValueObjectCast() =...
[truncated]

@adrian-prantl
Copy link
Collaborator Author

Ran command:
"v -ptr-depth 1 x"

Got output:
(Opaque *) x = 0x0000000100008000 <incomplete type "Opaque">

Copy link

github-actions bot commented Mar 7, 2024

⚠️ Python code formatter, darker found issues in your code. ⚠️

You can test this locally with the following command:
darker --check --diff -r 94c988bcfdea596e5c9078be8ec28688eb0d96a3...18812772780abee17dd106e0e8f8c78ab8d4dbf1 lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py
View the diff from darker here.
--- TestValueObjectErrors.py	2024-03-11 20:04:06.000000 +0000
+++ TestValueObjectErrors.py	2024-03-11 20:07:42.817865 +0000
@@ -7,8 +7,7 @@
 class ValueObjectErrorsTestCase(TestBase):
     def test(self):
         """Test that the error message for a missing type
         is visible when printing an object"""
         self.build()
-        lldbutil.run_to_source_breakpoint(self, "break here",
-                                          lldb.SBFileSpec('main.c'))
-        self.expect('v -ptr-depth 1 x', substrs=['<incomplete type "Opaque">'])
+        lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
+        self.expect("v -ptr-depth 1 x", substrs=['<incomplete type "Opaque">'])

Copy link

github-actions bot commented Mar 7, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@jimingham
Copy link
Collaborator

From looking at the code, it seems like there are two clear classes of users, those that need to check the error, and those that, in the error case, 0 is just as good as the error. The latter appears not infrequently as:

llvm::expectedToStdOptional(value_sp->GetNumChildren(max)).value_or(0)

which is a bit ugly, but also by embedding this everywhere inline it isn't easy to see who is checking errors and who doesn't need to.

Might be useful to have a GetNumChildrenUnchecked that returns 0 for the error, and use that in place of sprinkling this construct about.

@adrian-prantl
Copy link
Collaborator Author

From looking at the code, it seems like there are two clear classes of users, those that need to check the error, and those that, in the error case, 0 is just as good as the error. The latter appears not infrequently as:

llvm::expectedToStdOptional(value_sp->GetNumChildren(max)).value_or(0)

which is a bit ugly, but also by embedding this everywhere inline it isn't easy to see who is checking errors and who doesn't need to.

Might be useful to have a GetNumChildrenUnchecked that returns 0 for the error, and use that in place of sprinkling this construct about.

See the latest update in #84219

@adrian-prantl adrian-prantl force-pushed the numchildren-errormsg branch from cb496e1 to ea303d0 Compare March 8, 2024 17:58
@adrian-prantl
Copy link
Collaborator Author

Rebased

@adrian-prantl adrian-prantl requested a review from jimingham March 8, 2024 18:23
@adrian-prantl adrian-prantl force-pushed the numchildren-errormsg branch 5 times, most recently from 9b02d00 to 78866b8 Compare March 9, 2024 00:44
@adrian-prantl
Copy link
Collaborator Author

Found two more tests that were (positively) affected by this change!

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

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

big fan, LGTM

@@ -12,7 +12,7 @@
target var a
# CHECK-LABEL: target var a
# FIXME: This should also produce some kind of an error.
# CHECK: (A) a = {}
# CHECK: (A) a = <incomplete type "A">
Copy link
Member

Choose a reason for hiding this comment

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

nice!

This is a proof-of-concept patch that illustrates how to use the
Expected return values to surface rich error messages all the way up
to the ValueObjectPrinter.
@adrian-prantl adrian-prantl merged commit 6462ead into llvm:main Mar 11, 2024
adrian-prantl added a commit to adrian-prantl/llvm-project that referenced this pull request Mar 11, 2024
This is a proof-of-concept patch that illustrates how to use the
Expected return values to surface rich error messages all the way up
to the ValueObjectPrinter.

This is the final patch in the series that includes
llvm#83501 and
llvm#84219

(cherry picked from commit 6462ead)
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