diff --git a/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp b/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp index cafa301ce672f..44de91ab90807 100644 --- a/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp +++ b/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp @@ -341,17 +341,39 @@ bool lldb_private::formatters::swift::Data_SummaryProvider( // where the byte count is the size of _slice. Detect that layout and handle // it before falling through to the legacy enum logic below. { + CompilerType repr_type = representation_enum_sp->GetCompilerType(); + const uint32_t repr_flags = repr_type.GetTypeInfo(); + const bool is_struct = (repr_flags & lldb::eTypeIsStructUnion) && + !(repr_flags & lldb::eTypeIsEnumeration); + + static constexpr llvm::StringLiteral g__storage("_storage"); static constexpr llvm::StringLiteral g__slice("_slice"); + ValueObjectSP storage_sp = + representation_enum_sp->GetChildAtNamePath({g__storage}); ValueObjectSP slice_sp = representation_enum_sp->GetChildAtNamePath({g__slice}); - if (slice_sp) { + // Swift's Int is pointer-sized, so a Range is two pointers wide. + ProcessSP process_sp(valobj.GetProcessSP()); + const uint64_t int_size = process_sp ? process_sp->GetAddressByteSize() : 0; + const uint64_t range_size = 2 * int_size; + if (!int_size) + return false; + const uint64_t slice_size = + slice_sp ? llvm::expectedToStdOptional(slice_sp->GetByteSize()) + .value_or(0) + : 0; + + // Identify the layout structurally: a struct (not the legacy enum) with + // both _storage and a _slice that is exactly two Ints wide. + if (is_struct && storage_sp && slice_sp && slice_size == range_size) { DataExtractor extractor; Status error; - if (slice_sp->GetData(extractor, error) < 16 || error.Fail()) + if (slice_sp->GetData(extractor, error) < range_size || error.Fail()) return false; lldb::offset_t offset = 0; - int64_t lowerBound = (int64_t)extractor.GetU64(&offset); - int64_t upperBound = (int64_t)extractor.GetU64(&offset); + // GetAddress() reads a pointer-sized value. + int64_t lowerBound = (int64_t)extractor.GetAddress(&offset); + int64_t upperBound = (int64_t)extractor.GetAddress(&offset); int64_t count = upperBound - lowerBound; if (count == 1) diff --git a/lldb/test/API/lang/swift/array_tuple_resilient/main.swift b/lldb/test/API/lang/swift/array_tuple_resilient/main.swift index 93b277b8f0a26..c49faa25f528c 100644 --- a/lldb/test/API/lang/swift/array_tuple_resilient/main.swift +++ b/lldb/test/API/lang/swift/array_tuple_resilient/main.swift @@ -6,11 +6,11 @@ import Foundation var patatino : [(Data, Int64)] = [(Data([1, 2, 3]), 1001)] var tinky : [(Data, Data)] = [(Data([1, 2, 3]), Data([9]))] print(patatino) //%self.expect('frame variable -d run -- patatino', - //% substrs=['byte', '1 = 1001']) + //% substrs=['0 = 3 bytes', '1 = 1001']) //%self.expect('expr -d run -- patatino', - //% substrs=['byte', '1 = 1001']) + //% substrs=['0 = 3 bytes', '1 = 1001']) print(tinky) //%self.expect('frame variable -d run -- tinky', - //% substrs=['byte']) + //% substrs=['0 = 3 bytes', '1 = 1 byte']) //%self.expect('expr -d run -- tinky', - //% substrs=['byte']) + //% substrs=['0 = 3 bytes', '1 = 1 byte']) diff --git a/lldb/test/API/lang/swift/explicit_modules/simple/TestSwiftExplicitModules_part02.py b/lldb/test/API/lang/swift/explicit_modules/simple/TestSwiftExplicitModules_part02.py index f0d0063f0718e..403b4566669df 100644 --- a/lldb/test/API/lang/swift/explicit_modules/simple/TestSwiftExplicitModules_part02.py +++ b/lldb/test/API/lang/swift/explicit_modules/simple/TestSwiftExplicitModules_part02.py @@ -9,6 +9,11 @@ class TestSwiftExplicitModules(lldbtest.TestBase): @skipEmbeddedSwift @swiftTest @skipUnlessDarwin + # Not working correctly with DWARFImporter. NSData may get an + # incomplete definition that also isn't updated when Foundation is + # imported. + @skipIf(setting=("symbols.use-swift-clangimporter", "false"), + bugnumber="rdar://118337109") def test_import(self): """Test an implicit import inside an explicit build""" mod_cache = self.getBuildArtifact("my-clang-modules-cache") @@ -27,4 +32,4 @@ def test_import(self): error=True) self.expect("expression import Foundation") self.expect('expression Data([1, 2, 3])', - substrs=["byte"]) + substrs=["3 bytes"]) diff --git a/lldb/test/Shell/SwiftREPL/ResilientArray.test b/lldb/test/Shell/SwiftREPL/ResilientArray.test index 6510e57bd805e..90a3ca5abfbfa 100644 --- a/lldb/test/Shell/SwiftREPL/ResilientArray.test +++ b/lldb/test/Shell/SwiftREPL/ResilientArray.test @@ -11,6 +11,6 @@ import Foundation let x : [Data] = [Data([1, 2, 3]), Data([9])] // CHECK: {{x}}: [Foundation.Data] = 2 values { -// CHECK-NEXT: byte -// CHECK-NEXT: byte +// CHECK-NEXT: [0] = 3 bytes +// CHECK-NEXT: [1] = 1 byte // CHECK-NEXT: } diff --git a/lldb/test/Shell/SwiftREPL/ResilientDict.test b/lldb/test/Shell/SwiftREPL/ResilientDict.test index 8d8b7506ed36d..ac46ba54612c0 100644 --- a/lldb/test/Shell/SwiftREPL/ResilientDict.test +++ b/lldb/test/Shell/SwiftREPL/ResilientDict.test @@ -15,13 +15,13 @@ import Foundation let x : [Data:Int] = [Data([1, 2, 3]): 40, Data([9]): 230] // DICT-LABEL: {{x}}: [Foundation.Data : Int] = 2 key/value pairs { // DICT: [{{[0-1]}}] = { -// DICT: byte -// DICT: value = 40 +// DICT: key = 3 bytes +// DICT-NEXT: value = 40 // DICT-NEXT: } let y : [Data:Int] = [Data([1, 2, 3]): 40, Data([9]): 230] // DICT-LABEL: {{y}}: [Foundation.Data : Int] = 2 key/value pairs { // DICT: [{{[0-1]}}] = { -// DICT: byte -// DICT: value = 230 +// DICT: key = 1 byte +// DICT-NEXT: value = 230 // DICT-NEXT: }