From a34192928ffcd061af7671b4f0b3c46e6a2b2e3a Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Fri, 13 Dec 2024 12:58:35 -0800 Subject: [PATCH 1/2] [lldb] Introduce an ImportedDeclaration Introduce a debug info independent type, ImportedDeclaration, which is analogous to DWARF's DW_AT_imported_declaration, as well as a way to search them by name. (cherry picked from commit fbc062390a97e14a3bc69b1670ad25e6420ae9bf) --- lldb/include/lldb/Core/Module.h | 16 +++++++++ lldb/include/lldb/Core/ModuleList.h | 20 +++++++++++ .../include/lldb/Symbol/ImportedDeclaration.h | 34 +++++++++++++++++++ lldb/include/lldb/Symbol/SymbolFile.h | 17 ++++++++++ lldb/source/Core/Module.cpp | 6 ++++ lldb/source/Core/ModuleList.cpp | 18 ++++++++++ .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 16 +++++++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 4 +++ .../DWARF/SymbolFileDWARFDebugMap.cpp | 11 ++++++ .../DWARF/SymbolFileDWARFDebugMap.h | 3 ++ lldb/source/Symbol/CMakeLists.txt | 1 + lldb/source/Symbol/ImportedDeclaration.cpp | 18 ++++++++++ 12 files changed, 164 insertions(+) create mode 100644 lldb/include/lldb/Symbol/ImportedDeclaration.h create mode 100644 lldb/source/Symbol/ImportedDeclaration.cpp diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 4d038ec714194..0b0a465a09b2e 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -12,6 +12,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Symbol/ImportedDeclaration.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContextScope.h" #include "lldb/Symbol/TypeSystem.h" @@ -437,6 +438,21 @@ class Module : public std::enable_shared_from_this, /// TypeMap::InsertUnique(...). void FindTypes(const TypeQuery &query, TypeResults &results); + /// Finds imported declarations whose name match \p name. + /// + /// \param[in] name + /// The name to search the imported declaration by. + /// + /// \param[in] results + /// Any matching types will be populated into the \a results object. + /// + /// \param[in] find_one + /// If set to true, the search will stop after the first imported + /// declaration is found. + void FindImportedDeclarations(ConstString name, + std::vector &results, + bool find_one); + /// Get const accessor for the module architecture. /// /// \return diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 0ff03520b1773..faf1594f41970 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -12,6 +12,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/UserSettingsController.h" +#include "lldb/Symbol/ImportedDeclaration.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Iterable.h" #include "lldb/Utility/Status.h" @@ -397,6 +398,25 @@ class ModuleList { void FindTypes(Module *search_first, const TypeQuery &query, lldb_private::TypeResults &results) const; + /// Finds imported declarations whose name match \p name. + /// + /// \param[in] search_first + /// If non-null, this module will be searched before any other + /// modules. + /// + /// \param[in] name + /// The name to search the imported declaration by. + /// + /// \param[in] results + /// Any matching types will be populated into the \a results object. + /// + /// \param[in] find_one + /// If set to true, the search will stop after the first imported + /// declaration is found. + void FindImportedDeclarations(Module *search_first, ConstString name, + std::vector &results, + bool find_one) const; + bool FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const; /// Find addresses by file/line diff --git a/lldb/include/lldb/Symbol/ImportedDeclaration.h b/lldb/include/lldb/Symbol/ImportedDeclaration.h new file mode 100644 index 0000000000000..9c5919fa33d07 --- /dev/null +++ b/lldb/include/lldb/Symbol/ImportedDeclaration.h @@ -0,0 +1,34 @@ +//===-- ImportedDeclaration.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SYMBOL_IMPORTED_DECLARATION_H +#define LLDB_SYMBOL_IMPORTED_DECLARATION_H + +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/UserID.h" + +namespace lldb_private { + +struct ImportedDeclaration : public UserID { + + ImportedDeclaration(lldb::user_id_t uid, ConstString name, + SymbolFile *symbol_file) + : UserID(uid), m_name(name), m_symbol_file(symbol_file) {} + + ConstString GetName() const { return m_name; } + + std::vector GetDeclContext() const; + +private: + ConstString m_name; + SymbolFile *m_symbol_file = nullptr; +}; + +} // namespace lldb_private + +#endif // LLDB_SYMBOL_IMPORTED_DECLARATION_H diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index c1645380145b0..84abfe7204f3b 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -18,6 +18,8 @@ #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SourceModule.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeSystem.h" @@ -305,6 +307,21 @@ class SymbolFile : public PluginInterface { bool include_inlines, SymbolContextList &sc_list); virtual void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list); + /// Finds imported declarations whose name match \p name. + /// + /// \param[in] name + /// The name to search the imported declaration by. + /// + /// \param[in] results + /// Any matching types will be populated into the \a results object. + /// + /// \param[in] find_one + /// If set to true, the search will stop after the first imported + /// declaration is found. + virtual void + FindImportedDeclaration(ConstString name, + std::vector &declarations, + bool find_one) {} /// Find types using a type-matching object that contains all search /// parameters. diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 10da7b2020005..934e435cc7e89 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1011,6 +1011,12 @@ void Module::FindTypes(const TypeQuery &query, TypeResults &results) { if (SymbolFile *symbols = GetSymbolFile()) symbols->FindTypes(query, results); } +void Module::FindImportedDeclarations(ConstString name, + std::vector &results, + bool find_one) { + if (SymbolFile *symbols = GetSymbolFile()) + symbols->FindImportedDeclaration(name, results, find_one); +} static Debugger::DebuggerList DebuggersOwningModuleRequestingInterruption(Module &module) { diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index deb1f80ef096f..45acd2ca190db 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -831,6 +831,24 @@ void ModuleList::FindTypes(Module *search_first, const TypeQuery &query, } } +void ModuleList::FindImportedDeclarations( + Module *search_first, ConstString name, + std::vector &results, bool find_one) const { + std::lock_guard guard(m_modules_mutex); + if (search_first) { + search_first->FindImportedDeclarations(name, results, find_one); + if (find_one && !results.empty()) + return; + } + for (const auto &module_sp : m_modules) { + if (search_first != module_sp.get()) { + module_sp->FindImportedDeclarations(name, results, find_one); + } + if (find_one && !results.empty()) + return; + } +} + bool ModuleList::FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const { std::lock_guard guard(m_modules_mutex); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index b249edfcf03f8..b6515c436c3be 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2677,6 +2677,22 @@ void SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, }); } +void SymbolFileDWARF::FindImportedDeclaration( + ConstString name, std::vector &sc_list, + bool find_one) { + llvm::DenseSet resolved_dies; + m_index->GetNamespaces(name, [&](DWARFDIE die) { + if (die.Tag() != llvm::dwarf::DW_TAG_imported_declaration) + return true; + + if (name != die.GetName()) + return true; + + sc_list.emplace_back(die.GetID(), name, this); + return !find_one; + }); +} + void SymbolFileDWARF::GetMangledNamesForFunction( const std::string &scope_qualified_name, std::vector &mangled_names) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index a4c655ed39818..1654aa2b3542b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -195,6 +195,10 @@ class SymbolFileDWARF : public SymbolFileCommon { void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) override; + void FindImportedDeclaration(ConstString name, + std::vector &sc_list, + bool find_one) override; + void GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector &mangled_names) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 54ebda66a56c9..00141e6f76492 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1122,6 +1122,17 @@ void SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression ®ex, }); } +void SymbolFileDWARFDebugMap::FindImportedDeclaration( + ConstString name, std::vector &declarations, + bool find_one) { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { + oso_dwarf->FindImportedDeclaration(name, declarations, find_one); + if (find_one && !declarations.empty()) + return IterationAction::Stop; + return IterationAction::Continue; + }); +} + void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, TypeList &type_list) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index f1ddadf818d43..c4f2aa4b351ac 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -123,6 +123,9 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon { bool include_inlines, SymbolContextList &sc_list) override; void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) override; + void FindImportedDeclaration(ConstString name, + std::vector &declarations, + bool find_one) override; void FindTypes(const lldb_private::TypeQuery &match, lldb_private::TypeResults &results) override; CompilerDeclContext FindNamespace(ConstString name, diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt index 8eaf1d9246852..37d5d4e58543c 100644 --- a/lldb/source/Symbol/CMakeLists.txt +++ b/lldb/source/Symbol/CMakeLists.txt @@ -32,6 +32,7 @@ add_lldb_library(lldbSymbol ${PLUGIN_DEPENDENCY_ARG} DeclVendor.cpp FuncUnwinders.cpp Function.cpp + ImportedDeclaration.cpp LineEntry.cpp LineTable.cpp ObjectContainer.cpp diff --git a/lldb/source/Symbol/ImportedDeclaration.cpp b/lldb/source/Symbol/ImportedDeclaration.cpp new file mode 100644 index 0000000000000..4c5fb34d834c9 --- /dev/null +++ b/lldb/source/Symbol/ImportedDeclaration.cpp @@ -0,0 +1,18 @@ +//===-- ImportedDeclaration.cpp --------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/ImportedDeclaration.h" +#include "lldb/Symbol/SymbolFile.h" + +using namespace lldb; +using namespace lldb_private; + +std::vector +ImportedDeclaration::GetDeclContext() const { + return m_symbol_file->GetCompilerContextForUID(GetID()); +} From 15bb8ecccd8b371b9b33a876d8b04e8f8aa42eea Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Tue, 17 Dec 2024 14:49:31 -0800 Subject: [PATCH 2/2] [lldb] Handle @_originallyDefinedIn Types annotated with @_originallyDefinedIn don't live in the module listed in their mangled name. To account for this, the compiler emits a DW_TAG_imported_declaration for those types under the name of the swiftmodule these types can be found at. This patch implements the logic required to produce the mangled name that can be used in type reconstruction to successfully find these types. rdar://137146961 (cherry picked from commit ce1a9d565f537f81b3d40e67666c91e9cc178938) --- .../TypeSystem/Swift/SwiftASTContext.cpp | 10 + .../Plugins/TypeSystem/Swift/SwiftDemangle.h | 20 +- .../Swift/TypeSystemSwiftTypeRef.cpp | 178 +++++++++++++++++- .../TypeSystem/Swift/TypeSystemSwiftTypeRef.h | 14 ++ .../lang/swift/originally_defined_in/Makefile | 3 + .../TestSwiftOriginallyDefinedIn.py | 102 ++++++++++ .../swift/originally_defined_in/main.swift | 110 +++++++++++ 7 files changed, 433 insertions(+), 4 deletions(-) create mode 100644 lldb/test/API/lang/swift/originally_defined_in/Makefile create mode 100644 lldb/test/API/lang/swift/originally_defined_in/TestSwiftOriginallyDefinedIn.py create mode 100644 lldb/test/API/lang/swift/originally_defined_in/main.swift diff --git a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp index 32c13b03479d9..809b6a3ccd7f1 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp @@ -4772,6 +4772,16 @@ SwiftASTContext::ReconstructType(ConstString mangled_typename) { .getPointer(); assert(!found_type || &found_type->getASTContext() == *ast_ctx); + // This type might have been been found in reflection and annotated with + // @_originallyDefinedIn. The compiler emits a typelias for these type + // pointing them back to the types with the real module name. + if (!found_type) { + auto adjusted = + GetTypeSystemSwiftTypeRef()->AdjustTypeForOriginallyDefinedInModule( + mangled_typename); + found_type = + swift::Demangle::getTypeForMangling(**ast_ctx, adjusted).getPointer(); + } // Objective-C classes sometimes have private subclasses that are invisible // to the Swift compiler because they are declared and defined in a .m file. // If we can't reconstruct an ObjC type, walk up the type hierarchy until we diff --git a/lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.h b/lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.h index 0d5a46de4d98a..d87443331564f 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.h +++ b/lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.h @@ -59,8 +59,9 @@ NodeAtPath(swift::Demangle::NodePointer root, return ChildAtPath(root, kind_path.drop_front()); } -/// \return the child of the \p Type node. -static swift::Demangle::NodePointer GetType(swift::Demangle::NodePointer n) { +/// \return the child of the TypeMangling node. +static swift::Demangle::NodePointer +GetTypeMangling(swift::Demangle::NodePointer n) { using namespace swift::Demangle; if (!n || n->getKind() != Node::Kind::Global) return nullptr; @@ -68,6 +69,13 @@ static swift::Demangle::NodePointer GetType(swift::Demangle::NodePointer n) { if (!n || n->getKind() != Node::Kind::TypeMangling || !n->hasChildren()) return nullptr; n = n->getFirstChild(); + return n; +} + +/// \return the child of the \p Type node. +static swift::Demangle::NodePointer GetType(swift::Demangle::NodePointer n) { + using namespace swift::Demangle; + n = GetTypeMangling(n); if (!n || n->getKind() != Node::Kind::Type || !n->hasChildren()) return nullptr; n = n->getFirstChild(); @@ -80,6 +88,14 @@ GetDemangledType(swift::Demangle::Demangler &dem, llvm::StringRef name) { return GetType(dem.demangleSymbol(name)); } +/// Demangle a mangled type name and return the child of the \p TypeMangling +/// node. +inline swift::Demangle::NodePointer +GetDemangledTypeMangling(swift::Demangle::Demangler &dem, + llvm::StringRef name) { + return GetTypeMangling(dem.demangleSymbol(name)); +} + /// Wrap node in Global/TypeMangling/Type. static swift::Demangle::NodePointer mangleType(swift::Demangle::Demangler &dem, diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp index e6627320aecb7..5f8ee4414d421 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp @@ -36,6 +36,8 @@ #include "swift/ClangImporter/ClangImporter.h" #include "swift/../../lib/ClangImporter/ClangAdapter.h" +#include "swift/Demangling/Demangle.h" +#include "swift/Demangling/Demangler.h" #include "swift/Frontend/Frontend.h" #include "clang/APINotes/APINotesManager.h" @@ -150,6 +152,178 @@ TypeSystemSwiftTypeRef::CanonicalizeSugar(swift::Demangle::Demangler &dem, }); } +NodePointer TypeSystemSwiftTypeRef::FindTypeWithModuleAndIdentifierNode( + swift::Demangle::NodePointer node) { + if (!node || node->getKind() != Node::Kind::Type) + return nullptr; + + NodePointer current = node; + while (current && current->hasChildren() && + current->getFirstChild()->getKind() != Node::Kind::Module) { + current = current->getFirstChild(); + } + switch (current->getKind()) { + case Node::Kind::Structure: + case Node::Kind::Class: + case Node::Kind::Enum: + case Node::Kind::BoundGenericStructure: + case Node::Kind::BoundGenericClass: + case Node::Kind::BoundGenericEnum: + return current; + default: + return nullptr; + } +} + +std::string TypeSystemSwiftTypeRef::AdjustTypeForOriginallyDefinedInModule( + llvm::StringRef mangled_typename) { + if (mangled_typename.empty()) + return {}; + + swift::Demangle::Demangler dem; + auto *type_node = + swift_demangle::GetDemangledTypeMangling(dem, mangled_typename); + if (!type_node) + return {}; + + TargetSP target_sp(GetTargetWP().lock()); + if (!target_sp) + return {}; + + ModuleList &module_list = target_sp->GetImages(); + + // A map from the node containing the module and identifier of a specific type + // to a node with the modified module and identifier of that type. For + // example, given the following type: + // + // Module "a": + // + // @available(...) + // @_originallyDefinedIn(module: "Other", ...) + // public struct A { ... } + // The demangle tree of the mangled name stored in DWARF will be: + // + // kind=Global + // kind=TypeMangling + // kind=Type + // kind=Structure + // kind=Module, text="Other" + // kind=Identifier, text="A" + // + // This functions needs to construct the following tree: + // + // kind=Global + // kind=TypeMangling + // kind=Type + // kind=Structure + // kind=Module, text="a" + // kind=Identifier, text="A" + // + // type_to_renamed_type_nodes is populated with the nodes in the original tree + // node that need to be replaced mapping to their replacements. In this + // example that would be: + // + // kind=Structure + // kind=Module, text="Other" + // kind=Identifier, text="A" + // + // mapping to: + // + // kind=Structure + // kind=Module, text="a" + // kind=Identifier, text="A" + // + // We can't have a map from module nodes to renamed module nodes because those + // nodes might be reused elsewhere in the tree. + llvm::DenseMap type_to_renamed_type_nodes; + + // Visit the demangle tree and populate type_to_renamed_type_nodes. + PreOrderTraversal(type_node, [&](NodePointer node) { + // We're visiting the entire tree, but we only need to examine "Type" nodes. + if (node->getKind() != Node::Kind::Type) + return true; + + auto compiler_type = RemangleAsType(dem, node); + if (!compiler_type) + return true; + + // Find the node that contains the module and identifier nodes. + NodePointer node_with_module_and_name = + FindTypeWithModuleAndIdentifierNode(node); + if (!node_with_module_and_name) + return true; + + auto module_name = node_with_module_and_name->getFirstChild()->getText(); + // Clang types couldn't have been renamed. + if (module_name == swift::MANGLING_MODULE_OBJC) + return true; + + // If we already processed this node there's nothing to do (this can happen + // because nodes are shared in the tree). + if (type_to_renamed_type_nodes.contains(node_with_module_and_name)) + return true; + + // Look for the imported declarations that indicate the type has moved + // modules. + std::vector decls; + module_list.FindImportedDeclarations(GetModule(), + compiler_type.GetMangledTypeName(), + decls, /*find_one=*/true); + // If there are none there's nothing to do. + if (decls.empty()) + return true; + + std::vector declContext = + decls[0].GetDeclContext(); + + lldbassert(!declContext.empty() && + "Unexpected decl context for imported declaration!"); + if (declContext.empty()) + return true; + + auto module_context = declContext[0]; + + // If the mangled name's module and module context module match then + // there's nothing to do. + if (module_name == module_context.name) + return true; + + // Construct the node tree that will substituted in. + NodePointer new_node = dem.createNode(node_with_module_and_name->getKind()); + NodePointer new_module_node = dem.createNodeWithAllocatedText( + Node::Kind::Module, module_context.name); + new_node->addChild(new_module_node, dem); + new_node->addChild(node_with_module_and_name->getLastChild(), dem); + + type_to_renamed_type_nodes[node_with_module_and_name] = new_node; + return true; + }); + + // If there are no renamed modules, there's nothing to do. + if (type_to_renamed_type_nodes.empty()) + return mangled_typename.str(); + + NodePointer transformed = Transform(dem, type_node, [&](NodePointer node) { + return type_to_renamed_type_nodes.contains(node) + ? type_to_renamed_type_nodes[node] + : node; + }); + + auto mangling = mangleNode(swift_demangle::mangleType(dem, transformed)); + assert(mangling.isSuccess()); + if (!mangling.isSuccess()) { + LLDB_LOG(GetLog(LLDBLog::Types), + "[AdjustTypeForOriginallyDefinedInModule] Unexpected mangling " + "error when mangling adjusted node for type with mangled name {0}", + mangled_typename); + + return {}; + } + + auto str = mangling.result(); + return str; +} + llvm::StringRef TypeSystemSwiftTypeRef::GetBaseName(swift::Demangle::NodePointer node) { if (!node) @@ -230,7 +404,7 @@ TypeSP TypeSystemSwiftTypeRefForExpressions::LookupClangType( ConstString name(name_ref); if (m_clang_type_cache.Lookup(name.AsCString(), result)) return result; - + TargetSP target_sp = GetTargetWP().lock(); if (!target_sp) return {}; @@ -446,7 +620,7 @@ TypeSystemSwiftTypeRef::GetClangTypeNode(CompilerType clang_type, if (!is_vector) break; - auto qual_type = ClangUtil::GetQualType(clang_type); + auto qual_type = ClangUtil::GetQualType(clang_type); const auto *ptr = qual_type.getTypePtrOrNull(); if (!ptr) break; diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h index 487e2d0a02d8d..eacdf8e5e404c 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h @@ -370,6 +370,20 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { CanonicalizeSugar(swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node); + /// Finds the nominal type node (struct, class, enum) that contains the + /// module and identifier nodes for that type. If \p node is not a valid + /// type node, returns a nullptr. + static swift::Demangle::NodePointer + FindTypeWithModuleAndIdentifierNode(swift::Demangle::NodePointer node); + + /// Types with the @_originallyDefinedIn attribute are serialized with with + /// the original module name in reflection metadata. At the same time the type + /// is serialized with the swiftmodule name in debug info, but with a parent + /// module with the original module name. This function adjusts \type to look + /// up the type in reflection metadata if necessary. + std::string + AdjustTypeForOriginallyDefinedInModule(llvm::StringRef mangled_typename); + /// Return the canonicalized Demangle tree for a Swift mangled type name. swift::Demangle::NodePointer GetCanonicalDemangleTree(swift::Demangle::Demangler &dem, diff --git a/lldb/test/API/lang/swift/originally_defined_in/Makefile b/lldb/test/API/lang/swift/originally_defined_in/Makefile new file mode 100644 index 0000000000000..9cbc80dc6c211 --- /dev/null +++ b/lldb/test/API/lang/swift/originally_defined_in/Makefile @@ -0,0 +1,3 @@ +SWIFT_SOURCES := main.swift + + include Makefile.rules diff --git a/lldb/test/API/lang/swift/originally_defined_in/TestSwiftOriginallyDefinedIn.py b/lldb/test/API/lang/swift/originally_defined_in/TestSwiftOriginallyDefinedIn.py new file mode 100644 index 0000000000000..1b9ca376d79e6 --- /dev/null +++ b/lldb/test/API/lang/swift/originally_defined_in/TestSwiftOriginallyDefinedIn.py @@ -0,0 +1,102 @@ +import os +import lldb +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbtest as lldbtest +import lldbsuite.test.lldbutil as lldbutil + + +class TestSwiftOriginallyDefinedIn(lldbtest.TestBase): + @swiftTest + def test(self): + """Test that types with the @_originallyDefinedIn attribute can still be found in metadata""" + + self.build() + self.runCmd("setting set symbols.swift-enable-ast-context false") + filespec = lldb.SBFileSpec("main.swift") + target, process, thread, breakpoint1 = lldbutil.run_to_source_breakpoint( + self, "break here", filespec + ) + self.expect("frame variable a", substrs=["a = (i = 10)"]) + self.expect("frame variable b", substrs=["b = (i = 20)"]) + self.expect("frame variable d", substrs=["d = (i = 30)"]) + self.expect("frame variable e", substrs=["i = 50"]) + self.expect("frame variable f", substrs=["i = 40"]) + self.expect("frame variable g", substrs=["i = 60"]) + self.expect("frame variable h", substrs=["t = (i = 50)", "u = (i = 70)"]) + self.expect("frame variable i", substrs=["(i = 10)", "(i = 40)", "(i = 50)"]) + self.expect( + "frame variable complex", + substrs=[ + "t = t {", + "t = {", + "t = (i = 70)", + "u = (i = 30)", + "u = t {", + "t = (i = 50)", + ], + ) + + @swiftTest + def test_expr(self): + """Test that types with the @_originallyDefinedIn attribute can still be found in metadata""" + + self.build() + filespec = lldb.SBFileSpec("main.swift") + target, process, thread, breakpoint1 = lldbutil.run_to_source_breakpoint( + self, "break here", filespec + ) + self.expect("expr a", substrs=["(i = 10)"]) + self.expect("expr b", substrs=["(i = 20)"]) + self.expect("expr d", substrs=["(i = 30)"]) + self.expect("expr e", substrs=["(i = 50)"]) + self.expect("expr f", substrs=["i = 40"]) + self.expect("expr g", substrs=["i = 60"]) + self.expect("expr i", substrs=["(i = 10)", "(i = 40)", "(i = 50)"]) + self.expect( + "expr complex", + substrs=[ + "t = t {", + "t = {", + "t = (i = 70)", + "u = (i = 30)", + "u = t {", + "t = (i = 50)", + ], + ) + + @swiftTest + def test_expr_from_generic(self): + """Test that types with the @_originallyDefinedIn attribute can still be found in metadata""" + + self.build() + filespec = lldb.SBFileSpec("main.swift") + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( + self, "break for generic", filespec + ) + self.expect("expr t", substrs=["(i = 10)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect("expr t", substrs=["(i = 20)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect("expr t", substrs=["(i = 30)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect("expr t", substrs=["(i = 50)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect("expr t", substrs=["(i = 40)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect("expr t", substrs=["(i = 60)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect("expr t", substrs=["t = (i = 50)", "u = (i = 70)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect("expr t", substrs=["(i = 10)", "(i = 40)", "(i = 50)"]) + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect( + "expr t", + substrs=[ + "t = t {", + "t = {", + "t = (i = 70)", + "u = (i = 30)", + "u = t {", + "t = (i = 50)", + ], + ) diff --git a/lldb/test/API/lang/swift/originally_defined_in/main.swift b/lldb/test/API/lang/swift/originally_defined_in/main.swift new file mode 100644 index 0000000000000..83cc99e4e7c19 --- /dev/null +++ b/lldb/test/API/lang/swift/originally_defined_in/main.swift @@ -0,0 +1,110 @@ +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public struct A { + let i = 10 +} + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public struct B { + let i = 20 +} + +typealias Alias = B + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public enum C { + public struct D { + let i = 30 + } +} + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public enum E { + case t(T) + case empty +} + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public class F { + let i = 40 +} + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public enum G { + case i(Int) + case empty +} + +public struct Prop { + let i = 50 +} + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public struct Prop2 { + let i = 70 +} + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public struct Pair { + let t: T + let u: U +} + +@_originallyDefinedIn( + module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0) +@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *) +public class ClassPair { + let t: T + let u: U + init(t: T, u: U) { + self.t = t + self.u = u + } +} + +func generic(_ t: T) { + print("break for generic") +} + +func f() { + let a = A() + let b = Alias() + let d = C.D() + let e = E.t(Prop()) + let f = F() + let g = G.i(60) + let h = ClassPair(t: Prop(), u: Prop2()) + let i = (A(), F(), Prop()) + let complex = Pair(t: E.t(Pair(t: Prop2(), u: C.D())), u: E.t(Prop())) + print("break here") +} + +func g() { + generic(A()) + generic(Alias()) + generic(C.D()) + generic(E.t(Prop())) + generic(F()) + generic(G.i(60)) + generic(ClassPair(t: Prop(), u: Prop2())) + generic((A(), F(), Prop())) + generic(Pair(t: E.t(Pair(t: Prop2(), u: C.D())), u: E.t(Prop()))) +} + +f() +g()