[Lldb-commits] [lldb] Report back errors in GetNumChildren() (PR #84265)

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Fri Mar 8 16:44:12 PST 2024


https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/84265

>From 78866b8977b655109d85bd1c231b1659c5c90c8a Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Fri, 8 Mar 2024 14:46:13 -0800
Subject: [PATCH] Report back errors in GetNumChildren()

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.
---
 .../lldb/DataFormatters/ValueObjectPrinter.h  |  2 +-
 lldb/source/Core/ValueObjectVariable.cpp      |  3 ++-
 .../DataFormatters/ValueObjectPrinter.cpp     | 22 +++++++++++++++----
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  9 +++++---
 lldb/source/Symbol/CompilerType.cpp           |  3 ++-
 .../functionalities/valobj_errors/Makefile    |  9 ++++++++
 .../valobj_errors/TestValueObjectErrors.py    | 15 +++++++++++++
 .../functionalities/valobj_errors/hidden.c    |  4 ++++
 .../API/functionalities/valobj_errors/main.c  |  9 ++++++++
 .../x86/DW_AT_declaration-with-children.s     |  2 +-
 .../x86/debug-types-missing-signature.test    |  2 +-
 11 files changed, 68 insertions(+), 12 deletions(-)
 create mode 100644 lldb/test/API/functionalities/valobj_errors/Makefile
 create mode 100644 lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py
 create mode 100644 lldb/test/API/functionalities/valobj_errors/hidden.c
 create mode 100644 lldb/test/API/functionalities/valobj_errors/main.c

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/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp
index fb29c22c0ab5af..67d71c90a959d5 100644
--- a/lldb/source/Core/ValueObjectVariable.cpp
+++ b/lldb/source/Core/ValueObjectVariable.cpp
@@ -99,7 +99,8 @@ ValueObjectVariable::CalculateNumChildren(uint32_t max) {
   CompilerType type(GetCompilerType());
 
   if (!type.IsValid())
-    return 0;
+    return llvm::make_error<llvm::StringError>("invalid type",
+                                               llvm::inconvertibleErrorCode());
 
   ExecutionContext exe_ctx(GetExecutionContextRef());
   const bool omit_empty_base_classes = true;
diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
index b853199e878c95..bbdc2a99815706 100644
--- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -621,13 +621,17 @@ void ValueObjectPrinter::PrintChild(
   }
 }
 
-uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) {
+llvm::Expected<uint32_t>
+ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) {
   ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();
 
   if (m_options.m_pointer_as_array)
     return m_options.m_pointer_as_array.m_element_count;
 
-  uint32_t num_children = synth_valobj.GetNumChildrenIgnoringErrors();
+  auto num_children_or_err = synth_valobj.GetNumChildren();
+  if (!num_children_or_err)
+    return num_children_or_err;
+  uint32_t num_children = *num_children_or_err;
   print_dotdotdot = false;
   if (num_children) {
     const size_t max_num_children = GetMostSpecializedValue()
@@ -704,7 +708,12 @@ void ValueObjectPrinter::PrintChildren(
   ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();
 
   bool print_dotdotdot = false;
-  size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
+  auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);
+  if (!num_children_or_err) {
+    *m_stream << " <" << llvm::toString(num_children_or_err.takeError()) << '>';
+    return;
+  }
+  uint32_t num_children = *num_children_or_err;
   if (num_children) {
     bool any_children_printed = false;
 
@@ -753,7 +762,12 @@ bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
   ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();
 
   bool print_dotdotdot = false;
-  size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
+  auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);
+  if (!num_children_or_err) {
+    *m_stream << '<' << llvm::toString(num_children_or_err.takeError()) << '>';
+    return true;
+  }
+  uint32_t num_children = *num_children_or_err;
 
   if (num_children) {
     m_stream->PutChar('(');
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index c02b08cb478280..68d9165b90a47b 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -5268,7 +5268,8 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
                                 bool omit_empty_base_classes,
                                 const ExecutionContext *exe_ctx) {
   if (!type)
-    return 0;
+    return llvm::make_error<llvm::StringError>("invalid clang type",
+                                               llvm::inconvertibleErrorCode());
 
   uint32_t num_children = 0;
   clang::QualType qual_type(RemoveWrappingTypes(GetQualType(type)));
@@ -5325,9 +5326,11 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
       }
       num_children += std::distance(record_decl->field_begin(),
                                record_decl->field_end());
-    }
+    } else
+      return llvm::make_error<llvm::StringError>(
+          "incomplete type \"" + GetDisplayTypeName(type).GetString() + "\"",
+          llvm::inconvertibleErrorCode());
     break;
