Author: Adrian Prantl Date: 2024-03-11T13:04:56-07:00 New Revision: 6462eadbd316aed1b1074ed73bcaf1698886bba1
URL: https://github.com/llvm/llvm-project/commit/6462eadbd316aed1b1074ed73bcaf1698886bba1 DIFF: https://github.com/llvm/llvm-project/commit/6462eadbd316aed1b1074ed73bcaf1698886bba1.diff LOG: Report back errors in GetNumChildren() (#84265) 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 https://github.com/llvm/llvm-project/pull/83501 and https://github.com/llvm/llvm-project/pull/84219 Added: lldb/test/API/functionalities/valobj_errors/Makefile lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py lldb/test/API/functionalities/valobj_errors/hidden.c lldb/test/API/functionalities/valobj_errors/main.c Modified: lldb/include/lldb/DataFormatters/ValueObjectPrinter.h lldb/source/Core/ValueObjectVariable.cpp lldb/source/DataFormatters/ValueObjectPrinter.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp lldb/source/Symbol/CompilerType.cpp lldb/test/Shell/SymbolFile/DWARF/x86/DW_AT_declaration-with-children.s lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test Removed: ################################################################################ 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..8a114005c493bf --- /dev/null +++ b/lldb/test/API/functionalities/valobj_errors/TestValueObjectErrors.py @@ -0,0 +1,14 @@ +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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits