[lldb] Add SBType::FindDirectNestedType() function (#68705)

This patch adds a `SBType::FindDirectNestedType(name)` function which performs a non-recursive search in given class for a type with specified name. The intent is to perform a fast search in debug info, so that it can be used in formatters, and let them remain responsive.

This is driven by my work on formatters for Clang and LLVM types. In particular, by [`PointerIntPairInfo::MaskAndShiftConstants`](cde9f9df79/llvm/include/llvm/ADT/PointerIntPair.h (L174C16-L174C16)), which is required to extract pointer and integer from `PointerIntPair`.

Related Discourse thread: https://discourse.llvm.org/t/traversing-member-types-of-a-type/72452
This commit is contained in:
Vlad Serebrennikov 2023-10-14 10:52:34 +04:00 committed by GitHub
parent 02f67c097d
commit 93229c7bfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 96 additions and 0 deletions

View File

@ -720,6 +720,14 @@ SBType supports the eq/ne operator. For example,::
" "
) lldb::SBType::GetTypeFlags; ) lldb::SBType::GetTypeFlags;
%feature("docstring",
"Searches for a directly nested type that has the provided name.
Returns the type if it was found.
Returns invalid type if nothing was found.
"
) lldb::SBType::FindDirectNestedType;
%feature("docstring", %feature("docstring",
"Represents a list of :py:class:`SBType` s. "Represents a list of :py:class:`SBType` s.

View File

@ -215,6 +215,8 @@ public:
bool GetDescription(lldb::SBStream &description, bool GetDescription(lldb::SBStream &description,
lldb::DescriptionLevel description_level); lldb::DescriptionLevel description_level);
lldb::SBType FindDirectNestedType(const char *name);
lldb::SBType &operator=(const lldb::SBType &rhs); lldb::SBType &operator=(const lldb::SBType &rhs);
bool operator==(lldb::SBType &rhs); bool operator==(lldb::SBType &rhs);

View File

@ -304,6 +304,8 @@ public:
bool GetDescription(lldb_private::Stream &strm, bool GetDescription(lldb_private::Stream &strm,
lldb::DescriptionLevel description_level); lldb::DescriptionLevel description_level);
CompilerType FindDirectNestedType(llvm::StringRef name);
private: private:
bool CheckModule(lldb::ModuleSP &module_sp) const; bool CheckModule(lldb::ModuleSP &module_sp) const;
bool CheckExeModule(lldb::ModuleSP &module_sp) const; bool CheckExeModule(lldb::ModuleSP &module_sp) const;

View File

@ -142,6 +142,10 @@ public:
virtual lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) = 0; virtual lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) = 0;
/// Returns the direct parent context of specified type
virtual CompilerDeclContext
GetCompilerDeclContextForType(const CompilerType &type);
// Tests // Tests
#ifndef NDEBUG #ifndef NDEBUG
/// Verify the integrity of the type to catch CompilerTypes that mix /// Verify the integrity of the type to catch CompilerTypes that mix

View File

@ -586,6 +586,14 @@ lldb::TemplateArgumentKind SBType::GetTemplateArgumentKind(uint32_t idx) {
return eTemplateArgumentKindNull; return eTemplateArgumentKindNull;
} }
SBType SBType::FindDirectNestedType(const char *name) {
LLDB_INSTRUMENT_VA(this, name);
if (!IsValid())
return SBType();
return SBType(m_opaque_sp->FindDirectNestedType(name));
}
SBTypeList::SBTypeList() : m_opaque_up(new TypeListImpl()) { SBTypeList::SBTypeList() : m_opaque_up(new TypeListImpl()) {
LLDB_INSTRUMENT_VA(this); LLDB_INSTRUMENT_VA(this);
} }

View File

@ -2637,6 +2637,13 @@ TypeSystemClang::GetDeclContextForType(const CompilerType &type) {
return GetDeclContextForType(ClangUtil::GetQualType(type)); return GetDeclContextForType(ClangUtil::GetQualType(type));
} }
CompilerDeclContext
TypeSystemClang::GetCompilerDeclContextForType(const CompilerType &type) {
if (auto *decl_context = GetDeclContextForType(type))
return CreateDeclContext(decl_context);
return CompilerDeclContext();
}
/// Aggressively desugar the provided type, skipping past various kinds of /// Aggressively desugar the provided type, skipping past various kinds of
/// syntactic sugar and other constructs one typically wants to ignore. /// syntactic sugar and other constructs one typically wants to ignore.
/// The \p mask argument allows one to skip certain kinds of simplifications, /// The \p mask argument allows one to skip certain kinds of simplifications,

