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/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/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()); +} 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()