From 93229c7bfd97429aa0ac55b45e618bdb013702b2 Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov Date: Sat, 14 Oct 2023 10:52:34 +0400 Subject: [PATCH] [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`](https://github.com/llvm/llvm-project/blob/cde9f9df79805a0850310870d6dcc64004292727/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 --- lldb/bindings/interface/SBTypeDocstrings.i | 8 +++++ lldb/include/lldb/API/SBType.h | 2 ++ lldb/include/lldb/Symbol/Type.h | 2 ++ lldb/include/lldb/Symbol/TypeSystem.h | 4 +++ lldb/source/API/SBType.cpp | 8 +++++ .../TypeSystem/Clang/TypeSystemClang.cpp | 7 +++++ .../TypeSystem/Clang/TypeSystemClang.h | 3 ++ lldb/source/Symbol/Type.cpp | 17 ++++++++++ lldb/source/Symbol/TypeSystem.cpp | 5 +++ lldb/test/API/python_api/type/TestTypeList.py | 31 +++++++++++++++++++ lldb/test/API/python_api/type/main.cpp | 5 +++ llvm/docs/ReleaseNotes.rst | 4 +++ 12 files changed, 96 insertions(+) diff --git a/lldb/bindings/interface/SBTypeDocstrings.i b/lldb/bindings/interface/SBTypeDocstrings.i index 96421a6aa201..c49e9647ba04 100644 --- a/lldb/bindings/interface/SBTypeDocstrings.i +++ b/lldb/bindings/interface/SBTypeDocstrings.i @@ -720,6 +720,14 @@ SBType supports the eq/ne operator. For example,:: " ) 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", "Represents a list of :py:class:`SBType` s. diff --git a/lldb/include/lldb/API/SBType.h b/lldb/include/lldb/API/SBType.h index 5962f0c50dee..9980fe121830 100644 --- a/lldb/include/lldb/API/SBType.h +++ b/lldb/include/lldb/API/SBType.h @@ -215,6 +215,8 @@ public: bool GetDescription(lldb::SBStream &description, lldb::DescriptionLevel description_level); + lldb::SBType FindDirectNestedType(const char *name); + lldb::SBType &operator=(const lldb::SBType &rhs); bool operator==(lldb::SBType &rhs); diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index d7bccae5f413..c505262cd9ea 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -304,6 +304,8 @@ public: bool GetDescription(lldb_private::Stream &strm, lldb::DescriptionLevel description_level); + CompilerType FindDirectNestedType(llvm::StringRef name); + private: bool CheckModule(lldb::ModuleSP &module_sp) const; bool CheckExeModule(lldb::ModuleSP &module_sp) const; diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 56acb1db1546..5ac16be3347f 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -142,6 +142,10 @@ public: virtual lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) = 0; + /// Returns the direct parent context of specified type + virtual CompilerDeclContext + GetCompilerDeclContextForType(const CompilerType &type); + // Tests #ifndef NDEBUG /// Verify the integrity of the type to catch CompilerTypes that mix diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp index ee5b64474280..ac0e56303fae 100644 --- a/lldb/source/API/SBType.cpp +++ b/lldb/source/API/SBType.cpp @@ -586,6 +586,14 @@ lldb::TemplateArgumentKind SBType::GetTemplateArgumentKind(uint32_t idx) { 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()) { LLDB_INSTRUMENT_VA(this); } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index bcf4b6247806..f1353db2631d 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2637,6 +2637,13 @@ TypeSystemClang::GetDeclContextForType(const CompilerType &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 /// syntactic sugar and other constructs one typically wants to ignore. /// The \p mask argument allows one to skip certain kinds of simplifications, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 7805be92ec13..66e59ec985fb 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -219,6 +219,9 @@ public: static clang::DeclContext *GetDeclContextForType(const CompilerType &type); + CompilerDeclContext + GetCompilerDeclContextForType(const CompilerType &type) override; + uint32_t GetPointerByteSize() override; clang::TranslationUnitDecl *GetTranslationUnitDecl() { diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index 5f4c6303334a..548300d57095 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -1040,6 +1040,23 @@ bool TypeImpl::GetDescription(lldb_private::Stream &strm, 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 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() { return m_type.IsValid() && m_kind != lldb::eMemberFunctionKindUnknown; } diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index 24f202930565..874f12573eca 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -186,6 +186,11 @@ std::optional TypeSystem::ReportStatistics() { return std::nullopt; } +CompilerDeclContext +TypeSystem::GetCompilerDeclContextForType(const CompilerType &type) { + return CompilerDeclContext(); +} + #pragma mark TypeSystemMap TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {} diff --git a/lldb/test/API/python_api/type/TestTypeList.py b/lldb/test/API/python_api/type/TestTypeList.py index c2fcadc46ec1..c267defb58ed 100644 --- a/lldb/test/API/python_api/type/TestTypeList.py +++ b/lldb/test/API/python_api/type/TestTypeList.py @@ -119,6 +119,37 @@ class TypeAndTypeListTestCase(TestBase): 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'. id = task_head.GetChildMemberWithName("id") self.DebugSBValue(id) diff --git a/lldb/test/API/python_api/type/main.cpp b/lldb/test/API/python_api/type/main.cpp index b1ef62528385..98de9707d886 100644 --- a/lldb/test/API/python_api/type/main.cpp +++ b/lldb/test/API/python_api/type/main.cpp @@ -21,7 +21,12 @@ public: } my_type_is_nameless; struct name { int x; + enum E : int {} e; + enum E2 {} e2; } my_type_is_named; + enum E : unsigned char {} e; + union U { + } u; Task(int i, Task *n): id(i), next(n), diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 3453c7e61ae4..467b4b5320ad 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -191,6 +191,10 @@ Changes to LLDB * Methods in SBHostOS related to threads have had their implementations 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 ---------------------