Skip to content

[lldb] Print empty enums as if they were unrecognised normal enums #97553

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
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <incomplete type "const (unnamed struct)">
VARS: (const (unnamed enum)) e = 0x1
VARS: (const (unnamed enum)) ec = 0x1
VARS: (const (unnamed enum)) e = 1
VARS: (const (unnamed enum)) ec = 1
28 changes: 22 additions & 6 deletions lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,13 @@ class ValueObjectMockProcessTest : public ::testing::Test {
}

CompilerType
MakeEnumType(const std::vector<std::pair<const char *, int>> enumerators) {
CompilerType uint_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize(
lldb::eEncodingUint, 32);
MakeEnumType(const std::vector<std::pair<const char *, int>> enumerators,
bool is_signed) {
CompilerType int_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize(
is_signed ? lldb::eEncodingSint : lldb::eEncodingUint, 32);
CompilerType enum_type = m_type_system->CreateEnumerationType(
"TestEnum", m_type_system->GetTranslationUnitDecl(),
OptionalClangModuleID(), Declaration(), uint_type, false);
OptionalClangModuleID(), Declaration(), int_type, false);

m_type_system->StartTagDeclarationDefinition(enum_type);
Declaration decl;
Expand Down Expand Up @@ -123,12 +124,27 @@ 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.
TestDumpValueObject(MakeEnumType({}, false),
{{0, {}, "(TestEnum) test_var = 0\n"},
{1, {}, "(TestEnum) test_var = 1\n"},
{2, {}, "(TestEnum) test_var = 2\n"}});

TestDumpValueObject(MakeEnumType({}, true),
{{-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}}),
MakeEnumType({{"test_2", 2}, {"test_3", 3}}, false),
{{0, {}, "(TestEnum) test_var = 0\n"},
{1, {}, "(TestEnum) test_var = 1\n"},
{2, {}, "(TestEnum) test_var = test_2\n"},
Expand All @@ -152,7 +168,7 @@ TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) {
// as hex, a value of 0 shows nothing, and values with no exact enumerator are
// shown as combinations of the other values.
TestDumpValueObject(
MakeEnumType({{"test_2", 2}, {"test_4", 4}}),
MakeEnumType({{"test_2", 2}, {"test_4", 4}}, false),
{
{0, {}, "(TestEnum) test_var =\n"},
{1, {}, "(TestEnum) test_var = 0x1\n"},
Expand Down
Loading