[Lldb-commits] [lldb] [LLDB] Add more helper functions to CompilerType class (second try). (PR #73472)

via lldb-commits lldb-commits at lists.llvm.org
Wed Dec 6 10:04:07 PST 2023


https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/73472

>From a063ebd8ee8bbd491fff3449bc20d663d2e501ea Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 26 Nov 2023 17:24:39 -0800
Subject: [PATCH 1/4] [LLDB] Add more helper functions to CompilerType class
 (second try).

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).
---
 lldb/include/lldb/Symbol/CompilerType.h |  56 ++++-
 lldb/source/Symbol/CompilerType.cpp     | 285 ++++++++++++++++++++++--
 2 files changed, 320 insertions(+), 21 deletions(-)

diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index 0a9533a1ac0ef..a3331ad3269c0 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -112,9 +112,7 @@ class CompilerType {
 
   /// Tests.
   /// \{
-  explicit operator bool() const {
-    return m_type_system.lock() && m_type;
-  }
+  explicit operator bool() const { return m_type_system.lock() && m_type; }
 
   bool IsValid() const { return (bool)*this; }
 
@@ -194,6 +192,54 @@ class CompilerType {
   bool IsTypedefType() const;
 
   bool IsVoidType() const;
+
+  bool IsSmartPtrType() const;
+
+  bool IsInteger() const;
+
+  bool IsFloat() const;
+
+  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;
+
+  bool IsVirtualBase(CompilerType target_base, CompilerType *virtual_base,
+                     bool carry_virtual = false) const;
+
+  bool IsContextuallyConvertibleToBool() const;
+
+  bool IsBasicType() const;
+
+  std::string TypeDescription();
+
+  bool CompareTypes(CompilerType rhs) const;
+
+  const char *GetTypeTag();
+
+  uint32_t GetNumberOfNonEmptyBaseClasses();
+
+  CompilerType GetTemplateArgumentType(uint32_t idx);
+
+  CompilerType GetSmartPtrPointeeType();
+
   /// \}
 
   /// Type Completion.
@@ -436,8 +482,8 @@ class CompilerType {
                      ExecutionContextScope *exe_scope);
 
   /// Dump to stdout.
-  void DumpTypeDescription(lldb::DescriptionLevel level =
-                           lldb::eDescriptionLevelFull) const;
+  void DumpTypeDescription(
+      lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) const;
 
   /// Print a description of the type to a stream. The exact implementation
   /// varies, but the expectation is that eDescriptionLevelFull returns a
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index 78cc8dad94a9c..854d6cab01b50 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -54,7 +54,7 @@ bool CompilerType::IsArrayType(CompilerType *element_type_ptr, uint64_t *size,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->IsArrayType(m_type, element_type_ptr, size,
-                                      is_incomplete);
+                                         is_incomplete);
 
   if (element_type_ptr)
     element_type_ptr->Clear();
@@ -157,7 +157,8 @@ bool CompilerType::IsBlockPointerType(
     CompilerType *function_pointer_type_ptr) const {
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
-      return type_system_sp->IsBlockPointerType(m_type, function_pointer_type_ptr);
+      return type_system_sp->IsBlockPointerType(m_type,
+                                                function_pointer_type_ptr);
   return false;
 }
 
@@ -249,7 +250,7 @@ bool CompilerType::IsPossibleDynamicType(CompilerType *dynamic_pointee_type,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->IsPossibleDynamicType(m_type, dynamic_pointee_type,
-                                                check_cplusplus, check_objc);
+                                                   check_cplusplus, check_objc);
   return false;
 }
 
@@ -302,6 +303,256 @@ bool CompilerType::IsBeingDefined() const {
   return false;
 }
 
+bool CompilerType::IsSmartPtrType() const {
+  // These regular expressions cover shared, unique and weak pointers both from
+  // stdlibc++ and libc+++.
+
+  static llvm::Regex k_libcxx_std_unique_ptr_regex(
+      "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$");
+  static llvm::Regex k_libcxx_std_shared_ptr_regex(
+      "^std::__[[:alnum:]]+::shared_ptr<.+>(( )?&)?$");
+  static llvm::Regex k_libcxx_std_weak_ptr_regex(
+      "^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$");
+  //
+  static llvm::Regex k_libcxx_std_unique_ptr_regex_2(
+      "^std::unique_ptr<.+>(( )?&)?$");
+  static llvm::Regex k_libcxx_std_shared_ptr_regex_2(
+      "^std::shared_ptr<.+>(( )?&)?$");
+  static llvm::Regex k_libcxx_std_weak_ptr_regex_2(
+      "^std::weak_ptr<.+>(( )?&)?$");
+  //
+  llvm::StringRef name = GetTypeName();
+  return k_libcxx_std_unique_ptr_regex.match(name) ||
+         k_libcxx_std_shared_ptr_regex.match(name) ||
+         k_libcxx_std_weak_ptr_regex.match(name) ||
+         k_libcxx_std_unique_ptr_regex_2.match(name) ||
+         k_libcxx_std_shared_ptr_regex_2.match(name) ||
+         k_libcxx_std_weak_ptr_regex_2.match(name);
+}
+
+bool CompilerType::IsInteger() const {
+  // This is used when you don't care about the signedness of the integer.
+  bool is_signed;
+  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 {
+  // This is used when you don't care about the signedness of the enum.
+  bool is_signed;
+  return IsEnumerationType(is_signed);
+}
+
+bool CompilerType::IsUnscopedEnumerationType() const {
+  return IsEnumerationType() && !IsScopedEnumerationType();
+}
+
+bool CompilerType::IsIntegerOrUnscopedEnumerationType() const {
+  return IsInteger() || IsUnscopedEnumerationType();
+}
+
+bool CompilerType::IsSigned() const {
+  if (IsEnumerationType()) {
+    return IsEnumerationIntegerTypeSigned();
+  }
+  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;
+  }
+}
+
+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);
+}
+
+// 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`.
+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
+  }
+  if (name == canonical_name) {
+    return llvm::formatv("'{0}'", name);
+  }
+  return llvm::formatv("'{0}' (aka '{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()) {
+    // clang-format off
+    case lldb::eTypeClassClass:       return "class";
+    case lldb::eTypeClassEnumeration: return "enum";
+    case lldb::eTypeClassStruct:      return "struct";
+    case lldb::eTypeClassUnion:       return "union";
+    // clang-format on
+  default:
+    return "unknown";
+  }
+}
+
+uint32_t CompilerType::GetNumberOfNonEmptyBaseClasses() {
+  // Go through the base classes and count non-empty ones.
+  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;
+}
+
+CompilerType CompilerType::GetTemplateArgumentType(uint32_t idx) {
+  CompilerType empty_type;
+  if (!IsValid())
+    return empty_type;
+
+  CompilerType type;
+  const bool expand_pack = true;
+  switch (GetTemplateArgumentKind(idx, true)) {
+  case lldb::eTemplateArgumentKindType:
+    type = GetTypeTemplateArgument(idx, expand_pack);
+    break;
+  case lldb::eTemplateArgumentKindIntegral:
+    type = GetIntegralTemplateArgument(idx, expand_pack)->type;
+    break;
+  default:
+    break;
+  }
+  if (type.IsValid())
+    return type;
+  return empty_type;
+}
+
+CompilerType CompilerType::GetSmartPtrPointeeType() {
+  assert(IsSmartPtrType() &&
+         "the type should be a smart pointer (std::unique_ptr, std::shared_ptr "
+         "or std::weak_ptr");
+
+  return GetTemplateArgumentType(0);
+}
+
 // Type Completion
 
 bool CompilerType::GetCompleteType() const {
@@ -336,9 +587,9 @@ ConstString CompilerType::GetDisplayTypeName() const {
 uint32_t CompilerType::GetTypeInfo(
     CompilerType *pointee_or_element_compiler_type) const {
   if (IsValid())
-  if (auto type_system_sp = GetTypeSystem())
-    return type_system_sp->GetTypeInfo(m_type,
-                                       pointee_or_element_compiler_type);
+    if (auto type_system_sp = GetTypeSystem())
+      return type_system_sp->GetTypeInfo(m_type,
+                                         pointee_or_element_compiler_type);
   return 0;
 }
 
@@ -362,8 +613,9 @@ void CompilerType::SetCompilerType(lldb::TypeSystemWP type_system,
   m_type = type;
 }
 
-void CompilerType::SetCompilerType(CompilerType::TypeSystemSPWrapper type_system,
-                                   lldb::opaque_compiler_type_t type) {
+void CompilerType::SetCompilerType(
+    CompilerType::TypeSystemSPWrapper type_system,
+    lldb::opaque_compiler_type_t type) {
   m_type_system = type_system.GetSharedPointer();
   m_type = type;
 }
@@ -589,7 +841,7 @@ uint32_t CompilerType::GetNumChildren(bool omit_empty_base_classes,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetNumChildren(m_type, omit_empty_base_classes,
-                                       exe_ctx);
+                                            exe_ctx);
   return 0;
 }
 
@@ -601,8 +853,7 @@ lldb::BasicType CompilerType::GetBasicTypeEnumeration() const {
 }
 
 void CompilerType::ForEachEnumerator(
-    std::function<bool(const CompilerType &integer_type,
-                       ConstString name,
+    std::function<bool(const CompilerType &integer_type, ConstString name,
                        const llvm::APSInt &value)> const &callback) const {
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
@@ -623,7 +874,8 @@ CompilerType CompilerType::GetFieldAtIndex(size_t idx, std::string &name,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetFieldAtIndex(m_type, idx, name, bit_offset_ptr,
-                                        bitfield_bit_size_ptr, is_bitfield_ptr);
+                                             bitfield_bit_size_ptr,
+                                             is_bitfield_ptr);
   return CompilerType();
 }
 
@@ -647,7 +899,7 @@ CompilerType::GetDirectBaseClassAtIndex(size_t idx,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetDirectBaseClassAtIndex(m_type, idx,
-                                                    bit_offset_ptr);
+                                                       bit_offset_ptr);
   return CompilerType();
 }
 
@@ -657,7 +909,7 @@ CompilerType::GetVirtualBaseClassAtIndex(size_t idx,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetVirtualBaseClassAtIndex(m_type, idx,
-                                                     bit_offset_ptr);
+                                                        bit_offset_ptr);
   return CompilerType();
 }
 
@@ -738,7 +990,7 @@ size_t CompilerType::GetIndexOfChildMemberWithName(
   if (IsValid() && !name.empty()) {
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetIndexOfChildMemberWithName(
-        m_type, name, omit_empty_base_classes, child_indexes);
+          m_type, name, omit_empty_base_classes, child_indexes);
   }
   return 0;
 }
