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

This adds 23 new helper functions to LLDB's CompilerType class, things
like IsSmartPtrType, IsPromotableIntegerType,
GetNumberofNonEmptyBaseClasses, and GetTemplateArgumentType (to name a
few).

It also has run clang-format on the files CompilerType.{h,cpp}.

These helper functions are needed as part of the implementation for the
Data Inspection Language, (see
https://discourse.llvm.org/t/rfc-data-inspection-language/69893).
This commit is contained in:
cmtice
2023-12-14 14:10:19 -08:00
committed by GitHub
parent b1cc6f778d
commit e692d08360
2 changed files with 240 additions and 0 deletions

View File

@@ -194,6 +194,60 @@ public:
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;
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.

View File

@@ -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;
}
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;
}
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 {