diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 6e86818b1d237..eeefa8f376b13 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -877,14 +877,12 @@ - - - - + + diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs index df636135d3547..80889981a05b2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using System.Runtime.Versioning; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; @@ -20,6 +21,9 @@ namespace System [DebuggerTypeProxy(typeof(SpanDebugView<>))] [DebuggerDisplay("{ToString(),raw}")] [NonVersionable] +#pragma warning disable SYSLIB1056 // Specified native type is invalid + [NativeMarshalling(typeof(ReadOnlySpanMarshaller<,>))] +#pragma warning restore SYSLIB1056 // Specified native type is invalid public readonly ref struct ReadOnlySpan { /// A byref or a native ptr. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerAttribute.cs deleted file mode 100644 index 1bdad6fbaedc0..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerAttribute.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.InteropServices.Marshalling -{ - /// - /// Attribute used to indicate that the type can be used to convert a value of the provided to a native representation. - /// - /// - /// This attribute is recognized by the runtime-provided source generators for source-generated interop scenarios. - /// It is not used by the interop marshalling system at runtime. - /// - /// - [AttributeUsage(AttributeTargets.Struct)] - public sealed class CustomTypeMarshallerAttribute : Attribute - { - public CustomTypeMarshallerAttribute(Type managedType, CustomTypeMarshallerKind marshallerKind = CustomTypeMarshallerKind.Value) - { - ManagedType = managedType; - MarshallerKind = marshallerKind; - } - - /// - /// The managed type for which the attributed type is a marshaller - /// - public Type ManagedType { get; } - - /// - /// The required shape of the attributed type - /// - public CustomTypeMarshallerKind MarshallerKind { get; } - - /// - /// When the flag is set on the size of the caller-allocated buffer in number of elements. - /// - public int BufferSize { get; set; } - - /// - /// The marshalling directions this custom type marshaller supports. - /// - /// Default is - public CustomTypeMarshallerDirection Direction { get; set; } = CustomTypeMarshallerDirection.Ref; - - /// - /// The optional features for the that the marshaller supports. - /// - public CustomTypeMarshallerFeatures Features { get; set; } - - /// - /// This type is used as a placeholder for the first generic parameter when generic parameters cannot be used - /// to identify the managed type (i.e. when the marshaller type is generic over T and the managed type is T[]) - /// - public struct GenericPlaceholder - { - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerFeatures.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerFeatures.cs deleted file mode 100644 index 7c2520bbecd07..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerFeatures.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -using System; - -#if MICROSOFT_INTEROP_SOURCEGENERATION -namespace Microsoft.Interop -#else -namespace System.Runtime.InteropServices.Marshalling -#endif -{ - /// - /// Optional features supported by custom type marshallers. - /// - [Flags] - public enum CustomTypeMarshallerFeatures - { - /// - /// No optional features supported - /// - None = 0, - /// - /// The marshaller owns unmanaged resources that must be freed - /// - UnmanagedResources = 0x1, - /// - /// The marshaller can use a caller-allocated buffer instead of allocating in some scenarios - /// - CallerAllocatedBuffer = 0x2, - /// - /// The marshaller uses the two-stage marshalling design for its instead of the one-stage design. - /// - TwoStageMarshalling = 0x4 - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerKind.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerKind.cs deleted file mode 100644 index 02cba782fd6e0..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerKind.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#if MICROSOFT_INTEROP_SOURCEGENERATION -namespace Microsoft.Interop -#else -namespace System.Runtime.InteropServices.Marshalling -#endif -{ - /// - /// The shape of a custom type marshaller for usage in source-generated interop scenarios. - /// - /// - public enum CustomTypeMarshallerKind - { - /// - /// This custom type marshaller represents a single value. - /// - Value, - /// - /// This custom type marshaller represents a container of values that are placed sequentially in memory. - /// - LinearCollection - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalUsingAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalUsingAttribute.cs index f10c2743a6021..fefeba869b150 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalUsingAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalUsingAttribute.cs @@ -10,7 +10,7 @@ namespace System.Runtime.InteropServices.Marshalling /// This attribute is recognized by the runtime-provided source generators for source-generated interop scenarios. /// It is not used by the interop marshalling system at runtime. /// - /// + /// /// [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)] public sealed class MarshalUsingAttribute : Attribute @@ -26,7 +26,7 @@ public MarshalUsingAttribute() /// /// Create a that provides a native marshalling type and optionally size information. /// - /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with + /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with public MarshalUsingAttribute(Type nativeType) : this() { @@ -34,7 +34,7 @@ public MarshalUsingAttribute(Type nativeType) } /// - /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with + /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with /// public Type? NativeType { get; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/NativeMarshallingAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/NativeMarshallingAttribute.cs index c4883cba97a46..2c0d604b19196 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/NativeMarshallingAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/NativeMarshallingAttribute.cs @@ -10,7 +10,7 @@ namespace System.Runtime.InteropServices.Marshalling /// This attribute is recognized by the runtime-provided source generators for source-generated interop scenarios. /// It is not used by the interop marshalling system at runtime. /// - /// + /// /// [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Delegate)] public sealed class NativeMarshallingAttribute : Attribute @@ -18,14 +18,14 @@ public sealed class NativeMarshallingAttribute : Attribute /// /// Create a that provides a native marshalling type. /// - /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with + /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with public NativeMarshallingAttribute(Type nativeType) { NativeType = nativeType; } /// - /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with + /// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with /// public Type NativeType { get; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ReadOnlySpanMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ReadOnlySpanMarshaller.cs new file mode 100644 index 0000000000000..148c7aa38501c --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ReadOnlySpanMarshaller.cs @@ -0,0 +1,166 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Runtime.InteropServices.Marshalling +{ + /// + /// The type supports marshalling a from managed value + /// to a contiguous native array of the unmanaged values of the elements. + /// + /// The managed element type of the span. + /// The unmanaged type for the elements of the span. + /// + /// A marshalled with this marshaller will match the semantics of . + /// In particular, this marshaller will pass a non-null value for a zero-length span if the span was constructed with a non-null value. + /// + [CLSCompliant(false)] + [CustomMarshaller(typeof(ReadOnlySpan<>), MarshalMode.ManagedToUnmanagedIn, typeof(ReadOnlySpanMarshaller<,>.ManagedToUnmanagedIn))] + [CustomMarshaller(typeof(ReadOnlySpan<>), MarshalMode.UnmanagedToManagedOut, typeof(ReadOnlySpanMarshaller<,>.UnmanagedToManagedOut))] + [ContiguousCollectionMarshaller] + public static unsafe class ReadOnlySpanMarshaller + where TUnmanagedElement : unmanaged + { + /// + /// The marshaller type that supports marshalling from managed into unmanaged in a call from unmanaged code to managed code. + /// + public static unsafe class UnmanagedToManagedOut + { + /// + /// Allocate the space to store the unmanaged elements. + /// + /// The managed span. + /// The number of elements in the span. + /// A pointer to the block of memory for the unmanaged elements. + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(ReadOnlySpan managed, out int numElements) + { + // Emulate the pinning behavior: + // If the span is over a null reference, then pass a null pointer. + if (Unsafe.IsNullRef(ref MemoryMarshal.GetReference(managed))) + { + numElements = 0; + return null; + } + + numElements = managed.Length; + + // Always allocate at least one byte when the array is zero-length. + int spaceToAllocate = Math.Max(checked(sizeof(TUnmanagedElement) * numElements), 1); + return (TUnmanagedElement*)Marshal.AllocCoTaskMem(spaceToAllocate); + } + + /// + /// Get a span of the managed collection elements. + /// + /// The managed collection. + /// A span of the managed collection elements. + public static ReadOnlySpan GetManagedValuesSource(ReadOnlySpan managed) + => managed; + + /// + /// Get a span of the space where the unmanaged collection elements should be stored. + /// + /// The pointer to the block of memory for the unmanaged elements. + /// The number of elements that will be copied into the memory block. + /// A span over the unmanaged memory that can contain the specified number of elements. + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) + => new Span(unmanaged, numElements); + } + + /// + /// The marshaller type that supports marshalling from managed into unmanaged in a call from managed code to unmanaged code. + /// + public ref struct ManagedToUnmanagedIn + { + /// + /// The size of the caller-allocated buffer to allocate. + /// + // We'll keep the buffer size at a maximum of 200 bytes to avoid overflowing the stack. + public static int BufferSize { get; } = 0x200 / sizeof(TUnmanagedElement); + + private ReadOnlySpan _managedArray; + private TUnmanagedElement* _allocatedMemory; + private Span _span; + + /// + /// Initializes the marshaller. + /// + /// Span to be marshalled. + /// Buffer that may be used for marshalling. + /// + /// The must not be movable - that is, it should not be + /// on the managed heap or it should be pinned. + /// + public void FromManaged(ReadOnlySpan managed, Span buffer) + { + _allocatedMemory = null; + // Emulate the pinning behavior: + // If the span is over a null reference, then pass a null pointer. + if (Unsafe.IsNullRef(ref MemoryMarshal.GetReference(managed))) + { + _managedArray = null; + _span = default; + return; + } + + _managedArray = managed; + + // Always allocate at least one byte when the span is zero-length. + if (managed.Length <= buffer.Length) + { + _span = buffer[0..managed.Length]; + } + else + { + int bufferSize = checked(managed.Length * sizeof(TUnmanagedElement)); + _allocatedMemory = (TUnmanagedElement*)NativeMemory.Alloc((nuint)bufferSize); + _span = new Span(_allocatedMemory, managed.Length); + } + } + + /// + /// Gets a span that points to the memory where the managed values of the array are stored. + /// + /// Span over managed values of the array. + public ReadOnlySpan GetManagedValuesSource() => _managedArray; + + /// + /// Returns a span that points to the memory where the unmanaged values of the array should be stored. + /// + /// Span where unmanaged values of the array should be stored. + public Span GetUnmanagedValuesDestination() => _span; + + /// + /// Returns a reference to the marshalled array. + /// + public ref TUnmanagedElement GetPinnableReference() => ref MemoryMarshal.GetReference(_span); + + /// + /// Returns the unmanaged value representing the array. + /// + public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)Unsafe.AsPointer(ref GetPinnableReference()); + + /// + /// Frees resources. + /// + public void Free() + { + NativeMemory.Free(_allocatedMemory); + } + + /// + /// Pin the managed span to a pointer to pass directly to unmanaged code. + /// + /// The managed span. + /// A reference that can be pinned and directly passed to unmanaged code. + public static ref T GetPinnableReference(ReadOnlySpan managed) + { + return ref MemoryMarshal.GetReference(managed); + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/SpanMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/SpanMarshaller.cs new file mode 100644 index 0000000000000..bccaef9203e6d --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/SpanMarshaller.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Runtime.InteropServices.Marshalling +{ + /// + /// The type supports marshalling a from managed value + /// to a contiguous native array of the unmanaged values of the elements. + /// + /// The managed element type of the span. + /// The unmanaged type for the elements of the span. + /// + /// A marshalled with this marshaller will match the semantics of . + /// In particular, this marshaller will pass a non-null value for a zero-length span if the span was constructed with a non-null value. + /// + [CLSCompliant(false)] + [CustomMarshaller(typeof(Span<>), MarshalMode.Default, typeof(SpanMarshaller<,>))] + [CustomMarshaller(typeof(Span<>), MarshalMode.ManagedToUnmanagedIn, typeof(SpanMarshaller<,>.ManagedToUnmanagedIn))] + [ContiguousCollectionMarshaller] + public static unsafe class SpanMarshaller + where TUnmanagedElement : unmanaged + { + /// + /// Allocate the space to store the unmanaged elements. + /// + /// The managed span. + /// The number of elements in the span. + /// A pointer to the block of memory for the unmanaged elements. + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(Span managed, out int numElements) + { + // Emulate the pinning behavior: + // If the span is over a null reference, then pass a null pointer. + if (Unsafe.IsNullRef(ref MemoryMarshal.GetReference(managed))) + { + numElements = 0; + return null; + } + + numElements = managed.Length; + + // Always allocate at least one byte when the array is zero-length. + int spaceToAllocate = Math.Max(checked(sizeof(TUnmanagedElement) * numElements), 1); + return (TUnmanagedElement*)Marshal.AllocCoTaskMem(spaceToAllocate); + } + + /// + /// Get a span of the managed collection elements. + /// + /// The managed collection. + /// A span of the managed collection elements. + public static ReadOnlySpan GetManagedValuesSource(Span managed) + => managed; + + /// + /// Get a span of the space where the unmanaged collection elements should be stored. + /// + /// The pointer to the block of memory for the unmanaged elements. + /// The number of elements that will be copied into the memory block. + /// A span over the unmanaged memory that can contain the specified number of elements. + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) + => new Span(unmanaged, numElements); + + /// + /// Allocate the space to store the managed elements. + /// + /// The unmanaged value. + /// The number of elements in the unmanaged collection. + /// A span over enough memory to contain elements. + public static Span AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) + { + if (unmanaged is null) + return null; + + return new T[numElements]; + } + + /// + /// Get a span of the space where the managed collection elements should be stored. + /// + /// A span over the space to store the managed elements + /// A span over the managed memory that can contain the specified number of elements. + public static Span GetManagedValuesDestination(Span managed) + => managed; + + /// + /// Get a span of the native collection elements. + /// + /// The unmanaged value. + /// The number of elements in the unmanaged collection. + /// A span over the native collection elements. + public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) + => new ReadOnlySpan(unmanaged, numElements); + + /// + /// Free the allocated unmanaged memory. + /// + /// Allocated unmanaged memory + public static void Free(TUnmanagedElement* unmanaged) + => Marshal.FreeCoTaskMem((IntPtr)unmanaged); + + /// + /// The marshaller type that supports marshalling from managed into unmanaged in a call from managed code to unmanaged code. + /// + public ref struct ManagedToUnmanagedIn + { + // We'll keep the buffer size at a maximum of 200 bytes to avoid overflowing the stack. + public static int BufferSize { get; } = 0x200 / sizeof(TUnmanagedElement); + + private Span _managedArray; + private TUnmanagedElement* _allocatedMemory; + private Span _span; + + /// + /// Initializes the marshaller. + /// + /// Span to be marshalled. + /// Buffer that may be used for marshalling. + /// + /// The must not be movable - that is, it should not be + /// on the managed heap or it should be pinned. + /// + public void FromManaged(Span managed, Span buffer) + { + _allocatedMemory = null; + // Emulate the pinning behavior: + // If the span is over a null reference, then pass a null pointer. + if (Unsafe.IsNullRef(ref MemoryMarshal.GetReference(managed))) + { + _managedArray = null; + _span = default; + return; + } + + _managedArray = managed; + + if (managed.Length <= buffer.Length) + { + _span = buffer[0..managed.Length]; + } + else + { + int bufferSize = checked(managed.Length * sizeof(TUnmanagedElement)); + _allocatedMemory = (TUnmanagedElement*)NativeMemory.Alloc((nuint)bufferSize); + _span = new Span(_allocatedMemory, managed.Length); + } + } + + /// + /// Gets a span that points to the memory where the managed values of the array are stored. + /// + /// Span over managed values of the array. + public ReadOnlySpan GetManagedValuesSource() => _managedArray; + + /// + /// Returns a span that points to the memory where the unmanaged values of the array should be stored. + /// + /// Span where unmanaged values of the array should be stored. + public Span GetUnmanagedValuesDestination() => _span; + + /// + /// Returns a reference to the marshalled array. + /// + public ref TUnmanagedElement GetPinnableReference() => ref MemoryMarshal.GetReference(_span); + + /// + /// Returns the unmanaged value representing the array. + /// + public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)Unsafe.AsPointer(ref GetPinnableReference()); + + /// + /// Frees resources. + /// + public void Free() + { + NativeMemory.Free(_allocatedMemory); + } + + public static ref T GetPinnableReference(Span managed) + { + return ref MemoryMarshal.GetReference(managed); + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index dc8f2500ae1e8..49816d0e107f5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using System.Runtime.Versioning; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; @@ -19,6 +20,9 @@ namespace System [DebuggerTypeProxy(typeof(SpanDebugView<>))] [DebuggerDisplay("{ToString(),raw}")] [NonVersionable] +#pragma warning disable SYSLIB1056 // Specified native type is invalid + [NativeMarshalling(typeof(SpanMarshaller<,>))] +#pragma warning restore SYSLIB1056 // Specified native type is invalid public readonly ref struct Span { /// A byref or a native ptr. diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSStubCodeContext.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSStubCodeContext.cs index 1d0b0727ad1b8..abd0e3da24e97 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSStubCodeContext.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSStubCodeContext.cs @@ -25,7 +25,7 @@ internal sealed record JSImportCodeContext : JSStubCodeContext public JSImportCodeContext(JSImportData attributeData, StubCodeContext inner) { _inner = inner; - Direction = CustomTypeMarshallerDirection.In; + Direction = CustomTypeMarshallingDirection.In; AttributeData = attributeData; } @@ -37,7 +37,7 @@ internal sealed record JSExportCodeContext : JSStubCodeContext public JSExportCodeContext(JSExportData attributeData, StubCodeContext inner) { _inner = inner; - Direction = CustomTypeMarshallerDirection.Out; + Direction = CustomTypeMarshallingDirection.Out; AttributeData = attributeData; } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/FuncJSGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/FuncJSGenerator.cs index 03652eea4a8da..fed51dde6d6f6 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/FuncJSGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/FuncJSGenerator.cs @@ -53,12 +53,12 @@ public override IEnumerable Generate(TypePositionInfo info, Stu .Select(a => ParseTypeName(a.FullTypeName)) .ToArray(); - if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallerDirection.In && info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallingDirection.In && info.IsManagedReturnPosition) { yield return ToManagedMethod(target, source, jsty); } - if (context.CurrentStage == StubCodeContext.Stage.Marshal && context.Direction == CustomTypeMarshallerDirection.Out && info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Marshal && context.Direction == CustomTypeMarshallingDirection.Out && info.IsManagedReturnPosition) { yield return ToJSMethod(target, source, jsty); } @@ -68,12 +68,12 @@ public override IEnumerable Generate(TypePositionInfo info, Stu yield return x; } - if (context.CurrentStage == StubCodeContext.Stage.Invoke && context.Direction == CustomTypeMarshallerDirection.In && !info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Invoke && context.Direction == CustomTypeMarshallingDirection.In && !info.IsManagedReturnPosition) { yield return ToJSMethod(target, source, jsty); } - if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallerDirection.Out && !info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallingDirection.Out && !info.IsManagedReturnPosition) { yield return ToManagedMethod(target, source, jsty); } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/PrimitiveJSGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/PrimitiveJSGenerator.cs index b25b95710d5b1..e3920e46765fb 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/PrimitiveJSGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/PrimitiveJSGenerator.cs @@ -32,12 +32,12 @@ public override IEnumerable Generate(TypePositionInfo info, Stu ? Argument(IdentifierName(context.GetIdentifiers(info).native)) : _inner.AsArgument(info, context); - if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallerDirection.In && info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallingDirection.In && info.IsManagedReturnPosition) { yield return ToManagedMethod(target, source); } - if (context.CurrentStage == StubCodeContext.Stage.Marshal && context.Direction == CustomTypeMarshallerDirection.Out && info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Marshal && context.Direction == CustomTypeMarshallingDirection.Out && info.IsManagedReturnPosition) { yield return ToJSMethod(target, source); } @@ -47,12 +47,12 @@ public override IEnumerable Generate(TypePositionInfo info, Stu yield return x; } - if (context.CurrentStage == StubCodeContext.Stage.Invoke && context.Direction == CustomTypeMarshallerDirection.In && !info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Invoke && context.Direction == CustomTypeMarshallingDirection.In && !info.IsManagedReturnPosition) { yield return ToJSMethod(target, source); } - if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallerDirection.Out && !info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallingDirection.Out && !info.IsManagedReturnPosition) { yield return ToManagedMethod(target, source); } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/TaskJSGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/TaskJSGenerator.cs index 3bfa38c12ea22..86162f0e62c94 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/TaskJSGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Marshaling/TaskJSGenerator.cs @@ -45,14 +45,14 @@ public override IEnumerable Generate(TypePositionInfo info, Stu ? Argument(IdentifierName(context.GetIdentifiers(info).native)) : _inner.AsArgument(info, context); - if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallerDirection.In && info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallingDirection.In && info.IsManagedReturnPosition) { yield return jsty.ResultTypeInfo.FullTypeName == "void" ? ToManagedMethodVoid(target, source) : ToManagedMethod(target, source, jsty.ResultTypeInfo.Syntax); } - if (context.CurrentStage == StubCodeContext.Stage.Marshal && context.Direction == CustomTypeMarshallerDirection.Out && info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Marshal && context.Direction == CustomTypeMarshallingDirection.Out && info.IsManagedReturnPosition) { yield return jsty.ResultTypeInfo.FullTypeName == "void" ? ToJSMethodVoid(target, source) @@ -64,14 +64,14 @@ public override IEnumerable Generate(TypePositionInfo info, Stu yield return x; } - if (context.CurrentStage == StubCodeContext.Stage.Invoke && context.Direction == CustomTypeMarshallerDirection.In && !info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Invoke && context.Direction == CustomTypeMarshallingDirection.In && !info.IsManagedReturnPosition) { yield return jsty.ResultTypeInfo.FullTypeName == "void" ? ToJSMethodVoid(target, source) : ToJSMethod(target, source, jsty.ResultTypeInfo.Syntax); } - if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallerDirection.Out && !info.IsManagedReturnPosition) + if (context.CurrentStage == StubCodeContext.Stage.Unmarshal && context.Direction == CustomTypeMarshallingDirection.Out && !info.IsManagedReturnPosition) { yield return jsty.ResultTypeInfo.FullTypeName == "void" ? ToManagedMethodVoid(target, source) diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs index 8e380eeba243d..35180ee242f9e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs @@ -18,18 +18,10 @@ public class CustomTypeMarshallerAnalyzer : DiagnosticAnalyzer { private const string Category = "Usage"; - public const string MissingFeaturesKey = nameof(MissingFeaturesKey); - public static class MissingMemberNames { public const string Key = nameof(MissingMemberNames); public const char Delimiter = ' '; - - public const string ValueManagedToNativeConstructor = nameof(ValueManagedToNativeConstructor); - public const string ValueCallerAllocatedBufferConstructor = nameof(ValueCallerAllocatedBufferConstructor); - public const string CollectionManagedToNativeConstructor = nameof(CollectionManagedToNativeConstructor); - public const string CollectionCallerAllocatedBufferConstructor = nameof(CollectionCallerAllocatedBufferConstructor); - public const string CollectionNativeElementSizeConstructor = nameof(CollectionNativeElementSizeConstructor); } public static readonly DiagnosticDescriptor MarshallerTypeMustSpecifyManagedTypeRule = @@ -42,36 +34,6 @@ public static class MissingMemberNames isEnabledByDefault: true, description: GetResourceString(nameof(SR.MarshallerTypeMustSpecifyManagedTypeDescription))); - public static readonly DiagnosticDescriptor CustomTypeMarshallerAttributeMustBeValidRule = - new DiagnosticDescriptor( - Ids.InvalidCustomTypeMarshallerAttributeUsage, - GetResourceString(nameof(SR.InvalidCustomTypeMarshallerAttributeUsageTitle)), - GetResourceString(nameof(SR.CustomTypeMarshallerAttributeMustBeValidMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.CustomTypeMarshallerAttributeMustBeValidDescription))); - - public static readonly DiagnosticDescriptor MarshallerKindMustBeValidRule = - new DiagnosticDescriptor( - Ids.InvalidCustomTypeMarshallerAttributeUsage, - GetResourceString(nameof(SR.InvalidCustomTypeMarshallerAttributeUsageTitle)), - GetResourceString(nameof(SR.MarshallerKindMustBeValidMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.MarshallerKindMustBeValidDescription))); - - public static readonly DiagnosticDescriptor MarshallerDirectionMustBeValidRule = - new DiagnosticDescriptor( - Ids.InvalidCustomTypeMarshallerAttributeUsage, - GetResourceString(nameof(SR.InvalidCustomTypeMarshallerAttributeUsageTitle)), - GetResourceString(nameof(SR.MarshallerDirectionMustBeValidMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.MarshallerDirectionMustBeValidDescription))); - public static readonly DiagnosticDescriptor NativeTypeMustHaveCustomTypeMarshallerAttributeRule = new DiagnosticDescriptor( Ids.InvalidNativeType, @@ -112,16 +74,6 @@ public static class MissingMemberNames isEnabledByDefault: true, description: GetResourceString(nameof(SR.NativeTypeMustBePointerSizedDescription))); - public static readonly DiagnosticDescriptor CustomMarshallerTypeMustSupportDirectionRule = - new DiagnosticDescriptor( - Ids.InvalidCustomTypeMarshallerAttributeUsage, - GetResourceString(nameof(SR.InvalidCustomTypeMarshallerAttributeUsageTitle)), - GetResourceString(nameof(SR.CustomMarshallerTypeMustSupportDirectionMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.CustomMarshallerTypeMustSupportDirectionDescription))); - public static readonly DiagnosticDescriptor ValueInRequiresOneParameterConstructorRule = new DiagnosticDescriptor( Ids.CustomMarshallerTypeMustHaveRequiredShape, @@ -192,66 +144,6 @@ public static class MissingMemberNames isEnabledByDefault: true, description: GetResourceString(nameof(SR.LinearCollectionOutRequiresCollectionMethodsDescription))); - public static readonly DiagnosticDescriptor LinearCollectionOutRequiresIntConstructorRule = - new DiagnosticDescriptor( - Ids.CustomMarshallerTypeMustHaveRequiredShape, - GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)), - GetResourceString(nameof(SR.LinearCollectionOutRequiresIntConstructorMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.LinearCollectionOutRequiresIntConstructorDescription))); - - public static readonly DiagnosticDescriptor UnmanagedResourcesRequiresFreeNativeRule = - new DiagnosticDescriptor( - Ids.CustomMarshallerTypeMustHaveRequiredShape, - GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)), - GetResourceString(nameof(SR.UnmanagedResourcesRequiresFreeNativeMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.UnmanagedResourcesRequiresFreeNativeDescription))); - - public static readonly DiagnosticDescriptor OutTwoStageMarshallingRequiresFromNativeValueRule = - new DiagnosticDescriptor( - Ids.CustomMarshallerTypeMustHaveRequiredShape, - GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)), - GetResourceString(nameof(SR.OutTwoStageMarshallingRequiresFromNativeValueMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.OutTwoStageMarshallingRequiresFromNativeValueDescription))); - - public static readonly DiagnosticDescriptor InTwoStageMarshallingRequiresToNativeValueRule = - new DiagnosticDescriptor( - Ids.CustomMarshallerTypeMustHaveRequiredShape, - GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)), - GetResourceString(nameof(SR.InTwoStageMarshallingRequiresToNativeValueMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.InTwoStageMarshallingRequiresToNativeValueDescription))); - - public static readonly DiagnosticDescriptor GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule = - new DiagnosticDescriptor( - Ids.MissingAllocatingMarshallingFallback, - GetResourceString(nameof(SR.MissingAllocatingMarshallingFallbackTitle)), - GetResourceString(nameof(SR.GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackMessage)), - Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackDescription))); - - public static readonly DiagnosticDescriptor CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule = - new DiagnosticDescriptor( - Ids.MissingAllocatingMarshallingFallback, - GetResourceString(nameof(SR.MissingAllocatingMarshallingFallbackTitle)), - GetResourceString(nameof(SR.CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackMessage)), - Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackDescription))); - public static readonly DiagnosticDescriptor CallerAllocConstructorMustHaveBufferSizeRule = new DiagnosticDescriptor( Ids.CallerAllocConstructorMustHaveBufferSize, @@ -282,56 +174,6 @@ public static class MissingMemberNames isEnabledByDefault: true, description: GetResourceString(nameof(SR.NativeGenericTypeMustBeClosedOrMatchArityDescription))); - public static readonly DiagnosticDescriptor MarshallerGetPinnableReferenceRequiresTwoStageMarshallingRule = - new DiagnosticDescriptor( - Ids.ProvidedMethodsNotSpecifiedInFeatures, - GetResourceString(nameof(SR.ProvidedMethodsNotSpecifiedInFeaturesTitle)), - GetResourceString(nameof(SR.MarshallerGetPinnableReferenceRequiresTwoStageMarshallingMessage)), - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.MarshallerGetPinnableReferenceRequiresTwoStageMarshallingDescription))); - - public static readonly DiagnosticDescriptor FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule = - new DiagnosticDescriptor( - Ids.ProvidedMethodsNotSpecifiedInFeatures, - GetResourceString(nameof(SR.ProvidedMethodsNotSpecifiedInFeaturesTitle)), - GetResourceString(nameof(SR.FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureMessage)), - Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureDescription))); - - public static readonly DiagnosticDescriptor ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule = - new DiagnosticDescriptor( - Ids.ProvidedMethodsNotSpecifiedInFeatures, - GetResourceString(nameof(SR.ProvidedMethodsNotSpecifiedInFeaturesTitle)), - GetResourceString(nameof(SR.ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage)), - Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription))); - - public static readonly DiagnosticDescriptor FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule = - new DiagnosticDescriptor( - Ids.ProvidedMethodsNotSpecifiedInFeatures, - GetResourceString(nameof(SR.ProvidedMethodsNotSpecifiedInFeaturesTitle)), - GetResourceString(nameof(SR.FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage)), - Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription))); - - public static readonly DiagnosticDescriptor CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureRule = - new DiagnosticDescriptor( - Ids.ProvidedMethodsNotSpecifiedInFeatures, - GetResourceString(nameof(SR.ProvidedMethodsNotSpecifiedInFeaturesTitle)), - GetResourceString(nameof(SR.CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureMessage)), - Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: GetResourceString(nameof(SR.CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureDescription))); - public static readonly DiagnosticDescriptor TwoStageMarshallingNativeTypesMustMatchRule = new DiagnosticDescriptor( Ids.InvalidSignaturesInMarshallerShape, @@ -355,9 +197,6 @@ public static class MissingMemberNames public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create( MarshallerTypeMustSpecifyManagedTypeRule, - CustomTypeMarshallerAttributeMustBeValidRule, - MarshallerKindMustBeValidRule, - MarshallerDirectionMustBeValidRule, NativeTypeMustHaveCustomTypeMarshallerAttributeRule, NativeTypeMustBeBlittableRule, GetPinnableReferenceReturnTypeBlittableRule, @@ -367,20 +206,9 @@ public static class MissingMemberNames OutRequiresToManagedRule, LinearCollectionInRequiresCollectionMethodsRule, LinearCollectionOutRequiresCollectionMethodsRule, - LinearCollectionOutRequiresIntConstructorRule, - CustomMarshallerTypeMustSupportDirectionRule, - OutTwoStageMarshallingRequiresFromNativeValueRule, - InTwoStageMarshallingRequiresToNativeValueRule, - GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule, - CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule, CallerAllocConstructorMustHaveBufferSizeRule, RefNativeValueUnsupportedRule, NativeGenericTypeMustBeClosedOrMatchArityRule, - MarshallerGetPinnableReferenceRequiresTwoStageMarshallingRule, - FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule, - ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule, - FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule, - CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureRule, TwoStageMarshallingNativeTypesMustMatchRule, LinearCollectionElementTypesMustMatchRule); @@ -494,427 +322,20 @@ private static void AnalyzeManagedTypeMarshallingInfo( managedType.ToDisplayString())); } - (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? marshallerManagedType, _) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(entryType); - - marshallerManagedType = ManualTypeMarshallingHelper.ResolveManagedType(marshallerManagedType, entryType, context.Compilation); - - if (!hasCustomTypeMarshallerAttribute) - { - if (ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(entryType)) - { - // TEMPORARY: Don't analyze V2 analyzers in this method for now. - // We'll add support soon, but for now just don't emit warnings to use the V1 marshaller design - // when using the V2 design. - return; - } - context.ReportDiagnostic( - attributeData.CreateDiagnostic( - NativeTypeMustHaveCustomTypeMarshallerAttributeRule, - managedType.ToDisplayString())); - return; - } - - if (marshallerManagedType is null) - { - context.ReportDiagnostic( - attributeData.CreateDiagnostic( - NativeTypeMustHaveCustomTypeMarshallerAttributeRule, - managedType.ToDisplayString())); - return; - } - if (!TypeSymbolsConstructedFromEqualTypes(managedType, marshallerManagedType)) + if (!ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(entryType)) { - context.ReportDiagnostic( - attributeData.CreateDiagnostic( - NativeTypeMustHaveCustomTypeMarshallerAttributeRule, - managedType.ToDisplayString())); + // TODO: Report that the marshaller needs to be an entry-point marshaller type. return; } } - private static bool TypeSymbolsConstructedFromEqualTypes(ITypeSymbol left, ITypeSymbol right) - { - return (left, right) switch - { - (INamedTypeSymbol namedLeft, INamedTypeSymbol namedRight) => SymbolEqualityComparer.Default.Equals(namedLeft.ConstructedFrom, namedRight.ConstructedFrom), - _ => SymbolEqualityComparer.Default.Equals(left, right) - }; - } - +#pragma warning disable CA1822 // Mark members as static public void AnalyzeMarshallerType(SymbolAnalysisContext context) +#pragma warning restore CA1822 // Mark members as static { - INamedTypeSymbol marshallerType = (INamedTypeSymbol)context.Symbol; - (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? type, CustomTypeMarshallerData_V1? marshallerDataMaybe) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(marshallerType); - type = ManualTypeMarshallingHelper.ResolveManagedType(type, marshallerType, context.Compilation); - - if (!hasCustomTypeMarshallerAttribute) - { - return; - } - if (type is null) - { - context.ReportDiagnostic(marshallerType.CreateDiagnostic(MarshallerTypeMustSpecifyManagedTypeRule, marshallerType.ToDisplayString())); - return; - } - - if (marshallerDataMaybe is not { } marshallerData) - { - context.ReportDiagnostic(marshallerType.CreateDiagnostic(CustomTypeMarshallerAttributeMustBeValidRule, marshallerType.ToDisplayString())); - return; - } - - if (!Enum.IsDefined(typeof(CustomTypeMarshallerKind), marshallerData.Kind)) - { - context.ReportDiagnostic(marshallerType.CreateDiagnostic(MarshallerKindMustBeValidRule, marshallerType.ToDisplayString())); - return; - } - - if (type is INamedTypeSymbol { IsUnboundGenericType: true } generic) - { - if (generic.TypeArguments.Length != marshallerType.TypeArguments.Length) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - NativeGenericTypeMustBeClosedOrMatchArityRule, - marshallerType.ToDisplayString(), - type.ToDisplayString())); - return; - } - type = generic.ConstructedFrom.Construct(marshallerType.TypeArguments, marshallerType.TypeArgumentNullableAnnotations); - } - - IMethodSymbol? inConstructor = null; - IMethodSymbol? callerAllocatedSpanConstructor = null; - IMethodSymbol collectionOutConstructor = null; - foreach (IMethodSymbol ctor in marshallerType.Constructors) - { - if (ctor.IsStatic) - { - continue; - } - - if (inConstructor is null && ManualTypeMarshallingHelper_V1.IsManagedToNativeConstructor(ctor, type, marshallerData.Kind)) - { - inConstructor = ctor; - } - - if (callerAllocatedSpanConstructor is null && ManualTypeMarshallingHelper_V1.IsCallerAllocatedSpanConstructor(ctor, type, _spanOfT, marshallerData.Kind, out _)) - { - callerAllocatedSpanConstructor = ctor; - } - if (collectionOutConstructor is null && ctor.Parameters.Length == 1 && ctor.Parameters[0].Type.SpecialType == SpecialType.System_Int32) - { - collectionOutConstructor = ctor; - } - } - - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.In)) - { - if (inConstructor is null) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - GetInConstructorShapeRule(marshallerData.Kind), - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - GetInConstructorMissingMemberName(marshallerData.Kind)), - marshallerType.ToDisplayString(), - type.ToDisplayString())); - } - if (marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.CallerAllocatedBuffer)) - { - if (callerAllocatedSpanConstructor is null) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - GetCallerAllocatedBufferConstructorShapeRule(marshallerData.Kind), - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - GetCallerAllocatedBufferConstructorMissingMemberName(marshallerData.Kind)), - marshallerType.ToDisplayString(), - type.ToDisplayString())); - } - if (marshallerData.BufferSize == null) - { - context.ReportDiagnostic( - (callerAllocatedSpanConstructor ?? (ISymbol)marshallerType).CreateDiagnostic( - CallerAllocConstructorMustHaveBufferSizeRule, - marshallerType.ToDisplayString())); - } - } - else if (callerAllocatedSpanConstructor is not null) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureRule, - ImmutableDictionary.Empty.Add( - MissingFeaturesKey, - nameof(CustomTypeMarshallerFeatures.CallerAllocatedBuffer)), - marshallerType.ToDisplayString())); - } - - // Validate that this type can support marshalling when stackalloc is not usable. - if (callerAllocatedSpanConstructor is not null && inConstructor is null) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule, - marshallerType.ToDisplayString())); - } - } - - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && !ManualTypeMarshallingHelper_V1.HasToManagedMethod(marshallerType, type)) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - OutRequiresToManagedRule, - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - ShapeMemberNames_V1.Value.ToManaged), - marshallerType.ToDisplayString())); - } - - if (marshallerData.Kind == CustomTypeMarshallerKind.LinearCollection) - { - IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesSourceMethod(marshallerType, _readOnlySpanOfT); - IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesDestinationMethod(marshallerType, _spanOfT); - IMethodSymbol? getNativeValuesSourceMethod = ManualTypeMarshallingHelper_V1.FindGetNativeValuesSourceMethod(marshallerType, _readOnlySpanOfByte); - IMethodSymbol? getNativeValuesDestinationMethod = ManualTypeMarshallingHelper_V1.FindGetNativeValuesDestinationMethod(marshallerType, _spanOfByte); - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.In) && (getManagedValuesSourceMethod is null || getNativeValuesDestinationMethod is null)) - { - var missingMembers = (getManagedValuesSourceMethod, getNativeValuesDestinationMethod) switch - { - (null, not null) => ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource, - (not null, null) => ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination, - (null, null) => $"{ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination}", - (not null, not null) => string.Empty - }; - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - LinearCollectionInRequiresCollectionMethodsRule, - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - missingMembers), - marshallerType.ToDisplayString())); - } - - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && (getNativeValuesSourceMethod is null || getManagedValuesDestinationMethod is null)) - { - var missingMembers = (getNativeValuesSourceMethod, getManagedValuesDestinationMethod) switch - { - (not null, null) => ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource, - (null, not null) => ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination, - (null, null) => $"{ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination}", - (not null, not null) => string.Empty - }; - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - LinearCollectionOutRequiresCollectionMethodsRule, - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - missingMembers), - marshallerType.ToDisplayString())); - } - - if (getManagedValuesSourceMethod is not null - && getManagedValuesDestinationMethod is not null - && !SymbolEqualityComparer.Default.Equals( - ((INamedTypeSymbol)getManagedValuesSourceMethod.ReturnType).TypeArguments[0], - ((INamedTypeSymbol)getManagedValuesDestinationMethod.ReturnType).TypeArguments[0])) - { - context.ReportDiagnostic(getManagedValuesSourceMethod.CreateDiagnostic(LinearCollectionElementTypesMustMatchRule)); - } - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && collectionOutConstructor is null) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - LinearCollectionOutRequiresIntConstructorRule, - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - MissingMemberNames.CollectionNativeElementSizeConstructor), - marshallerType.ToDisplayString())); - } - } - - - // Validate that the native type has at least one marshalling direction (either managed to native or native to managed) - if ((marshallerData.Direction & CustomTypeMarshallerDirection.Ref) == CustomTypeMarshallerDirection.None) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - CustomMarshallerTypeMustSupportDirectionRule, - marshallerType.ToDisplayString())); - } - - if (marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources) && !ManualTypeMarshallingHelper_V1.HasFreeNativeMethod(marshallerType)) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - UnmanagedResourcesRequiresFreeNativeRule, - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - ShapeMemberNames_V1.Value.FreeNative), - marshallerType.ToDisplayString(), - type.ToDisplayString())); - } - else if (!marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources) && ManualTypeMarshallingHelper_V1.HasFreeNativeMethod(marshallerType)) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule, - ImmutableDictionary.Empty.Add( - MissingFeaturesKey, - nameof(CustomTypeMarshallerFeatures.UnmanagedResources)), - marshallerType.ToDisplayString())); - } - - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(marshallerType); - IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper_V1.FindFromNativeValueMethod(marshallerType); - bool toNativeValueMethodIsRefReturn = toNativeValueMethod is { ReturnsByRef: true } or { ReturnsByRefReadonly: true }; - ITypeSymbol nativeType = marshallerType; - - if (marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.TwoStageMarshalling)) - { - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.In) && toNativeValueMethod is null) - { - context.ReportDiagnostic(marshallerType.CreateDiagnostic( - InTwoStageMarshallingRequiresToNativeValueRule, - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - ShapeMemberNames_V1.Value.ToNativeValue), - marshallerType.ToDisplayString())); - } - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && fromNativeValueMethod is null) - { - context.ReportDiagnostic(marshallerType.CreateDiagnostic( - OutTwoStageMarshallingRequiresFromNativeValueRule, - ImmutableDictionary.Empty.Add( - MissingMemberNames.Key, - ShapeMemberNames_V1.Value.FromNativeValue), - marshallerType.ToDisplayString())); - } - - // ToNativeValue and FromNativeValue must be provided with the same type. - if (toNativeValueMethod is not null - && fromNativeValueMethod is not null - && !SymbolEqualityComparer.Default.Equals(toNativeValueMethod.ReturnType, fromNativeValueMethod.Parameters[0].Type)) - { - context.ReportDiagnostic(toNativeValueMethod.CreateDiagnostic(TwoStageMarshallingNativeTypesMustMatchRule)); - } - } - else if (fromNativeValueMethod is not null) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule, - ImmutableDictionary.Empty.Add( - MissingFeaturesKey, - nameof(CustomTypeMarshallerFeatures.TwoStageMarshalling)), - marshallerType.ToDisplayString())); - } - else if (toNativeValueMethod is not null) - { - context.ReportDiagnostic( - marshallerType.CreateDiagnostic( - ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule, - ImmutableDictionary.Empty.Add( - MissingFeaturesKey, - nameof(CustomTypeMarshallerFeatures.TwoStageMarshalling)), - marshallerType.ToDisplayString())); - } - - if (toNativeValueMethod is not null) - { - if (toNativeValueMethodIsRefReturn) - { - context.ReportDiagnostic( - toNativeValueMethod.CreateDiagnostic( - RefNativeValueUnsupportedRule, - marshallerType.ToDisplayString())); - } - - nativeType = toNativeValueMethod.ReturnType; - } - else if (ManualTypeMarshallingHelper.FindGetPinnableReference(marshallerType) is IMethodSymbol marshallerGetPinnableReferenceMethod) - { - // If we don't have a ToNativeValue method, then we disallow a GetPinnableReference on the marshaler type. - // We do this since there is no valid use case that we can think of for a GetPinnableReference on a blittable type - // being a requirement to calculate the value of the fields of the same blittable instance, - // so we're pre-emptively blocking this until a use case is discovered. - context.ReportDiagnostic( - marshallerGetPinnableReferenceMethod.CreateDiagnostic( - MarshallerGetPinnableReferenceRequiresTwoStageMarshallingRule, - nativeType.ToDisplayString())); - } - - if (!nativeType.IsConsideredBlittable()) - { - context.ReportDiagnostic( - (toNativeValueMethod ?? (ISymbol)marshallerType).CreateDiagnostic( - NativeTypeMustBeBlittableRule, - nativeType.ToDisplayString(), - type.ToDisplayString())); - } - - if (SymbolEqualityComparer.Default.Equals(ManualTypeMarshallingHelper.GetDefaultMarshallerEntryType(type).entryType, marshallerType) - && ManualTypeMarshallingHelper.FindGetPinnableReference(type) is IMethodSymbol managedGetPinnableReferenceMethod) - { - if (!managedGetPinnableReferenceMethod.ReturnType.IsConsideredBlittable()) - { - context.ReportDiagnostic(managedGetPinnableReferenceMethod.CreateDiagnostic(GetPinnableReferenceReturnTypeBlittableRule)); - } - // Validate that our marshaler supports scenarios where GetPinnableReference cannot be used. - if (!marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.In)) - { - context.ReportDiagnostic( - type.CreateDiagnostic( - GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule, - type.ToDisplayString())); - } - - // If the managed type has a GetPinnableReference method, make sure that the Value getter is also a pointer-sized primitive. - // This ensures that marshalling via pinning the managed value and marshalling via the default marshaller will have the same ABI. - if (toNativeValueMethod is not null - && !toNativeValueMethodIsRefReturn // Ref returns are already reported above as invalid, so don't issue another warning here about them - && nativeType is not ( - IPointerTypeSymbol or - { SpecialType: SpecialType.System_IntPtr } or - { SpecialType: SpecialType.System_UIntPtr })) - { - context.ReportDiagnostic( - toNativeValueMethod.CreateDiagnostic( - NativeTypeMustBePointerSizedRule, - nativeType.ToDisplayString(), - managedGetPinnableReferenceMethod.ContainingType.ToDisplayString())); - } - } + // TODO: Implement for the V2 shapes } - - private static DiagnosticDescriptor GetInConstructorShapeRule(CustomTypeMarshallerKind kind) => kind switch - { - CustomTypeMarshallerKind.Value => ValueInRequiresOneParameterConstructorRule, - CustomTypeMarshallerKind.LinearCollection => LinearCollectionInRequiresTwoParameterConstructorRule, - _ => throw new UnreachableException() - }; - private static string GetInConstructorMissingMemberName(CustomTypeMarshallerKind kind) => kind switch - { - CustomTypeMarshallerKind.Value => MissingMemberNames.ValueManagedToNativeConstructor, - CustomTypeMarshallerKind.LinearCollection => MissingMemberNames.CollectionManagedToNativeConstructor, - _ => throw new UnreachableException() - }; - private static DiagnosticDescriptor GetCallerAllocatedBufferConstructorShapeRule(CustomTypeMarshallerKind kind) => kind switch - { - CustomTypeMarshallerKind.Value => ValueInCallerAllocatedBufferRequiresSpanConstructorRule, - CustomTypeMarshallerKind.LinearCollection => LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorRule, - _ => throw new UnreachableException() - }; - private static string GetCallerAllocatedBufferConstructorMissingMemberName(CustomTypeMarshallerKind kind) => kind switch - { - CustomTypeMarshallerKind.Value => MissingMemberNames.ValueCallerAllocatedBufferConstructor, - CustomTypeMarshallerKind.LinearCollection => MissingMemberNames.CollectionCallerAllocatedBufferConstructor, - _ => throw new UnreachableException() - }; } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs index 084acbe9d0255..33fbd671c1355 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs @@ -22,7 +22,6 @@ namespace Microsoft.Interop.Analyzers public class CustomTypeMarshallerFixer : CodeFixProvider { private const string AddMissingCustomTypeMarshallerMembersKey = nameof(AddMissingCustomTypeMarshallerMembersKey); - private const string AddMissingCustomTypeMarshallerFeaturesKey = nameof(AddMissingCustomTypeMarshallerFeaturesKey); private sealed class CustomFixAllProvider : DocumentBasedFixAllProvider { @@ -41,15 +40,7 @@ protected override async Task FixAllAsync(FixAllContext fixAllContext, { SyntaxNode node = root.FindNode(diagnosticsBySpan.Key); - AddMissingMembers(fixAllContext, editor, diagnosticsBySpan, node); - } - break; - case AddMissingCustomTypeMarshallerFeaturesKey: - foreach (IGrouping diagnosticsBySpan in diagnostics.GroupBy(d => d.Location.SourceSpan)) - { - SyntaxNode node = root.FindNode(diagnosticsBySpan.Key); - - await AddMissingFeatures(fixAllContext, editor, diagnosticsBySpan, node).ConfigureAwait(false); + AddMissingMembers(editor, diagnosticsBySpan, node); } break; default: @@ -59,7 +50,7 @@ protected override async Task FixAllAsync(FixAllContext fixAllContext, return editor.GetChangedDocument(); } - private static void AddMissingMembers(FixAllContext fixAllContext, DocumentEditor editor, IEnumerable diagnostics, SyntaxNode node) + private static void AddMissingMembers(DocumentEditor editor, IEnumerable diagnostics, SyntaxNode node) { var (missingMemberNames, _) = GetRequiredShapeMissingMemberNames(diagnostics); ITypeSymbol marshallerType = (ITypeSymbol)editor.SemanticModel.GetDeclaredSymbol(node); @@ -73,24 +64,6 @@ private static void AddMissingMembers(FixAllContext fixAllContext, DocumentEdito editor.SemanticModel.Compilation, gen)); } - - private static async Task AddMissingFeatures(FixAllContext fixAllContext, DocumentEditor editor, IEnumerable diagnostics, SyntaxNode node) - { - var (featuresToAdd, _) = GetFeaturesToAdd(diagnostics); - ITypeSymbol marshallerType = (ITypeSymbol)editor.SemanticModel.GetDeclaredSymbol(node); - AttributeData customTypeMarshallerAttribute = marshallerType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.CustomTypeMarshallerAttribute); - - SyntaxNode attributeSyntax = await customTypeMarshallerAttribute.ApplicationSyntaxReference!.GetSyntaxAsync(fixAllContext.CancellationToken).ConfigureAwait(false); - - editor.ReplaceNode( - attributeSyntax, - (node, gen) => - CustomTypeMarshallerFixer.AddMissingFeatures( - gen.GetName(node), - customTypeMarshallerAttribute, - featuresToAdd, - gen)); - } } public override FixAllProvider? GetFixAllProvider() => new CustomFixAllProvider(); @@ -120,18 +93,6 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) AddMissingCustomTypeMarshallerMembersKey), missingMembersDiagnostics); } - - var (featuresToAdd, featuresToAddDiagnostics) = GetFeaturesToAdd(context.Diagnostics); - - if (featuresToAddDiagnostics.Count > 0 && featuresToAdd != CustomTypeMarshallerFeatures.None) - { - context.RegisterCodeFix( - CodeAction.Create( - SR.AddMissingFeaturesToCustomTypeMarshaller, - ct => AddMissingFeatures(doc, node, featuresToAdd, ct), - AddMissingCustomTypeMarshallerFeaturesKey), - featuresToAddDiagnostics); - } } private static (List missingMembers, List fixedDiagnostics) GetRequiredShapeMissingMemberNames(IEnumerable diagnostics) @@ -152,78 +113,6 @@ private static (List missingMembers, List fixedDiagnostics) return (missingMemberNames, requiredShapeDiagnostics); } - private static (CustomTypeMarshallerFeatures featuresToAdd, List fixedDiagnostics) GetFeaturesToAdd(IEnumerable diagnostics) - { - List featuresToAddDiagnostics = new(); - CustomTypeMarshallerFeatures featuresToAdd = CustomTypeMarshallerFeatures.None; - foreach (var diagnostic in diagnostics) - { - if (diagnostic.Id == AnalyzerDiagnostics.Ids.ProvidedMethodsNotSpecifiedInFeatures) - { - featuresToAddDiagnostics.Add(diagnostic); - if (diagnostic.Properties.TryGetValue(CustomTypeMarshallerAnalyzer.MissingFeaturesKey, out string missingFeatures) - && Enum.TryParse(missingFeatures, out CustomTypeMarshallerFeatures featuresValue)) - { - featuresToAdd |= featuresValue; - } - } - } - - return (featuresToAdd, featuresToAddDiagnostics); - } - private static async Task AddMissingFeatures(Document doc, SyntaxNode node, CustomTypeMarshallerFeatures featuresToAdd, CancellationToken ct) - { - var editor = await DocumentEditor.CreateAsync(doc, ct).ConfigureAwait(false); - var gen = editor.Generator; - - ISymbol marshallerType = editor.SemanticModel.GetDeclaredSymbol(node, ct); - - AttributeData customTypeMarshallerAttribute = marshallerType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.CustomTypeMarshallerAttribute); - - SyntaxNode attributeSyntax = await customTypeMarshallerAttribute.ApplicationSyntaxReference!.GetSyntaxAsync(ct).ConfigureAwait(false); - - SyntaxNode updatedDeclaration = AddMissingFeatures(gen.GetName(attributeSyntax), customTypeMarshallerAttribute, featuresToAdd, gen); - - editor.ReplaceNode(attributeSyntax, updatedDeclaration); - - return editor.GetChangedDocument(); - } - - private static SyntaxNode AddMissingFeatures(string attributeName, AttributeData? customTypeMarshallerAttribute, CustomTypeMarshallerFeatures featuresToAdd, SyntaxGenerator gen) - { - SyntaxNode newAttributeSyntax = gen.Attribute(attributeName); - - newAttributeSyntax = gen.AddAttributeArguments(newAttributeSyntax, customTypeMarshallerAttribute.ConstructorArguments.Select(a => gen.AttributeArgument(gen.TypedConstantExpression(a)))); - - CustomTypeMarshallerFeatures newFeaturesValue = featuresToAdd; - int? featuresArgLocation = null; - - newAttributeSyntax = gen.AddAttributeArguments(newAttributeSyntax, customTypeMarshallerAttribute.NamedArguments - .Where((a, i) => - { - if (a.Key == "Features") - { - // Capture the original location of the 'Features' named argument so we can update it "in place". - featuresArgLocation = customTypeMarshallerAttribute.ConstructorArguments.Length + i; - newFeaturesValue |= (CustomTypeMarshallerFeatures)a.Value.Value; - return false; - } - return true; - }) - .Select(a => gen.AttributeArgument(a.Key, gen.TypedConstantExpression(a.Value)))); - - SyntaxNode featureAttributeArgument = gen.AttributeArgument("Features", - gen.GetEnumValueAsFlagsExpression( - customTypeMarshallerAttribute.AttributeClass.GetMembers(ManualTypeMarshallingHelper_V1.CustomMarshallerAttributeFields.Features).OfType().First().Type, - (int)newFeaturesValue, - includeZeroValueFlags: false)); - - newAttributeSyntax = featuresArgLocation is null - ? gen.AddAttributeArguments(newAttributeSyntax, new[] { featureAttributeArgument }) - : gen.InsertAttributeArguments(newAttributeSyntax, featuresArgLocation.Value, new[] { featureAttributeArgument }); - - return newAttributeSyntax; - } private static async Task AddMissingMembers(Document doc, SyntaxNode node, List missingMemberNames, CancellationToken ct) { @@ -240,165 +129,8 @@ private static async Task AddMissingMembers(Document doc, SyntaxNode n private static SyntaxNode AddMissingMembers(SyntaxNode node, ITypeSymbol marshallerType, List missingMemberNames, Compilation compilation, SyntaxGenerator gen) { - INamedTypeSymbol @byte = compilation.GetSpecialType(SpecialType.System_Byte); - INamedTypeSymbol @object = compilation.GetSpecialType(SpecialType.System_Object); - INamedTypeSymbol spanOfT = compilation.GetTypeByMetadataName(TypeNames.System_Span_Metadata)!; - INamedTypeSymbol spanOfByte = spanOfT.Construct(@byte)!; - INamedTypeSymbol readOnlySpanOfT = compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata)!; - INamedTypeSymbol readOnlySpanOfByte = readOnlySpanOfT.Construct(@byte)!; - INamedTypeSymbol int32 = compilation.GetSpecialType(SpecialType.System_Int32); - - SyntaxNode updatedDeclaration = node; - - - (_, ITypeSymbol managedType, _) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(marshallerType); - - IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper_V1.FindFromNativeValueMethod(marshallerType); - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(marshallerType); - IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesSourceMethod(marshallerType, readOnlySpanOfT); - IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesDestinationMethod(marshallerType, spanOfT); - - SyntaxNode[] throwNotImplementedStatements = new[] - { - gen.ThrowStatement(gen.ObjectCreationExpression(gen.DottedName("System.NotImplementedException"))) - }; - - foreach (string missingMemberName in missingMemberNames) - { - switch (missingMemberName) - { - case CustomTypeMarshallerAnalyzer.MissingMemberNames.ValueManagedToNativeConstructor: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration( - gen.GetName(node), - new[] - { - gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType)) - }, - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case CustomTypeMarshallerAnalyzer.MissingMemberNames.ValueCallerAllocatedBufferConstructor: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration( - gen.GetName(node), - new[] - { - gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType)), - gen.ParameterDeclaration("buffer", type: gen.TypeExpression(spanOfByte)) - }, - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case CustomTypeMarshallerAnalyzer.MissingMemberNames.CollectionManagedToNativeConstructor: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration( - gen.GetName(node), - new[] - { - gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType)), - gen.ParameterDeclaration("nativeElementSize", type: gen.TypeExpression(int32)) - }, - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case CustomTypeMarshallerAnalyzer.MissingMemberNames.CollectionCallerAllocatedBufferConstructor: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration( - gen.GetName(node), - new[] - { - gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType)), - gen.ParameterDeclaration("buffer", type: gen.TypeExpression(spanOfByte)), - gen.ParameterDeclaration("nativeElementSize", type: gen.TypeExpression(int32)) - }, - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case CustomTypeMarshallerAnalyzer.MissingMemberNames.CollectionNativeElementSizeConstructor: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration( - gen.GetName(node), - new[] - { - gen.ParameterDeclaration("nativeElementSize", type: gen.TypeExpression(int32)) - }, - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.Value.ToManaged: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames_V1.Value.ToManaged, - returnType: gen.TypeExpression(managedType), - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.Value.FreeNative: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(ShapeMemberNames_V1.Value.FreeNative, - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.Value.FromNativeValue: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames_V1.Value.FromNativeValue, - parameters: new[] - { - gen.ParameterDeclaration("value", - type: gen.TypeExpression(toNativeValueMethod?.ReturnType ?? @byte)) - }, - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.Value.ToNativeValue: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames_V1.Value.ToNativeValue, - returnType: gen.TypeExpression(fromNativeValueMethod?.Parameters[0].Type ?? @byte), - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource: - INamedTypeSymbol? getManagedValuesDestinationReturnType = (INamedTypeSymbol?)getManagedValuesDestinationMethod?.ReturnType; - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource, - returnType: gen.TypeExpression( - readOnlySpanOfT.Construct( - getManagedValuesDestinationReturnType?.TypeArguments[0] ?? @object)), - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination, - returnType: gen.TypeExpression(spanOfByte), - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource, - parameters: new[] - { - gen.ParameterDeclaration("numElements", type: gen.TypeExpression(int32)) - }, - returnType: gen.TypeExpression(readOnlySpanOfByte), - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - case ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination: - INamedTypeSymbol? getManagedValuesSourceReturnType = (INamedTypeSymbol?)getManagedValuesSourceMethod?.ReturnType; - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination, - parameters: new[] - { - gen.ParameterDeclaration("numElements", type: gen.TypeExpression(int32)) - }, - returnType: gen.TypeExpression( - spanOfT.Construct( - getManagedValuesSourceReturnType?.TypeArguments[0] ?? @object)), - accessibility: Accessibility.Public, - statements: throwNotImplementedStatements)); - break; - default: - break; - } - } - - return updatedDeclaration; + // TODO: Implement adding the missing members for the V2 shapes + return node; } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerDirection.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomTypeMarshallingDirection.cs similarity index 80% rename from src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerDirection.cs rename to src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomTypeMarshallingDirection.cs index 7c1748171b47b..25dd1dd095402 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomTypeMarshallerDirection.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomTypeMarshallingDirection.cs @@ -1,19 +1,16 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.ComponentModel; -#if MICROSOFT_INTEROP_SOURCEGENERATION + namespace Microsoft.Interop -#else -namespace System.Runtime.InteropServices.Marshalling -#endif { /// /// A direction of marshalling data into or out of the managed environment /// [Flags] - public enum CustomTypeMarshallerDirection + public enum CustomTypeMarshallingDirection { /// /// No marshalling direction diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.V1.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.V1.cs deleted file mode 100644 index 83e02fa4e3e58..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.V1.cs +++ /dev/null @@ -1,227 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Runtime.InteropServices; -using Microsoft.CodeAnalysis; - -namespace Microsoft.Interop -{ - public readonly record struct CustomTypeMarshallerData_V1(CustomTypeMarshallerKind Kind, CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures Features, int? BufferSize); - - public static class ShapeMemberNames_V1 - { - public abstract class Value - { - public const string ToNativeValue = nameof(ToNativeValue); - public const string FromNativeValue = nameof(FromNativeValue); - public const string GetPinnableReference = nameof(GetPinnableReference); - public const string FreeNative = nameof(FreeNative); - public const string ToManaged = nameof(ToManaged); - } - - public abstract class LinearCollection : Value - { - public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination); - public const string GetManagedValuesSource = nameof(GetManagedValuesSource); - public const string GetNativeValuesDestination = nameof(GetNativeValuesDestination); - public const string GetNativeValuesSource = nameof(GetNativeValuesSource); - } - } - public static class ManualTypeMarshallingHelper_V1 - { - public static class CustomMarshallerAttributeFields - { - public const string BufferSize = nameof(BufferSize); - public const string Direction = nameof(Direction); - public const string Features = nameof(Features); - } - - public static (bool hasAttribute, ITypeSymbol? managedType, CustomTypeMarshallerData_V1? kind) GetMarshallerShapeInfo(ITypeSymbol marshallerType) - { - var attr = marshallerType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.CustomTypeMarshallerAttribute); - if (attr is null) - { - return (false, null, null); - } - if (attr.ConstructorArguments.Length == 0) - { - return (true, null, null); - } - CustomTypeMarshallerKind kind = CustomTypeMarshallerKind.Value; - ITypeSymbol? managedType = attr.ConstructorArguments[0].Value as ITypeSymbol; - if (attr.ConstructorArguments.Length > 1) - { - if (attr.ConstructorArguments[1].Value is not int i) - { - return (true, managedType, null); - } - kind = (CustomTypeMarshallerKind)i; - } - var namedArguments = attr.NamedArguments.ToImmutableDictionary(); - int? bufferSize = namedArguments.TryGetValue(CustomMarshallerAttributeFields.BufferSize, out TypedConstant bufferSizeConstant) ? bufferSizeConstant.Value as int? : null; - CustomTypeMarshallerDirection direction = namedArguments.TryGetValue(CustomMarshallerAttributeFields.Direction, out TypedConstant directionConstant) ? (CustomTypeMarshallerDirection)directionConstant.Value : CustomTypeMarshallerDirection.Ref; - CustomTypeMarshallerFeatures features = namedArguments.TryGetValue(CustomMarshallerAttributeFields.Features, out TypedConstant featuresConstant) ? (CustomTypeMarshallerFeatures)featuresConstant.Value : CustomTypeMarshallerFeatures.None; - return (true, managedType, new CustomTypeMarshallerData_V1(kind, direction, features, bufferSize)); - } - - /// - /// Get the supported for a marshaller type - /// - /// The marshaller type. - /// The mananged type that would be marshalled. - /// Supported - public static CustomTypeMarshallerPinning GetMarshallerPinningFeatures(ITypeSymbol marshallerType, ITypeSymbol? managedType) - { - CustomTypeMarshallerPinning pinning = CustomTypeMarshallerPinning.None; - - if (ManualTypeMarshallingHelper.FindGetPinnableReference(marshallerType) is not null) - { - pinning |= CustomTypeMarshallerPinning.NativeType; - } - - if (managedType is not null && ManualTypeMarshallingHelper.FindGetPinnableReference(managedType) is not null) - { - pinning |= CustomTypeMarshallerPinning.ManagedType; - } - - return pinning; - } - - public static bool HasToManagedMethod(ITypeSymbol nativeType, ITypeSymbol managedType) - { - return nativeType.GetMembers(ShapeMemberNames_V1.Value.ToManaged) - .OfType() - .Any(m => m.Parameters.IsEmpty - && !m.ReturnsByRef - && !m.ReturnsByRefReadonly - && SymbolEqualityComparer.Default.Equals(m.ReturnType, managedType) - && !m.IsStatic); - } - - public static bool IsManagedToNativeConstructor( - IMethodSymbol ctor, - ITypeSymbol managedType, - CustomTypeMarshallerKind variant) - { - if (variant == CustomTypeMarshallerKind.LinearCollection) - { - return ctor.Parameters.Length == 2 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) - && ctor.Parameters[1].Type.SpecialType == SpecialType.System_Int32; - } - return ctor.Parameters.Length == 1 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type); - } - - public static bool IsCallerAllocatedSpanConstructor( - IMethodSymbol ctor, - ITypeSymbol managedType, - ITypeSymbol spanOfT, - CustomTypeMarshallerKind variant, - out ITypeSymbol? spanElementType) - { - spanElementType = null; - if (variant == CustomTypeMarshallerKind.LinearCollection) - { - return ctor.Parameters.Length == 3 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) - && IsSpanOfUnmanagedType(ctor.Parameters[1].Type, spanOfT, out spanElementType) - && spanElementType.SpecialType == SpecialType.System_Byte - && ctor.Parameters[2].Type.SpecialType == SpecialType.System_Int32; - } - return ctor.Parameters.Length == 2 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) - && IsSpanOfUnmanagedType(ctor.Parameters[1].Type, spanOfT, out spanElementType); - - static bool IsSpanOfUnmanagedType(ITypeSymbol typeToCheck, ITypeSymbol spanOfT, out ITypeSymbol? typeArgument) - { - typeArgument = null; - if (typeToCheck is INamedTypeSymbol namedType - && SymbolEqualityComparer.Default.Equals(spanOfT, namedType.ConstructedFrom) - && namedType.TypeArguments.Length == 1 - && namedType.TypeArguments[0].IsUnmanagedType) - { - typeArgument = namedType.TypeArguments[0]; - return true; - } - - return false; - } - } - - public static bool HasFreeNativeMethod(ITypeSymbol type) - { - return type.GetMembers(ShapeMemberNames_V1.Value.FreeNative) - .OfType() - .Any(m => m is { IsStatic: false, Parameters.Length: 0, ReturnType.SpecialType: SpecialType.System_Void }); - } - - public static IMethodSymbol? FindToNativeValueMethod(ITypeSymbol type) - { - return type.GetMembers(ShapeMemberNames_V1.Value.ToNativeValue) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0 }); - } - - public static IMethodSymbol? FindFromNativeValueMethod(ITypeSymbol type) - { - return type.GetMembers(ShapeMemberNames_V1.Value.FromNativeValue) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 1, ReturnType.SpecialType: SpecialType.System_Void }); - } - - public static bool TryGetElementTypeFromLinearCollectionMarshaller(ITypeSymbol type, ITypeSymbol readOnlySpanOfT, out ITypeSymbol elementType) - { - if (FindGetManagedValuesSourceMethod(type, readOnlySpanOfT) is not IMethodSymbol managedValuesSourceMethod) - { - elementType = null!; - return false; - } - - elementType = ((INamedTypeSymbol)managedValuesSourceMethod.ReturnType).TypeArguments[0]; - return true; - } - - public static IMethodSymbol? FindGetManagedValuesSourceMethod(ITypeSymbol type, ITypeSymbol readOnlySpanOfT) - { - return type - .GetMembers(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 0, ReturnType: INamedTypeSymbol { ConstructedFrom: INamedTypeSymbol returnType } } - && SymbolEqualityComparer.Default.Equals(returnType, readOnlySpanOfT)); - } - - public static IMethodSymbol? FindGetManagedValuesDestinationMethod(ITypeSymbol type, ITypeSymbol spanOfT) - { - return type - .GetMembers(ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 1, ReturnType: INamedTypeSymbol { ConstructedFrom: INamedTypeSymbol returnType } } - && m.Parameters[0].Type.SpecialType == SpecialType.System_Int32 - && SymbolEqualityComparer.Default.Equals(returnType, spanOfT)); - } - - public static IMethodSymbol? FindGetNativeValuesDestinationMethod(ITypeSymbol type, ITypeSymbol spanOfByte) - { - return type - .GetMembers(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 0, ReturnType: INamedTypeSymbol returnType } - && SymbolEqualityComparer.Default.Equals(returnType, spanOfByte)); - } - - public static IMethodSymbol? FindGetNativeValuesSourceMethod(ITypeSymbol type, ITypeSymbol readOnlySpanOfByte) - { - return type - .GetMembers(ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 1, ReturnType: INamedTypeSymbol returnType } - && m.Parameters[0].Type.SpecialType == SpecialType.System_Int32 - && SymbolEqualityComparer.Default.Equals(returnType, readOnlySpanOfByte)); - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs index 8827eacd59020..89a11309070ff 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs @@ -229,8 +229,7 @@ private static bool TryGetMarshallersFromEntryType( } } - if (innerType.ToDisplayString() != TypeNames.CustomTypeMarshallerAttributeGenericPlaceholder - && innerType.ToDisplayString() != TypeNames.CustomMarshallerAttributeGenericPlaceholder) + if (innerType.ToDisplayString() != TypeNames.CustomMarshallerAttributeGenericPlaceholder) { return managedType; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs index 100d756bc32e5..611a4b1cb0c65 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs @@ -56,31 +56,6 @@ public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext conte return CreateCustomNativeTypeMarshaller(info, context, marshalInfo); } - if (info.MarshallingAttributeInfo is NativeMarshallingAttributeInfo_V1 marshalInfoV1) - { - if (Options.RuntimeMarshallingDisabled || marshalInfoV1.IsStrictlyBlittable) - { - return CreateCustomNativeTypeMarshaller_V1(info, context, marshalInfoV1); - } - - if (marshalInfoV1.NativeValueType is SpecialTypeInfo specialType - && specialType.SpecialType.IsAlwaysBlittable()) - { - return CreateCustomNativeTypeMarshaller_V1(info, context, marshalInfoV1); - } - - if (marshalInfoV1.NativeValueType is PointerTypeInfo) - { - return CreateCustomNativeTypeMarshaller_V1(info, context, marshalInfoV1); - } - - throw new MarshallingNotSupportedException(info, context) - { - NotSupportedDetails = SR.RuntimeMarshallingMustBeDisabled, - DiagnosticProperties = AddDisableRuntimeMarshallingAttributeProperties - }; - } - if (info.MarshallingAttributeInfo is UnmanagedBlittableMarshallingInfo blittableInfo) { if (Options.RuntimeMarshallingDisabled || blittableInfo.IsStrictlyBlittable) @@ -141,11 +116,6 @@ ExpressionSyntax GetExpressionForParam(TypePositionInfo paramInfo) type = marshallerData.CollectionElementType; marshallingInfo = marshallerData.CollectionElementMarshallingInfo; } - else if (marshallingInfo is NativeLinearCollectionMarshallingInfo_V1 collectionInfoV1) - { - type = collectionInfoV1.ElementType; - marshallingInfo = collectionInfoV1.ElementMarshallingInfo; - } else { throw new MarshallingNotSupportedException(info, context) @@ -269,9 +239,7 @@ private IMarshallingGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo marshallingGenerator = new StaticPinnableManagedValueMarshaller(marshallingGenerator, marshallerData.MarshallerType.Syntax); } - return marshalInfo.IsPinnableManagedType - ? new PinnableManagedValueMarshaller(marshallingGenerator) - : marshallingGenerator; + return marshallingGenerator; } private IMarshallingGenerator CreateNativeCollectionMarshaller( @@ -351,16 +319,13 @@ private IMarshallingGenerator CreateNativeCollectionMarshaller( marshallingGenerator = new StaticPinnableManagedValueMarshaller(marshallingGenerator, marshallerTypeSyntax); } - return marshalInfo.IsPinnableManagedType && elementIsBlittable - ? new PinnableManagedValueMarshaller(marshallingGenerator) - : marshallingGenerator; + return marshallingGenerator; } private static bool ElementTypeIsSometimesNonBlittable(TypePositionInfo elementInfo) { if (elementInfo.MarshallingAttributeInfo is NoMarshallingInfo - || elementInfo.MarshallingAttributeInfo is UnmanagedBlittableMarshallingInfo { IsStrictlyBlittable: true } - || elementInfo.MarshallingAttributeInfo is NativeMarshallingAttributeInfo_V1 { IsStrictlyBlittable: true }) + || elementInfo.MarshallingAttributeInfo is UnmanagedBlittableMarshallingInfo { IsStrictlyBlittable: true }) { return false; } @@ -419,159 +384,6 @@ private void ValidateCustomNativeTypeMarshallingSupported(TypePositionInfo info, } } - private IMarshallingGenerator CreateCustomNativeTypeMarshaller_V1(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo_V1 marshalInfo) - { - ValidateCustomNativeTypeMarshallingSupported_V1(info, context, marshalInfo); - - ICustomNativeTypeMarshallingStrategy marshallingStrategy = new SimpleCustomNativeTypeMarshalling(marshalInfo.NativeMarshallingType.Syntax); - - if ((marshalInfo.MarshallingFeatures & CustomTypeMarshallerFeatures.CallerAllocatedBuffer) != 0) - { - if (marshalInfo.BufferSize is null) - { - throw new MarshallingNotSupportedException(info, context); - } - marshallingStrategy = new StackallocOptimizationMarshalling(marshallingStrategy, marshalInfo.BufferElementType.Syntax, marshalInfo.BufferSize.Value); - } - - if ((marshalInfo.MarshallingFeatures & CustomTypeMarshallerFeatures.UnmanagedResources) != 0) - { - marshallingStrategy = new FreeNativeCleanupStrategy(marshallingStrategy); - } - - // Collections have extra configuration, so handle them here. - if (marshalInfo is NativeLinearCollectionMarshallingInfo_V1 collectionMarshallingInfo) - { - return CreateNativeCollectionMarshaller_V1(info, context, collectionMarshallingInfo, marshallingStrategy); - } - else if (marshalInfo.NativeValueType is not null) - { - marshallingStrategy = new CustomNativeTypeWithToFromNativeValueMarshalling(marshallingStrategy, marshalInfo.NativeValueType.Syntax); - if (marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.NativeType) && marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.TwoStageMarshalling)) - { - marshallingStrategy = new PinnableMarshallerTypeMarshalling(marshallingStrategy); - } - } - - IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false); - - if (marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.ManagedType)) - { - return new PinnableManagedValueMarshaller(marshallingGenerator); - } - - return marshallingGenerator; - } - - private static void ValidateCustomNativeTypeMarshallingSupported_V1(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo_V1 marshalInfo) - { - // The marshalling method for this type doesn't support marshalling from native to managed, - // but our scenario requires marshalling from native to managed. - if ((info.RefKind == RefKind.Ref || info.RefKind == RefKind.Out || info.IsManagedReturnPosition) - && !marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.Out)) - { - throw new MarshallingNotSupportedException(info, context) - { - NotSupportedDetails = string.Format(SR.CustomTypeMarshallingNativeToManagedUnsupported, marshalInfo.NativeMarshallingType.FullTypeName) - }; - } - - // The marshalling method for this type doesn't support marshalling from managed to native by value, - // but our scenario requires marshalling from managed to native by value. - if (!info.IsByRef - && !info.IsManagedReturnPosition - && context.SingleFrameSpansNativeContext - && !(marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.ManagedType) - || marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.CallerAllocatedBuffer) - || marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.In))) - { - throw new MarshallingNotSupportedException(info, context) - { - NotSupportedDetails = string.Format(SR.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName) - }; - } - - // The marshalling method for this type doesn't support marshalling from managed to native by reference, - // but our scenario requires marshalling from managed to native by reference. - // "in" byref supports stack marshalling. - if (info.RefKind == RefKind.In - && !(context.SingleFrameSpansNativeContext && marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.CallerAllocatedBuffer)) - && !marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.In)) - { - throw new MarshallingNotSupportedException(info, context) - { - NotSupportedDetails = string.Format(SR.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName) - }; - } - - // The marshalling method for this type doesn't support marshalling from managed to native by reference, - // but our scenario requires marshalling from managed to native by reference. - // "ref" byref marshalling doesn't support stack marshalling - // The "Out" direction for "ref" was checked above - if (info.RefKind == RefKind.Ref - && !marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.In)) - { - throw new MarshallingNotSupportedException(info, context) - { - NotSupportedDetails = string.Format(SR.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName) - }; - } - } - - private IMarshallingGenerator CreateNativeCollectionMarshaller_V1( - TypePositionInfo info, - StubCodeContext context, - NativeLinearCollectionMarshallingInfo_V1 collectionInfo, - ICustomNativeTypeMarshallingStrategy marshallingStrategy) - { - var elementInfo = new TypePositionInfo(collectionInfo.ElementType, collectionInfo.ElementMarshallingInfo) - { - ManagedIndex = info.ManagedIndex, - RefKind = CreateElementRefKind(info.RefKind, info.ByValueContentsMarshalKind) - }; - IMarshallingGenerator elementMarshaller = _elementMarshallingGenerator.Create( - elementInfo, - new LinearCollectionElementMarshallingCodeContext(StubCodeContext.Stage.Setup, string.Empty, string.Empty, context)); - - ExpressionSyntax numElementsExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)); - if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In)) - { - // In this case, we need a numElementsExpression supplied from metadata, so we'll calculate it here. - numElementsExpression = GetNumElementsExpressionFromMarshallingInfo(info, collectionInfo.ElementCountInfo, context); - } - - bool elementIsBlittable = elementMarshaller is BlittableMarshaller; - if (elementIsBlittable) - { - marshallingStrategy = new LinearCollectionWithBlittableElementsMarshalling(marshallingStrategy, collectionInfo.ElementType.Syntax, numElementsExpression); - } - else - { - marshallingStrategy = new LinearCollectionWithNonBlittableElementsMarshalling(marshallingStrategy, elementMarshaller, elementInfo, numElementsExpression); - } - - marshallingStrategy = new CustomNativeTypeWithToFromNativeValueMarshalling(marshallingStrategy, collectionInfo.NativeValueType.Syntax); - if (collectionInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.NativeType) && collectionInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.TwoStageMarshalling)) - { - marshallingStrategy = new PinnableMarshallerTypeMarshalling(marshallingStrategy); - } - - TypeSyntax nativeElementType = elementMarshaller.AsNativeType(elementInfo); - marshallingStrategy = new SizeOfElementMarshalling( - marshallingStrategy, - SizeOfExpression(nativeElementType)); - - IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false); - - // Elements in the collection must be blittable to use the pinnable marshaller. - if (collectionInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.ManagedType) && elementIsBlittable) - { - return new PinnableManagedValueMarshaller(marshallingGenerator); - } - - return marshallingGenerator; - } - private static RefKind CreateElementRefKind(RefKind refKind, ByValueContentsMarshalKind byValueContentsMarshalKind) { if (refKind == RefKind.None) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs index aa6520c959b64..604530f800f64 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs @@ -14,10 +14,10 @@ namespace Microsoft.Interop /// internal sealed class CustomNativeTypeMarshallingGenerator : IMarshallingGenerator { - private readonly ICustomTypeMarshallingStrategyBase _nativeTypeMarshaller; + private readonly ICustomTypeMarshallingStrategy _nativeTypeMarshaller; private readonly bool _enableByValueContentsMarshalling; - public CustomNativeTypeMarshallingGenerator(ICustomTypeMarshallingStrategyBase nativeTypeMarshaller, bool enableByValueContentsMarshalling) + public CustomNativeTypeMarshallingGenerator(ICustomTypeMarshallingStrategy nativeTypeMarshaller, bool enableByValueContentsMarshalling) { _nativeTypeMarshaller = nativeTypeMarshaller; _enableByValueContentsMarshalling = enableByValueContentsMarshalling; @@ -54,14 +54,7 @@ public IEnumerable Generate(TypePositionInfo info, StubCodeCont case StubCodeContext.Stage.Marshal: if (!info.IsManagedReturnPosition && info.RefKind != RefKind.Out) { - if (_nativeTypeMarshaller is ICustomNativeTypeMarshallingStrategy strategyWithConstructorArgs) - { - return strategyWithConstructorArgs.GenerateMarshalStatements(info, context, strategyWithConstructorArgs.GetNativeTypeConstructorArguments(info, context)); - } - else if (_nativeTypeMarshaller is ICustomTypeMarshallingStrategy strategyWithNoConstructorArgs) - { - return strategyWithNoConstructorArgs.GenerateMarshalStatements(info, context); - } + return _nativeTypeMarshaller.GenerateMarshalStatements(info, context); } break; case StubCodeContext.Stage.Pin: diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs deleted file mode 100644 index b7699f4855990..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs +++ /dev/null @@ -1,1281 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - -namespace Microsoft.Interop -{ - internal interface ICustomNativeTypeMarshallingStrategy : ICustomTypeMarshallingStrategyBase - { - IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context); - - IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments); - } - - /// - /// Marshalling support for a type that has a custom native type. - /// - internal sealed class SimpleCustomNativeTypeMarshalling : ICustomNativeTypeMarshallingStrategy - { - private readonly TypeSyntax _nativeTypeSyntax; - - public SimpleCustomNativeTypeMarshalling(TypeSyntax nativeTypeSyntax) - { - _nativeTypeSyntax = nativeTypeSyntax; - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _nativeTypeSyntax; - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return true; - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - return Array.Empty(); - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - // = new(); - yield return ExpressionStatement( - AssignmentExpression( - SyntaxKind.SimpleAssignmentExpression, - IdentifierName(context.GetIdentifiers(info).native), - ImplicitObjectCreationExpression() - .WithArgumentList(ArgumentList(SeparatedList(nativeTypeConstructorArguments))))); - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return Array.Empty(); - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - // If the current element is being marshalled by-value [Out], then don't call the ToManaged method and do the assignment. - // The assignment will end up being a no-op and will not be observed. - if (!info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out)) - { - yield break; - } - - (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); - // = .ToManaged(); - yield return ExpressionStatement( - AssignmentExpression( - SyntaxKind.SimpleAssignmentExpression, - IdentifierName(managedIdentifier), - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.Value.ToManaged))))); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - return Array.Empty(); - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - yield return Argument(IdentifierName(context.GetIdentifiers(info).managed)); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - return Array.Empty(); - } - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - return Array.Empty(); - } - } - - /// - /// A context that redefines the 'native' identifier for a TypePositionInfo to be the marshaller identifier. - /// - internal sealed record CustomNativeTypeWithToFromNativeValueContext : StubCodeContext - { - public CustomNativeTypeWithToFromNativeValueContext(StubCodeContext parentContext) - { - ParentContext = parentContext; - CurrentStage = parentContext.CurrentStage; - } - - public override (TargetFramework framework, Version version) GetTargetFramework() - => ParentContext!.GetTargetFramework(); - - public override bool SingleFrameSpansNativeContext => ParentContext!.SingleFrameSpansNativeContext; - - public override bool AdditionalTemporaryStateLivesAcrossStages => ParentContext!.AdditionalTemporaryStateLivesAcrossStages; - - public override (string managed, string native) GetIdentifiers(TypePositionInfo info) - { - return (ParentContext!.GetIdentifiers(info).managed, MarshallerHelpers.GetMarshallerIdentifier(info, ParentContext)); - } - } - - /// - /// Marshaller that enables support of ToNativeValue/FromNativeValue methods on a native type. - /// - internal sealed class CustomNativeTypeWithToFromNativeValueMarshalling : ICustomNativeTypeMarshallingStrategy - { - private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller; - private readonly TypeSyntax _nativeValueTypeSyntax; - - public CustomNativeTypeWithToFromNativeValueMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax nativeValueTypeSyntax) - { - _innerMarshaller = innerMarshaller; - _nativeValueTypeSyntax = nativeValueTypeSyntax; - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _nativeValueTypeSyntax; - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return true; - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - - // When temporary state does not live across stages, the marshaller state is uninitialized - // in any stage other than Marshal and Unmarshal. So, we need to reinitialize it here in Cleanup - // from the native value so we can safely run any cleanup functionality in the marshaller. - if (!context.AdditionalTemporaryStateLivesAcrossStages) - { - yield return GenerateFromNativeValueInvocation(info, context, subContext); - } - - foreach (StatementSyntax statement in _innerMarshaller.GenerateCleanupStatements(info, subContext)) - { - yield return statement; - } - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, subContext, nativeTypeConstructorArguments)) - { - yield return statement; - } - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - - foreach (StatementSyntax statement in _innerMarshaller.GeneratePinnedMarshalStatements(info, subContext)) - { - yield return statement; - } - - // = .ToNativeValue(); - yield return ExpressionStatement( - AssignmentExpression( - SyntaxKind.SimpleAssignmentExpression, - IdentifierName(context.GetIdentifiers(info).native), - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(subContext.GetIdentifiers(info).native), - IdentifierName(ShapeMemberNames_V1.Value.ToNativeValue)), - ArgumentList()))); - } - - private static StatementSyntax GenerateFromNativeValueInvocation(TypePositionInfo info, StubCodeContext context, CustomNativeTypeWithToFromNativeValueContext subContext) - { - // .FromNativeValue(); - return ExpressionStatement( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(subContext.GetIdentifiers(info).native), - IdentifierName(ShapeMemberNames_V1.Value.FromNativeValue)), - ArgumentList(SingletonSeparatedList(Argument(IdentifierName(context.GetIdentifiers(info).native)))))); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - - if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In)) - { - yield return GenerateFromNativeValueInvocation(info, context, subContext); - } - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - - foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, subContext)) - { - yield return statement; - } - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - return _innerMarshaller.GetNativeTypeConstructorArguments(info, subContext); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - yield return LocalDeclarationStatement( - VariableDeclaration( - _innerMarshaller.AsNativeType(info), - SingletonSeparatedList( - VariableDeclarator(subContext.GetIdentifiers(info).native) - .WithInitializer(EqualsValueClause(LiteralExpression(SyntaxKind.DefaultLiteralExpression)))))); - - foreach (StatementSyntax statement in _innerMarshaller.GenerateSetupStatements(info, subContext)) - { - yield return statement; - } - } - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - return _innerMarshaller.GeneratePinStatements(info, subContext); - } - } - - /// - /// Marshaller that enables support for a stackalloc constructor variant on a native type. - /// - internal sealed class StackallocOptimizationMarshalling : ICustomNativeTypeMarshallingStrategy - { - private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller; - private readonly TypeSyntax _bufferElementType; - private readonly int _bufferSize; - - public StackallocOptimizationMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax bufferElementType, int bufferSize) - { - _innerMarshaller = innerMarshaller; - _bufferElementType = bufferElementType; - _bufferSize = bufferSize; - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _innerMarshaller.AsNativeType(info); - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateCleanupStatements(info, context); - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - if (StackAllocOptimizationValid(info, context)) - { - // * __stackptr = stackalloc [<_bufferSize>]; - yield return LocalDeclarationStatement( - VariableDeclaration( - PointerType(_bufferElementType), - SingletonSeparatedList( - VariableDeclarator(GetStackAllocPointerIdentifier(info, context)) - .WithInitializer(EqualsValueClause( - StackAllocArrayCreationExpression( - ArrayType( - _bufferElementType, - SingletonList(ArrayRankSpecifier(SingletonSeparatedList( - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(_bufferSize)) - )))))))))); - } - - foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, context, nativeTypeConstructorArguments)) - { - yield return statement; - } - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinnedMarshalStatements(info, context); - } - - private static bool StackAllocOptimizationValid(TypePositionInfo info, StubCodeContext context) - { - return context.SingleFrameSpansNativeContext && (!info.IsByRef || info.RefKind == RefKind.In); - } - - private static string GetStackAllocPointerIdentifier(TypePositionInfo info, StubCodeContext context) - { - return context.GetAdditionalIdentifier(info, "stackptr"); - } - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinStatements(info, context); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateSetupStatements(info, context); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalCaptureStatements(info, context); - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalStatements(info, context); - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - foreach (ArgumentSyntax arg in _innerMarshaller.GetNativeTypeConstructorArguments(info, context)) - { - yield return arg; - } - if (StackAllocOptimizationValid(info, context)) - { - yield return Argument( - ObjectCreationExpression( - GenericName(Identifier(TypeNames.System_Span), - TypeArgumentList(SingletonSeparatedList( - _bufferElementType)))) - .WithArgumentList( - ArgumentList(SeparatedList(new ArgumentSyntax[] - { - Argument(IdentifierName(GetStackAllocPointerIdentifier(info, context))), - Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(_bufferSize))) - })))); - } - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.UsesNativeIdentifier(info, context); - } - } - - /// - /// Marshaller that enables support for a FreeNative method on a native type. - /// - internal sealed class FreeNativeCleanupStrategy : ICustomNativeTypeMarshallingStrategy - { - private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller; - - public FreeNativeCleanupStrategy(ICustomNativeTypeMarshallingStrategy innerMarshaller) - { - _innerMarshaller = innerMarshaller; - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _innerMarshaller.AsNativeType(info); - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - foreach (StatementSyntax statement in _innerMarshaller.GenerateCleanupStatements(info, context)) - { - yield return statement; - } - - // .FreeNative(); - yield return ExpressionStatement( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(context.GetIdentifiers(info).native), - IdentifierName(ShapeMemberNames_V1.Value.FreeNative)))); - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - return _innerMarshaller.GenerateMarshalStatements(info, context, nativeTypeConstructorArguments); - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinnedMarshalStatements(info, context); - } - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinStatements(info, context); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateSetupStatements(info, context); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalCaptureStatements(info, context); - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalStatements(info, context); - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GetNativeTypeConstructorArguments(info, context); - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.UsesNativeIdentifier(info, context); - } - } - - /// - /// Marshaller that calls the GetPinnableReference method on the marshaller value and enables support for the ToNativeValue and FromNativeValue methods. - /// - internal sealed class PinnableMarshallerTypeMarshalling : ICustomNativeTypeMarshallingStrategy - { - private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller; - - public PinnableMarshallerTypeMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller) - { - _innerMarshaller = innerMarshaller; - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _innerMarshaller.AsNativeType(info); - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateCleanupStatements(info, context); - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - return _innerMarshaller.GenerateMarshalStatements(info, context, nativeTypeConstructorArguments); - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinnedMarshalStatements(info, context); - } - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - // The type of the ignored identifier isn't relevant, so we use void* for all. - // fixed (void* = &); - var subContext = new CustomNativeTypeWithToFromNativeValueContext(context); - yield return FixedStatement( - VariableDeclaration( - PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))), - SingletonSeparatedList( - VariableDeclarator(Identifier(context.GetAdditionalIdentifier(info, "ignored"))) - .WithInitializer(EqualsValueClause( - IdentifierName(subContext.GetIdentifiers(info).native))))), - EmptyStatement()); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateSetupStatements(info, context); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalCaptureStatements(info, context); - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalStatements(info, context); - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GetNativeTypeConstructorArguments(info, context); - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.UsesNativeIdentifier(info, context); - } - } - - /// - /// Marshaller that enables support for native types with the constructor variants that take a sizeOfElement int parameter. - /// - internal sealed class SizeOfElementMarshalling : ICustomNativeTypeMarshallingStrategy - { - private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller; - private readonly ExpressionSyntax _sizeOfElementExpression; - - public SizeOfElementMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, ExpressionSyntax sizeOfElementExpression) - { - _innerMarshaller = innerMarshaller; - _sizeOfElementExpression = sizeOfElementExpression; - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _innerMarshaller.AsNativeType(info); - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - // When temporary state does not live across stages, the marshaller state is uninitialized - // in any stage other than Marshal and Unmarshal. So, we need to reinitialize it here in Cleanup - // from the native data so we can safely run any cleanup functionality in the marshaller. - if (!context.AdditionalTemporaryStateLivesAcrossStages) - { - foreach (StatementSyntax statement in GenerateUnmarshallerCollectionInitialization(info, context)) - { - yield return statement; - } - } - - foreach (StatementSyntax statement in _innerMarshaller.GenerateCleanupStatements(info, context)) - { - yield return statement; - } - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - return _innerMarshaller.GenerateMarshalStatements(info, context, nativeTypeConstructorArguments); - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinnedMarshalStatements(info, context); - } - - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinStatements(info, context); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateSetupStatements(info, context); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - // To fulfill the generic contiguous collection marshaller design, - // we need to emit code to initialize the collection marshaller with the size of native elements - // and set the unmanaged collection length before we marshal back the native data. - // This ensures that the marshaller object has enough state to successfully set up the ManagedValues - // and NativeValueStorage spans when the actual collection value is unmarshalled from native to the marshaller. - foreach (StatementSyntax statement in GenerateUnmarshallerCollectionInitialization(info, context)) - { - yield return statement; - } - foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalCaptureStatements(info, context)) - { - yield return statement; - } - } - - private IEnumerable GenerateUnmarshallerCollectionInitialization(TypePositionInfo info, StubCodeContext context) - { - string marshalerIdentifier = MarshallerHelpers.GetMarshallerIdentifier(info, context); - if (info.RefKind == RefKind.Out || info.IsManagedReturnPosition) - { - yield return ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, - IdentifierName(marshalerIdentifier), - ImplicitObjectCreationExpression().AddArgumentListArguments(Argument(_sizeOfElementExpression)))); - } - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalStatements(info, context); - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - foreach (ArgumentSyntax arg in _innerMarshaller.GetNativeTypeConstructorArguments(info, context)) - { - yield return arg; - } - yield return Argument(_sizeOfElementExpression); - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.UsesNativeIdentifier(info, context); - } - } - - /// - /// Marshaller that enables support for marshalling blittable elements of a collection via a native type that implements the LinearCollection marshalling spec. - /// - internal sealed class LinearCollectionWithBlittableElementsMarshalling : ICustomNativeTypeMarshallingStrategy - { - private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller; - private readonly TypeSyntax _elementType; - private readonly ExpressionSyntax _numElementsExpression; - - public LinearCollectionWithBlittableElementsMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax elementType, ExpressionSyntax numElementsExpression) - { - _innerMarshaller = innerMarshaller; - _elementType = elementType; - _numElementsExpression = numElementsExpression; - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _innerMarshaller.AsNativeType(info); - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateCleanupStatements(info, context); - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - string nativeIdentifier = context.GetIdentifiers(info).native; - foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, context, nativeTypeConstructorArguments)) - { - yield return statement; - } - - if (!info.IsByRef && info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Out) - { - // If the parameter is marshalled by-value [Out], then we don't marshal the contents of the collection. - // We do clear the span, so that if the invoke target doesn't fill it, we aren't left with undefined content. - // .GetNativeValuesDestination().Clear(); - yield return ExpressionStatement( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), - ArgumentList()), - IdentifierName("Clear")))); - yield break; - } - - // .GetManagedValuesSource().CopyTo(MemoryMarshal.Cast>(.GetNativeValuesDestination())); - yield return ExpressionStatement( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), - ArgumentList()), - IdentifierName("CopyTo"))) - .AddArgumentListArguments( - Argument( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - GenericName( - Identifier("Cast")) - .WithTypeArgumentList( - TypeArgumentList( - SeparatedList( - new[] - { - PredefinedType(Token(SyntaxKind.ByteKeyword)), - _elementType - }))))) - .AddArgumentListArguments( - Argument( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), - ArgumentList())))))); - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinnedMarshalStatements(info, context); - } - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinStatements(info, context); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateSetupStatements(info, context); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalCaptureStatements(info, context); - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - string nativeIdentifier = context.GetIdentifiers(info).native; - string numElementsIdentifier = context.GetAdditionalIdentifier(info, "numElements"); - - ExpressionSyntax copySource; - ExpressionSyntax copyDestination; - if (!info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out)) - { - // .GetNativeValuesDestination() - copySource = InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination))); - - // MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(.GetManagedValuesSource()), .GetManagedValuesSource().Length) - copyDestination = InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParseName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - IdentifierName("CreateSpan")), - ArgumentList( - SeparatedList(new[] - { - Argument( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - ParseName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - IdentifierName("GetReference")), - ArgumentList(SingletonSeparatedList( - Argument( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)))))))) - .WithRefKindKeyword( - Token(SyntaxKind.RefKeyword)), - Argument( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource))), - IdentifierName("Length"))) - }))); - - } - else - { - yield return LocalDeclarationStatement( - VariableDeclaration( - PredefinedType(Token(SyntaxKind.IntKeyword)), - SingletonSeparatedList( - VariableDeclarator(numElementsIdentifier).WithInitializer(EqualsValueClause(_numElementsExpression))))); - - // .GetNativeValuesSource() - copySource = InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource)), - ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier))))); - - // .GetManagedValuesDestination() - copyDestination = InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination)), - ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier))))); - } - - // MemoryMarshal.Cast>().CopyTo(); - yield return ExpressionStatement( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - GenericName( - Identifier("Cast")) - .WithTypeArgumentList( - TypeArgumentList( - SeparatedList( - new[] - { - PredefinedType(Token(SyntaxKind.ByteKeyword)), - _elementType - }))))) - .AddArgumentListArguments( - Argument(copySource)), - IdentifierName("CopyTo"))) - .AddArgumentListArguments( - Argument(copyDestination))); - - foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, context)) - { - yield return statement; - } - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GetNativeTypeConstructorArguments(info, context); - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.UsesNativeIdentifier(info, context); - } - } - - /// - /// Marshaller that enables support for marshalling non-blittable elements of a collection via a native type that implements the LinearCollection marshalling spec. - /// - internal sealed class LinearCollectionWithNonBlittableElementsMarshalling : ICustomNativeTypeMarshallingStrategy - { - private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller; - private readonly IMarshallingGenerator _elementMarshaller; - private readonly TypePositionInfo _elementInfo; - private readonly ExpressionSyntax _numElementsExpression; - - public LinearCollectionWithNonBlittableElementsMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, - IMarshallingGenerator elementMarshaller, - TypePositionInfo elementInfo, - ExpressionSyntax numElementsExpression) - { - _innerMarshaller = innerMarshaller; - _elementMarshaller = elementMarshaller; - _elementInfo = elementInfo; - _numElementsExpression = numElementsExpression; - } - - private LocalDeclarationStatementSyntax GenerateNativeValuesDestinationDeclaration(TypePositionInfo info, StubCodeContext context) - { - string nativeIdentifier = context.GetIdentifiers(info).native; - string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context); - return LocalDeclarationStatement(VariableDeclaration( - GenericName( - Identifier(TypeNames.System_Span), - TypeArgumentList( - SingletonSeparatedList(_elementMarshaller.AsNativeType(_elementInfo).GetCompatibleGenericTypeParameterSyntax())) - ), - SingletonSeparatedList( - VariableDeclarator(Identifier(nativeSpanIdentifier)) - .WithInitializer(EqualsValueClause( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - GenericName( - Identifier("Cast")) - .WithTypeArgumentList( - TypeArgumentList( - SeparatedList( - new[] - { - PredefinedType(Token(SyntaxKind.ByteKeyword)), - _elementMarshaller.AsNativeType(_elementInfo).GetCompatibleGenericTypeParameterSyntax() - }))))) - .AddArgumentListArguments( - Argument( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), - ArgumentList())))))))); - } - - private LocalDeclarationStatementSyntax GenerateNativeValuesSourceDeclaration(TypePositionInfo info, StubCodeContext context, string numElementsIdentifier) - { - string nativeIdentifier = context.GetIdentifiers(info).native; - string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context); - return LocalDeclarationStatement(VariableDeclaration( - GenericName( - Identifier(TypeNames.System_ReadOnlySpan), - TypeArgumentList( - SingletonSeparatedList(_elementMarshaller.AsNativeType(_elementInfo).GetCompatibleGenericTypeParameterSyntax())) - ), - SingletonSeparatedList( - VariableDeclarator(Identifier(nativeSpanIdentifier)) - .WithInitializer(EqualsValueClause( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - GenericName( - Identifier("Cast")) - .WithTypeArgumentList( - TypeArgumentList( - SeparatedList( - new[] - { - PredefinedType(Token(SyntaxKind.ByteKeyword)), - _elementMarshaller.AsNativeType(_elementInfo).GetCompatibleGenericTypeParameterSyntax() - }))))) - .AddArgumentListArguments( - Argument( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource)), - ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier)))))))))))); - } - - private LocalDeclarationStatementSyntax GeneratedManagedValuesSourceDeclaration(TypePositionInfo info, StubCodeContext context) - { - string nativeIdentifier = context.GetIdentifiers(info).native; - string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context); - return LocalDeclarationStatement(VariableDeclaration( - GenericName( - Identifier(TypeNames.System_ReadOnlySpan), - TypeArgumentList( - SingletonSeparatedList(_elementInfo.ManagedType.Syntax)) - ), - SingletonSeparatedList( - VariableDeclarator(Identifier(managedSpanIdentifier)) - .WithInitializer(EqualsValueClause( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), - ArgumentList())))))); - } - - private LocalDeclarationStatementSyntax GeneratedManagedValuesDestinationDeclaration(TypePositionInfo info, StubCodeContext context, string numElementsIdentifier) - { - string nativeIdentifier = context.GetIdentifiers(info).native; - string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context); - return LocalDeclarationStatement(VariableDeclaration( - GenericName( - Identifier(TypeNames.System_Span), - TypeArgumentList( - SingletonSeparatedList(_elementInfo.ManagedType.Syntax)) - ), - SingletonSeparatedList( - VariableDeclarator(Identifier(managedSpanIdentifier)) - .WithInitializer(EqualsValueClause( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination)), - ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier)))))))))); - } - - private StatementSyntax GenerateContentsMarshallingStatement(TypePositionInfo info, StubCodeContext context, ExpressionSyntax lengthExpression, params StubCodeContext.Stage[] stagesToGeneratePerElement) - { - string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context); - string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context); - var elementSetupSubContext = new LinearCollectionElementMarshallingCodeContext( - StubCodeContext.Stage.Setup, - managedSpanIdentifier, - nativeSpanIdentifier, - context); - - TypePositionInfo localElementInfo = _elementInfo with - { - InstanceIdentifier = info.InstanceIdentifier, - RefKind = info.IsByRef ? info.RefKind : info.ByValueContentsMarshalKind.GetRefKindForByValueContentsKind(), - ManagedIndex = info.ManagedIndex, - NativeIndex = info.NativeIndex - }; - - List elementStatements = new(); - - foreach (var stage in stagesToGeneratePerElement) - { - var elementSubContext = elementSetupSubContext with { CurrentStage = stage }; - elementStatements.AddRange(_elementMarshaller.Generate(localElementInfo, elementSubContext)); - } - - if (elementStatements.Any()) - { - StatementSyntax marshallingStatement = Block( - List(_elementMarshaller.Generate(localElementInfo, elementSetupSubContext) - .Concat(elementStatements))); - - if (_elementMarshaller.AsNativeType(_elementInfo) is PointerTypeSyntax elementNativeType) - { - PointerNativeTypeAssignmentRewriter rewriter = new(elementSetupSubContext.GetIdentifiers(localElementInfo).native, elementNativeType); - marshallingStatement = (StatementSyntax)rewriter.Visit(marshallingStatement); - } - - // Iterate through the elements of the native collection to unmarshal them - return MarshallerHelpers.GetForLoop(lengthExpression, elementSetupSubContext.IndexerIdentifier) - .WithStatement(marshallingStatement); - } - return EmptyStatement(); - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _innerMarshaller.AsNativeType(info); - } - - public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) - { - StatementSyntax contentsCleanupStatements = GenerateContentsMarshallingStatement(info, context, - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(MarshallerHelpers.GetNativeSpanIdentifier(info, context)), - IdentifierName("Length")), - StubCodeContext.Stage.Cleanup); - - if (!contentsCleanupStatements.IsKind(SyntaxKind.EmptyStatement)) - { - yield return Block( - GenerateNativeValuesDestinationDeclaration(info, context), - contentsCleanupStatements); - } - - foreach (StatementSyntax statement in _innerMarshaller.GenerateCleanupStatements(info, context)) - { - yield return statement; - } - } - - public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) - { - foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, context, nativeTypeConstructorArguments)) - { - yield return statement; - } - - if (!info.IsByRef && info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Out) - { - // If the parameter is marshalled by-value [Out], then we don't marshal the contents of the collection. - // We do clear the span, so that if the invoke target doesn't fill it, we aren't left with undefined content. - // .GetNativeValuesDestination().Clear(); - string nativeIdentifier = context.GetIdentifiers(info).native; - yield return ExpressionStatement( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), - ArgumentList()), - IdentifierName("Clear")))); - yield break; - } - - yield return Block( - GeneratedManagedValuesSourceDeclaration(info, context), - GenerateNativeValuesDestinationDeclaration(info, context), - GenerateContentsMarshallingStatement(info, context, - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(MarshallerHelpers.GetManagedSpanIdentifier(info, context)), - IdentifierName("Length")), - StubCodeContext.Stage.Marshal, - // Using the PinnedMarshal stage here isn't strictly valid as we don't guarantee that GetPinnableReference - // is pinned, but for our existing marshallers this is not an issue and we'll be removing support for stateful element marshallers soon - // (at which point we can remove this) - // and address this problem better when we bring them back in the future. - StubCodeContext.Stage.PinnedMarshal)); - } - - public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinnedMarshalStatements(info, context); - } - - - public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GeneratePinStatements(info, context); - } - - public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateSetupStatements(info, context); - } - - public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GenerateUnmarshalCaptureStatements(info, context); - } - - private StatementSyntax GenerateByValueUnmarshalStatement(TypePositionInfo info, StubCodeContext context) - { - // Use ManagedSource and NativeDestination spans for by-value marshalling since we're just marshalling back the contents, - // not the array itself. - // This code is ugly since we're now enforcing readonly safety with ReadOnlySpan for all other scenarios, - // but this is an uncommon case so we don't want to design the API around enabling just it. - var (_, nativeIdentifier) = context.GetIdentifiers(info); - string numElementsIdentifier = context.GetAdditionalIdentifier(info, "numElements"); - // int = .GetManagedValuesSource().Length; - LocalDeclarationStatementSyntax numElementsDeclaration = LocalDeclarationStatement( - VariableDeclaration( - PredefinedType(Token(SyntaxKind.IntKeyword)), - SingletonSeparatedList( - VariableDeclarator(numElementsIdentifier).WithInitializer(EqualsValueClause( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), - ArgumentList()), - IdentifierName("Length"))))))); - - string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context); - // Span = MemoryMarshal.CreateSpan(ref Unsafe.AsRef(ref .GetManagedValuesSource().GetPinnableReference(), )); - LocalDeclarationStatementSyntax managedValuesDeclaration = LocalDeclarationStatement(VariableDeclaration( - GenericName( - Identifier(TypeNames.System_Span), - TypeArgumentList( - SingletonSeparatedList(_elementInfo.ManagedType.Syntax)) - ), - SingletonSeparatedList(VariableDeclarator(managedSpanIdentifier).WithInitializer(EqualsValueClause( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParseName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - IdentifierName("CreateSpan"))) - .WithArgumentList( - ArgumentList( - SeparatedList( - new[] - { - Argument( - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - ParseName(TypeNames.System_Runtime_CompilerServices_Unsafe), - IdentifierName("AsRef")), - ArgumentList(SingletonSeparatedList( - Argument( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), - ArgumentList()), - IdentifierName("GetPinnableReference")), - ArgumentList())) - .WithRefKindKeyword( - Token(SyntaxKind.InKeyword)))))) - .WithRefKindKeyword( - Token(SyntaxKind.RefKeyword)), - Argument( - IdentifierName(numElementsIdentifier)) - })))))))); - - LocalDeclarationStatementSyntax nativeValuesDeclaration = GenerateNativeValuesDestinationDeclaration(info, context); - - return Block(numElementsDeclaration, - managedValuesDeclaration, - nativeValuesDeclaration, - GenerateContentsMarshallingStatement(info, context, - IdentifierName(numElementsIdentifier), - StubCodeContext.Stage.UnmarshalCapture, - StubCodeContext.Stage.Unmarshal)); - } - - public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) - { - string numElementsIdentifier = context.GetAdditionalIdentifier(info, "numElements"); - if (!info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out)) - { - yield return GenerateByValueUnmarshalStatement(info, context); - } - else - { - yield return Block(LocalDeclarationStatement( - VariableDeclaration( - PredefinedType(Token(SyntaxKind.IntKeyword)), - SingletonSeparatedList( - VariableDeclarator(numElementsIdentifier).WithInitializer(EqualsValueClause(_numElementsExpression))))), - GeneratedManagedValuesDestinationDeclaration(info, context, numElementsIdentifier), - GenerateNativeValuesSourceDeclaration(info, context, numElementsIdentifier), - GenerateContentsMarshallingStatement(info, context, - IdentifierName(numElementsIdentifier), - StubCodeContext.Stage.UnmarshalCapture, - StubCodeContext.Stage.Unmarshal)); - } - - foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, context)) - { - yield return statement; - } - } - - public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.GetNativeTypeConstructorArguments(info, context); - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.UsesNativeIdentifier(info, context); - } - - /// - /// Rewrite assignment expressions to the native identifier to cast to IntPtr. - /// This handles the case where the native type of a non-blittable managed type is a pointer, - /// which are unsupported in generic type parameters. - /// - private sealed class PointerNativeTypeAssignmentRewriter : CSharpSyntaxRewriter - { - private readonly string _nativeIdentifier; - private readonly PointerTypeSyntax _nativeType; - - public PointerNativeTypeAssignmentRewriter(string nativeIdentifier, PointerTypeSyntax nativeType) - { - _nativeIdentifier = nativeIdentifier; - _nativeType = nativeType; - } - - public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax node) - { - if (node.Left.ToString() == _nativeIdentifier) - { - return node.WithRight( - CastExpression(MarshallerHelpers.SystemIntPtrType, node.Right)); - } - - if (node.Right.ToString() == _nativeIdentifier) - { - return node.WithRight(CastExpression(_nativeType, node.Right)); - } - - return base.VisitAssignmentExpression(node); - } - - public override SyntaxNode? VisitArgument(ArgumentSyntax node) - { - if (node.Expression.ToString() == _nativeIdentifier) - { - return node.WithExpression( - CastExpression(_nativeType, node.Expression)); - } - - return base.VisitArgument(node); - } - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs index 514baa76bb5f9..0fd72c2bd72f1 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs @@ -13,7 +13,7 @@ namespace Microsoft.Interop /// /// The base interface for implementing various aspects of the custom native type and collection marshalling specs. /// - internal interface ICustomTypeMarshallingStrategyBase + internal interface ICustomTypeMarshallingStrategy { TypeSyntax AsNativeType(TypePositionInfo info); @@ -30,10 +30,7 @@ internal interface ICustomTypeMarshallingStrategyBase IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context); bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context); - } - internal interface ICustomTypeMarshallingStrategy : ICustomTypeMarshallingStrategyBase - { IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context); IEnumerable GenerateGuaranteedUnmarshalStatements(TypePositionInfo info, StubCodeContext context); IEnumerable GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context); diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs index a6dd7678f254f..d6bfac0cbe6da 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs @@ -272,15 +272,18 @@ public bool AnyIncomingEdge(int to) public static IEnumerable GetDependentElementsOfMarshallingInfo( MarshallingInfo elementMarshallingInfo) { - if (elementMarshallingInfo is NativeLinearCollectionMarshallingInfo_V1 nestedCollection) + if (elementMarshallingInfo is NativeLinearCollectionMarshallingInfo nestedCollection) { if (nestedCollection.ElementCountInfo is CountElementCountInfo { ElementInfo: TypePositionInfo nestedCountElement }) { yield return nestedCountElement; } - foreach (TypePositionInfo nestedElements in GetDependentElementsOfMarshallingInfo(nestedCollection.ElementMarshallingInfo)) + foreach (KeyValuePair mode in nestedCollection.Marshallers.Modes) { - yield return nestedElements; + foreach (TypePositionInfo nestedElements in GetDependentElementsOfMarshallingInfo(mode.Value.CollectionElementMarshallingInfo)) + { + yield return nestedElements; + } } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs index 62977de2de3e4..3c3f921711228 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs @@ -99,14 +99,6 @@ public sealed record UnmanagedBlittableMarshallingInfo( bool IsStrictlyBlittable ) : MarshallingInfo; - [Flags] - public enum CustomTypeMarshallerPinning - { - None = 0, - ManagedType = 0x1, - NativeType = 0x2 - } - public abstract record CountInfo { private protected CountInfo() { } @@ -156,49 +148,11 @@ public sealed record NativeLinearCollectionMarshallingInfo( Marshallers, IsPinnableManagedType); - /// - /// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute - /// - public record NativeMarshallingAttributeInfo_V1( - ManagedTypeInfo NativeMarshallingType, - ManagedTypeInfo? NativeValueType, - CustomTypeMarshallerDirection Direction, - CustomTypeMarshallerFeatures MarshallingFeatures, - CustomTypeMarshallerPinning PinningFeatures, - bool IsStrictlyBlittable, - ManagedTypeInfo? BufferElementType, - int? BufferSize) : MarshallingInfo; - /// /// The type of the element is a SafeHandle-derived type with no marshalling attributes. /// public sealed record SafeHandleMarshallingInfo(bool AccessibleDefaultConstructor, bool IsAbstract) : MarshallingInfo; - /// - /// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute - /// with a contiguous collection marshaller - /// - public sealed record NativeLinearCollectionMarshallingInfo_V1( - ManagedTypeInfo NativeMarshallingType, - ManagedTypeInfo? NativeValueType, - CustomTypeMarshallerDirection Direction, - CustomTypeMarshallerFeatures MarshallingFeatures, - CustomTypeMarshallerPinning PinningFeatures, - int? BufferSize, - CountInfo ElementCountInfo, - ManagedTypeInfo ElementType, - MarshallingInfo ElementMarshallingInfo) : NativeMarshallingAttributeInfo_V1( - NativeMarshallingType, - NativeValueType, - Direction, - MarshallingFeatures, - PinningFeatures, - IsStrictlyBlittable: false, - SpecialTypeInfo.Byte, - BufferSize - ); - - /// /// Marshalling information is lacking because of support not because it is /// unknown or non-existent. Includes information about element types in case @@ -591,200 +545,73 @@ private MarshallingInfo CreateNativeMarshallingInfo( ImmutableHashSet inspectedElements, ref int maxIndirectionDepthUsed) { - if (ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(entryPointType)) + if (!ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(entryPointType)) { - if (!entryPointType.IsStatic) - { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerTypeMustBeStatic), entryPointType.ToDisplayString(), type.ToDisplayString()); - return NoMarshallingInfo.Instance; - } + return NoMarshallingInfo.Instance; + } - ManagedTypeInfo entryPointTypeInfo = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType); - bool isPinnableManagedType = !isMarshalUsingAttribute && ManualTypeMarshallingHelper.FindGetPinnableReference(type) is not null; + if (!entryPointType.IsStatic) + { + _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerTypeMustBeStatic), entryPointType.ToDisplayString(), type.ToDisplayString()); + return NoMarshallingInfo.Instance; + } - bool isLinearCollectionMarshalling = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryPointType); - if (isLinearCollectionMarshalling) - { - // Update the entry point type with the type arguments based on the managed type - if (type is IArrayTypeSymbol arrayManagedType) - { - if (entryPointType.Arity != 2) - { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString()); - return NoMarshallingInfo.Instance; - } + ManagedTypeInfo entryPointTypeInfo = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType); + bool isPinnableManagedType = !isMarshalUsingAttribute && ManualTypeMarshallingHelper.FindGetPinnableReference(type) is not null; - entryPointType = entryPointType.ConstructedFrom.Construct( - arrayManagedType.ElementType, - entryPointType.TypeArguments.Last()); - } - else if (type is INamedTypeSymbol namedManagedType) - { - // Entry point type for linear collection marshalling must have the arity of the managed type + 1 - // for the element unmanaged type placeholder - if (entryPointType.Arity != namedManagedType.Arity + 1) - { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString()); - return NoMarshallingInfo.Instance; - } - - entryPointType = entryPointType.ConstructedFrom.Construct( - namedManagedType.TypeArguments.Add(entryPointType.TypeArguments.Last()).ToArray()); - } - else + bool isLinearCollectionMarshalling = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryPointType); + if (isLinearCollectionMarshalling) + { + // Update the entry point type with the type arguments based on the managed type + if (type is IArrayTypeSymbol arrayManagedType) + { + if (entryPointType.Arity != 2) { _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString()); return NoMarshallingInfo.Instance; } - int maxIndirectionDepthUsedLocal = maxIndirectionDepthUsed; - Func getMarshallingInfoForElement = (ITypeSymbol elementType) => GetMarshallingInfo(elementType, new Dictionary(), 1, ImmutableHashSet.Empty, ref maxIndirectionDepthUsedLocal); - if (ManualTypeMarshallingHelper.TryGetLinearCollectionMarshallersFromEntryType(entryPointType, type, _compilation, getMarshallingInfoForElement, out CustomTypeMarshallers? marshallers)) - { - maxIndirectionDepthUsed = maxIndirectionDepthUsedLocal; - return new NativeLinearCollectionMarshallingInfo( - entryPointTypeInfo, - marshallers.Value, - isPinnableManagedType, - parsedCountInfo, - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType.TypeParameters.Last())); - } + entryPointType = entryPointType.ConstructedFrom.Construct( + arrayManagedType.ElementType, + entryPointType.TypeArguments.Last()); } - else + else if (type is INamedTypeSymbol namedManagedType) { - if (ManualTypeMarshallingHelper.TryGetValueMarshallersFromEntryType(entryPointType, type, _compilation, out CustomTypeMarshallers? marshallers)) + // Entry point type for linear collection marshalling must have the arity of the managed type + 1 + // for the element unmanaged type placeholder + if (entryPointType.Arity != namedManagedType.Arity + 1) { - return new NativeMarshallingAttributeInfo(entryPointTypeInfo, marshallers.Value, isPinnableManagedType); - } - } - } - - return CreateNativeMarshallingInfo_V1(type, entryPointType, attrData, isMarshalUsingAttribute, indirectionLevel, parsedCountInfo, useSiteAttributes, inspectedElements, ref maxIndirectionDepthUsed); - } - - private MarshallingInfo CreateNativeMarshallingInfo_V1( - ITypeSymbol type, - INamedTypeSymbol nativeType, - AttributeData attrData, - bool isMarshalUsingAttribute, - int indirectionLevel, - CountInfo parsedCountInfo, - Dictionary useSiteAttributes, - ImmutableHashSet inspectedElements, - ref int maxIndirectionDepthUsed) - { - if (nativeType.IsUnboundGenericType) - { - if (isMarshalUsingAttribute) - { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.NativeGenericTypeMustBeClosedOrMatchArityMessage), nativeType.ToDisplayString()); - return NoMarshallingInfo.Instance; - } - else if (type is INamedTypeSymbol namedType) - { - if (namedType.Arity != nativeType.Arity) - { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.NativeGenericTypeMustBeClosedOrMatchArityMessage), nativeType.ToDisplayString()); + _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString()); return NoMarshallingInfo.Instance; } - else - { - nativeType = nativeType.ConstructedFrom.Construct(namedType.TypeArguments.ToArray()); - } + + entryPointType = entryPointType.ConstructedFrom.Construct( + namedManagedType.TypeArguments.Add(entryPointType.TypeArguments.Last()).ToArray()); } else { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.NativeGenericTypeMustBeClosedOrMatchArityMessage), nativeType.ToDisplayString()); + _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString()); return NoMarshallingInfo.Instance; } - } - - var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(nativeType); - if (customTypeMarshallerData is null) - { - return NoMarshallingInfo.Instance; - } - if (customTypeMarshallerData.Value.Kind == CustomTypeMarshallerKind.LinearCollection) - { - INamedTypeSymbol readOnlySpanOfT = _compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata)!; - if (!ManualTypeMarshallingHelper_V1.TryGetElementTypeFromLinearCollectionMarshaller(nativeType, readOnlySpanOfT, out ITypeSymbol elementType)) + int maxIndirectionDepthUsedLocal = maxIndirectionDepthUsed; + Func getMarshallingInfoForElement = (ITypeSymbol elementType) => GetMarshallingInfo(elementType, new Dictionary(), 1, ImmutableHashSet.Empty, ref maxIndirectionDepthUsedLocal); + if (ManualTypeMarshallingHelper.TryGetLinearCollectionMarshallersFromEntryType(entryPointType, type, _compilation, getMarshallingInfoForElement, out CustomTypeMarshallers? marshallers)) { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.CollectionNativeTypeMustHaveRequiredShapeMessage), nativeType.ToDisplayString()); - return NoMarshallingInfo.Instance; + maxIndirectionDepthUsed = maxIndirectionDepthUsedLocal; + return new NativeLinearCollectionMarshallingInfo( + entryPointTypeInfo, + marshallers.Value, + isPinnableManagedType, + parsedCountInfo, + ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType.TypeParameters.Last())); } - - CustomTypeMarshallerPinning pinning = ManualTypeMarshallingHelper_V1.GetMarshallerPinningFeatures(nativeType, isMarshalUsingAttribute ? null : type); - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(nativeType); - ManagedTypeInfo? nativeValueType = toNativeValueMethod is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(toNativeValueMethod.ReturnType) : null; - return new NativeLinearCollectionMarshallingInfo_V1( - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeType), - nativeValueType, - customTypeMarshallerData.Value.Direction, - customTypeMarshallerData.Value.Features, - pinning, - customTypeMarshallerData.Value.BufferSize, - parsedCountInfo, - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType), - GetMarshallingInfo(elementType, useSiteAttributes, indirectionLevel + 1, inspectedElements, ref maxIndirectionDepthUsed)); } - - return CreateNativeMarshallingInfoForValue_V1( - type, - nativeType, - attrData, - customTypeMarshallerData.Value, - allowPinningManagedType: !isMarshalUsingAttribute); - } - - private MarshallingInfo CreateNativeMarshallingInfoForValue_V1( - ITypeSymbol type, - INamedTypeSymbol nativeType, - AttributeData attrData, - CustomTypeMarshallerData_V1 customTypeMarshallerData, - bool allowPinningManagedType) - { - ManagedTypeInfo? bufferElementTypeInfo = null; - if (customTypeMarshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.CallerAllocatedBuffer)) + else if (ManualTypeMarshallingHelper.TryGetValueMarshallersFromEntryType(entryPointType, type, _compilation, out CustomTypeMarshallers? marshallers)) { - ITypeSymbol? bufferElementType = null; - INamedTypeSymbol spanOfT = _compilation.GetTypeByMetadataName(TypeNames.System_Span_Metadata)!; - foreach (IMethodSymbol ctor in nativeType.Constructors) - { - if (ManualTypeMarshallingHelper_V1.IsCallerAllocatedSpanConstructor(ctor, type, spanOfT, customTypeMarshallerData.Kind, out bufferElementType)) - break; - } - - // Attribute data may be null when using runtime-provided marshallers by default for certain types (strings, for example) - // without the user explicitly putting an attribute on the type or parameter. The marshallers should have the correct shape - // already in thoses cases, so the diagnostic here is not so interesting. - if (bufferElementType is null) - { - if (attrData is not null) - { - _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.ValueInCallerAllocatedBufferRequiresSpanConstructorMessage), nativeType.ToDisplayString(), type.ToDisplayString()); - } - - return NoMarshallingInfo.Instance; - } - - bufferElementTypeInfo = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(bufferElementType); + return new NativeMarshallingAttributeInfo(entryPointTypeInfo, marshallers.Value, isPinnableManagedType); } - - CustomTypeMarshallerPinning pinning = ManualTypeMarshallingHelper_V1.GetMarshallerPinningFeatures(nativeType, allowPinningManagedType ? type : null); - - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(nativeType); - ManagedTypeInfo? nativeValueType = toNativeValueMethod is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(toNativeValueMethod.ReturnType) : null; - - return new NativeMarshallingAttributeInfo_V1( - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeType), - nativeValueType, - customTypeMarshallerData.Direction, - customTypeMarshallerData.Features, - pinning, - nativeType.IsStrictlyBlittable(), - bufferElementTypeInfo, - customTypeMarshallerData.BufferSize); + return NoMarshallingInfo.Instance; } private bool TryCreateTypeBasedMarshallingInfo( @@ -932,33 +759,9 @@ private MarshallingInfo CreateArrayMarshallingInfo( ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller.TypeParameters.Last())); } } - else - { - arrayMarshaller = arrayMarshaller.Construct(typeArgumentToInsert); - } - var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(arrayMarshaller); - Debug.Assert(customTypeMarshallerData is not null); - - ITypeSymbol? nativeValueType = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(arrayMarshaller)?.ReturnType; - - INamedTypeSymbol readOnlySpanOfT = _compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata)!; - if (!ManualTypeMarshallingHelper_V1.TryGetElementTypeFromLinearCollectionMarshaller(arrayMarshaller, readOnlySpanOfT, out elementType)) - { - Debug.Fail("Runtime-provided array marshallers should have a valid shape"); - return NoMarshallingInfo.Instance; - } - - return new NativeLinearCollectionMarshallingInfo_V1( - NativeMarshallingType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller), - NativeValueType: nativeValueType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeValueType) : null, - Direction: customTypeMarshallerData.Value.Direction, - MarshallingFeatures: customTypeMarshallerData.Value.Features, - PinningFeatures: CustomTypeMarshallerPinning.NativeType, - customTypeMarshallerData.Value.BufferSize, - ElementCountInfo: countInfo, - ElementType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType), - ElementMarshallingInfo: elementMarshallingInfo); + Debug.WriteLine("Default marshallers for arrays should be a valid shape."); + return NoMarshallingInfo.Instance; } private MarshallingInfo CreateStringMarshallingInfo( @@ -999,15 +802,7 @@ private MarshallingInfo CreateStringMarshallingInfo( } } - var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(stringMarshaller); - Debug.Assert(customTypeMarshallerData is not null); - - return CreateNativeMarshallingInfoForValue_V1( - type, - stringMarshaller, - null, - customTypeMarshallerData.Value, - allowPinningManagedType: marshallerName is TypeNames.Utf16StringMarshaller); + return new MissingSupportMarshallingInfo(); } private MarshallingInfo GetBlittableMarshallingInfo(ITypeSymbol type) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj index 02621feb27336..d2dd79ffb36dc 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj @@ -9,16 +9,8 @@ - - - - - + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs index b7670ed2e49f6..7fab9de7c407a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs @@ -81,10 +81,10 @@ public enum Stage public Stage CurrentStage { get; init; } = Stage.Invalid; /// - /// CustomTypeMarshallerDirection.In means method import like [LibraryImport]. - /// CustomTypeMarshallerDirection.Out means method export like in [UnmanagedCallersOnly] or in [JSExport] + /// CustomTypeMarshallingDirection.In means method import like [LibraryImport]. + /// CustomTypeMarshallingDirection.Out means method export like in [UnmanagedCallersOnly] or in [JSExport] /// - public CustomTypeMarshallerDirection Direction { get; init; } = CustomTypeMarshallerDirection.In; + public CustomTypeMarshallingDirection Direction { get; init; } = CustomTypeMarshallingDirection.In; /// /// Gets the currently targeted framework and version for stub code generation. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index 6edf393c32e81..7059257114698 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -13,9 +13,6 @@ public static class TypeNames public const string MarshalUsingAttribute = "System.Runtime.InteropServices.Marshalling.MarshalUsingAttribute"; - public const string CustomTypeMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute"; - public const string CustomTypeMarshallerAttributeGenericPlaceholder = "System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute.GenericPlaceholder"; - public const string CustomMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute"; public const string CustomMarshallerAttributeGenericPlaceholder = CustomMarshallerAttribute + ".GenericPlaceholder"; public const string ContiguousCollectionMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshallerAttribute"; diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 940490d75dc28..f9e3fcdfb7390 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2200,72 +2200,6 @@ public ref struct ManagedToUnmanagedIn public void Free() { throw null; } } } - - [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class)] - public sealed partial class ContiguousCollectionMarshallerAttribute : System.Attribute - { - } - - [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class, AllowMultiple = true)] - public sealed partial class CustomMarshallerAttribute : System.Attribute - { - public CustomMarshallerAttribute(System.Type managedType, System.Runtime.InteropServices.Marshalling.MarshalMode marshalMode, System.Type marshallerType) { } - public System.Type ManagedType { get { throw null; } } - public System.Runtime.InteropServices.Marshalling.MarshalMode MarshalMode { get { throw null; } } - public System.Type MarshallerType { get { throw null; } } - public struct GenericPlaceholder - { - } - } - - [System.AttributeUsageAttribute(System.AttributeTargets.Struct)] - public sealed partial class CustomTypeMarshallerAttribute : System.Attribute - { - public CustomTypeMarshallerAttribute(System.Type managedType, System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerKind marshallerKind = System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerKind.Value) { } - public System.Type ManagedType { get { throw null; } } - public System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerKind MarshallerKind { get { throw null; } } - public int BufferSize { get { throw null; } set { } } - public System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerDirection Direction { get { throw null; } set { } } - public System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures Features { get { throw null; } set { } } - public struct GenericPlaceholder - { - } - } - [System.FlagsAttribute] - public enum CustomTypeMarshallerDirection - { - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - None = 0, - In = 0x1, - Out = 0x2, - Ref = In | Out, - } - [System.FlagsAttribute] - public enum CustomTypeMarshallerFeatures - { - None = 0, - UnmanagedResources = 0x1, - CallerAllocatedBuffer = 0x2, - TwoStageMarshalling = 0x4 - } - public enum CustomTypeMarshallerKind - { - Value, - LinearCollection - } - public enum MarshalMode - { - Default = 0, - ManagedToUnmanagedIn = 1, - ManagedToUnmanagedRef = 2, - ManagedToUnmanagedOut = 3, - UnmanagedToManagedIn = 4, - UnmanagedToManagedRef = 5, - UnmanagedToManagedOut = 6, - ElementIn = 7, - ElementRef = 8, - ElementOut = 9 - } [System.AttributeUsageAttribute(System.AttributeTargets.Parameter | System.AttributeTargets.ReturnValue, AllowMultiple = true)] public sealed partial class MarshalUsingAttribute : System.Attribute { @@ -2277,12 +2211,6 @@ public MarshalUsingAttribute(System.Type nativeType) { } public int ElementIndirectionDepth { get { throw null; } set { } } public const string ReturnsCountValue = "return-value"; } - [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class | System.AttributeTargets.Enum | System.AttributeTargets.Delegate)] - public sealed partial class NativeMarshallingAttribute : System.Attribute - { - public NativeMarshallingAttribute(System.Type nativeType) { } - public System.Type NativeType { get { throw null; } } - } [System.CLSCompliant(false)] [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(CustomMarshallerAttribute.GenericPlaceholder*[]), System.Runtime.InteropServices.Marshalling.MarshalMode.Default, diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs deleted file mode 100644 index 3e9af57776a96..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs +++ /dev/null @@ -1,270 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace System.Runtime.InteropServices.Marshalling -{ - // Stack-alloc threshold set to 256 bytes to enable small arrays to be passed on the stack. - // Number kept small to ensure that P/Invokes with a lot of array parameters doesn't - // blow the stack since this is a new optimization in the code-generated interop. - [CustomTypeMarshaller(typeof(ReadOnlySpan<>), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)] - public unsafe ref struct ReadOnlySpanMarshaller - { - private ReadOnlySpan _managedSpan; - private readonly int _sizeOfNativeElement; - private IntPtr _allocatedMemory; - - public ReadOnlySpanMarshaller(int sizeOfNativeElement) - : this() - { - _sizeOfNativeElement = sizeOfNativeElement; - } - - public ReadOnlySpanMarshaller(ReadOnlySpan managed, int sizeOfNativeElement) - :this(managed, Span.Empty, sizeOfNativeElement) - { - } - - public ReadOnlySpanMarshaller(ReadOnlySpan managed, Span stackSpace, int sizeOfNativeElement) - { - _allocatedMemory = default; - _sizeOfNativeElement = sizeOfNativeElement; - if (managed.Length == 0) - { - _managedSpan = default; - NativeValueStorage = default; - return; - } - _managedSpan = managed; - int spaceToAllocate = managed.Length * sizeOfNativeElement; - if (spaceToAllocate <= stackSpace.Length) - { - NativeValueStorage = stackSpace[0..spaceToAllocate]; - } - else - { - _allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate); - NativeValueStorage = new Span((void*)_allocatedMemory, spaceToAllocate); - } - } - - public ReadOnlySpan GetManagedValuesSource() => _managedSpan; - - public Span GetNativeValuesDestination() => NativeValueStorage; - - private Span NativeValueStorage { get; } - - public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(NativeValueStorage); - - public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - - public void FreeNative() - { - Marshal.FreeCoTaskMem(_allocatedMemory); - } - } - - [CustomTypeMarshaller(typeof(Span<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)] - public unsafe ref struct SpanMarshaller - { - private Span _managedSpan; - private readonly int _sizeOfNativeElement; - private IntPtr _allocatedMemory; - - public SpanMarshaller(int sizeOfNativeElement) - : this() - { - _sizeOfNativeElement = sizeOfNativeElement; - } - - public SpanMarshaller(Span managed, int sizeOfNativeElement) - :this(managed, Span.Empty, sizeOfNativeElement) - { - } - - public SpanMarshaller(Span managed, Span stackSpace, int sizeOfNativeElement) - { - _allocatedMemory = default; - _sizeOfNativeElement = sizeOfNativeElement; - if (managed.Length == 0) - { - _managedSpan = default; - NativeValueStorage = default; - return; - } - _managedSpan = managed; - int spaceToAllocate = managed.Length * sizeOfNativeElement; - if (spaceToAllocate <= stackSpace.Length) - { - NativeValueStorage = stackSpace[0..spaceToAllocate]; - } - else - { - _allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate); - NativeValueStorage = new Span((void*)_allocatedMemory, spaceToAllocate); - } - } - - private Span NativeValueStorage { get; set; } - - public ReadOnlySpan GetManagedValuesSource() => _managedSpan; - public Span GetManagedValuesDestination(int length) => _managedSpan = new T[length]; - public Span GetNativeValuesDestination() => NativeValueStorage; - public ReadOnlySpan GetNativeValuesSource(int length) => NativeValueStorage = new Span((void*)_allocatedMemory, length * _sizeOfNativeElement); - public ref byte GetPinnableReference() => ref NativeValueStorage.GetPinnableReference(); - public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - public void FromNativeValue(byte* value) => _allocatedMemory = (IntPtr)value; - - public Span ToManaged() - { - return _managedSpan; - } - - public void FreeNative() - { - Marshal.FreeCoTaskMem(_allocatedMemory); - } - } - - [CustomTypeMarshaller(typeof(Span<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)] - public unsafe ref struct NeverNullSpanMarshaller - { - private SpanMarshaller _inner; - - public NeverNullSpanMarshaller(int sizeOfNativeElement) - : this() - { - _inner = new SpanMarshaller(sizeOfNativeElement); - } - - public NeverNullSpanMarshaller(Span managed, int sizeOfNativeElement) - { - _inner = new SpanMarshaller(managed, sizeOfNativeElement); - } - - public NeverNullSpanMarshaller(Span managed, Span stackSpace, int sizeOfNativeElement) - { - _inner = new SpanMarshaller(managed, stackSpace, sizeOfNativeElement); - } - - - public ReadOnlySpan GetManagedValuesSource() => _inner.GetManagedValuesSource(); - public Span GetManagedValuesDestination(int length) => _inner.GetManagedValuesDestination(length); - public Span GetNativeValuesDestination() => _inner.GetNativeValuesDestination(); - public ReadOnlySpan GetNativeValuesSource(int length) => _inner.GetNativeValuesSource(length); - public ref byte GetPinnableReference() => ref _inner.GetPinnableReference(); - public byte* ToNativeValue() => _inner.GetManagedValuesSource().Length == 0 ? (byte*)0xa5a5a5a5 : (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - public void FromNativeValue(byte* value) => _inner.FromNativeValue(value); - - public Span ToManaged() => _inner.ToManaged(); - - public void FreeNative() - { - _inner.FreeNative(); - } - } - - [CustomTypeMarshaller(typeof(ReadOnlySpan<>), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)] - public unsafe ref struct NeverNullReadOnlySpanMarshaller - { - private ReadOnlySpanMarshaller _inner; - - public NeverNullReadOnlySpanMarshaller(int sizeOfNativeElement) - : this() - { - _inner = new ReadOnlySpanMarshaller(sizeOfNativeElement); - } - - public NeverNullReadOnlySpanMarshaller(ReadOnlySpan managed, int sizeOfNativeElement) - { - _inner = new ReadOnlySpanMarshaller(managed, sizeOfNativeElement); - } - - public NeverNullReadOnlySpanMarshaller(ReadOnlySpan managed, Span stackSpace, int sizeOfNativeElement) - { - _inner = new ReadOnlySpanMarshaller(managed, stackSpace, sizeOfNativeElement); - } - - public ReadOnlySpan GetManagedValuesSource() => _inner.GetManagedValuesSource(); - public Span GetNativeValuesDestination() => _inner.GetNativeValuesDestination(); - public ref byte GetPinnableReference() => ref _inner.GetPinnableReference(); - public byte* ToNativeValue() => _inner.GetManagedValuesSource().Length == 0 ? (byte*)0xa5a5a5a5 : (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - - public void FreeNative() - { - _inner.FreeNative(); - } - } - - // Stack-alloc threshold set to 0 so that the generator can use the constructor that takes a stackSpace to let the marshaller know that the original data span can be used and safely pinned. - [CustomTypeMarshaller(typeof(Span<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0)] - public unsafe ref struct DirectSpanMarshaller - where T : unmanaged - { - private T* _allocatedMemory; - private T* _nativeValue; - private Span _data; - - public DirectSpanMarshaller(int sizeOfNativeElement) - :this() - { - } - - public DirectSpanMarshaller(Span managed, int sizeOfNativeElement) - :this(sizeOfNativeElement) - { - if (managed.Length == 0) - { - return; - } - - int spaceToAllocate = managed.Length * Unsafe.SizeOf(); - _allocatedMemory = (T*)Marshal.AllocCoTaskMem(spaceToAllocate); - _data = managed; - } - - public DirectSpanMarshaller(Span managed, Span stackSpace, int sizeOfNativeElement) - :this(sizeOfNativeElement) - { - Debug.Assert(stackSpace.IsEmpty); - _data = managed; - } - - public ReadOnlySpan GetManagedValuesSource() => _data; - public Span GetManagedValuesDestination(int length) => _data = new Span(_nativeValue, length); - public Span GetNativeValuesDestination() => _allocatedMemory != null - ? new Span(_allocatedMemory, _data.Length * Unsafe.SizeOf()) - : MemoryMarshal.Cast(_data); - - public ReadOnlySpan GetNativeValuesSource(int length) => new ReadOnlySpan(_nativeValue, length * sizeof(T)); - - public ref T GetPinnableReference() => ref _data.GetPinnableReference(); - - public T* ToNativeValue() - { - if (_allocatedMemory != null) - { - return _allocatedMemory; - } - return (T*)Unsafe.AsPointer(ref GetPinnableReference()); - } - - public void FromNativeValue(T* value) - { - _allocatedMemory = null; - _nativeValue = value; - } - - public Span ToManaged() - { - return _data; - } - - public void FreeNative() - { - Marshal.FreeCoTaskMem((IntPtr)_allocatedMemory); - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs index c0aef85bc270d..0d21155ee771a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs @@ -72,10 +72,6 @@ public partial class Arrays [LibraryImport(NativeExportsNE_Binary, EntryPoint = "double_values")] public static partial void DoubleValues([In, Out] IntStructWrapper[] array, int length); - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")] - [return:MarshalAs(UnmanagedType.U1)] - public static partial bool AndAllMembers(BoolStruct_V1[] pArray, int length); - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_bool_struct_array")] [return: MarshalAs(UnmanagedType.U1)] public static partial bool AndAllMembers(BoolStruct[] pArray, int length); diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.V1.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.V1.cs deleted file mode 100644 index ea039de946ead..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.V1.cs +++ /dev/null @@ -1,246 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using SharedTypes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -using System.Text; - -using Xunit; - -namespace LibraryImportGenerator.IntegrationTests -{ - partial class NativeExportsNE - { - public partial class Collections - { - public partial class V1 - { - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")] - public static partial int Sum([MarshalUsing(typeof(ListMarshaller_V1))] List values, int numValues); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array_ref")] - public static partial int SumInArray([MarshalUsing(typeof(ListMarshaller_V1))] in List values, int numValues); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "duplicate_int_array")] - public static partial void Duplicate([MarshalUsing(typeof(ListMarshaller_V1), CountElementName = "numValues")] ref List values, int numValues); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array")] - [return: MarshalUsing(typeof(ListMarshaller_V1), CountElementName = "numValues")] - public static partial List CreateRange(int start, int end, out int numValues); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array_out")] - public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(typeof(ListMarshaller_V1), CountElementName = "numValues")] out List res); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")] - public static partial int SumStringLengths([MarshalUsing(typeof(ListMarshaller_V1)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List strArray); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")] - public static partial int SumStringLengths([MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] WrappedList_V1 strArray); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_replace")] - public static partial void ReverseStrings_Ref([MarshalUsing(typeof(ListMarshaller_V1), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] ref List strArray, out int numElements); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_return")] - [return: MarshalUsing(typeof(ListMarshaller_V1), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] - public static partial List ReverseStrings_Return([MarshalUsing(typeof(ListMarshaller_V1), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List strArray, out int numElements); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_out")] - public static partial void ReverseStrings_Out( - [MarshalUsing(typeof(ListMarshaller_V1)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List strArray, - out int numElements, - [MarshalUsing(typeof(ListMarshaller_V1), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] out List res); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")] - [return: MarshalUsing(typeof(ListMarshaller_V1), ConstantElementCount = sizeof(long))] - public static partial List GetLongBytes(long l); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")] - [return: MarshalAs(UnmanagedType.U1)] - public static partial bool AndAllMembers([MarshalUsing(typeof(ListMarshaller_V1))] List pArray, int length); - } - } - } - - public class CollectionTests_V1 - { - [Fact] - public void BlittableElementColllectionMarshalledToNativeAsExpected() - { - var list = new List { 1, 5, 79, 165, 32, 3 }; - Assert.Equal(list.Sum(), NativeExportsNE.Collections.V1.Sum(list, list.Count)); - } - - [Fact] - public void NullBlittableElementColllectionMarshalledToNativeAsExpected() - { - Assert.Equal(-1, NativeExportsNE.Collections.V1.Sum(null, 0)); - } - - [Fact] - public void BlittableElementColllectionInParameter() - { - var list = new List { 1, 5, 79, 165, 32, 3 }; - Assert.Equal(list.Sum(), NativeExportsNE.Collections.V1.SumInArray(list, list.Count)); - } - - [Fact] - public void BlittableElementCollectionRefParameter() - { - var list = new List { 1, 5, 79, 165, 32, 3 }; - var newList = list; - NativeExportsNE.Collections.V1.Duplicate(ref newList, list.Count); - Assert.Equal((IEnumerable)list, newList); - } - - [Fact] - public void BlittableElementCollectionReturnedFromNative() - { - int start = 5; - int end = 20; - - IEnumerable expected = Enumerable.Range(start, end - start); - Assert.Equal(expected, NativeExportsNE.Collections.V1.CreateRange(start, end, out _)); - - List res; - NativeExportsNE.Collections.V1.CreateRange_Out(start, end, out _, out res); - Assert.Equal(expected, res); - } - - [Fact] - public void NullBlittableElementCollectionReturnedFromNative() - { - Assert.Null(NativeExportsNE.Collections.V1.CreateRange(1, 0, out _)); - - List res; - NativeExportsNE.Collections.V1.CreateRange_Out(1, 0, out _, out res); - Assert.Null(res); - } - - private static List GetStringList() - { - return new() - { - "ABCdef 123$%^", - "🍜 !! 🍜 !!", - "🌲 木 🔥 火 🌾 土 🛡 金 🌊 水" , - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vitae posuere mauris, sed ultrices leo. Suspendisse potenti. Mauris enim enim, blandit tincidunt consequat in, varius sit amet neque. Morbi eget porttitor ex. Duis mattis aliquet ante quis imperdiet. Duis sit.", - string.Empty, - null - }; - } - - [Fact] - public void ByValueCollectionWithNonBlittableElements() - { - var strings = GetStringList(); - Assert.Equal(strings.Sum(str => str?.Length ?? 0), NativeExportsNE.Collections.V1.SumStringLengths(strings)); - } - - [Fact] - public void ByValueNullCollectionWithNonBlittableElements() - { - Assert.Equal(0, NativeExportsNE.Collections.V1.SumStringLengths(null)); - } - - [Fact] - public void ByValueCollectionWithNonBlittableElements_WithDefaultMarshalling() - { - var strings = new WrappedList_V1(GetStringList()); - Assert.Equal(strings.Wrapped.Sum(str => str?.Length ?? 0), NativeExportsNE.Collections.V1.SumStringLengths(strings)); - } - - [Fact] - public void ByRefCollectionWithNonBlittableElements() - { - var strings = GetStringList(); - var expectedStrings = strings.Select(s => ReverseChars(s)).ToList(); - NativeExportsNE.Collections.V1.ReverseStrings_Ref(ref strings, out _); - - Assert.Equal((IEnumerable)expectedStrings, strings); - } - - [Fact] - public void ReturnCollectionWithNonBlittableElements() - { - var strings = GetStringList(); - var expectedStrings = strings.Select(s => ReverseChars(s)).ToList(); - Assert.Equal(expectedStrings, NativeExportsNE.Collections.V1.ReverseStrings_Return(strings, out _)); - - List res; - NativeExportsNE.Collections.V1.ReverseStrings_Out(strings, out _, out res); - Assert.Equal(expectedStrings, res); - } - - [Fact] - public void ByRefNullCollectionWithNonBlittableElements() - { - List strings = null; - NativeExportsNE.Collections.V1.ReverseStrings_Ref(ref strings, out _); - - Assert.Null(strings); - } - - [Fact] - public void ReturnNullCollectionWithNonBlittableElements() - { - List strings = null; - Assert.Null(NativeExportsNE.Collections.V1.ReverseStrings_Return(strings, out _)); - - List res; - NativeExportsNE.Collections.V1.ReverseStrings_Out(strings, out _, out res); - Assert.Null(res); - } - - [Fact] - public void ConstantSizeCollection() - { - var longVal = 0x12345678ABCDEF10L; - - Assert.Equal(longVal, MemoryMarshal.Read(CollectionsMarshal.AsSpan(NativeExportsNE.Collections.V1.GetLongBytes(longVal)))); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void CollectionWithSimpleNonBlittableTypeMarshalling(bool result) - { - var boolValues = new List - { - new BoolStruct_V1 - { - b1 = true, - b2 = true, - b3 = true, - }, - new BoolStruct_V1 - { - b1 = true, - b2 = true, - b3 = true, - }, - new BoolStruct_V1 - { - b1 = true, - b2 = true, - b3 = result, - }, - }; - - Assert.Equal(result, NativeExportsNE.Collections.V1.AndAllMembers(boolValues, boolValues.Count)); - } - - private static string ReverseChars(string value) - { - if (value == null) - return null; - - var chars = value.ToCharArray(); - Array.Reverse(chars); - return new string(chars); - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.V1.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.V1.cs deleted file mode 100644 index f3f159423933f..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.V1.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -using System.Text; -using SharedTypes; - -using Xunit; - -namespace LibraryImportGenerator.IntegrationTests -{ - partial class NativeExportsNE - { - internal partial class V1 - { - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_deepduplicate")] - public static partial void DeepDuplicateStrings(StringContainer_V1 strings, out StringContainer_V1 pStringsOut); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_reverse_strings")] - public static partial void ReverseStrings(ref StringContainer_V1 strings); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes_as_double")] - public static partial double GetLongBytesAsDouble([MarshalUsing(typeof(DoubleToLongMarshaller_V1))] double d); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "negate_bools")] - public static partial void NegateBools( - BoolStruct_V1 boolStruct, - out BoolStruct_V1 pBoolStructOut); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_bools_ref")] - [return: MarshalAs(UnmanagedType.U1)] - public static partial bool AndBoolsRef(in BoolStruct_V1 boolStruct); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "double_int_ref")] - public static partial IntWrapper_V1 DoubleIntRef(IntWrapper_V1 pInt); - } - } - - public class CustomMarshallingTests_V1 - { - [Fact] - public void NonBlittableStructWithFree() - { - var stringContainer = new StringContainer_V1 - { - str1 = "Foo", - str2 = "Bar" - }; - - NativeExportsNE.V1.DeepDuplicateStrings(stringContainer, out var stringContainer2); - - Assert.Equal(stringContainer, stringContainer2); - } - - [Fact] - public void MarshalUsing() - { - double d = 1234.56789; - - Assert.Equal(d, NativeExportsNE.V1.GetLongBytesAsDouble(d)); - } - - [Fact] - public void NonBlittableStructWithoutAllocation() - { - var boolStruct = new BoolStruct_V1 - { - b1 = true, - b2 = false, - b3 = true - }; - - NativeExportsNE.V1.NegateBools(boolStruct, out BoolStruct_V1 boolStructNegated); - - Assert.Equal(!boolStruct.b1, boolStructNegated.b1); - Assert.Equal(!boolStruct.b2, boolStructNegated.b2); - Assert.Equal(!boolStruct.b3, boolStructNegated.b3); - } - - [Fact] - public void GetPinnableReferenceMarshalling() - { - int originalValue = 42; - var wrapper = new IntWrapper_V1 { i = originalValue }; - - var retVal = NativeExportsNE.V1.DoubleIntRef(wrapper); - - Assert.Equal(originalValue * 2, wrapper.i); - Assert.Equal(originalValue * 2, retVal.i); - } - - [Fact] - public void NonBlittableStructRef() - { - var stringContainer = new StringContainer_V1 - { - str1 = "Foo", - str2 = "Bar" - }; - - var expected = new StringContainer_V1 - { - str1 = ReverseUTF8Bytes(stringContainer.str1), - str2 = ReverseUTF8Bytes(stringContainer.str2) - }; - - var stringContainerCopy = stringContainer; - - NativeExportsNE.V1.ReverseStrings(ref stringContainerCopy); - - Assert.Equal(expected, stringContainerCopy); - } - - [Theory] - [InlineData(true, true, true)] - [InlineData(true, true, false)] - [InlineData(true, false, true)] - [InlineData(true, false, false)] - [InlineData(false, true, true)] - [InlineData(false, true, false)] - [InlineData(false, false, true)] - [InlineData(false, false, false)] - public void NonBlittableStructIn(bool b1, bool b2, bool b3) - { - var container = new BoolStruct_V1 - { - b1 = b1, - b2 = b2, - b3 = b3 - }; - - Assert.Equal(b1 && b2 && b3, NativeExportsNE.V1.AndBoolsRef(container)); - } - - private static string ReverseChars(string value) - { - if (value == null) - return null; - - var chars = value.ToCharArray(); - Array.Reverse(chars); - return new string(chars); - } - - private static string ReverseUTF8Bytes(string value) - { - if (value == null) - return null; - - byte[] bytes = Encoding.UTF8.GetBytes(value); - Array.Reverse(bytes); - return Encoding.UTF8.GetString(bytes); - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs index 5e9a86c4a27db..e65fedafe021a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs @@ -156,18 +156,6 @@ public void NonBlittableStructWithoutAllocation() Assert.Equal(!boolStruct.b3, boolStructNegated.b3); } - [Fact] - public void ManagedTypeGetPinnableReferenceMarshalling() - { - int originalValue = 42; - var wrapper = new IntWrapper { i = originalValue }; - - var retVal = NativeExportsNE.Stateless.DoubleIntRef(wrapper); - - Assert.Equal(originalValue * 2, wrapper.i); - Assert.Equal(originalValue * 2, retVal.i); - } - [Fact] public void MarshallerStaticGetPinnableReferenceMarshalling() { diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SetLastErrorTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SetLastErrorTests.cs index b0ed8cdaff25d..68b98d6586eda 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SetLastErrorTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SetLastErrorTests.cs @@ -9,21 +9,19 @@ namespace LibraryImportGenerator.IntegrationTests { - [CustomTypeMarshaller(typeof(int))] - public struct SetLastErrorMarshaller + [CustomMarshaller(typeof(int), MarshalMode.Default, typeof(SetLastErrorMarshaller))] + public static class SetLastErrorMarshaller { - public int val; - - public SetLastErrorMarshaller(int i) + public static int ConvertToUnmanaged(int i) { - val = i; + return i; } - public int ToManaged() + public static int ConvertToManaged(int i ) { // Explicity set the last error to something else on unmarshalling - Marshal.SetLastPInvokeError(val * 2); - return val; + Marshal.SetLastPInvokeError(i * 2); + return i; } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs index d621c159edf87..7afa431c5c631 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs @@ -19,37 +19,30 @@ partial class NativeExportsNE public partial class Span { [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")] - public static partial int Sum([MarshalUsing(typeof(SpanMarshaller))] Span values, int numValues); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")] - public static partial int SumNeverNull([MarshalUsing(typeof(NeverNullSpanMarshaller))] Span values, int numValues); - + public static partial int Sum(Span values, int numValues); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array")] - public static partial int SumNeverNull([MarshalUsing(typeof(NeverNullReadOnlySpanMarshaller))] ReadOnlySpan values, int numValues); + public static partial int Sum(ReadOnlySpan values, int numValues); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_int_array_ref")] - public static partial int SumInArray([MarshalUsing(typeof(SpanMarshaller))] in Span values, int numValues); + public static partial int SumInArray(in Span values, int numValues); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "duplicate_int_array")] - public static partial void Duplicate([MarshalUsing(typeof(SpanMarshaller), CountElementName = "numValues")] ref Span values, int numValues); - - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "duplicate_int_array")] - public static partial void DuplicateRaw([MarshalUsing(typeof(DirectSpanMarshaller), CountElementName = "numValues")] ref Span values, int numValues); + public static partial void Duplicate([MarshalUsing(CountElementName = "numValues")] ref Span values, int numValues); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array")] - [return: MarshalUsing(typeof(SpanMarshaller), CountElementName = "numValues")] + [return: MarshalUsing(CountElementName = "numValues")] public static partial Span CreateRange(int start, int end, out int numValues); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array_out")] - public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(typeof(SpanMarshaller), CountElementName = "numValues")] out Span res); + public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(CountElementName = "numValues")] out Span res); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")] - [return: MarshalUsing(typeof(SpanMarshaller), ConstantElementCount = sizeof(long))] + [return: MarshalUsing(ConstantElementCount = sizeof(long))] public static partial Span GetLongBytes(long l); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")] [return: MarshalAs(UnmanagedType.U1)] - public static partial bool AndAllMembers([MarshalUsing(typeof(SpanMarshaller))] Span pArray, int length); + public static partial bool AndAllMembers(Span pArray, int length); } } @@ -69,15 +62,17 @@ public void DefaultBlittableElementSpanMarshalledToNativeAsExpected() } [Fact] - public void NeverNullSpanMarshallerMarshalsDefaultAsNonNull() + public void ZeroLengthSpanMarshalsAsNonNull() { - Assert.Equal(0, NativeExportsNE.Span.SumNeverNull(Span.Empty, 0)); + Span list = new int[0]; + Assert.Equal(0, NativeExportsNE.Span.Sum(list, list.Length)); } [Fact] - public void NeverNullReadOnlySpanMarshallerMarshalsDefaultAsNonNull() + public void ZeroLengthReadOnlySpanMarshalsAsNonNull() { - Assert.Equal(0, NativeExportsNE.Span.SumNeverNull(ReadOnlySpan.Empty, 0)); + ReadOnlySpan list = new int[0]; + Assert.Equal(0, NativeExportsNE.Span.Sum(list, list.Length)); } [Fact] @@ -96,16 +91,6 @@ public void BlittableElementSpanRefParameter() Assert.Equal((IEnumerable)list, newSpan.ToArray()); } - [Fact] - public unsafe void DirectSpanMarshaller() - { - var list = new int[] { 1, 5, 79, 165, 32, 3 }; - Span newSpan = list; - NativeExportsNE.Span.DuplicateRaw(ref newSpan, list.Length); - Assert.Equal((IEnumerable)list, newSpan.ToArray()); - Marshal.FreeCoTaskMem((IntPtr)Unsafe.AsPointer(ref newSpan.GetPinnableReference())); - } - [Fact] public void BlittableElementSpanReturnedFromNative() { @@ -135,21 +120,21 @@ public void NullBlittableElementSpanReturnedFromNative() [InlineData(false)] public void SpanWithSimpleNonBlittableTypeMarshalling(bool result) { - var boolValues = new BoolStruct_V1[] + var boolValues = new BoolStruct[] { - new BoolStruct_V1 + new BoolStruct { b1 = true, b2 = true, b3 = true, }, - new BoolStruct_V1 + new BoolStruct { b1 = true, b2 = true, b3 = true, }, - new BoolStruct_V1 + new BoolStruct { b1 = true, b2 = true, diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs index 7032a471e6b38..2550efbcec4ed 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs @@ -41,17 +41,21 @@ partial class Foo public static partial void {|CS8795:PInvoke|}(S {|#0:s|}); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) {} +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; - public S ToManaged() => new S(); + public static S ConvertToManaged(Native n) => default; } "; var expectedPropertiesFile = "[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling]" + Environment.NewLine; @@ -72,17 +76,21 @@ partial class Foo public static partial void {|CS8795:PInvoke|}(S {|#0:s|}); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) {} +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; - public S ToManaged() => new S(); + public static S ConvertToManaged(Native n) => default; } "; var propertiesFile = @" diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs index 6082c923a2928..7c240d55eabf6 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs @@ -27,16 +27,21 @@ partial class C public static partial S Method(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; }"; Compilation comp = await TestUtils.CreateCompilation(source); @@ -80,16 +85,21 @@ partial class C public static partial S Method(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; }"; Compilation comp = await TestUtils.CreateCompilation(source); @@ -173,16 +183,21 @@ partial class C public static partial S Method(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; }"; Compilation comp = await TestUtils.CreateCompilation(source); @@ -207,16 +222,21 @@ partial class C public static partial S Method(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; }"; Compilation comp = await TestUtils.CreateCompilation(source); @@ -241,16 +261,21 @@ partial class C public static partial S Method(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; }"; Compilation comp = await TestUtils.CreateCompilation(source); diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs index a91bf5f5a74ef..55a6bc63c42ed 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs @@ -34,16 +34,21 @@ partial class C public static partial S Method1(); }} -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S {{ }} -[CustomTypeMarshaller(typeof(S))] struct Native {{ - public Native(S s) {{ }} - public S ToManaged() {{ return default; }} +}} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; }} "; Compilation origComp = await TestUtils.CreateCompilation(source); @@ -77,16 +82,21 @@ partial class C public static partial S Method1(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; } "; Compilation origComp = await TestUtils.CreateCompilation(source); @@ -122,16 +132,21 @@ partial class C public static partial S Method1(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; } "; Compilation origComp = await TestUtils.CreateCompilation(source); @@ -171,16 +186,21 @@ partial class C public static partial S Method1(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; } "; Compilation origComp = await TestUtils.CreateCompilation(source); @@ -224,16 +244,21 @@ partial class C public static partial S Method1(); }} -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S {{ }} -[CustomTypeMarshaller(typeof(S))] struct Native {{ - public Native(S s) {{ }} - public S ToManaged() {{ return default; }} +}} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; }} "; Compilation origComp = await TestUtils.CreateCompilation(source); @@ -274,16 +299,21 @@ partial class C public static partial S Method1(); } -[NativeMarshalling(typeof(Native))] +[NativeMarshalling(typeof(Marshaller))] struct S { } -[CustomTypeMarshaller(typeof(S))] struct Native { - public Native(S s) { } - public S ToManaged() { return default; } +} + +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller +{ + public static Native ConvertToUnmanaged(S s) => default; + + public static S ConvertToManaged(Native n) => default; } "; Compilation origComp = await TestUtils.CreateCompilation(source); diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs index 74e9477065dcd..dcacad93c9204 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs @@ -383,13 +383,13 @@ public static string BasicParametersAndModifiersWithStringMarshallingCustomType< public static string CustomStringMarshallingParametersAndModifiers() { string typeName = typeof(T).ToString(); - return BasicParametersAndModifiersWithStringMarshallingCustomType(typeName, "Native", DisableRuntimeMarshalling) + $@" -[CustomTypeMarshaller(typeof({typeName}))] -struct Native + return BasicParametersAndModifiersWithStringMarshallingCustomType(typeName, "Marshaller", DisableRuntimeMarshalling) + $@" +[CustomMarshaller(typeof({typeName}), MarshalMode.Default, typeof(Marshaller))] +static class Marshaller {{ - public Native({typeName} s) {{ }} + public static nint ConvertToUnmanaged({typeName} s) => default; - public {typeName} ToManaged() => default; + public static {typeName} ConvertToManaged(nint i) => default; }}"; } @@ -1177,248 +1177,6 @@ public void FromUnmanaged(Native n) {} } } - public static class CustomStructMarshalling_V1 - { - public static string NonBlittableUserDefinedType(bool defineNativeMarshalling = true) => $@" -{(defineNativeMarshalling ? "[NativeMarshalling(typeof(Native))]" : string.Empty)} -struct S -{{ -#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value - public bool b; -#pragma warning restore CS0649 -}} -"; - private static string NativeTypeIn = @" -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In)] -struct Native -{ - private int i; - public Native(S s) - { - i = s.b ? 1 : 0; - } -} -"; - private static string NativeTypeOut = @" -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.Out)] -struct Native -{ -#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value - private int i; -#pragma warning restore CS0649 - public S ToManaged() => new S { b = i != 0 }; -} -"; - public static string NativeTypeRef = @" -[CustomTypeMarshaller(typeof(S))] -struct Native -{ - private int i; - public Native(S s) - { - i = s.b ? 1 : 0; - } - - public S ToManaged() => new S { b = i != 0 }; -} -"; - public static string ManagedToNativeOnlyOutParameter => BasicParameterWithByRefModifier("out", "S") - + NonBlittableUserDefinedType() - + NativeTypeIn; - - public static string NativeToManagedOnlyOutParameter => BasicParameterWithByRefModifier("out", "S") - + NonBlittableUserDefinedType() - + NativeTypeOut; - - public static string ManagedToNativeOnlyReturnValue => BasicReturnType("S") - + NonBlittableUserDefinedType() - + NativeTypeIn; - - public static string NativeToManagedOnlyReturnValue => BasicReturnType("S") - + NonBlittableUserDefinedType() - + NativeTypeOut; - - public static string NativeToManagedOnlyInParameter => BasicParameterWithByRefModifier("in", "S") - + NonBlittableUserDefinedType() - + NativeTypeOut; - - public static string ParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) - + NonBlittableUserDefinedType(defineNativeMarshalling: true) - + NativeTypeRef; - - public static string MarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Native") - + NonBlittableUserDefinedType(defineNativeMarshalling: false) - + NativeTypeRef; - - public static string StackallocParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S") - + NonBlittableUserDefinedType() + @" -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 1)] -struct Native -{ - private int i; - public Native(S s, System.Span b) - { - i = s.b ? 1 : 0; - } - - public S ToManaged() => new S { b = i != 0 }; -} -"; - public static string StackallocOnlyRefParameter = BasicParameterWithByRefModifier("ref", "S") - + NonBlittableUserDefinedType() + @" -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.Out, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 1)] -struct Native -{ - private int i; - public Native(S s, System.Span b) - { - i = s.b ? 1 : 0; - } - - public S ToManaged() => new S { b = i != 0 }; -} -"; - public static string OptionalStackallocParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) - + NonBlittableUserDefinedType() + @" -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 1)] -struct Native -{ - private int i; - public Native(S s, System.Span b) - { - i = s.b ? 1 : 0; - } - public Native(S s) - { - i = s.b ? 1 : 0; - } - - public S ToManaged() => new S { b = i != 0 }; -} -"; - public static string StackallocTwoStageParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S") - + NonBlittableUserDefinedType() + @" -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)] -struct Native -{ - public Native(S s, System.Span b) { } - - public S ToManaged() => new S { b = true }; - - public int ToNativeValue() => throw null; - public void FromNativeValue(int value) { } -} -"; - public static string TwoStageParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) - + NonBlittableUserDefinedType() + @" -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native -{ - public Native(S s) { } - - public S ToManaged() => new S { b = true }; - - public int ToNativeValue() => throw null; - public void FromNativeValue(int value) { } -} -"; - public static string TwoStageRefReturn = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) - + NonBlittableUserDefinedType() + @" -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - public Native(S s) { } - - public ref byte ToNativeValue() => throw null; -} -"; - public static string PinnableParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) + @" -[NativeMarshalling(typeof(Native))] -class S -{ - public int i; - - public ref int GetPinnableReference() => ref i; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private int* ptr; - public Native(S s) - { - ptr = (int*)Marshal.AllocHGlobal(sizeof(int)); - *ptr = s.i; - } - - public S ToManaged() => new S { i = *ptr }; - - public nint ToNativeValue() => (nint)ptr; - public void FromNativeValue(nint value) => ptr = (int*)value; -} -"; - public static string NativeTypePinnable(string nativeType, string pinnedType) => BasicParameterWithByRefModifier("in", "S") - + NonBlittableUserDefinedType() + @$" -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)] -unsafe ref struct Native -{{ - public Native(S s) {{ }} - public Native(S s, System.Span buffer) {{ }} - - public ref {pinnedType} GetPinnableReference() => throw null; - - public S ToManaged() => new S {{ b = true }}; - - public {nativeType}* ToNativeValue() => throw null; - public void FromNativeValue({nativeType}* value) {{ }} - - public void FreeNative() {{ }} -}} -"; - } - - public static string ArrayMarshallingWithCustomStructElementWithValueProperty => MarshalAsArrayParametersAndModifiers("IntStructWrapper", DisableRuntimeMarshalling) + @" -[NativeMarshalling(typeof(IntStructWrapperNative))] -public struct IntStructWrapper -{ - public int Value; -} - -[CustomTypeMarshaller(typeof(IntStructWrapper), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -public struct IntStructWrapperNative -{ - public IntStructWrapperNative(IntStructWrapper managed) - { - } - - public int ToNativeValue() => throw null; - public void FromNativeValue(int value) => throw null; - - public IntStructWrapper ToManaged() => new IntStructWrapper { Value = 1 }; -} -"; - - public static string ArrayMarshallingWithCustomStructElement => MarshalAsArrayParametersAndModifiers("IntStructWrapper", DisableRuntimeMarshalling) + @" -[NativeMarshalling(typeof(IntStructWrapperNative))] -public struct IntStructWrapper -{ - public int Value; -} - -[CustomTypeMarshaller(typeof(IntStructWrapper))] -public struct IntStructWrapperNative -{ - private int value; - - public IntStructWrapperNative(IntStructWrapper managed) - { - value = managed.Value; - } - - public IntStructWrapper ToManaged() => new IntStructWrapper { Value = value }; -} -"; - public static string SafeHandleWithCustomDefaultConstructorAccessibility(bool privateCtor) => BasicParametersAndModifiers("MySafeHandle") + $@" class MySafeHandle : SafeHandle {{ @@ -1998,146 +1756,6 @@ out int pOutSize } } - public static class CustomCollectionMarshalling_V1 - { - public static string ByValue(string elementType) => BasicParameterByValue($"TestCollection<{elementType}>", DisableRuntimeMarshalling) + @" -[NativeMarshalling(typeof(Marshaller<>))] -class TestCollection {} - -[CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Marshaller -{ - public Marshaller(int nativeElementSize) : this() {} - public Marshaller(TestCollection managed, int nativeElementSize) : this() {} - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetManagedValuesDestination(int length) => throw null; - public System.ReadOnlySpan GetNativeValuesSource(int length) => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; - public void FromNativeValue(System.IntPtr value) => throw null; - public TestCollection ToManaged() => throw null; -} -"; - - public static string ByValue() => ByValue(typeof(T).ToString()); - - public static string CustomCollectionWithMarshaller(bool enableDefaultMarshalling) - { - string nativeMarshallingAttribute = enableDefaultMarshalling ? "[NativeMarshalling(typeof(Marshaller<>))]" : string.Empty; - return nativeMarshallingAttribute + @"class TestCollection {} - - [CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] - ref struct Marshaller - { - public Marshaller(int nativeElementSize) : this() {} - public Marshaller(TestCollection managed, int nativeElementSize) : this() {} - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetManagedValuesDestination(int length) => throw null; - public System.ReadOnlySpan GetNativeValuesSource(int length) => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; - public void FromNativeValue(System.IntPtr value) => throw null; - public TestCollection ToManaged() => throw null; - }"; - } - - public static string DefaultMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionCountInfoParametersAndModifiers($"TestCollection<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: true); - - public static string DefaultMarshallerParametersAndModifiers() => DefaultMarshallerParametersAndModifiers(typeof(T).ToString()); - - public static string CustomMarshallerParametersAndModifiers(string elementType) => MarshalUsingCollectionParametersAndModifiers($"TestCollection<{elementType}>", $"Marshaller<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: false); - - public static string CustomMarshallerParametersAndModifiers() => CustomMarshallerParametersAndModifiers(typeof(T).ToString()); - - public static string CustomMarshallerReturnValueLength(string elementType) => MarshalUsingCollectionReturnValueLength($"TestCollection<{elementType}>", $"Marshaller<{elementType}>") + CustomCollectionWithMarshaller(enableDefaultMarshalling: false); - - public static string CustomMarshallerReturnValueLength() => CustomMarshallerReturnValueLength(typeof(T).ToString()); - - public static string GenericCollectionMarshallingArityMismatch => BasicParameterByValue("TestCollection", DisableRuntimeMarshalling) + @" -[NativeMarshalling(typeof(Marshaller<,>))] -class TestCollection {} - -[CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Marshaller -{ - public Marshaller(TestCollection managed, int nativeElementSize) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetManagedValuesDestination(int length) => throw null; - public System.ReadOnlySpan GetNativeValuesSource(int length) => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; - public void FromNativeValue(System.IntPtr value) => throw null; - - public TestCollection ToManaged() => throw null; -}"; - - public static string GenericCollectionWithCustomElementMarshalling => $@" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -{DisableRuntimeMarshalling} -partial class Test -{{ - [LibraryImport(""DoesNotExist"")] - [return:MarshalUsing(ConstantElementCount=10)] - [return:MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] - public static partial TestCollection Method( - [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] TestCollection p, - [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] in TestCollection pIn, - int pRefSize, - [MarshalUsing(CountElementName = ""pRefSize""), MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] ref TestCollection pRef, - [MarshalUsing(CountElementName = ""pOutSize"")][MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] out TestCollection pOut, - out int pOutSize - ); -}} - -struct IntWrapper -{{ - public IntWrapper(int i){{}} - public int ToManaged() => throw null; -}} - -" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true); - - public static string GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth => $@" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -{DisableRuntimeMarshalling} -partial class Test -{{ - [LibraryImport(""DoesNotExist"")] - public static partial void Method( - [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] TestCollection p); -}} - -struct IntWrapper -{{ - public IntWrapper(int i){{}} - public int ToManaged() => throw null; -}} - -" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true); - - public static string GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth => $@" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -{DisableRuntimeMarshalling} -partial class Test -{{ - [LibraryImport(""DoesNotExist"")] - public static partial void Method( - [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 2)] TestCollection p); -}} - -struct IntWrapper -{{ - public IntWrapper(int i){{}} - public int ToManaged() => throw null; -}} - -" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true); - } - public static string MarshalUsingCollectionCountInfoParametersAndModifiers(string collectionType) => $@" using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; @@ -2417,20 +2035,27 @@ public struct S public string s; }} -[CustomTypeMarshaller(typeof(S))] -public struct Native +[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] +public static class Marshaller {{ - private System.IntPtr p; - public Native(S s) + public static Native ConvertToUnmanaged(S s) => new(s); + + public static S ConvertToManaged(Native unmanaged) => unmanaged.ToManaged(); + + public struct Native {{ - p = System.IntPtr.Zero; - }} + private System.IntPtr p; + public Native(S s) + {{ + p = System.IntPtr.Zero; + }} - public S ToManaged() => new S {{ s = string.Empty }}; + public S ToManaged() => new S {{ s = string.Empty }}; + }} }} "; - public static string TypeUsage(string attr) => MarshalUsingParametersAndModifiers("S", "Native", attr); + public static string TypeUsage(string attr) => MarshalUsingParametersAndModifiers("S", "Marshaller", attr); } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs index 49ef5594422f0..fb1a83e132679 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs @@ -107,11 +107,6 @@ public static IEnumerable CodeSnippetsToCompile() yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.ManagedToNativeOnlyReturnValue, 1, 0 }; yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedOnlyInParameter, 1, 0 }; yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.StackallocOnlyRefParameter, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling_V1.TwoStageRefReturn, 3, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling_V1.ManagedToNativeOnlyOutParameter, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling_V1.ManagedToNativeOnlyReturnValue, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling_V1.NativeToManagedOnlyInParameter, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomStructMarshalling_V1.StackallocOnlyRefParameter, 1, 0 }; // Abstract SafeHandle type by reference yield return new object[] { ID(), CodeSnippets.BasicParameterWithByRefModifier("ref", "System.Runtime.InteropServices.SafeHandle"), 1, 0 }; @@ -124,13 +119,10 @@ public static IEnumerable CodeSnippetsToCompile() // Generic collection marshaller has different arity than collection. yield return new object[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateless.GenericCollectionMarshallingArityMismatch, 2, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionMarshallingArityMismatch, 2, 0 }; yield return new object[] { ID(), CodeSnippets.MarshalAsAndMarshalUsingOnReturnValue, 2, 0 }; yield return new object[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateless.CustomElementMarshallingDuplicateElementIndirectionDepth, 2, 0 }; yield return new object[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateless.CustomElementMarshallingUnusedElementIndirectionDepth, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth, 2, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth, 1, 0 }; yield return new object[] { ID(), CodeSnippets.RecursiveCountElementNameOnReturnValue, 2, 0 }; yield return new object[] { ID(), CodeSnippets.RecursiveCountElementNameOnParameter, 2, 0 }; yield return new object[] { ID(), CodeSnippets.MutuallyRecursiveCountElementNameOnParameter, 4, 0 }; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs index 0bf26309e7d8d..7a3f9002dd93e 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -124,11 +124,11 @@ public static IEnumerable CodeSnippetsToCompile() // [In, Out] attributes // By value non-blittable array yield return new[] { ID(), CodeSnippets.ByValueParameterWithModifier("S[]", "Out") - + CodeSnippets.CustomStructMarshalling_V1.NonBlittableUserDefinedType() - + CodeSnippets.CustomStructMarshalling_V1.NativeTypeRef }; + + CodeSnippets.CustomStructMarshalling.NonBlittableUserDefinedType() + + CodeSnippets.CustomStructMarshalling.Stateless.Default }; yield return new[] { ID(), CodeSnippets.ByValueParameterWithModifier("S[]", "In, Out") - + CodeSnippets.CustomStructMarshalling_V1.NonBlittableUserDefinedType() - + CodeSnippets.CustomStructMarshalling_V1.NativeTypeRef }; + + CodeSnippets.CustomStructMarshalling.NonBlittableUserDefinedType() + + CodeSnippets.CustomStructMarshalling.Stateless.Default }; // Enums yield return new[] { ID(), CodeSnippets.EnumParameters }; @@ -207,19 +207,6 @@ public static IEnumerable CodeSnippetsToCompile() yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.OptionalStackallocParametersAndModifiers }; yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.DefaultModeByValueInParameter }; yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.DefaultModeReturnValue }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.ParametersAndModifiers }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.StackallocParametersAndModifiersNoRef }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.StackallocTwoStageParametersAndModifiersNoRef }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.OptionalStackallocParametersAndModifiers }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.TwoStageParametersAndModifiers }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.PinnableParametersAndModifiers }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.NativeTypePinnable("byte", "byte") }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.NativeTypePinnable("byte", "int") }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.MarshalUsingParametersAndModifiers }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.NativeToManagedOnlyOutParameter }; - yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.NativeToManagedOnlyReturnValue }; - yield return new[] { ID(), CodeSnippets.ArrayMarshallingWithCustomStructElement }; - yield return new[] { ID(), CodeSnippets.ArrayMarshallingWithCustomStructElementWithValueProperty }; // Escaped C# keyword identifiers yield return new[] { ID(), CodeSnippets.ByValueParameterWithName("Method", "@event") }; @@ -329,18 +316,6 @@ public static IEnumerable CustomCollections() yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateful.ByValueWithStaticPinning() }; yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateful.ByValueWithStaticPinning() }; yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.ByValue() }; yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; @@ -418,32 +393,6 @@ public static IEnumerable CustomCollections() yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateful.NonBlittableElementNativeToManagedOnlyOutParameter }; yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateful.NonBlittableElementNativeToManagedOnlyReturnValue }; yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling.Stateful.CustomElementMarshalling }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.CustomMarshallerReturnValueLength() }; - yield return new[] { ID(), CodeSnippets.CustomCollectionMarshalling_V1.GenericCollectionWithCustomElementMarshalling }; yield return new[] { ID(), CodeSnippets.CollectionsOfCollectionsStress }; } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs index 392fab00502b2..ceb7db81a1a89 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs @@ -17,1866 +17,5 @@ namespace LibraryImportGenerator.UnitTests [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] public class CustomTypeMarshallerFixerTests { - [Fact] - public async Task NullNativeType_ReportsDiagnostic() - { - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[{|#0:NativeMarshalling(null)|}] -struct S -{ - public string s; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustHaveCustomTypeMarshallerAttributeRule).WithLocation(0).WithArguments("S"), - source); - } - - [Fact] - public async Task NonNamedNativeType_ReportsDiagnostic() - { - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[{|#0:NativeMarshalling(typeof(int*))|}] -struct S -{ - public string s; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustHaveCustomTypeMarshallerAttributeRule).WithLocation(0).WithArguments("S"), - source); - } - - [Fact] - public async Task NonBlittableNativeType_ReportsDiagnostic() - { - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S))] -struct {|#0:Native|} -{ - private string value; - - public Native(S s) - { - value = s.s; - } - - public S ToManaged() => new S { s = value }; -}"; - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"), - source); - } - - [Fact] - public async Task ClassNativeType_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -struct S -{ - public string s; -} - -[{|CS0592:CustomTypeMarshaller|}(typeof(S))] -class {|#0:Native|} -{ - private IntPtr value; - - public Native(S s) - { - } - - public S ToManaged() => new S(); -}"; - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"), - source); - } - - [Fact] - public async Task BlittableNativeType_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S))] -struct Native -{ - private IntPtr value; - - public Native(S s) - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task BlittableNativeWithNonBlittableToNativeValue_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native -{ - private IntPtr value; - - public Native(S s) - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); - - public string {|#0:ToNativeValue|}() => throw null; - public void FromNativeValue(string value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("string", "S"), - source); - } - - [Fact] - public async Task NonBlittableNativeTypeWithBlittableToNativeValue_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native -{ - private string value; - - public Native(S s) - { - value = s.s; - } - - public S ToManaged() => new S() { s = value }; - - public IntPtr ToNativeValue() => throw null; - public void FromNativeValue(IntPtr value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task NonBlittableGetPinnableReferenceReturnType_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public string s; - - public ref string {|#0:GetPinnableReference|}() => ref s; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private IntPtr value; - - public Native(S s) - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); - - public IntPtr ToNativeValue() => throw null; - public void FromNativeValue(IntPtr value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(GetPinnableReferenceReturnTypeBlittableRule).WithLocation(0), - source); - } - - [Fact] - public async Task BlittableGetPinnableReferenceReturnType_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; - - public ref byte GetPinnableReference() => ref c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private IntPtr value; - - public Native(S s) : this() - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); - - public IntPtr ToNativeValue() => throw null; - public void FromNativeValue(IntPtr value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task NonBlittableMarshallerGetPinnableReferenceReturnType_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public char c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private IntPtr value; - - public Native(S s) - { - value = IntPtr.Zero; - } - - public ref char GetPinnableReference() => ref System.Runtime.CompilerServices.Unsafe.NullRef(); - - public S ToManaged() => new S(); - - public IntPtr ToNativeValue() => throw null; - public void FromNativeValue(IntPtr value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task BlittableMarshallerGetPinnableReferenceReturnType_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private IntPtr value; - - public Native(S s) : this() - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); - - public ref byte GetPinnableReference() => ref System.Runtime.CompilerServices.Unsafe.NullRef(); - - public IntPtr ToNativeValue() => throw null; - public void FromNativeValue(IntPtr value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task TypeWithGetPinnableReferenceNonPointerReturnType_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; - - public ref byte GetPinnableReference() => ref c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private IntPtr value; - - public Native(S s) : this() - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); - - public int {|#0:ToNativeValue|}() => throw null; - public void FromNativeValue(int value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustBePointerSizedRule).WithLocation(0).WithArguments("int", "S"), - source); - } - - [Fact] - public async Task TypeWithGetPinnableReferencePointerReturnType_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; - - public ref byte GetPinnableReference() => ref c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private IntPtr value; - - public Native(S s) : this() - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); - - public int* ToNativeValue() => throw null; - public void FromNativeValue(int* value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task TypeWithGetPinnableReferenceByRefValuePropertyType_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; - - public ref byte GetPinnableReference() => ref c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private S value; - - public Native(S s) : this() - { - value = s; - } - public ref byte {|#0:ToNativeValue|}() => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(RefNativeValueUnsupportedRule).WithLocation(0).WithArguments("Native"), - source); - } - - [Fact] - public async Task NativeTypeWithGetPinnableReferenceByRefValuePropertyType_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private S value; - - public Native(S s) : this() - { - value = s; - } - - public ref byte GetPinnableReference() => ref value.c; - - public ref byte {|#0:ToNativeValue|}() => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(RefNativeValueUnsupportedRule).WithLocation(0).WithArguments("Native"), - source); - } - - [Fact] - public async Task NativeTypeWithGetPinnableReferenceNoValueProperty_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In)] -unsafe struct Native -{ - private byte value; - - public Native(S s) : this() - { - value = s.c; - } - - public ref byte {|#0:GetPinnableReference|}() => ref System.Runtime.CompilerServices.Unsafe.NullRef(); -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(MarshallerGetPinnableReferenceRequiresTwoStageMarshallingRule).WithLocation(0).WithArguments("Native"), - source); - } - - [Fact] - public async Task NativeTypeWithGetPinnableReferenceWithNonPointerValueProperty_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - private byte value; - - public Native(S s) : this() - { - value = s.c; - } - - public ref byte GetPinnableReference() => ref System.Runtime.CompilerServices.Unsafe.NullRef(); - - public int ToNativeValue() => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task NativeTypeWithNoMarshallingMethods_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.None)] -struct {|#0:Native|} -{ -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(CustomMarshallerTypeMustSupportDirectionRule).WithLocation(0).WithArguments("Native", "S"), - source); - } - - [Fact] - public async Task CollectionNativeTypeWithNoMarshallingMethods_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.None)] -struct {|#0:Native|} -{ -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(CustomMarshallerTypeMustSupportDirectionRule).WithLocation(0).WithArguments("Native", "S"), - source); - } - - [Fact] - public async Task CollectionNativeTypeWithWrongConstructor_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct {|#0:Native|} -{ - public Native(S s) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Native -{ - public Native(S s) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; - - public Native(S managed, int nativeElementSize) - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(LinearCollectionInRequiresTwoParameterConstructorRule).WithLocation(0).WithArguments("Native", "S"), - fixedSource); - } - - [Fact] - public async Task CollectionNativeTypeWithCorrectConstructor_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Native -{ - public Native(S s, int nativeElementSize) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task CollectionNativeTypeWithIncorrectStackallocConstructor_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)] -ref struct {|#0:Native|} -{ - public Native(S s, Span stackSpace) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)] -ref struct Native -{ - public Native(S s, Span stackSpace) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; - - public Native(S managed, int nativeElementSize) - { - throw new NotImplementedException(); - } - - public Native(S managed, Span buffer, int nativeElementSize) - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - fixedSource, - VerifyCS.Diagnostic(LinearCollectionInRequiresTwoParameterConstructorRule).WithLocation(0).WithArguments("Native", "S"), - VerifyCS.Diagnostic(LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorRule).WithLocation(0).WithArguments("Native", "S")); - } - - [Fact] - public async Task CollectionNativeTypeWithOnlyStackallocConstructor_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)] -ref struct {|#0:Native|} -{ - public Native(S s, Span stackSpace, int nativeElementSize) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)] -ref struct Native -{ - public Native(S s, Span stackSpace, int nativeElementSize) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; - - public Native(S managed, int nativeElementSize) - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - fixedSource, - VerifyCS.Diagnostic(CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule).WithLocation(0).WithArguments("Native", "S"), - VerifyCS.Diagnostic(LinearCollectionInRequiresTwoParameterConstructorRule).WithLocation(0).WithArguments("Native", "S")); - } - - [Fact] - public async Task CollectionNativeTypeWithMissingManagedValuesSource_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct {|#0:Native|} -{ - public Native(S s, int nativeElementSize) : this() {} - - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Native -{ - public Native(S s, int nativeElementSize) : this() {} - - public System.Span GetNativeValuesDestination() => throw null; - public System.IntPtr ToNativeValue() => throw null; - - public ReadOnlySpan GetManagedValuesSource() - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("Native", "S"), - fixedSource); - } - - [Fact] - public async Task CollectionNativeTypeWithMissingNativeValuesDestination_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct {|#0:Native|} -{ - public Native(S s, int nativeElementSize) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.IntPtr ToNativeValue() => throw null; -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Native -{ - public Native(S s, int nativeElementSize) : this() {} - - public System.ReadOnlySpan GetManagedValuesSource() => throw null; - public System.IntPtr ToNativeValue() => throw null; - - public Span GetNativeValuesDestination() - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("Native", "S"), - fixedSource); - } - - [Fact] - public async Task CollectionNativeTypeWithCorrectRefShape_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Native -{ - public Native(int nativeElementSize) : this() {} - public Native(S s, int nativeElementSize) : this() {} - - public ReadOnlySpan GetManagedValuesSource() => throw null; - public Span GetNativeValuesDestination() => throw null; - public ReadOnlySpan GetNativeValuesSource(int length) => throw null; - public Span GetManagedValuesDestination(int length) => throw null; - public IntPtr ToNativeValue() => throw null; - public void FromNativeValue(IntPtr value) => throw null; - public S ToManaged() => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task CollectionNativeTypeWithMismatched_Element_Type_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -ref struct Native -{ - public Native(int nativeElementSize) : this() {} - public Native(S s, int nativeElementSize) : this() {} - - public ReadOnlySpan {|#0:GetManagedValuesSource|}() => throw null; - public Span GetNativeValuesDestination() => throw null; - public ReadOnlySpan GetNativeValuesSource(int length) => throw null; - public Span GetManagedValuesDestination(int length) => throw null; - public IntPtr ToNativeValue() => throw null; - public void FromNativeValue(IntPtr value) => throw null; - public S ToManaged() => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - source, - VerifyCS.Diagnostic(LinearCollectionElementTypesMustMatchRule) - .WithLocation(0)); - } - - [Fact] - public async Task NativeTypeWithOnlyConstructor_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In)] -struct Native -{ - public Native(S s) {} -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task NativeTypeWithOnlyToManagedMethod_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.Out)] -struct Native -{ - public S ToManaged() => new S(); -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task NativeTypeWithIncorrectStackallocConstructor_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x100)] -struct {|#0:Native|} -{ - public Native(S managed) {} - public Native(S s, int i) {} - public Native(S s, Span buffer) {} -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x100)] -struct Native -{ - public Native(S managed) {} - public Native(S s, int i) {} - public Native(S s, Span buffer) {} - - public Native(S managed, Span buffer) - { - throw new NotImplementedException(); - } -}"; - await VerifyCS.VerifyCodeFixAsync(source, - fixedSource, - VerifyCS.Diagnostic(ValueInCallerAllocatedBufferRequiresSpanConstructorRule).WithLocation(0).WithArguments("Native", "S")); - } - - [Fact] - public async Task NativeTypeWithOnlyStackallocConstructor_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x100)] -struct {|#0:Native|} -{ - public Native(S s, Span buffer) {} -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x100)] -struct Native -{ - public Native(S s, Span buffer) {} - - public Native(S managed) - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - fixedSource, - VerifyCS.Diagnostic(CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule).WithLocation(0).WithArguments("Native", "S"), - VerifyCS.Diagnostic(ValueInRequiresOneParameterConstructorRule).WithLocation(0).WithArguments("Native", "S")); - } - - [Fact] - public async Task TypeWithOnlyGetPinnableReference_AndInSupport_ReportsDiagnostics() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class {|#0:S|} -{ - public byte c; - public ref byte GetPinnableReference() => ref c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.Out)] -struct {|#1:Native|} -{ - public S ToManaged() => default; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule).WithLocation(0).WithArguments("S", "Native"), - source); - } - - [Fact] - public async Task NativeTypeWithConstructorAndFromNativeValueMethod_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct {|#0:Native|} -{ - public Native(S s) {} - - public void FromNativeValue(IntPtr value) => throw null; - - public S ToManaged() => new S(); -}"; - - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native -{ - public Native(S s) {} - - public void FromNativeValue(IntPtr value) => throw null; - - public S ToManaged() => new S(); - - public IntPtr ToNativeValue() - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(InTwoStageMarshallingRequiresToNativeValueRule).WithLocation(0).WithArguments("Native"), - fixedSource); - } - - [Fact] - public async Task NativeTypeWithToManagedAndToNativeValueMethod_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct {|#0:Native|} -{ - public Native(S managed) {} - - public S ToManaged() => new S(); - - public IntPtr ToNativeValue() => IntPtr.Zero; -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native -{ - public Native(S managed) {} - - public S ToManaged() => new S(); - - public IntPtr ToNativeValue() => IntPtr.Zero; - - public void FromNativeValue(IntPtr value) - { - throw new NotImplementedException(); - } -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(OutTwoStageMarshallingRequiresFromNativeValueRule).WithLocation(0).WithArguments("Native"), - fixedSource); - } - - [Fact] - public async Task BlittableNativeTypeOnMarshalUsingParameter_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S))] -struct Native -{ - private IntPtr value; - - public Native(S s) - { - value = IntPtr.Zero; - } - - public S ToManaged() => new S(); -} - - -static class Test -{ - static void Foo([MarshalUsing(typeof(Native))] S s) - {} -} -"; - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task NonBlittableNativeTypeOnMarshalUsingParameter_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S))] -struct {|#0:Native|} -{ - private string value; - - public Native(S s) : this() - { - } - - public S ToManaged() => new S(); -} - - -static class Test -{ - static void Foo([MarshalUsing(typeof(Native))] S s) - {} -} -"; - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"), - source); - } - - [Fact] - public async Task NonBlittableNativeTypeOnMarshalUsingReturn_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S))] -struct {|#0:Native|} -{ - private string value; - - public Native(S s) : this() - { - } - - public S ToManaged() => new S(); -} - - -static class Test -{ - [return: MarshalUsing(typeof(Native))] - static S Foo() => new S(); -} -"; - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"), - source); - } - - [Fact] - public async Task GenericNativeTypeWithGenericMemberInstantiatedWithBlittable_DoesNotReportDiagnostic() - { - - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native - where T : unmanaged -{ - public Native(S s) - { - } - - public S ToManaged() => new S(); - - public T ToNativeValue() => throw null; - public void FromNativeValue(T value) => throw null; -}"; - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task UninstantiatedGenericNativeTypeOnNonGeneric_ReportsDiagnostic() - { - - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[{|#0:NativeMarshalling(typeof(Native<>))|}] -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native - where T : unmanaged -{ - public Native(S s) - { - } - - public S ToManaged() => new S(); - - public T ToNativeValue() => throw null; - public void FromNativeValue(T value) => throw null; -}"; - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeGenericTypeMustBeClosedOrMatchArityRule).WithLocation(0).WithArguments("Native<>", "S"), - source); - } - - [Fact] - public async Task MarshalUsingUninstantiatedGenericNativeType_ReportsDiagnostic() - { - - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native - where T : unmanaged -{ - public Native(S s) - { - } - - public S ToManaged() => new S(); - - public T ToNativeValue() => throw null; - public void FromNativeValue(T value) => throw null; -} - -static class Test -{ - static void Foo([{|#0:MarshalUsing(typeof(Native<>))|}] S s) - {} -}"; - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(NativeGenericTypeMustBeClosedOrMatchArityRule).WithLocation(0).WithArguments("Native<>", "S"), - source); - } - - [Fact] - public async Task UninstantiatedGenericNativeTypeOnGenericWithArityMismatch_ReportsDiagnostic() - { - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[{|#0:NativeMarshalling(typeof(Native<,>))|}] -struct S -{ - public string s; -} - -[CustomTypeMarshaller(typeof(S<>), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct {|#1:Native|} - where T : new() -{ - public Native(S s) - { - } - - public S ToManaged() => new S(); - - public T ToNativeValue() => throw null; - public void FromNativeValue(T value) => throw null; -}"; - await VerifyCS.VerifyCodeFixAsync(source, - source, - VerifyCS.Diagnostic(NativeTypeMustHaveCustomTypeMarshallerAttributeRule).WithLocation(0).WithArguments("S"), - VerifyCS.Diagnostic(NativeGenericTypeMustBeClosedOrMatchArityRule).WithLocation(1).WithArguments("Native", "S<>")); - } - - [Fact] - public async Task UninstantiatedGenericNativeTypeOnGenericWithArityMatch_DoesNotReportDiagnostic() - { - string source = @" -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native<>))] -struct S -{ - public T t; -} - -[CustomTypeMarshaller(typeof(S<>), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -struct Native - where T : new() -{ - public Native(S s) - { - } - - public S ToManaged() => new S(); - - public T ToNativeValue() => throw null; - public void FromNativeValue(T value) => throw null; -}"; - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task NativeTypeWithStackallocConstructorWithoutBufferSize_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer)] -struct Native -{ - public Native(S s) {} - public {|#0:Native|}(S s, Span buffer) {} -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - VerifyCS.Diagnostic(CallerAllocConstructorMustHaveBufferSizeRule).WithLocation(0).WithArguments("Native"), - source); - } - - [Fact] - public async Task CustomTypeMarshallerForTypeWithPlaceholder_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder), Direction = CustomTypeMarshallerDirection.In)] -struct Native -{ - public Native(T a) {} -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task CustomTypeMarshallerForArrayTypeWithPlaceholder_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), Direction = CustomTypeMarshallerDirection.In)] -struct Native -{ - public Native(T[] a) {} -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task CustomTypeMarshallerForPointerTypeWithPlaceholder_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*), Direction = CustomTypeMarshallerDirection.In)] -unsafe struct Native where T : unmanaged -{ - public Native(T* a) {} -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task CustomTypeMarshallerForArrayOfPointerTypeWithPlaceholder_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), Direction = CustomTypeMarshallerDirection.In)] -unsafe struct Native where T : unmanaged -{ - public Native(T*[] a) {} -}"; - - await VerifyCS.VerifyCodeFixAsync(source, source); - } - - [Fact] - public async Task CustomTypeMarshallerWithFreeNativeMethod_NoUnmanagedResourcesFeatures_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In)] -unsafe struct {|#0:Native|} -{ - public Native(S s){} - - public void FreeNative() { } -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.Value, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources)] -unsafe struct Native -{ - public Native(S s){} - - public void FreeNative() { } -}"; - await VerifyCS.VerifyCodeFixAsync(source, - fixedSource, - VerifyCS.Diagnostic(FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule) - .WithArguments("Native") - .WithLocation(0)); - } - [Fact] - public async Task CustomTypeMarshallerWithCallerAllocatedBufferConstructor_NoFeature_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, BufferSize = 0x100)] -unsafe struct {|#0:Native|} -{ - public Native(S s){} - - public Native(S s, Span buffer) { } -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.Value, Direction = CustomTypeMarshallerDirection.In, BufferSize = 256, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer)] -unsafe struct Native -{ - public Native(S s){} - - public Native(S s, Span buffer) { } -}"; - await VerifyCS.VerifyCodeFixAsync(source, - fixedSource, - VerifyCS.Diagnostic(CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureRule) - .WithArguments("Native") - .WithLocation(0)); - } - - [Fact] - public async Task Add_Feature_Declaration_Preserves_Attribute_Argument_Location() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.None, Direction = CustomTypeMarshallerDirection.In)] -unsafe struct {|#0:Native|} -{ - public Native(S s){} - - public void FreeNative() { } -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.Value, Features = CustomTypeMarshallerFeatures.UnmanagedResources, Direction = CustomTypeMarshallerDirection.In)] -unsafe struct Native -{ - public Native(S s){} - - public void FreeNative() { } -}"; - await VerifyCS.VerifyCodeFixAsync(source, - fixedSource, - VerifyCS.Diagnostic(FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule) - .WithArguments("Native") - .WithLocation(0)); - } - - [Fact] - public async Task CustomTypeMarshallerWithTwoStageMarshallingMethod_NoFeature_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S))] -unsafe struct {|#0:Native|} -{ - public Native(S s){} - - public int ToNativeValue() => throw null; - - public S ToManaged() => throw null; -} - -[CustomTypeMarshaller(typeof(S))] -unsafe struct {|#1:Native2|} -{ - public Native2(S s){} - - public void FromNativeValue(int value) { } - - public S ToManaged() => throw null; -}"; - string fixedSource = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -struct S { } - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.Value, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - public Native(S s){} - - public int ToNativeValue() => throw null; - - public S ToManaged() => throw null; - - public void FromNativeValue(int value) - { - throw new NotImplementedException(); - } -} - -[CustomTypeMarshaller(typeof(S), CustomTypeMarshallerKind.Value, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native2 -{ - public Native2(S s){} - - public void FromNativeValue(int value) { } - - public S ToManaged() => throw null; - - public int ToNativeValue() - { - throw new NotImplementedException(); - } -}"; - await VerifyCS.VerifyCodeFixAsync(source, - new[] - { - VerifyCS.Diagnostic(ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule) - .WithArguments("Native") - .WithLocation(0), - VerifyCS.Diagnostic(FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule) - .WithArguments("Native2") - .WithLocation(1) - }, - fixedSource, - // One code-fix run is expected for each of the two diagnostics. - // Each fix of the "specifiy the feature" diagnostic will result in code that reports another diagnostic - // for the missing other member. - // The second two code-fix runs are the fixes for those diagnostics. - numIncrementalIterations: 4, - // The first run adds the feature flag and the second adds the missing members for the feature. - numFixAllIterations: 2); - } - - [Fact] - public async Task Mismatched_NativeValue_Type_ReportsDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - public Native(S s) { } - - public S ToManaged() => new S(); - - public int {|#0:ToNativeValue|}() => throw null; - public void FromNativeValue(long value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - source, - VerifyCS.Diagnostic(TwoStageMarshallingNativeTypesMustMatchRule) - .WithLocation(0)); - } - - [Fact] - public async Task Same_NativeValue_Type_DifferentName_DoesNotReportDiagnostic() - { - string source = @" -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -using Value2 = N.Value; - -namespace N -{ - struct Value - { - private int i; - } -} - -[NativeMarshalling(typeof(Native))] -class S -{ - public byte c; -} - -[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] -unsafe struct Native -{ - public Native(S s) { } - - public S ToManaged() => new S(); - - public N.Value ToNativeValue() => throw null; - public void FromNativeValue(Value2 value) => throw null; -}"; - - await VerifyCS.VerifyCodeFixAsync(source, - source); - } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs index 62a093779c39c..0341ecc02346b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using static SharedTypes.BoolStructMarshaller; namespace NativeExports { @@ -236,12 +237,12 @@ public static void Append(int** values, int numOriginalValues, int newValue) [UnmanagedCallersOnly(EntryPoint = "and_all_members")] [DNNE.C99DeclCode("struct bool_struct;")] - public static byte AndAllMembers([DNNE.C99Type("struct bool_struct*")] BoolStructNative_V1* pArray, int length) + public static byte AndAllMembers([DNNE.C99Type("struct bool_struct*")] BoolStructNative* pArray, int length) { bool result = true; for (int i = 0; i < length; i++) { - BoolStruct_V1 managed = pArray[i].ToManaged(); + BoolStruct managed = BoolStructMarshaller.ConvertToManaged(pArray[i]); result &= managed.b1 && managed.b2 && managed.b3; } return (byte)(result ? 1 : 0); diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs index cc213bcbbd978..1d4ce7828ea5b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs @@ -5,6 +5,8 @@ using System.Buffers.Binary; using System.Runtime.InteropServices; using SharedTypes; +using static SharedTypes.BoolStructMarshaller; +using static SharedTypes.StringContainerMarshaller; namespace NativeExports { @@ -13,16 +15,16 @@ public static unsafe class CustomMarshalling [UnmanagedCallersOnly(EntryPoint = "stringcontainer_deepduplicate")] [DNNE.C99DeclCode("struct string_container { char* str1; char* str2; };")] public static void DeepDuplicateStrings( - [DNNE.C99Type("struct string_container")] StringContainerNative_V1 strings, - [DNNE.C99Type("struct string_container*")] StringContainerNative_V1* pStringsOut) + [DNNE.C99Type("struct string_container")] StringContainerNative strings, + [DNNE.C99Type("struct string_container*")] StringContainerNative* pStringsOut) { // Round trip through the managed view to allocate a new native instance. - *pStringsOut = new StringContainerNative_V1(strings.ToManaged()); + *pStringsOut = StringContainerMarshaller.In.ConvertToUnmanaged(StringContainerMarshaller.Out.ConvertToManaged(strings)); } [UnmanagedCallersOnly(EntryPoint = "stringcontainer_reverse_strings")] public static void ReverseStrings( - [DNNE.C99Type("struct string_container*")] StringContainerNative_V1* strings) + [DNNE.C99Type("struct string_container*")] StringContainerNative* strings) { strings->str1 = (IntPtr)Strings.Reverse((byte*)strings->str1); strings->str2 = (IntPtr)Strings.Reverse((byte*)strings->str2); @@ -50,10 +52,10 @@ public static int ReturnZero(int* ret) [UnmanagedCallersOnly(EntryPoint = "negate_bools")] [DNNE.C99DeclCode("struct bool_struct { int8_t b1; int8_t b2; int8_t b3; };")] public static void NegateBools( - [DNNE.C99Type("struct bool_struct")] BoolStructNative_V1 boolStruct, - [DNNE.C99Type("struct bool_struct*")] BoolStructNative_V1* pBoolStructOut) + [DNNE.C99Type("struct bool_struct")] BoolStructNative boolStruct, + [DNNE.C99Type("struct bool_struct*")] BoolStructNative* pBoolStructOut) { - *pBoolStructOut = new BoolStructNative_V1 + *pBoolStructOut = new BoolStructNative { b1 = (byte)(boolStruct.b1 != 0 ? 0 : 1), b2 = (byte)(boolStruct.b2 != 0 ? 0 : 1), @@ -63,7 +65,7 @@ public static void NegateBools( [UnmanagedCallersOnly(EntryPoint = "and_bools_ref")] public static byte AndBoolsRef( - [DNNE.C99Type("struct bool_struct*")] BoolStructNative_V1* boolStruct) + [DNNE.C99Type("struct bool_struct*")] BoolStructNative* boolStruct) { return (byte)(boolStruct->b1 != 0 && boolStruct->b2 != 0 && boolStruct->b3 != 0 ? 1 : 0); } diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs deleted file mode 100644 index 78b8d1bda0203..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs +++ /dev/null @@ -1,283 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -using System.Text; - -namespace SharedTypes -{ - [NativeMarshalling(typeof(StringContainerNative_V1))] - public struct StringContainer_V1 - { - public string str1; - public string str2; - } - - [CustomTypeMarshaller(typeof(StringContainer_V1), Features = CustomTypeMarshallerFeatures.UnmanagedResources)] - public struct StringContainerNative_V1 - { - public IntPtr str1; - public IntPtr str2; - - public StringContainerNative_V1(StringContainer_V1 managed) - { - str1 = Marshal.StringToCoTaskMemUTF8(managed.str1); - str2 = Marshal.StringToCoTaskMemUTF8(managed.str2); - } - - public StringContainer_V1 ToManaged() - { - return new StringContainer_V1 - { - str1 = Marshal.PtrToStringUTF8(str1), - str2 = Marshal.PtrToStringUTF8(str2) - }; - } - - public void FreeNative() - { - Marshal.FreeCoTaskMem(str1); - Marshal.FreeCoTaskMem(str2); - } - } - - [CustomTypeMarshaller(typeof(double), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public struct DoubleToLongMarshaller_V1 - { - public long l; - - public DoubleToLongMarshaller_V1(double d) - { - l = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref d, 1))[0]; - } - - public double ToManaged() => MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref l, 1))[0]; - - public long ToNativeValue() => l; - - public void FromNativeValue(long value) => l = value; - } - - [NativeMarshalling(typeof(BoolStructNative_V1))] - public struct BoolStruct_V1 - { - public bool b1; - public bool b2; - public bool b3; - } - - [CustomTypeMarshaller(typeof(BoolStruct_V1))] - public struct BoolStructNative_V1 - { - public byte b1; - public byte b2; - public byte b3; - public BoolStructNative_V1(BoolStruct_V1 bs) - { - b1 = (byte)(bs.b1 ? 1 : 0); - b2 = (byte)(bs.b2 ? 1 : 0); - b3 = (byte)(bs.b3 ? 1 : 0); - } - - public BoolStruct_V1 ToManaged() - { - return new BoolStruct_V1 - { - b1 = b1 != 0, - b2 = b2 != 0, - b3 = b3 != 0 - }; - } - } - - [NativeMarshalling(typeof(IntWrapperMarshaler_V1))] - public class IntWrapper_V1 - { - public int i; - - public ref int GetPinnableReference() => ref i; - } - - [CustomTypeMarshaller(typeof(IntWrapper_V1), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public unsafe struct IntWrapperMarshaler_V1 - { - public IntWrapperMarshaler_V1(IntWrapper_V1 managed) - { - Value = (int*)Marshal.AllocCoTaskMem(sizeof(int)); - *Value = managed.i; - } - - private int* Value { get; set; } - - public int* ToNativeValue() => Value; - public void FromNativeValue(int* value) => Value = value; - - public IntWrapper_V1 ToManaged() => new IntWrapper_V1 { i = *Value }; - - public void FreeNative() - { - Marshal.FreeCoTaskMem((IntPtr)Value); - } - } - - [NativeMarshalling(typeof(IntStructWrapperNative))] - public struct IntStructWrapper - { - public int Value; - } - - [CustomTypeMarshaller(typeof(IntStructWrapper))] - public struct IntStructWrapperNative - { - public int value; - public IntStructWrapperNative(IntStructWrapper managed) - { - value = managed.Value; - } - - public IntStructWrapper ToManaged() => new IntStructWrapper { Value = value }; - } - - [CustomTypeMarshaller(typeof(List<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)] - public unsafe ref struct ListMarshaller_V1 - { - private List managedList; - private readonly int sizeOfNativeElement; - private IntPtr allocatedMemory; - - public ListMarshaller_V1(int sizeOfNativeElement) - : this() - { - this.sizeOfNativeElement = sizeOfNativeElement; - } - - public ListMarshaller_V1(List managed, int sizeOfNativeElement) - :this(managed, Span.Empty, sizeOfNativeElement) - { - } - - public ListMarshaller_V1(List managed, Span stackSpace, int sizeOfNativeElement) - { - allocatedMemory = default; - this.sizeOfNativeElement = sizeOfNativeElement; - if (managed is null) - { - managedList = null; - NativeValueStorage = default; - return; - } - managedList = managed; - // Always allocate at least one byte when the list is zero-length. - int spaceToAllocate = Math.Max(managed.Count * sizeOfNativeElement, 1); - if (spaceToAllocate <= stackSpace.Length) - { - NativeValueStorage = stackSpace[0..spaceToAllocate]; - } - else - { - allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate); - NativeValueStorage = new Span((void*)allocatedMemory, spaceToAllocate); - } - } - - public ReadOnlySpan GetManagedValuesSource() => CollectionsMarshal.AsSpan(managedList); - - public Span GetManagedValuesDestination(int length) - { - if (allocatedMemory == IntPtr.Zero) - { - managedList = null; - return default; - } - managedList = new List(length); - for (int i = 0; i < length; i++) - { - managedList.Add(default); - } - return CollectionsMarshal.AsSpan(managedList); - } - - private Span NativeValueStorage { get; set; } - - public Span GetNativeValuesDestination() => NativeValueStorage; - - public ReadOnlySpan GetNativeValuesSource(int length) - { - return allocatedMemory == IntPtr.Zero ? default : NativeValueStorage = new Span((void*)allocatedMemory, length * sizeOfNativeElement); - } - - public ref byte GetPinnableReference() => ref NativeValueStorage.GetPinnableReference(); - - public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - - public void FromNativeValue(byte* value) - { - allocatedMemory = (IntPtr)value; - } - - public List ToManaged() => managedList; - - public void FreeNative() - { - Marshal.FreeCoTaskMem(allocatedMemory); - } - } - - [NativeMarshalling(typeof(WrappedListMarshaller_V1<>))] - public struct WrappedList_V1 - { - public WrappedList_V1(List list) - { - Wrapped = list; - } - - public List Wrapped { get; } - - public ref T GetPinnableReference() => ref CollectionsMarshal.AsSpan(Wrapped).GetPinnableReference(); - } - - [CustomTypeMarshaller(typeof(WrappedList_V1<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)] - public unsafe ref struct WrappedListMarshaller_V1 - { - private ListMarshaller_V1 _marshaller; - - public WrappedListMarshaller_V1(int sizeOfNativeElement) - : this() - { - this._marshaller = new ListMarshaller_V1(sizeOfNativeElement); - } - - public WrappedListMarshaller_V1(WrappedList_V1 managed, int sizeOfNativeElement) - : this(managed, Span.Empty, sizeOfNativeElement) - { - } - - public WrappedListMarshaller_V1(WrappedList_V1 managed, Span stackSpace, int sizeOfNativeElement) - { - this._marshaller = new ListMarshaller_V1(managed.Wrapped, stackSpace, sizeOfNativeElement); - } - - public ReadOnlySpan GetManagedValuesSource() => _marshaller.GetManagedValuesSource(); - - public Span GetManagedValuesDestination(int length) => _marshaller.GetManagedValuesDestination(length); - - public Span GetNativeValuesDestination() => _marshaller.GetNativeValuesDestination(); - - public ReadOnlySpan GetNativeValuesSource(int length) => _marshaller.GetNativeValuesSource(length); - - public ref byte GetPinnableReference() => ref _marshaller.GetPinnableReference(); - - public byte* ToNativeValue() => _marshaller.ToNativeValue(); - - public void FromNativeValue(byte* value) => _marshaller.FromNativeValue(value); - - public WrappedList_V1 ToManaged() => new(_marshaller.ToManaged()); - - public void FreeNative() => _marshaller.FreeNative(); - } -} diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs index 72d033260fa9f..c150564ad621d 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs @@ -137,6 +137,30 @@ public static BoolStruct ConvertToManaged(BoolStructNative unmanaged) } } + [NativeMarshalling(typeof(IntStructWrapperMarshaller))] + public struct IntStructWrapper + { + public int Value; + } + + [CustomMarshaller(typeof(IntStructWrapper), MarshalMode.Default, typeof(IntStructWrapperMarshaller))] + public static class IntStructWrapperMarshaller + { + public static IntStructWrapperNative ConvertToUnmanaged(IntStructWrapper managed) + { + return new() { value = managed.Value }; + } + public static IntStructWrapper ConvertToManaged(IntStructWrapperNative unmanaged) + { + return new() { Value = unmanaged.value }; + } + } + + public struct IntStructWrapperNative + { + public int value; + } + [NativeMarshalling(typeof(IntWrapperMarshaller))] public class IntWrapper { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index b88ace77e31e0..5f078cb9590e2 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -4501,6 +4501,7 @@ public void CopyTo(System.Memory destination) { } public override string ToString() { throw null; } public bool TryCopyTo(System.Memory destination) { throw null; } } + [System.Runtime.InteropServices.Marshalling.NativeMarshallingAttribute(typeof(System.Runtime.InteropServices.Marshalling.ReadOnlySpanMarshaller<,>))] public readonly ref partial struct ReadOnlySpan { private readonly object _dummy; @@ -4926,6 +4927,7 @@ public SerializableAttribute() { } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, out float result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out float result) { throw null; } } + [System.Runtime.InteropServices.Marshalling.NativeMarshallingAttribute(typeof(System.Runtime.InteropServices.Marshalling.SpanMarshaller<,>))] public readonly ref partial struct Span { private readonly object _dummy; @@ -13242,6 +13244,105 @@ public enum UnmanagedType LPUTF8Str = 48, } } +namespace System.Runtime.InteropServices.Marshalling +{ + [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class)] + public sealed partial class ContiguousCollectionMarshallerAttribute : System.Attribute + { + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class, AllowMultiple = true)] + public sealed partial class CustomMarshallerAttribute : System.Attribute + { + public CustomMarshallerAttribute(System.Type managedType, System.Runtime.InteropServices.Marshalling.MarshalMode marshalMode, System.Type marshallerType) { } + public System.Type ManagedType { get { throw null; } } + public System.Runtime.InteropServices.Marshalling.MarshalMode MarshalMode { get { throw null; } } + public System.Type MarshallerType { get { throw null; } } + public struct GenericPlaceholder + { + } + } + public enum MarshalMode + { + Default = 0, + ManagedToUnmanagedIn = 1, + ManagedToUnmanagedRef = 2, + ManagedToUnmanagedOut = 3, + UnmanagedToManagedIn = 4, + UnmanagedToManagedRef = 5, + UnmanagedToManagedOut = 6, + ElementIn = 7, + ElementRef = 8, + ElementOut = 9 + } + [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class | System.AttributeTargets.Enum | System.AttributeTargets.Delegate)] + public sealed partial class NativeMarshallingAttribute : System.Attribute + { + public NativeMarshallingAttribute(System.Type nativeType) { } + public System.Type NativeType { get { throw null; } } + } + [System.CLSCompliant(false)] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.ReadOnlySpan<>), + System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, + typeof(System.Runtime.InteropServices.Marshalling.ReadOnlySpanMarshaller<,>.ManagedToUnmanagedIn))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.ReadOnlySpan<>), + System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedOut, + typeof(System.Runtime.InteropServices.Marshalling.ReadOnlySpanMarshaller<,>.UnmanagedToManagedOut))] + [System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshaller] + public static unsafe class ReadOnlySpanMarshaller where TUnmanagedElement : unmanaged + { + public ref struct ManagedToUnmanagedIn + { + private object _dummy; + private int _dummyPrimitive; + public static int BufferSize { get { throw null; } } + public void FromManaged(System.ReadOnlySpan managed, System.Span buffer) { } + public System.ReadOnlySpan GetManagedValuesSource() { throw null; } + public System.Span GetUnmanagedValuesDestination() { throw null; } + public ref TUnmanagedElement GetPinnableReference() { throw null; } + public TUnmanagedElement* ToUnmanaged() { throw null; } + public void Free() { } + public static ref T GetPinnableReference(System.ReadOnlySpan managed) { throw null; } + } + public static class UnmanagedToManagedOut + { + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(System.ReadOnlySpan managed, out int numElements) { throw null; } + public static System.ReadOnlySpan GetManagedValuesSource(System.ReadOnlySpan managed) { throw null; } + public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } + } + } + [System.CLSCompliant(false)] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.Span<>), + System.Runtime.InteropServices.Marshalling.MarshalMode.Default, + typeof(System.Runtime.InteropServices.Marshalling.SpanMarshaller<,>))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.Span<>), + System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, + typeof(System.Runtime.InteropServices.Marshalling.SpanMarshaller<,>.ManagedToUnmanagedIn))] + [System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshaller] + public static unsafe class SpanMarshaller where TUnmanagedElement : unmanaged + { + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(System.Span managed, out int numElements) { throw null; } + public static System.ReadOnlySpan GetManagedValuesSource(System.Span managed) { throw null; } + public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } + public static System.Span AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) { throw null; } + public static System.Span GetManagedValuesDestination(System.Span managed) { throw null; } + public static System.ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) { throw null; } + public static void Free(TUnmanagedElement* unmanaged) { throw null; } + public ref struct ManagedToUnmanagedIn + { + private object _dummy; + private int _dummyPrimitive; + public static int BufferSize { get { throw null; } } + public void FromManaged(System.Span managed, System.Span buffer) { } + public System.ReadOnlySpan GetManagedValuesSource() { throw null; } + public System.Span GetUnmanagedValuesDestination() { throw null; } + public ref TUnmanagedElement GetPinnableReference() { throw null; } + public TUnmanagedElement* ToUnmanaged() { throw null; } + public void Free() { } + public static ref T GetPinnableReference(System.Span managed) { throw null; } + } + } +} namespace System.Runtime.Remoting { public partial class ObjectHandle : System.MarshalByRefObject