diff --git a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp index 1d3ac3ff049ff..c70ca4d0387fb 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp @@ -2076,8 +2076,7 @@ ReadVector(Process &process, ValueObject &valobj, const SIMDElementFormatter &formatter, unsigned num_elements) { Status error; static ConstString g_storage("_storage"); - static ConstString g_value("_value"); - ValueObjectSP value_sp = valobj.GetChildAtNamePath({g_storage, g_value}); + ValueObjectSP value_sp = valobj.GetChildMemberWithName(g_storage); if (!value_sp) return std::nullopt; diff --git a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp index 6bd7e1b65a226..bf1dde348a5f8 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp @@ -1015,30 +1015,34 @@ SwiftLanguage::GetHardcodedSynthetics() { g_formatters.push_back( [](lldb_private::ValueObject &valobj, lldb::DynamicValueType dyn_type, FormatManager &format_manager) -> lldb::SyntheticChildrenSP { - struct IsEligible { - static bool Check(ValueObject &valobj, const CompilerType &type) { - bool is_imported = false; - - if (type.IsValid()) { - auto swift_ast_ctx = - type.GetTypeSystem().dyn_cast_or_null(); - if (swift_ast_ctx && swift_ast_ctx->IsImportedType( - type.GetOpaqueQualType(), nullptr)) - is_imported = true; - } + // Determine if this is an Objective-C object that benefits + // from the ObjC synthetic child provider. + std::function is_eligible = + [&](ValueObject &valobj, CompilerType type) { + if (!type.IsValid()) + return false; - ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); - if (is_imported && type.GetNumFields(&exe_ctx) == 0) - return true; - if (valobj.IsBaseClass() && type.IsRuntimeGeneratedType()) { - auto parent(valobj.GetParent()); - if (!parent) + CompilerType clang_type; + if (auto ts = + type.GetTypeSystem().dyn_cast_or_null()) + if (ts->IsImportedType(type.GetOpaqueQualType(), &clang_type)) + // Could be an Objective-C object with no debug info; we + // can get ivars from the runtime. + if (!clang_type) + return true; + // Is this an Objective-C object with debug info? + if (clang_type && Flags(clang_type.GetTypeClass()) + .AnySet(eTypeClassObjCInterface | + eTypeClassObjCObjectPointer | + eTypeClassObjCObject)) + return true; + if (valobj.IsBaseClass() && type.IsRuntimeGeneratedType()) { + if (ValueObject *parent = valobj.GetParent()) + return is_eligible(*parent, parent->GetCompilerType()); return false; - return IsEligible::Check(*parent, parent->GetCompilerType()); - } - return false; - } - }; + } + return false; + }; if (dyn_type == lldb::eNoDynamicValues) return nullptr; @@ -1048,7 +1052,7 @@ SwiftLanguage::GetHardcodedSynthetics() { g_runtime_synths_category_name, can_create)); if (!category_sp || category_sp->IsEnabled() == false) return nullptr; - if (IsEligible::Check(valobj, type)) { + if (is_eligible(valobj, type)) { ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return nullptr; diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h index 87d96a18ac451..24aef864e8529 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h @@ -402,7 +402,7 @@ class SwiftLanguageRuntime : public LanguageRuntime { llvm::Expected GetNumChildren(CompilerType type, ExecutionContextScope *exe_scope, bool include_superclass = true, - bool include_clang_types = true); + bool omit_empty_base_classes = true); /// Determine the enum case name for the \p data value of the enum \p type. /// This is performed using Swift reflection. @@ -435,11 +435,10 @@ class SwiftLanguageRuntime : public LanguageRuntime { /// don't have an index. /// /// \returns {true, {num_idexes}} on success. - std::pair> - GetIndexOfChildMemberWithName(CompilerType type, llvm::StringRef name, - ExecutionContext *exe_ctx, - bool omit_empty_base_classes, - std::vector &child_indexes); + std::pair> GetIndexOfChildMemberWithName( + CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx, + bool omit_empty_base_classes, bool include_clang_types, + std::vector &child_indexes); /// Ask Remote Mirrors about a child of a composite type. llvm::Expected GetChildCompilerTypeAtIndex( diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp index f3ad5a2008c61..116ffa543155b 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "LLDBMemoryReader.h" +#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" #include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h" #include "ReflectionContextInterface.h" #include "SwiftLanguageRuntime.h" @@ -33,7 +34,9 @@ #include "lldb/ValueObject/ValueObjectMemory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" +#include "lldb/lldb-enumerations.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTWalker.h" @@ -728,7 +731,7 @@ class SwiftRuntimeTypeVisitor { CompilerType m_type; ValueObject *m_valobj = nullptr; bool m_hide_superclass = false; - bool m_include_clang_types = false; + bool m_omit_empty_base_classes = true; bool m_visit_superclass = false; void SetFlavor() { @@ -757,26 +760,27 @@ class SwiftRuntimeTypeVisitor { using VisitCallback = std::function; SwiftRuntimeTypeVisitor(SwiftLanguageRuntime &runtime, CompilerType type, - ValueObject *valobj) - : m_runtime(runtime), m_type(type), m_valobj(valobj) { + ValueObject *valobj, bool omit_empty_base_classes) + : m_runtime(runtime), m_type(type), m_valobj(valobj), + m_omit_empty_base_classes(omit_empty_base_classes) { if (valobj) m_exe_ctx = valobj->GetExecutionContextRef(); SetFlavor(); } SwiftRuntimeTypeVisitor(SwiftLanguageRuntime &runtime, CompilerType type, ExecutionContextScope *exe_scope, - bool hide_superclass, bool include_clang_types) + bool hide_superclass, bool omit_empty_base_classes) : m_runtime(runtime), m_type(type), m_hide_superclass(hide_superclass), - m_include_clang_types(include_clang_types) { + m_omit_empty_base_classes(omit_empty_base_classes) { if (exe_scope) exe_scope->CalculateExecutionContext(m_exe_ctx); SetFlavor(); } SwiftRuntimeTypeVisitor(SwiftLanguageRuntime &runtime, CompilerType type, ExecutionContext *exe_ctx, bool hide_superclass, - bool include_clang_types, bool visit_superclass) + bool omit_empty_base_classes, bool visit_superclass) : m_runtime(runtime), m_type(type), m_hide_superclass(hide_superclass), - m_include_clang_types(include_clang_types), + m_omit_empty_base_classes(omit_empty_base_classes), m_visit_superclass(visit_superclass) { if (exe_ctx) m_exe_ctx = *exe_ctx; @@ -800,9 +804,7 @@ class SwiftRuntimeTypeVisitor { llvm::Expected SwiftRuntimeTypeVisitor::VisitImpl(std::optional visit_only, - VisitCallback visit_callback) - -{ + VisitCallback visit_callback) { if (!m_type) return llvm::createStringError("invalid type"); @@ -854,19 +856,91 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional visit_only, return success; } - // FIXME: Remove this entire mode. - assert(!m_include_clang_types || (m_include_clang_types && count_only)); - if (m_include_clang_types && count_only) { + auto visit_clang_type = + [&](CompilerType clang_type) -> llvm::Expected { + auto swiftify = [&](CompilerType type) { + if (!type.GetTypeSystem().isa_and_nonnull()) + return type; + CompilerType swift_type = ts.ConvertClangTypeToSwiftType(type); + return swift_type ? swift_type : type; + }; + unsigned depth = 0; + auto n_or_err = + clang_type.GetNumChildren(m_omit_empty_base_classes, &m_exe_ctx); + if (!n_or_err) + return n_or_err.takeError(); + unsigned n = *n_or_err; + bool is_signed, is_enum = clang_type.IsEnumerationType(is_signed); + if (count_only) + return is_enum ? 1 : n; + if (is_enum) { + auto get_name = [&]() -> std::string { return "rawValue"; }; + auto get_info = [&]() -> llvm::Expected { + auto ts = + clang_type.GetTypeSystem().dyn_cast_or_null(); + + if (!ts) + return llvm::createStringError("no clang type system"); + clang::EnumDecl *enum_decl = ts->GetAsEnumDecl(clang_type); + if (!enum_decl) + return llvm::createStringError("no enum decl"); + swift::Demangle::Demangler dem; + CompilerType raw_value = + CompilerType(ts, enum_decl->getIntegerType().getAsOpaquePtr()); + + auto bit_size = + raw_value.GetBitSize(m_exe_ctx.GetBestExecutionContextScope()); + if (!bit_size) + return bit_size.takeError(); + ChildInfo child; + child.byte_size = *bit_size / 8; + child.byte_offset = 0; + child.bitfield_bit_size = 0; + child.bitfield_bit_offset = 0; + child.is_base_class = false; + child.is_deref_of_parent = false; + child.language_flags = 0; + return child; + }; + return visit_callback(clang_type, depth, get_name, get_info); + } + for (unsigned i = 0; i < n; ++i) + if (!visit_only || *visit_only == i) { + bool transparent_pointers = false; + bool ignore_array_bounds = false; + std::string child_name; + ChildInfo child; + auto child_type_or_err = clang_type.GetChildCompilerTypeAtIndex( + &m_exe_ctx, i, transparent_pointers, m_omit_empty_base_classes, + ignore_array_bounds, child_name, child.byte_size, child.byte_offset, + child.bitfield_bit_size, child.bitfield_bit_offset, + child.is_base_class, child.is_deref_of_parent, nullptr, + child.language_flags); + if (!child_type_or_err) + return child_type_or_err.takeError(); + CompilerType type = swiftify(*child_type_or_err); + auto get_name = [&]() -> std::string { return child_name; }; + auto get_info = [&]() -> llvm::Expected { return child; }; + if (auto err = visit_callback(type, depth, get_name, get_info)) + return err; + } + return success; + }; + + { CompilerType clang_type = m_runtime.LookupAnonymousClangType( m_type.GetMangledTypeName().AsCString()); if (!clang_type) ts.IsImportedType(m_type.GetOpaqueQualType(), &clang_type); if (clang_type) { clang_type = GetTypedefedTypeRecursive(clang_type); - bool is_signed; - if (clang_type.IsEnumerationType(is_signed)) - return 1; - return clang_type.GetNumChildren(true, &m_exe_ctx); + auto result = visit_clang_type(clang_type); + if (result) + return result; + // FIXME: It would be nice not to fall through here. CFStringRef + // needs this path right now. + LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), result.takeError(), + "could not resolve as clang type: {0}"); } } @@ -1113,6 +1187,57 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional visit_only, if (ts.IsBuiltinType(m_type)) return 0; + // Resolve ObjC references via the ObjC runtime. + auto visit_objcclass = [&](const swift::reflection::ObjCClassTypeRef &tr) + -> llvm::Expected { + const std::string &name = tr.getName(); + auto *process = m_exe_ctx.GetProcessPtr(); + if (!process) + return llvm::createStringError( + "cannot resolve objc type without process"); + auto objc_runtime = SwiftLanguageRuntime::GetObjCRuntime(*process); + if (!objc_runtime) + return llvm::createStringError("no Objective-C runtime"); + AppleObjCRuntime::ObjCISA isa = objc_runtime->GetISA(ConstString(name)); + if (!isa) + return llvm::createStringError("no Objective-C class " + name); + AppleObjCRuntime::ClassDescriptorSP desc_sp = + objc_runtime->GetClassDescriptorFromISA(isa); + if (!desc_sp) + return llvm::createStringError("no class descriptor for " + name); + bool has_super = !m_hide_superclass && desc_sp->GetSuperclass(); + unsigned n = 0; + if (count_only) + return has_super ? n + 1 : n; + + unsigned depth = 0; + if (has_super) + if (!visit_only || *visit_only == i) { + if (AppleObjCRuntime::ClassDescriptorSP superclass_desc_sp = + desc_sp->GetSuperclass()) { + auto get_name = [&]() -> std::string { + return superclass_desc_sp->GetClassName().GetString(); + }; + auto get_info = [&]() -> llvm::Expected { + return ChildInfo(); + }; + CompilerType type; + if (TypeSP type_sp = superclass_desc_sp->GetType()) + type = type_sp->GetForwardCompilerType(); + if (auto err = visit_callback(type, depth, get_name, get_info)) + return err; + if (visit_only) + return success; + } + } + // We could query the runtime for the children here but that + // would be inconsistent with SwiftASTContext. + return success; + }; + if (auto *obj_tr = + llvm::dyn_cast_or_null(tr)) + return visit_objcclass(*obj_tr); + LLDBTypeInfoProvider tip(m_runtime, ts); auto cti_or_err = reflection_ctx->GetClassInstanceTypeInfo( *tr, &tip, ts.GetDescriptorFinder()); @@ -1452,9 +1577,9 @@ SwiftLanguageRuntime::GetNumFields(CompilerType type, llvm::Expected SwiftLanguageRuntime::GetNumChildren( CompilerType type, ExecutionContextScope *exe_scope, - bool include_superclass, bool include_clang_types) { + bool include_superclass, bool omit_empty_base_classes) { SwiftRuntimeTypeVisitor visitor(*this, type, exe_scope, !include_superclass, - include_clang_types); + omit_empty_base_classes); return visitor.CountChildren(); } @@ -1622,8 +1747,10 @@ SwiftLanguageRuntime::ProjectEnum(ValueObject &valobj) { std::pair> SwiftLanguageRuntime::GetIndexOfChildMemberWithName( CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx, - bool omit_empty_base_classes, std::vector &child_indexes) { - SwiftRuntimeTypeVisitor visitor(*this, type, exe_ctx, false, false, true); + bool omit_empty_base_classes, bool include_clang_types, + std::vector &child_indexes) { + SwiftRuntimeTypeVisitor visitor(*this, type, exe_ctx, false, + include_clang_types, true); bool found = false; unsigned i = 0, last_depth = 0; llvm::Error error = visitor.VisitAllChildren( @@ -1640,7 +1767,7 @@ SwiftLanguageRuntime::GetIndexOfChildMemberWithName( return info_or_err.takeError(); // All enum children are index 0. if (info_or_err->is_enum || name == get_child_name()) { - // The only access paths supperted are into base classes, + // The only access paths supported are into base classes, // which are always at index 0. for (unsigned j = 0; j < depth; ++j) child_indexes.push_back(0); @@ -1670,7 +1797,7 @@ llvm::Expected SwiftLanguageRuntime::GetChildCompilerTypeAtIndex( uint64_t &language_flags) { CompilerType child_type; bool found = false; - SwiftRuntimeTypeVisitor visitor(*this, type, valobj); + SwiftRuntimeTypeVisitor visitor(*this, type, valobj, omit_empty_base_classes); llvm::Error error = visitor.VisitChildAtIndex( idx, [&](CompilerType type, unsigned depth, auto get_child_name, diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp index a104754ad04d5..a9af8f057c5ed 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp @@ -3025,6 +3025,7 @@ bool Equivalent(std::optional l, std::optional r) { // Assume that any value is "better" than none. if (l.has_value() && !r.has_value()) return true; + llvm::dbgs() << l << " != " << r << "\n"; return false; } @@ -3037,7 +3038,7 @@ bool Equivalent(std::optional l, std::optional r) { if (l.has_value() && !r.has_value()) return true; if (!l.has_value() && r.has_value()) { - llvm::dbgs() << "{} != \n"; + llvm::dbgs() << "{} != " << r->GetMangledTypeName() << "\n"; return false; } return Equivalent(*l, *r); @@ -4096,15 +4097,8 @@ TypeSystemSwiftTypeRef::GetNumChildren(opaque_compiler_type_t type, if (auto *exe_scope = exe_ctx->GetBestExecutionContextScope()) if (auto *runtime = SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) - return runtime->GetNumChildren(GetCanonicalType(type), exe_scope); - - if (CompilerType clang_type = GetAsClangTypeOrNull(type)) { - bool is_signed; - // Clang-imported enum types always have one child in Swift. - if (clang_type.IsEnumerationType(is_signed)) - return 1; - return clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx); - } + return runtime->GetNumChildren(GetCanonicalType(type), exe_scope, + true, omit_empty_base_classes); return llvm::createStringError(llvm::inconvertibleErrorCode(), "incomplete type information"); }; @@ -4239,7 +4233,10 @@ TypeSystemSwiftTypeRef::ConvertClangTypeToSwiftType(CompilerType clang_type) { swift::Demangle::Demangler dem; swift::Demangle::NodePointer node = GetClangTypeTypeNode(dem, clang_type); - return RemangleAsType(dem, node, GetManglingFlavor()); + CompilerType result = RemangleAsType(dem, node, GetManglingFlavor()); + m_imported_type_map.Insert(result.GetMangledTypeName().AsCString(), + clang_type); + return result; } llvm::Expected @@ -4293,7 +4290,7 @@ TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( if (auto *runtime = SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) { auto result = runtime->GetChildCompilerTypeAtIndex( - {weak_from_this(), type}, idx, transparent_pointers, + GetCanonicalType(type), idx, transparent_pointers, omit_empty_base_classes, ignore_array_bounds, child_name, child_byte_size, child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, @@ -4310,109 +4307,6 @@ TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( if (!result) error = llvm::toString(result.takeError()); } - // Clang types can be resolved even without a process. - bool is_signed; - if (CompilerType clang_type = GetAsClangTypeOrNull(type)) { - if (clang_type.IsEnumerationType(is_signed) && idx == 0) - // C enums get imported into Swift as structs with a "rawValue" field. - if (auto ts = clang_type.GetTypeSystem() - .dyn_cast_or_null()) - if (clang::EnumDecl *enum_decl = ts->GetAsEnumDecl(clang_type)) { - swift::Demangle::Demangler dem; - CompilerType raw_value = CompilerType( - ts, enum_decl->getIntegerType().getAsOpaquePtr()); - child_name = "rawValue"; - auto bit_size = raw_value.GetBitSize( - exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr); - if (!bit_size) - return bit_size.takeError(); - child_byte_size = *bit_size / 8; - child_byte_offset = 0; - child_bitfield_bit_size = 0; - child_bitfield_bit_offset = 0; - child_is_base_class = false; - child_is_deref_of_parent = false; - language_flags = 0; - return RemangleAsType(dem, GetClangTypeTypeNode(dem, raw_value), - GetManglingFlavor(exe_ctx)); - } - // Otherwise defer to TypeSystemClang. - // - // Swift skips bitfields when counting children. Unfortunately - // this means we need to do this inefficient linear search here. - CompilerType clang_child_type; - for (size_t clang_idx = 0, swift_idx = 0; swift_idx <= idx; - ++clang_idx) { - child_bitfield_bit_size = 0; - child_bitfield_bit_offset = 0; - auto clang_child_type_or_err = clang_type.GetChildCompilerTypeAtIndex( - exe_ctx, clang_idx, transparent_pointers, omit_empty_base_classes, - ignore_array_bounds, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, - child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent, valobj, language_flags); - if (!clang_child_type_or_err) - LLDB_LOG_ERROR( - GetLog(LLDBLog::Types), clang_child_type_or_err.takeError(), - "could not find child {1} using clang: {0}", clang_idx); - else - clang_child_type = *clang_child_type_or_err; - if (!child_bitfield_bit_size && !child_bitfield_bit_offset) - ++swift_idx; - // FIXME: Why is this necessary? - if (clang_child_type.IsTypedefType() && - clang_child_type.GetTypeName() == - clang_child_type.GetTypedefedType().GetTypeName()) - clang_child_type = clang_child_type.GetTypedefedType(); - } - if (clang_child_type) { - // TypeSystemSwiftTypeRef can't properly handle C anonymous types, as - // the only identifier CompilerTypes backed by this type system carry - // is the type's mangled name. This is problematic for anonymous - // types, as sibling anonymous types will share the exact same mangled - // name, making it impossible to diferentiate between them. For - // example, the following two anonymous structs in "MyStruct" share - // the same name (which is MyStruct::(anonymous struct)): - // - // struct MyStruct { - // struct { - // float x; - // float y; - // float z; - // }; - // struct { - // int a; - // }; - // }; - // - // For this reason, forward any lookups of anonymous types to - // TypeSystemClang instead, as that type system carries enough - // information to handle anonymous types properly. - auto ts_clang = clang_child_type.GetTypeSystem() - .dyn_cast_or_null(); - if (ts_clang && - ts_clang->IsAnonymousType(clang_child_type.GetOpaqueQualType())) - return clang_child_type; - - std::string prefix; - swift::Demangle::Demangler dem; - swift::Demangle::NodePointer node = - GetClangTypeTypeNode(dem, clang_child_type); - if (!node) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "object has no address"); - - switch (node->getChild(0)->getKind()) { - case swift::Demangle::Node::Kind::Class: - prefix = "ObjectiveC."; - break; - default: - break; - } - child_name = prefix + child_name; - return RemangleAsType(dem, node, GetManglingFlavor(exe_ctx)); - } - } } if (!exe_scope) LLDB_LOGF(GetLog(LLDBLog::Types), @@ -4523,7 +4417,7 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName( if (auto *runtime = SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) { auto found_numidx = runtime->GetIndexOfChildMemberWithName( - GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes, + GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes, true, child_indexes); // Only use the SwiftASTContext fallback if there was an // error. If the runtime had complete type info and couldn't @@ -4727,10 +4621,13 @@ bool TypeSystemSwiftTypeRef::IsImportedType(opaque_compiler_type_t type, bool ignore_modules = false; if (!IsClangImportedType(node, decl_context, ignore_modules)) return false; - if (original_type) - if (TypeSP clang_type = LookupClangType(AsMangledName(type), decl_context, - ignore_modules)) + if (original_type) { + if (auto cached = m_imported_type_map.Lookup(AsMangledName(type))) + *original_type = cached; + else if (TypeSP clang_type = LookupClangType( + AsMangledName(type), decl_context, ignore_modules)) *original_type = clang_type->GetForwardCompilerType(); + } return true; }; // We can't validate the result because ReconstructType may call this diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h index 8b073c9591391..bf30f9ed84f27 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h @@ -625,6 +625,10 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { /// All lldb::Type pointers produced by DWARFASTParser Swift go here. ThreadSafeDenseMap m_swift_type_map; + + /// A cache of Clang types that this TypeSystem mapped into Swift. + ThreadSafeDenseMap m_imported_type_map; + /// An LRU cache for \ref GetManglingFlavor(). std::pair m_lru_is_embedded = { nullptr, swift::Mangle::ManglingFlavor::Default}; diff --git a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py index ea4f48052a1ef..f15885aa7512c 100644 --- a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py +++ b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py @@ -13,8 +13,6 @@ class MTCSwiftPropertyTestCase(TestBase): - @expectedFailureAll(bugnumber="rdar://60396797", - setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py index dd92af8db8ef3..97db099d0a51f 100644 --- a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py +++ b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py @@ -13,8 +13,6 @@ class MTCSwiftTestCase(TestBase): - @expectedFailureAll(bugnumber="rdar://60396797", - setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/c_type_external_provider/Makefile b/lldb/test/API/lang/swift/c_type_external_provider/Makefile deleted file mode 100644 index f6a450cd2e635..0000000000000 --- a/lldb/test/API/lang/swift/c_type_external_provider/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -SWIFT_SOURCES := main.swift -SWIFT_BRIDGING_HEADER := bridging-header.h -include Makefile.rules diff --git a/lldb/test/API/lang/swift/c_type_external_provider/TestSwiftCTypeExternalProvider.py b/lldb/test/API/lang/swift/c_type_external_provider/TestSwiftCTypeExternalProvider.py deleted file mode 100644 index 793a3e62dac8f..0000000000000 --- a/lldb/test/API/lang/swift/c_type_external_provider/TestSwiftCTypeExternalProvider.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Tests that LLDB uses the external type info provider for C types. -""" -import lldb -from lldbsuite.test.lldbtest import * -from lldbsuite.test.decorators import * -import lldbsuite.test.lldbutil as lldbutil - - - -class TestSwiftCTypeExternalProvider(TestBase): - def setUp(self): - TestBase.setUp(self) - self.main_source = "main.swift" - self.main_source_spec = lldb.SBFileSpec(self.main_source) - - @swiftTest - def test_swift_regex(self): - """Test that C types with builtin metadata emitted are looked up using - external type info provider.""" - self.build() - log = self.getBuildArtifact("types.log") - self.runCmd('log enable lldb types -f "%s"' % log) - lldbutil.run_to_source_breakpoint( - self, 'Set breakpoint here', self.main_source_spec) - - # Consult the second field to ensure we call GetIndexOfChildMemberWithName. - self.expect('frame var dummy.second', substrs=['2']) - - # Make sure we look up the type with the external type info provider. - provider_log_found = False - with open(log, "r", encoding='utf-8') as logfile: - for line in logfile: - if '[LLDBTypeInfoProvider] Looking up debug type info for So5DummyV' in line: - provider_log_found = True - break - self.assertTrue(provider_log_found) - diff --git a/lldb/test/API/lang/swift/c_type_external_provider/bridging-header.h b/lldb/test/API/lang/swift/c_type_external_provider/bridging-header.h deleted file mode 100644 index 0047665f51b07..0000000000000 --- a/lldb/test/API/lang/swift/c_type_external_provider/bridging-header.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef bridging_header_h -#define bridging_header_h - -struct Dummy { - int first; - int second; -}; -#endif /* bridging_header_h */ diff --git a/lldb/test/API/lang/swift/c_type_external_provider/main.swift b/lldb/test/API/lang/swift/c_type_external_provider/main.swift deleted file mode 100644 index 45352f240b494..0000000000000 --- a/lldb/test/API/lang/swift/c_type_external_provider/main.swift +++ /dev/null @@ -1,6 +0,0 @@ -var dummy = Dummy() -dummy.first = 1; -dummy.second = 2; -// Print dummy so we ensure we generate it's metadata. -print(Dummy.self) // Set breakpoint here. - diff --git a/lldb/test/API/lang/swift/clangimporter/objc_runtime_ivars/TestObjCIvarDiscovery.py b/lldb/test/API/lang/swift/clangimporter/objc_runtime_ivars/TestObjCIvarDiscovery.py index c024989b0e7bc..c86d236678328 100644 --- a/lldb/test/API/lang/swift/clangimporter/objc_runtime_ivars/TestObjCIvarDiscovery.py +++ b/lldb/test/API/lang/swift/clangimporter/objc_runtime_ivars/TestObjCIvarDiscovery.py @@ -74,14 +74,16 @@ def do_test(self, dbg): substrs=["Contents/Resources/DWARF/aTestFramework"], matching=False) - self.runCmd("frame variable -d run --show-types --ptr-depth=1") + if self.TraceOn(): + self.runCmd("log enable lldb types") + self.runCmd("frame variable -d run --show-types --ptr-depth=1") obj = self.prepare_value(self.frame().FindVariable("object")) mysubclass = self.prepare_value(obj.GetChildAtIndex(0)) myclass = self.prepare_value(mysubclass.GetChildAtIndex(0)) - m_pair = myclass.GetChildMemberWithName("m_pair") + self.assertEqual(m_pair.GetNumChildren(), 2) m_pair_A = m_pair.GetChildMemberWithName("A") m_pair_B = m_pair.GetChildMemberWithName("B") @@ -98,30 +100,29 @@ def do_test(self, dbg): m_numbers = self.prepare_value( myclass.GetChildMemberWithName("m_myclass_numbers")) - self.assertTrue( - m_numbers.GetSummary() == '3 elements', + self.assertEqual( + m_numbers.GetSummary(), '3 elements', "m_myclass_numbers != 3 elements") m_subclass_ivar = mysubclass.GetChildMemberWithName("m_subclass_ivar") - self.assertTrue( - m_subclass_ivar.GetValueAsUnsigned() == 42, + self.assertEqual( + m_subclass_ivar.GetValueAsUnsigned(), 42, "m_subclass_ivar != 42") m_mysubclass_s = mysubclass.GetChildMemberWithName("m_mysubclass_s") - self.assertTrue( - m_mysubclass_s.GetSummary() == '"an NSString here"', + self.assertEqual( + m_mysubclass_s.GetSummary(), '"an NSString here"', 'm_subclass_s != "an NSString here"') swiftivar = obj.GetChildMemberWithName("swiftivar") - self.assertTrue( - swiftivar.GetSummary() == '"Hey Swift!"', "swiftivar != Hey Swift") + self.assertEqual( + swiftivar.GetSummary(), '"Hey Swift!"', "swiftivar != Hey Swift") silly = self.prepare_value(obj.GetChildMemberWithName("silly")) silly.GetNumChildren() - # FIXME: SwiftRuntimeTypeVisitor counts but does not return members of ObjC classes. silly_x = silly.GetChildMemberWithName("x") - silly_x = silly.GetChildAtIndex(1) silly_url = silly.GetChildMemberWithName("url") - self.assertTrue(silly_x.GetValueAsUnsigned() == 12, "x != 12") + self.assertEqual(silly_x.GetValueAsUnsigned(), 12, "x != 12") + # FIXME: Private ivars are invisible, but shows up in the frame var output. #self.assertTrue(silly_url.GetSummary() == '"http://www.apple.com"', "url != apple.com") diff --git a/lldb/test/API/lang/swift/dwarfimporter/C/TestSwiftDWARFImporterC.py b/lldb/test/API/lang/swift/dwarfimporter/C/TestSwiftDWARFImporterC.py index f18f98ddbaf7b..a0326099f5931 100644 --- a/lldb/test/API/lang/swift/dwarfimporter/C/TestSwiftDWARFImporterC.py +++ b/lldb/test/API/lang/swift/dwarfimporter/C/TestSwiftDWARFImporterC.py @@ -42,6 +42,8 @@ def test_dwarf_importer(self): self.build() target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( self, 'break here', lldb.SBFileSpec('main.swift')) + log = self.getBuildArtifact("types.log") + self.runCmd('log enable lldb types -f "%s"' % log) lldbutil.check_variable(self, target.FindFirstGlobalVariable("pureSwift"), value="42") @@ -56,12 +58,15 @@ def test_dwarf_importer(self): "sub", "x = 1", "y = 2", "z = 3", "swift struct c member"]) self.expect("target variable typedef", substrs=["x = 5", "y = 6"]) - #self.expect("target variable union", - # substrs=["(DoubleLongUnion)", "long_val = 42"]) + self.expect("target variable union", + substrs=["(DoubleLongUnion)", "long_val = 42"]) self.expect("target variable fromSubmodule", substrs=["(FromSubmodule)", "x = 1", "y = 2", "z = 3"]) self.expect("target variable withPointer", substrs=["(WithPointer)", "ptr = nil"]) + self.filecheck('platform shell cat ""%s"' % log, __file__, + '--check-prefix=CHECK-TYPEINFO') + # CHECK-TYPEINFO: [LLDBTypeInfoProvider] Looking up debug type info for So4CMYKV @skipIf(archs=['ppc64le'], bugnumber='SR-10214') @swiftTest @@ -107,14 +112,6 @@ def test_negative(self): # This can't be resolved. self.expect("expr swiftStructCMember", error=True) - found = False - import io - logfile = io.open(log, "r", encoding='utf-8') - for line in logfile: - if "missing required module" in line: - found = True - self.assertTrue(found) - - process.Clear() - target.Clear() - lldb.SBDebugger.MemoryPressureDetected() + self.filecheck('platform shell cat ""%s"' % log, __file__, + '--check-prefix=CHECK-MISSING') + # CHECK-MISSING: missing required module diff --git a/lldb/test/API/lang/swift/objc_obj_field/Header.h b/lldb/test/API/lang/swift/objc_obj_field/Header.h new file mode 100644 index 0000000000000..899a1c2c71ef7 --- /dev/null +++ b/lldb/test/API/lang/swift/objc_obj_field/Header.h @@ -0,0 +1,10 @@ + +#include + +@protocol ObjcProtocol +@end + +@interface ObjcClass : NSObject +@property NSString *someString; +- (instancetype)init; +@end diff --git a/lldb/test/API/lang/swift/objc_obj_field/Makefile b/lldb/test/API/lang/swift/objc_obj_field/Makefile new file mode 100644 index 0000000000000..3a47f3d63c66d --- /dev/null +++ b/lldb/test/API/lang/swift/objc_obj_field/Makefile @@ -0,0 +1,6 @@ +SWIFT_SOURCES := main.swift +SWIFT_BRIDGING_HEADER := Header.h +OBJC_SOURCES := objc.m +SWIFT_OBJC_INTEROP := 1 + +include Makefile.rules diff --git a/lldb/test/API/lang/swift/objc_obj_field/TestSwiftObjCObjField.py b/lldb/test/API/lang/swift/objc_obj_field/TestSwiftObjCObjField.py new file mode 100644 index 0000000000000..27848ae5003ec --- /dev/null +++ b/lldb/test/API/lang/swift/objc_obj_field/TestSwiftObjCObjField.py @@ -0,0 +1,37 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil + + +class TestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @swiftTest + @skipUnlessDarwin + def test(self): + self.build() + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.swift") + ) + frame = thread.frames[0] + self.expect('settings set symbols.swift-enable-ast-context false') + c = frame.FindVariable("c") + self.assertEqual(c.GetNumChildren(), 1) + obj = c.GetChildAtIndex(0) + self.assertEqual(obj.GetNumChildren(), 2) + base = obj.GetChildAtIndex(0) + self.assertEqual(base.GetName(), "baseNSObject@0") + string = obj.GetChildAtIndex(1) + self.assertEqual(string.GetSummary(), '"The objc string"') + + objty = obj.GetType() + # FIXME: Should be Objective-C.ObjcClass! + self.assertEqual(objty.GetName(), "__C.ObjcClass") + # FIXME: This doesn't actually work because GetNumberOfFields + # does not take an SBExecutionContext, so there is no runtime. + # self.assertEqual(objty.GetNumberOfFields(), 1) + # self.assertEqual(objty.GetNumberOfDirectBaseClasses(), 1) + + # Instead end-to-end-test this. + self.expect("frame var c.objcClass._someString", substrs=['"The objc string"']) diff --git a/lldb/test/API/lang/swift/objc_obj_field/main.swift b/lldb/test/API/lang/swift/objc_obj_field/main.swift new file mode 100644 index 0000000000000..e7371389ac803 --- /dev/null +++ b/lldb/test/API/lang/swift/objc_obj_field/main.swift @@ -0,0 +1,10 @@ +class C { + let objcClass = ObjcClass()! +} + +func f(_ c: C) { + print("break here") +} + +f(C()) + diff --git a/lldb/test/API/lang/swift/objc_obj_field/objc.m b/lldb/test/API/lang/swift/objc_obj_field/objc.m new file mode 100644 index 0000000000000..3c1f4a5f53d67 --- /dev/null +++ b/lldb/test/API/lang/swift/objc_obj_field/objc.m @@ -0,0 +1,13 @@ +#include "Header.h" + +@implementation ObjcClass + +- (instancetype)init { + self = [super init]; + if (self) { + self.someString = @"The objc string"; + } + return self; +} + +@end