-
   case clang::Type::ObjCObject:
   case clang::Type::ObjCInterface:
     if (GetCompleteQualType(&getASTContext(), qual_type)) {
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index 85dd2d841a5a0c..8e4c3c761f784e 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -777,7 +777,8 @@ CompilerType::GetNumChildren(bool omit_empty_base_classes,
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetNumChildren(m_type, omit_empty_base_classes,
                                        exe_ctx);
-  return 0;
+  return llvm::make_error<llvm::StringError>("invalid type",
+                                             llvm::inconvertibleErrorCode());
 }
 
 lldb::BasicType CompilerType::GetBasicTypeEnumeration() const {
diff --git a/lldb/test/API/functionalities/valobj_errors/Makefile b/lldb/test/API/functionalities/valobj_errors/Makefile
new file mode 100644
index 00000000000000..d2c966a71411b2
--- /dev/null
+++ b/lldb/test/API/functionalities/valobj_errors/Makefile
@@ -0,0 +1,9 @@
+C_SOURCES := main.c
+LD_EXTRAS = hidden.o
+
+a.out: hidden.o
+
+hidden.o: hidden.c
+	$(CC) -g0 -c -o $@ $<
+
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py b/lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py
new file mode 100644
index 00000000000000..5346e61b2b0c45
--- /dev/null
+++ b/lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py
@@ -0,0 +1,15 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+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">'])
diff --git a/lldb/test/API/functionalities/valobj_errors/hidden.c b/lldb/test/API/functionalities/valobj_errors/hidden.c
new file mode 100644
index 00000000000000..d3b93ce1ab9cf5
--- /dev/null
+++ b/lldb/test/API/functionalities/valobj_errors/hidden.c
@@ -0,0 +1,4 @@
+struct Opaque {
+  int i, j, k;
+} *global;
+struct Opaque *getOpaque() { return &global; }
diff --git a/lldb/test/API/functionalities/valobj_errors/main.c b/lldb/test/API/functionalities/valobj_errors/main.c
new file mode 100644
index 00000000000000..fabdca9d3a2ecd
--- /dev/null
+++ b/lldb/test/API/functionalities/valobj_errors/main.c
@@ -0,0 +1,9 @@
+struct Opaque;
+struct Opaque *getOpaque();
+void puts(const char *);
+
+int main() {
+  struct Opaque *x = getOpaque();
+  puts("break here\n");
+  return (int)x;
+}
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_AT_declaration-with-children.s b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_AT_declaration-with-children.s
index bc462ca32e9ce0..8633d02f492e67 100644
--- a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_AT_declaration-with-children.s
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_AT_declaration-with-children.s
@@ -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">
 expr a
 # CHECK-LABEL: expr a
 # CHECK: incomplete type 'A' where a complete type is required
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test
index e94b10a68d4e93..548dd6cdbc2753 100644
--- a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test
@@ -21,6 +21,6 @@ RUN: not %lldb %t -b -o "expression (EC) 1" 2>&1 | FileCheck --check-prefix=PRIN
 PRINTEC: use of undeclared identifier 'EC'
 
 RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s
-VARS: (const (unnamed struct)) a = {}
+VARS: (const (unnamed struct)) a = <incomplete type "const (unnamed struct)">
 VARS: (const (unnamed enum)) e = 0x1
 VARS: (const (unnamed enum)) ec = 0x1



More information about the lldb-commits mailing list