Skip to content

Commit

Permalink
Reland "[lldb] Print empty enums as if they were unrecognised normal …
Browse files Browse the repository at this point in the history
…enums (llvm#97553)"

This reverts commit 927def4.

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.
  • Loading branch information
DavidSpickett committed Jul 4, 2024
1 parent 173514d commit 328d9f6
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 42 deletions.
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
72 changes: 46 additions & 26 deletions lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#include "gtest/gtest.h"

#include <type_traits>

using namespace lldb;
using namespace lldb_private;

Expand Down Expand Up @@ -70,28 +72,12 @@ class ValueObjectMockProcessTest : public ::testing::Test {
m_type_system = m_holder->GetAST();
}

CompilerType
MakeEnumType(const std::vector<std::pair<const char *, int>> 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<uint32_t, DumpValueObjectOptions, const char *>> &tests) {
template <typename UnderlyingType>
void TestDumpEnum(
const std::vector<std::pair<const char *, UnderlyingType>> enumerators,
const std::vector<std::tuple<UnderlyingType, DumpValueObjectOptions,
const char *>> &tests) {
CompilerType enum_type = MakeEnumType(enumerators);
StreamString strm;
ConstString var_name("test_var");
ByteOrder endian = endian::InlHostByteOrder();
Expand All @@ -107,6 +93,27 @@ class ValueObjectMockProcessTest : public ::testing::Test {
}
}

template <typename UnderlyingType>
CompilerType MakeEnumType(
const std::vector<std::pair<const char *, UnderlyingType>> enumerators) {
CompilerType int_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize(
std::is_same<UnderlyingType, int>::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;

Expand All @@ -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<unsigned>({}, {{0, {}, "(TestEnum) test_var = 0\n"},
{1, {}, "(TestEnum) test_var = 1\n"},
{2, {}, "(TestEnum) test_var = 2\n"}});

TestDumpEnum<int>({}, {{-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<unsigned>(
{{"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"},
Expand All @@ -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<unsigned>(
{{"test_2", 2}, {"test_4", 4}},
{
{0, {}, "(TestEnum) test_var = 0x0\n"},
{1, {}, "(TestEnum) test_var = 0x1\n"},
Expand Down

0 comments on commit 328d9f6

Please sign in to comment.