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 ---------------------