View File

@ -219,6 +219,9 @@ public:
static clang::DeclContext *GetDeclContextForType(const CompilerType &type); static clang::DeclContext *GetDeclContextForType(const CompilerType &type);
CompilerDeclContext
GetCompilerDeclContextForType(const CompilerType &type) override;
uint32_t GetPointerByteSize() override; uint32_t GetPointerByteSize() override;
clang::TranslationUnitDecl *GetTranslationUnitDecl() { clang::TranslationUnitDecl *GetTranslationUnitDecl() {

View File

@ -1040,6 +1040,23 @@ bool TypeImpl::GetDescription(lldb_private::Stream &strm,
return true; return true;
} }
CompilerType TypeImpl::FindDirectNestedType(llvm::StringRef name) {
if (name.empty())
return CompilerType();
auto type_system = GetTypeSystem(/*prefer_dynamic*/ false);
auto *symbol_file = type_system->GetSymbolFile();
auto decl_context = type_system->GetCompilerDeclContextForType(m_static_type);
if (!decl_context.IsValid())
return CompilerType();
llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
TypeMap search_result;
symbol_file->FindTypes(ConstString(name), decl_context, /*max_matches*/ 1,
searched_symbol_files, search_result);
if (search_result.Empty())
return CompilerType();
return search_result.GetTypeAtIndex(0)->GetFullCompilerType();
}
bool TypeMemberFunctionImpl::IsValid() { bool TypeMemberFunctionImpl::IsValid() {
return m_type.IsValid() && m_kind != lldb::eMemberFunctionKindUnknown; return m_type.IsValid() && m_kind != lldb::eMemberFunctionKindUnknown;
} }

View File

@ -186,6 +186,11 @@ std::optional<llvm::json::Value> TypeSystem::ReportStatistics() {
return std::nullopt; return std::nullopt;
} }
CompilerDeclContext
TypeSystem::GetCompilerDeclContextForType(const CompilerType &type) {
return CompilerDeclContext();
}
#pragma mark TypeSystemMap #pragma mark TypeSystemMap
TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {} TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {}

View File

@ -119,6 +119,37 @@ class TypeAndTypeListTestCase(TestBase):
self.assertEqual(task_type, task_head_pointee_type) self.assertEqual(task_type, task_head_pointee_type)
# Check whether we can find a directly nested type by name
name_type = task_type.FindDirectNestedType("name")
self.assertTrue(name_type)
self.DebugSBType(name_type)
enum_type = task_type.FindDirectNestedType("E")
self.assertTrue(enum_type)
self.DebugSBType(enum_type)
union_type = task_type.FindDirectNestedType("U")
self.assertTrue(union_type)
self.DebugSBType(union_type)
# Check that we don't find indirectly nested types
self.assertTrue(enum_type.size == 1)
invalid_type = task_type.FindDirectNestedType("E2")
self.assertFalse(invalid_type)
# Check that FindDirectNestedType handles types without DeclContext
# and other errorneous inputs
task_ptr_type = task_type.GetPointerType()
invalid_type = task_ptr_type.FindDirectNestedType("name")
self.assertFalse(invalid_type)
invalid_type = task_type.FindDirectNestedType("")
self.assertFalse(invalid_type)
invalid_type = task_type.FindDirectNestedType(None)
self.assertFalse(invalid_type)
# We'll now get the child member 'id' from 'task_head'. # We'll now get the child member 'id' from 'task_head'.
id = task_head.GetChildMemberWithName("id") id = task_head.GetChildMemberWithName("id")
self.DebugSBValue(id) self.DebugSBValue(id)

View File

@ -21,7 +21,12 @@ public:
} my_type_is_nameless; } my_type_is_nameless;
struct name { struct name {
int x; int x;
enum E : int {} e;
enum E2 {} e2;
} my_type_is_named; } my_type_is_named;
enum E : unsigned char {} e;
union U {
} u;
Task(int i, Task *n): Task(int i, Task *n):
id(i), id(i),
next(n), next(n),

View File

@ -191,6 +191,10 @@ Changes to LLDB
* Methods in SBHostOS related to threads have had their implementations * Methods in SBHostOS related to threads have had their implementations
removed. These methods will return a value indicating failure. removed. These methods will return a value indicating failure.
* ``SBType::FindDirectNestedType`` function is added. It's useful
for formatters to quickly find directly nested type when it's known
where to search for it, avoiding more expensive global search via
``SBTarget::FindFirstType``.
Changes to Sanitizers Changes to Sanitizers
--------------------- ---------------------