@@ -772,7 +1024,8 @@ std::optional<CompilerType::IntegralTemplateArgument>
 CompilerType::GetIntegralTemplateArgument(size_t idx, bool expand_pack) const {
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
-      return type_system_sp->GetIntegralTemplateArgument(m_type, idx, expand_pack);
+      return type_system_sp->GetIntegralTemplateArgument(m_type, idx,
+                                                         expand_pack);
   return std::nullopt;
 }
 

>From 29cd28dc39af596a0a126dbf9cf3d1b233fc78be Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 29 Nov 2023 12:35:47 -0800
Subject: [PATCH 2/4] [LLDB] Add more helper functions to CompilerType class
 (second try).

Address most of the reviewer comments:
  - Fix formatting issues
  - Add/Move Doxygen function comments in header file.
  - Undo clang-format changes to code that I didn't touch.
  - Other requested fixes.
---
 lldb/include/lldb/Symbol/CompilerType.h |  19 +++-
 lldb/source/Symbol/CompilerType.cpp     | 131 +++++++++++-------------
 2 files changed, 78 insertions(+), 72 deletions(-)

diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index a3331ad3269c0..274b1a60a5c6a 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -112,7 +112,9 @@ class CompilerType {
 
   /// Tests.
   /// \{
-  explicit operator bool() const { return m_type_system.lock() && m_type; }
+  explicit operator bool() const {
+    return m_type_system.lock() && m_type;
+  }
 
   bool IsValid() const { return (bool)*this; }
 
@@ -193,12 +195,16 @@ class CompilerType {
 
   bool IsVoidType() const;
 
+  /// This determines if the type is a shared, unique or weak pointer, either
+  /// from stdlibc++ or libc+++.
   bool IsSmartPtrType() 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;
@@ -221,9 +227,15 @@ class CompilerType {
 
   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. 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;
@@ -234,6 +246,7 @@ class CompilerType {
 
   const char *GetTypeTag();
 
+  /// Go through the base classes and count non-empty ones.
   uint32_t GetNumberOfNonEmptyBaseClasses();
 
   CompilerType GetTemplateArgumentType(uint32_t idx);
@@ -482,8 +495,8 @@ class CompilerType {
                      ExecutionContextScope *exe_scope);
 
   /// Dump to stdout.
-  void DumpTypeDescription(
-      lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) const;
+  void DumpTypeDescription(lldb::DescriptionLevel level =
+                           lldb::eDescriptionLevelFull) const;
 
   /// Print a description of the type to a stream. The exact implementation
   /// varies, but the expectation is that eDescriptionLevelFull returns a
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index 854d6cab01b50..089199ae5310d 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -54,7 +54,7 @@ bool CompilerType::IsArrayType(CompilerType *element_type_ptr, uint64_t *size,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->IsArrayType(m_type, element_type_ptr, size,
-                                         is_incomplete);
+                                      is_incomplete);
 
   if (element_type_ptr)
     element_type_ptr->Clear();
@@ -157,8 +157,7 @@ bool CompilerType::IsBlockPointerType(
     CompilerType *function_pointer_type_ptr) const {
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
-      return type_system_sp->IsBlockPointerType(m_type,
-                                                function_pointer_type_ptr);
+      return type_system_sp->IsBlockPointerType(m_type, function_pointer_type_ptr);
   return false;
 }
 
@@ -250,7 +249,7 @@ bool CompilerType::IsPossibleDynamicType(CompilerType *dynamic_pointee_type,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->IsPossibleDynamicType(m_type, dynamic_pointee_type,
-                                                   check_cplusplus, check_objc);
+                                                check_cplusplus, check_objc);
   return false;
 }
 
@@ -304,35 +303,34 @@ bool CompilerType::IsBeingDefined() const {
 }
 
 bool CompilerType::IsSmartPtrType() const {
-  // These regular expressions cover shared, unique and weak pointers both from
-  // stdlibc++ and libc+++.
 
-  static llvm::Regex k_libcxx_std_unique_ptr_regex(
+  // libc++ smart pointers
+  static const llvm::Regex k_libcxx_std_unique_ptr_regex(
       "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$");
-  static llvm::Regex k_libcxx_std_shared_ptr_regex(
+  static const llvm::Regex k_libcxx_std_shared_ptr_regex(
       "^std::__[[:alnum:]]+::shared_ptr<.+>(( )?&)?$");
-  static llvm::Regex k_libcxx_std_weak_ptr_regex(
+  static const llvm::Regex k_libcxx_std_weak_ptr_regex(
       "^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$");
-  //
-  static llvm::Regex k_libcxx_std_unique_ptr_regex_2(
+
+  // libstdc++ smart pointers
+  static const llvm::Regex k_libstdcxx_std_unique_ptr_regex(
       "^std::unique_ptr<.+>(( )?&)?$");
-  static llvm::Regex k_libcxx_std_shared_ptr_regex_2(
+  static const llvm::Regex k_libstdcxx_std_shared_ptr_regex(
       "^std::shared_ptr<.+>(( )?&)?$");
-  static llvm::Regex k_libcxx_std_weak_ptr_regex_2(
+  static const llvm::Regex k_libstdcxx_std_weak_ptr_regex(
       "^std::weak_ptr<.+>(( )?&)?$");
-  //
+
   llvm::StringRef name = GetTypeName();
   return k_libcxx_std_unique_ptr_regex.match(name) ||
          k_libcxx_std_shared_ptr_regex.match(name) ||
          k_libcxx_std_weak_ptr_regex.match(name) ||
-         k_libcxx_std_unique_ptr_regex_2.match(name) ||
-         k_libcxx_std_shared_ptr_regex_2.match(name) ||
-         k_libcxx_std_weak_ptr_regex_2.match(name);
+         k_libstdcxx_std_unique_ptr_regex.match(name) ||
+         k_libstdcxx_std_shared_ptr_regex.match(name) ||
+         k_libstdcxx_std_weak_ptr_regex.match(name);
 }
 
 bool CompilerType::IsInteger() const {
-  // This is used when you don't care about the signedness of the integer.
-  bool is_signed;
+  bool is_signed = false; // May be reset by the call below.
   return IsIntegerType(is_signed);
 }
 
@@ -343,8 +341,7 @@ bool CompilerType::IsFloat() const {
 }
 
 bool CompilerType::IsEnumerationType() const {
-  // This is used when you don't care about the signedness of the enum.
-  bool is_signed;
+  bool is_signed = false; // May be reset by the call below.
   return IsEnumerationType(is_signed);
 }
 
@@ -357,9 +354,9 @@ bool CompilerType::IsIntegerOrUnscopedEnumerationType() const {
 }
 
 bool CompilerType::IsSigned() const {
-  if (IsEnumerationType()) {
+  if (IsEnumerationType())
     return IsEnumerationIntegerTypeSigned();
-  }
+
   return GetTypeInfo() & lldb::eTypeIsSigned;
 }
 
@@ -373,9 +370,9 @@ bool CompilerType::IsBoolean() const {
 }
 
 bool CompilerType::IsEnumerationIntegerTypeSigned() const {
-  if (IsValid()) {
+  if (IsValid())
     return GetEnumerationIntegerType().GetTypeInfo() & lldb::eTypeIsSigned;
-  }
+
   return false;
 }
 
@@ -386,9 +383,8 @@ bool CompilerType::IsScalarOrUnscopedEnumerationType() const {
 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()) {
+  if (IsUnscopedEnumerationType())
     return true;
-  }
 
   switch (GetCanonicalType().GetBasicTypeEnumeration()) {
   case lldb::eBasicTypeBool:
@@ -407,6 +403,8 @@ bool CompilerType::IsPromotableIntegerType() const {
   default:
     return false;
   }
+
+  llvm_unreachable("All cases handled above.");
 }
 
 bool CompilerType::IsPointerToVoid() const {
@@ -426,15 +424,11 @@ bool CompilerType::IsRecordType() const {
           lldb::eTypeClassUnion);
 }
 
-// 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`.
 bool CompilerType::IsVirtualBase(CompilerType target_base,
                                  CompilerType *virtual_base,
                                  bool carry_virtual) const {
-  if (CompareTypes(target_base)) {
+  if (CompareTypes(target_base))
     return carry_virtual;
-  }
 
   if (!carry_virtual) {
     uint32_t num_virtual_bases = GetNumVirtualBaseClasses();
@@ -443,9 +437,9 @@ bool CompilerType::IsVirtualBase(CompilerType target_base,
       auto base = GetVirtualBaseClassAtIndex(i, &bit_offset);
       if (base.IsVirtualBase(target_base, virtual_base,
                              /*carry_virtual*/ true)) {
-        if (virtual_base) {
+        if (virtual_base)
           *virtual_base = base;
-        }
+
         return true;
       }
     }
@@ -455,9 +449,8 @@ bool CompilerType::IsVirtualBase(CompilerType target_base,
   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)) {
+    if (base.IsVirtualBase(target_base, virtual_base, carry_virtual))
       return true;
-    }
   }
 
   return false;
@@ -476,13 +469,14 @@ bool CompilerType::IsBasicType() const {
 std::string CompilerType::TypeDescription() {
   auto name = GetTypeName();
   auto canonical_name = GetCanonicalType().GetTypeName();
-  if (name.IsEmpty() || canonical_name.IsEmpty()) {
-    return "''"; // should not happen
-  }
-  if (name == canonical_name) {
+  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}' (aka '{1}')", name, canonical_name);
+
+  return llvm::formatv("'{0}' (canonically referred to as '{1}')", name,
+                       canonical_name);
 }
 
 bool CompilerType::CompareTypes(CompilerType rhs) const {
@@ -496,19 +490,21 @@ bool CompilerType::CompareTypes(CompilerType rhs) const {
 
 const char *CompilerType::GetTypeTag() {
   switch (GetTypeClass()) {
-    // clang-format off
-    case lldb::eTypeClassClass:       return "class";
-    case lldb::eTypeClassEnumeration: return "enum";
-    case lldb::eTypeClassStruct:      return "struct";
-    case lldb::eTypeClassUnion:       return "union";
-    // clang-format on
+  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() {
-  // Go through the base classes and count non-empty ones.
   uint32_t ret = 0;
   uint32_t num_direct_bases = GetNumDirectBaseClasses();
 
@@ -516,9 +512,8 @@ uint32_t CompilerType::GetNumberOfNonEmptyBaseClasses() {
     uint32_t bit_offset;
     CompilerType base_type = GetDirectBaseClassAtIndex(i, &bit_offset);
     if (base_type.GetNumFields() > 0 ||
-        base_type.GetNumberOfNonEmptyBaseClasses() > 0) {
+        base_type.GetNumberOfNonEmptyBaseClasses() > 0)
       ret += 1;
-    }
   }
   return ret;
 }
@@ -546,9 +541,9 @@ CompilerType CompilerType::GetTemplateArgumentType(uint32_t idx) {
 }
 
 CompilerType CompilerType::GetSmartPtrPointeeType() {
-  assert(IsSmartPtrType() &&
-         "the type should be a smart pointer (std::unique_ptr, std::shared_ptr "
-         "or std::weak_ptr");
+  if (!IsSmartPtrType())
+    // TODO: Should consider issuing a warning here.
+    return GetPointeeType();
 
   return GetTemplateArgumentType(0);
 }
@@ -587,9 +582,9 @@ ConstString CompilerType::GetDisplayTypeName() const {
 uint32_t CompilerType::GetTypeInfo(
     CompilerType *pointee_or_element_compiler_type) const {
   if (IsValid())
-    if (auto type_system_sp = GetTypeSystem())
-      return type_system_sp->GetTypeInfo(m_type,
-                                         pointee_or_element_compiler_type);
+  if (auto type_system_sp = GetTypeSystem())
+    return type_system_sp->GetTypeInfo(m_type,
+                                       pointee_or_element_compiler_type);
   return 0;
 }
 
@@ -613,9 +608,8 @@ void CompilerType::SetCompilerType(lldb::TypeSystemWP type_system,
   m_type = type;
 }
 
-void CompilerType::SetCompilerType(
-    CompilerType::TypeSystemSPWrapper type_system,
-    lldb::opaque_compiler_type_t type) {
+void CompilerType::SetCompilerType(CompilerType::TypeSystemSPWrapper type_system,
+                                   lldb::opaque_compiler_type_t type) {
   m_type_system = type_system.GetSharedPointer();
   m_type = type;
 }
@@ -841,7 +835,7 @@ uint32_t CompilerType::GetNumChildren(bool omit_empty_base_classes,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetNumChildren(m_type, omit_empty_base_classes,
-                                            exe_ctx);
+                                       exe_ctx);
   return 0;
 }
 
@@ -853,7 +847,8 @@ lldb::BasicType CompilerType::GetBasicTypeEnumeration() const {
 }
 
 void CompilerType::ForEachEnumerator(
-    std::function<bool(const CompilerType &integer_type, ConstString name,
+    std::function<bool(const CompilerType &integer_type,
+                       ConstString name,
                        const llvm::APSInt &value)> const &callback) const {
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
@@ -874,8 +869,7 @@ CompilerType CompilerType::GetFieldAtIndex(size_t idx, std::string &name,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetFieldAtIndex(m_type, idx, name, bit_offset_ptr,
-                                             bitfield_bit_size_ptr,
-                                             is_bitfield_ptr);
+                                        bitfield_bit_size_ptr, is_bitfield_ptr);
   return CompilerType();
 }
 
@@ -899,7 +893,7 @@ CompilerType::GetDirectBaseClassAtIndex(size_t idx,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetDirectBaseClassAtIndex(m_type, idx,
-                                                       bit_offset_ptr);
+                                                    bit_offset_ptr);
   return CompilerType();
 }
 
@@ -909,7 +903,7 @@ CompilerType::GetVirtualBaseClassAtIndex(size_t idx,
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetVirtualBaseClassAtIndex(m_type, idx,
-                                                        bit_offset_ptr);
+                                                     bit_offset_ptr);
   return CompilerType();
 }
 
@@ -990,7 +984,7 @@ size_t CompilerType::GetIndexOfChildMemberWithName(
   if (IsValid() && !name.empty()) {
     if (auto type_system_sp = GetTypeSystem())
       return type_system_sp->GetIndexOfChildMemberWithName(
-          m_type, name, omit_empty_base_classes, child_indexes);
+        m_type, name, omit_empty_base_classes, child_indexes);
   }
   return 0;
 }
@@ -1024,8 +1018,7 @@ std::optional<CompilerType::IntegralTemplateArgument>
 CompilerType::GetIntegralTemplateArgument(size_t idx, bool expand_pack) const {
   if (IsValid())
     if (auto type_system_sp = GetTypeSystem())
-      return type_system_sp->GetIntegralTemplateArgument(m_type, idx,
-                                                         expand_pack);
+      return type_system_sp->GetIntegralTemplateArgument(m_type, idx, expand_pack);
   return std::nullopt;
 }
 

>From 6ea102eb67e3a8723e3b1e2356df548328571ec5 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 5 Dec 2023 07:11:40 -0800
Subject: [PATCH 3/4] [LLDB] Add more helper functions to CompilerType class
 (second try).

Update comment for "IsVirtualBase" member function as requested.
---
 lldb/include/lldb/Symbol/CompilerType.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index 274b1a60a5c6a..6f275b454ccd0 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -230,8 +230,11 @@ class CompilerType {
   //// 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. Note: This may only be defined in
-  /// TypeSystemClang.
+  /// 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;
 

>From 11a10240c32d24aa2b49e50c3476a5d6f16921b1 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 6 Dec 2023 10:01:44 -0800
Subject: [PATCH 4/4] [LLDB] Add more helper functions to CompilerType class
 (second try).

Remove smart pointer functions from the new helper functions for
CompilerType class.
---
 lldb/include/lldb/Symbol/CompilerType.h |  6 -----
 lldb/source/Symbol/CompilerType.cpp     | 35 -------------------------
 2 files changed, 41 deletions(-)

diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index 6f275b454ccd0..559146aa6ae94 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -195,10 +195,6 @@ class CompilerType {
 
   bool IsVoidType() const;
 
-  /// This determines if the type is a shared, unique or weak pointer, either
-  /// from stdlibc++ or libc+++.
-  bool IsSmartPtrType() const;
-
   /// This is used when you don't care about the signedness of the integer.
   bool IsInteger() const;
 
@@ -254,8 +250,6 @@ class CompilerType {
 
   CompilerType GetTemplateArgumentType(uint32_t idx);
 
-  CompilerType GetSmartPtrPointeeType();
-
   /// \}
 
   /// Type Completion.
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index 089199ae5310d..d8d1537d0bed6 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -302,33 +302,6 @@ bool CompilerType::IsBeingDefined() const {
   return false;
 }
 
-bool CompilerType::IsSmartPtrType() const {
-
-  // libc++ smart pointers
-  static const llvm::Regex k_libcxx_std_unique_ptr_regex(
-      "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$");
-  static const llvm::Regex k_libcxx_std_shared_ptr_regex(
-      "^std::__[[:alnum:]]+::shared_ptr<.+>(( )?&)?$");
-  static const llvm::Regex k_libcxx_std_weak_ptr_regex(
-      "^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$");
-
-  // libstdc++ smart pointers
-  static const llvm::Regex k_libstdcxx_std_unique_ptr_regex(
-      "^std::unique_ptr<.+>(( )?&)?$");
-  static const llvm::Regex k_libstdcxx_std_shared_ptr_regex(
-      "^std::shared_ptr<.+>(( )?&)?$");
-  static const llvm::Regex k_libstdcxx_std_weak_ptr_regex(
-      "^std::weak_ptr<.+>(( )?&)?$");
-
-  llvm::StringRef name = GetTypeName();
-  return k_libcxx_std_unique_ptr_regex.match(name) ||
-         k_libcxx_std_shared_ptr_regex.match(name) ||
-         k_libcxx_std_weak_ptr_regex.match(name) ||
-         k_libstdcxx_std_unique_ptr_regex.match(name) ||
-         k_libstdcxx_std_shared_ptr_regex.match(name) ||
-         k_libstdcxx_std_weak_ptr_regex.match(name);
-}
-
 bool CompilerType::IsInteger() const {
   bool is_signed = false; // May be reset by the call below.
   return IsIntegerType(is_signed);
@@ -540,14 +513,6 @@ CompilerType CompilerType::GetTemplateArgumentType(uint32_t idx) {
   return empty_type;
 }
 
-CompilerType CompilerType::GetSmartPtrPointeeType() {
-  if (!IsSmartPtrType())
-    // TODO: Should consider issuing a warning here.
-    return GetPointeeType();
-
-  return GetTemplateArgumentType(0);
-}
-
 // Type Completion
 
 bool CompilerType::GetCompleteType() const {



More information about the lldb-commits mailing list