Skip to content

[LLDB] Add more helper functions to CompilerType class (second try). #73472

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 6 commits into from
Dec 14, 2023
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
54 changes: 54 additions & 0 deletions lldb/include/lldb/Symbol/CompilerType.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,60 @@ class CompilerType {
bool IsTypedefType() const;

bool IsVoidType() const;

/// This is used when you don't care about the signedness of the integer.
bool IsInteger() const;

bool IsFloat() const;

/// This is used when you don't care about the signedness of the enum.
bool IsEnumerationType() const;

bool IsUnscopedEnumerationType() const;

bool IsIntegerOrUnscopedEnumerationType() const;

bool IsSigned() const;

bool IsNullPtrType() const;

bool IsBoolean() const;

bool IsEnumerationIntegerTypeSigned() const;

bool IsScalarOrUnscopedEnumerationType() const;

bool IsPromotableIntegerType() const;

bool IsPointerToVoid() const;

bool IsRecordType() const;

//// Checks whether `target_base` is a virtual base of `type` (direct or
/// indirect). If it is, stores the first virtual base type on the path from
/// `type` to `target_type`. Parameter "virtual_base" is where the first
/// virtual base type gets stored. Parameter "carry_virtual" is used to
/// denote that we're in a recursive check of virtual base classes and we
/// have already seen a virtual base class (so should only check direct
/// base classes).
/// Note: This may only be defined in TypeSystemClang.
bool IsVirtualBase(CompilerType target_base, CompilerType *virtual_base,
bool carry_virtual = false) const;

/// This may only be defined in TypeSystemClang.
bool IsContextuallyConvertibleToBool() const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems extremely specific to the C language family. I don't think that's a problem, but it would be nice to at least document that this may be only defined in TypeSystemClang?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done? I think?


bool IsBasicType() const;

std::string TypeDescription();

bool CompareTypes(CompilerType rhs) const;

const char *GetTypeTag();

/// Go through the base classes and count non-empty ones.
uint32_t GetNumberOfNonEmptyBaseClasses();

/// \}

/// Type Completion.
Expand Down
186 changes: 186 additions & 0 deletions lldb/source/Symbol/CompilerType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,192 @@ bool CompilerType::IsBeingDefined() const {
return false;
}

bool CompilerType::IsInteger() const {
bool is_signed = false; // May be reset by the call below.
return IsIntegerType(is_signed);
}

bool CompilerType::IsFloat() const {
uint32_t count = 0;
bool is_complex = false;
return IsFloatingPointType(count, is_complex);
}

bool CompilerType::IsEnumerationType() const {
bool is_signed = false; // May be reset by the call below.
return IsEnumerationType(is_signed);
}

bool CompilerType::IsUnscopedEnumerationType() const {
return IsEnumerationType() && !IsScopedEnumerationType();
}

bool CompilerType::IsIntegerOrUnscopedEnumerationType() const {
return IsInteger() || IsUnscopedEnumerationType();
}

bool CompilerType::IsSigned() const {
return GetTypeInfo() & lldb::eTypeIsSigned;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function looks like it's working around a bug in GetTypeInfo?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(i.e., could this be fixed by modifying TypeSystemClang::GetTypeInfo to return the sign bit on enums?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adrian-prantl Actually I think it already works properly without special-casing enums (I went back and looked and could not figure out why I had done this). I've cleaned it up now and removed the special casing. Are you OK with me committing this now?

}

bool CompilerType::IsNullPtrType() const {
return GetCanonicalType().GetBasicTypeEnumeration() ==
lldb::eBasicTypeNullPtr;
}

bool CompilerType::IsBoolean() const {
return GetCanonicalType().GetBasicTypeEnumeration() == lldb::eBasicTypeBool;
}

bool CompilerType::IsEnumerationIntegerTypeSigned() const {
if (IsValid())
return GetEnumerationIntegerType().GetTypeInfo() & lldb::eTypeIsSigned;

return false;
}

bool CompilerType::IsScalarOrUnscopedEnumerationType() const {
return IsScalarType() || IsUnscopedEnumerationType();
}

bool CompilerType::IsPromotableIntegerType() const {
// Unscoped enums are always considered as promotable, even if their
// underlying type does not need to be promoted (e.g. "int").
if (IsUnscopedEnumerationType())
return true;

switch (GetCanonicalType().GetBasicTypeEnumeration()) {
case lldb::eBasicTypeBool:
case lldb::eBasicTypeChar:
case lldb::eBasicTypeSignedChar:
case lldb::eBasicTypeUnsignedChar:
case lldb::eBasicTypeShort:
case lldb::eBasicTypeUnsignedShort:
case lldb::eBasicTypeWChar:
case lldb::eBasicTypeSignedWChar:
case lldb::eBasicTypeUnsignedWChar:
case lldb::eBasicTypeChar16:
case lldb::eBasicTypeChar32:
return true;

default:
return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This likely needs a llvm_unreachable("All cases handled above."); to appease gcc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


llvm_unreachable("All cases handled above.");
}

bool CompilerType::IsPointerToVoid() const {
if (!IsValid())
return false;

return IsPointerType() &&
GetPointeeType().GetBasicTypeEnumeration() == lldb::eBasicTypeVoid;
}

bool CompilerType::IsRecordType() const {
if (!IsValid())
return false;

return GetCanonicalType().GetTypeClass() &
(lldb::eTypeClassClass | lldb::eTypeClassStruct |
lldb::eTypeClassUnion);
}

bool CompilerType::IsVirtualBase(CompilerType target_base,
CompilerType *virtual_base,
bool carry_virtual) const {
if (CompareTypes(target_base))
return carry_virtual;

if (!carry_virtual) {
uint32_t num_virtual_bases = GetNumVirtualBaseClasses();
for (uint32_t i = 0; i < num_virtual_bases; ++i) {
uint32_t bit_offset;
auto base = GetVirtualBaseClassAtIndex(i, &bit_offset);
if (base.IsVirtualBase(target_base, virtual_base,
/*carry_virtual*/ true)) {
if (virtual_base)
*virtual_base = base;

return true;
}
}
}

uint32_t num_direct_bases = GetNumDirectBaseClasses();
for (uint32_t i = 0; i < num_direct_bases; ++i) {
uint32_t bit_offset;
auto base = GetDirectBaseClassAtIndex(i, &bit_offset);
if (base.IsVirtualBase(target_base, virtual_base, carry_virtual))
return true;
}

return false;
}

bool CompilerType::IsContextuallyConvertibleToBool() const {
return IsScalarType() || IsUnscopedEnumerationType() || IsPointerType() ||
IsNullPtrType() || IsArrayType();
}

bool CompilerType::IsBasicType() const {
return GetCanonicalType().GetBasicTypeEnumeration() !=
lldb::eBasicTypeInvalid;
}

std::string CompilerType::TypeDescription() {
auto name = GetTypeName();
auto canonical_name = GetCanonicalType().GetTypeName();
if (name.IsEmpty() || canonical_name.IsEmpty())
return "''"; // Should not happen, unless the input is broken somehow.

if (name == canonical_name)
return llvm::formatv("'{0}'", name);

return llvm::formatv("'{0}' (canonically referred to as '{1}')", name,
canonical_name);
}

bool CompilerType::CompareTypes(CompilerType rhs) const {
if (*this == rhs)
return true;

const ConstString name = GetFullyUnqualifiedType().GetTypeName();
const ConstString rhs_name = rhs.GetFullyUnqualifiedType().GetTypeName();
return name == rhs_name;
}

const char *CompilerType::GetTypeTag() {
switch (GetTypeClass()) {
case lldb::eTypeClassClass:
return "class";
case lldb::eTypeClassEnumeration:
return "enum";
case lldb::eTypeClassStruct:
return "struct";
case lldb::eTypeClassUnion:
return "union";
default:
return "unknown";
}
llvm_unreachable("All cases are covered by code above.");
}

uint32_t CompilerType::GetNumberOfNonEmptyBaseClasses() {
uint32_t ret = 0;
uint32_t num_direct_bases = GetNumDirectBaseClasses();

for (uint32_t i = 0; i < num_direct_bases; ++i) {
uint32_t bit_offset;
CompilerType base_type = GetDirectBaseClassAtIndex(i, &bit_offset);
if (base_type.GetNumFields() > 0 ||
base_type.GetNumberOfNonEmptyBaseClasses() > 0)
ret += 1;
}
return ret;
}

// Type Completion

bool CompilerType::GetCompleteType() const {
Expand Down