diff --git a/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/Makefile b/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/Makefile new file mode 100644 index 000000000000..1c9f30513ba0 --- /dev/null +++ b/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/Makefile @@ -0,0 +1,4 @@ +LEVEL = ../../../../make +SWIFT_SOURCES := main.swift +SWIFT_OBJC_INTEROP := 1 +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py b/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py new file mode 100644 index 000000000000..1048d65fc050 --- /dev/null +++ b/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py @@ -0,0 +1,5 @@ +import lldbsuite.test.lldbinline as lldbinline +from lldbsuite.test.decorators import * + +lldbinline.MakeInlineTest(__file__, globals(), + decorators=[swiftTest,skipUnlessDarwin]) diff --git a/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/main.swift b/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/main.swift new file mode 100644 index 000000000000..0555b4b19802 --- /dev/null +++ b/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/decimal/main.swift @@ -0,0 +1,18 @@ +import Foundation + +func main() { + let x = Decimal(42.5) + let y = Decimal(422.5) + let z = Decimal(-23.6) + let patatino = Decimal(12345567888.1234) + return //%self.expect("frame var -d run -- x", substrs=['42.5']) + //%self.expect("expr -d run -- x", substrs=['42.5']) + //%self.expect("frame var -d run -- y", substrs=['422.5']) + //%self.expect("expr -d run -- y", substrs=['422.5']) + //%self.expect("frame var -d run -- z", substrs=['-23.6']) + //%self.expect("expr -d run -- z", substrs=['-23.6']) + //%self.expect("frame var -d run -- patatino", substrs=['12345567888.123']) + //%self.expect("expr -d run -- patatino", substrs=['12345567888.123']) +} + +main() diff --git a/source/Plugins/Language/Swift/FoundationValueTypes.cpp b/source/Plugins/Language/Swift/FoundationValueTypes.cpp index 4f540c26619c..789429089745 100644 --- a/source/Plugins/Language/Swift/FoundationValueTypes.cpp +++ b/source/Plugins/Language/Swift/FoundationValueTypes.cpp @@ -471,6 +471,85 @@ bool lldb_private::formatters::swift::Data_SummaryProvider( return true; } +bool lldb_private::formatters::swift::Decimal_SummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + + // The layout of the type is: + // public struct Decimal { + // fileprivate var __exponent : Int8 + // fileprivate var __lengthAndFlags: UInt8 + // fileprivate var __reserved: UInt16 + // public var _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, + // UInt16, UInt16) + // We do have to harcode the offset of the variables because they're + // fileprivate, but we can access `_mantissa` by name. + + ProcessSP process(valobj.GetProcessSP()); + if (!process) + return false; + + Status error; + DataExtractor data_extractor; + if (!valobj.GetData(data_extractor, error)) + return false; + + offset_t offset_ptr = 0; + int8_t exponent = data_extractor.GetU8(&offset_ptr); + uint8_t length_and_flags = data_extractor.GetU8(&offset_ptr); + uint8_t length = length_and_flags & 0xf; + bool isNegative = length_and_flags & 0x10; + + static ConstString g_mantissa("_mantissa"); + ValueObjectSP mantissa_sp = valobj.GetChildAtNamePath(g_mantissa); + if (!mantissa_sp) + return false; + + // Easy case. length == 0 is either `NaN` or `0`. + if (length == 0) { + if (isNegative) + stream.Printf("NaN"); + else + stream.Printf("0"); + return true; + } + + // Mantissa is represented as a tuple of 8 UInt16. + const uint8_t num_children = 8; + if (mantissa_sp->GetNumChildren() != num_children) + return false; + + std::vector mantissa_elements; + for (int i = 0; i < 8; ++i) { + ValueObjectSP child_sp = mantissa_sp->GetChildAtIndex(i, true); + if (!child_sp) + return false; + static ConstString g_value("_value"); + ValueObjectSP value_sp = child_sp->GetChildAtNamePath(g_value); + if (!value_sp) + return false; + auto val = value_sp->GetValueAsUnsigned(0) & 0xffff; + mantissa_elements.push_back(static_cast(val)); + } + + // Compute the value using mantissa and exponent + double d = 0.0; + for (int i = std::min(length, num_children); i > 0; i--) { + d = (d * 65536) + mantissa_elements[i - 1]; + } + + if (exponent < 0) + for (int i = exponent; i < 0; ++i) + d /= 10.0; + else + for (int i = 0; i < exponent; ++i) + d *= 10.0; + + if (isNegative) + d = -d; + + stream.Printf("%lf\n", d); + return true; +} class URLComponentsSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd { public: diff --git a/source/Plugins/Language/Swift/FoundationValueTypes.h b/source/Plugins/Language/Swift/FoundationValueTypes.h index 826bd4814931..9fd188e438fe 100644 --- a/source/Plugins/Language/Swift/FoundationValueTypes.h +++ b/source/Plugins/Language/Swift/FoundationValueTypes.h @@ -46,6 +46,9 @@ bool UUID_SummaryProvider(ValueObject &valobj, Stream &stream, bool Data_SummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); +bool Decimal_SummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + SyntheticChildrenFrontEnd * URLComponentsSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/source/Plugins/Language/Swift/SwiftLanguage.cpp b/source/Plugins/Language/Swift/SwiftLanguage.cpp index 48176119ed59..d75965b7c1d0 100644 --- a/source/Plugins/Language/Swift/SwiftLanguage.cpp +++ b/source/Plugins/Language/Swift/SwiftLanguage.cpp @@ -626,6 +626,12 @@ LoadFoundationValueTypesFormatters(lldb::TypeCategoryImplSP swift_category_sp) { "Data summary provider", ConstString("Foundation.Data"), TypeSummaryImpl::Flags(summary_flags).SetDontShowChildren(true)); + lldb_private::formatters::AddCXXSummary( + swift_category_sp, + lldb_private::formatters::swift::Decimal_SummaryProvider, + "Decimal summary provider", ConstString("Foundation.Decimal"), + TypeSummaryImpl::Flags(summary_flags).SetDontShowChildren(true)); + lldb_private::formatters::AddCXXSynthetic( swift_category_sp, lldb_private::formatters::swift::URLComponentsSyntheticFrontEndCreator,