From 328d9f62976defb96cba8102ea54f44cf88c8032 Mon Sep 17 00:00:00 2001 From: David Spickett Date: Thu, 4 Jul 2024 07:51:47 +0000 Subject: [PATCH] Reland "[lldb] Print empty enums as if they were unrecognised normal enums (#97553)" This reverts commit 927def49728371d746476e79a6570cd93a4d335c. I've refactored the tests so that we're explicit about whether the enum is signed or not. Which means we use the proper types throughout. --- .../TypeSystem/Clang/TypeSystemClang.cpp | 33 +++++---- .../x86/debug-types-missing-signature.test | 4 +- .../DumpValueObjectOptionsTests.cpp | 72 ++++++++++++------- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 9c77a5d6e66eef..f70efe5ed57e46 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -8656,20 +8656,25 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s, // every enumerator is either a one bit value or a superset of the previous // enumerators. Also 0 doesn't make sense when the enumerators are used as // flags. - for (auto *enumerator : enum_decl->enumerators()) { - llvm::APSInt init_val = enumerator->getInitVal(); - uint64_t val = - qual_type_is_signed ? init_val.getSExtValue() : init_val.getZExtValue(); - if (qual_type_is_signed) - val = llvm::SignExtend64(val, 8 * byte_size); - if (llvm::popcount(val) != 1 && (val & ~covered_bits) != 0) - can_be_bitfield = false; - covered_bits |= val; - ++num_enumerators; - if (val == enum_svalue) { - // Found an exact match, that's all we need to do. - s.PutCString(enumerator->getNameAsString()); - return true; + clang::EnumDecl::enumerator_range enumerators = enum_decl->enumerators(); + if (enumerators.empty()) + can_be_bitfield = false; + else { + for (auto *enumerator : enumerators) { + llvm::APSInt init_val = enumerator->getInitVal(); + uint64_t val = qual_type_is_signed ? init_val.getSExtValue() + : init_val.getZExtValue(); + if (qual_type_is_signed) + val = llvm::SignExtend64(val, 8 * byte_size); + if (llvm::popcount(val) != 1 && (val & ~covered_bits) != 0) + can_be_bitfield = false; + covered_bits |= val; + ++num_enumerators; + if (val == enum_svalue) { + // Found an exact match, that's all we need to do. + s.PutCString(enumerator->getNameAsString()); + return true; + } } } 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 548dd6cdbc2753..b2c792ed6003e8 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 @@ -22,5 +22,5 @@ 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 enum)) e = 0x1 -VARS: (const (unnamed enum)) ec = 0x1 +VARS: (const (unnamed enum)) e = 1 +VARS: (const (unnamed enum)) ec = 1 diff --git a/lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp b/lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp index a7ccd74721f66f..950e981a3f5a4f 100644 --- a/lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp +++ b/lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp @@ -18,6 +18,8 @@ #include "gtest/gtest.h" +#include + using namespace lldb; using namespace lldb_private; @@ -70,28 +72,12 @@ class ValueObjectMockProcessTest : public ::testing::Test { m_type_system = m_holder->GetAST(); } - CompilerType - MakeEnumType(const std::vector> enumerators) { - CompilerType uint_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize( - lldb::eEncodingUint, 32); - CompilerType enum_type = m_type_system->CreateEnumerationType( - "TestEnum", m_type_system->GetTranslationUnitDecl(), - OptionalClangModuleID(), Declaration(), uint_type, false); - - m_type_system->StartTagDeclarationDefinition(enum_type); - Declaration decl; - for (auto [name, value] : enumerators) - m_type_system->AddEnumerationValueToEnumerationType(enum_type, decl, name, - value, 32); - m_type_system->CompleteTagDeclarationDefinition(enum_type); - - return enum_type; - } - - void TestDumpValueObject( - CompilerType enum_type, - const std::vector< - std::tuple> &tests) { + template + void TestDumpEnum( + const std::vector> enumerators, + const std::vector> &tests) { + CompilerType enum_type = MakeEnumType(enumerators); StreamString strm; ConstString var_name("test_var"); ByteOrder endian = endian::InlHostByteOrder(); @@ -107,6 +93,27 @@ class ValueObjectMockProcessTest : public ::testing::Test { } } + template + CompilerType MakeEnumType( + const std::vector> enumerators) { + CompilerType int_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize( + std::is_same::value ? lldb::eEncodingSint + : lldb::eEncodingUint, + 32); + CompilerType enum_type = m_type_system->CreateEnumerationType( + "TestEnum", m_type_system->GetTranslationUnitDecl(), + OptionalClangModuleID(), Declaration(), int_type, false); + + m_type_system->StartTagDeclarationDefinition(enum_type); + Declaration decl; + for (auto [name, value] : enumerators) + m_type_system->AddEnumerationValueToEnumerationType(enum_type, decl, name, + value, 32); + m_type_system->CompleteTagDeclarationDefinition(enum_type); + + return enum_type; + } + ExecutionContext m_exe_ctx; TypeSystemClang *m_type_system; @@ -123,12 +130,25 @@ class ValueObjectMockProcessTest : public ::testing::Test { lldb::ProcessSP m_process_sp; }; +TEST_F(ValueObjectMockProcessTest, EmptyEnum) { + // All values of an empty enum should be shown as plain numbers. + TestDumpEnum({}, {{0, {}, "(TestEnum) test_var = 0\n"}, + {1, {}, "(TestEnum) test_var = 1\n"}, + {2, {}, "(TestEnum) test_var = 2\n"}}); + + TestDumpEnum({}, {{-2, {}, "(TestEnum) test_var = -2\n"}, + {-1, {}, "(TestEnum) test_var = -1\n"}, + {0, {}, "(TestEnum) test_var = 0\n"}, + {1, {}, "(TestEnum) test_var = 1\n"}, + {2, {}, "(TestEnum) test_var = 2\n"}}); +} + TEST_F(ValueObjectMockProcessTest, Enum) { // This is not a bitfield-like enum, so values are printed as decimal by // default. Also we only show the enumerator name if the value is an // exact match. - TestDumpValueObject( - MakeEnumType({{"test_2", 2}, {"test_3", 3}}), + TestDumpEnum( + {{"test_2", 2}, {"test_3", 3}}, {{0, {}, "(TestEnum) test_var = 0\n"}, {1, {}, "(TestEnum) test_var = 1\n"}, {2, {}, "(TestEnum) test_var = test_2\n"}, @@ -151,8 +171,8 @@ TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) { // set. lldb treats this as a "bitfield like enum". This means we show values // as hex, and values without exact matches are shown as a combination of // enumerators and any remaining value left over. - TestDumpValueObject( - MakeEnumType({{"test_2", 2}, {"test_4", 4}}), + TestDumpEnum( + {{"test_2", 2}, {"test_4", 4}}, { {0, {}, "(TestEnum) test_var = 0x0\n"}, {1, {}, "(TestEnum) test_var = 0x1\n"},