Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Koritzinsky <jekoritz@microsoft.com>2022-03-23 19:06:32 +0300
committerGitHub <noreply@github.com>2022-03-23 19:06:32 +0300
commita02b49a0486e92ace50803b977adf8c533ab118f (patch)
tree738b0eff3dbbb212c4b26b6b0a82bf7c333bb981 /src/libraries
parent3c126e6e42b0f9c879cae93d94a1deb7e7680f66 (diff)
Add the CustomTypeMarshallerAttribute type to make it easier to identify marshaller types (#65591)
Diffstat (limited to 'src/libraries')
-rw-r--r--src/libraries/Common/src/Interop/Interop.Ldap.cs15
-rw-r--r--src/libraries/Common/src/Interop/Windows/Advapi32/Interop.LsaLookupNames2.cs1
-rw-r--r--src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs2
-rw-r--r--src/libraries/Common/src/Interop/Windows/WebSocket/Interop.Structs.cs1
-rw-r--r--src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs5
-rw-r--r--src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs1
-rw-r--r--src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs1
-rw-r--r--src/libraries/Common/src/System/Runtime/InteropServices/ArrayMarshaller.cs97
-rw-r--r--src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerDirection.cs37
-rw-r--r--src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerFeatures.cs34
-rw-r--r--src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerKind.cs28
-rw-r--r--src/libraries/Common/src/System/Runtime/InteropServices/GeneratedMarshallingAttribute.cs66
-rw-r--r--src/libraries/Common/src/System/Runtime/InteropServices/HandleRefMarshaller.cs3
-rw-r--r--src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs18
-rw-r--r--src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs1
-rw-r--r--src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/BitmapData.cs3
-rw-r--r--src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/ColorMatrix.cs3
-rw-r--r--src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderEmf.cs3
-rw-r--r--src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderWmf.cs9
-rw-r--r--src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/WmfPlaceableFileHeader.cs3
-rw-r--r--src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AnalyzerDiagnostics.cs30
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs909
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs404
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ManualTypeMarshallingAnalyzer.cs535
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxGeneratorExtensions.cs67
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.Designer.cs636
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.resx258
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/LinearCollectionElementMarshallingCodeContext.cs (renamed from src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ContiguousCollectionElementMarshallingCodeContext.cs)12
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs246
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs82
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs454
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs18
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs205
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj7
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.Designer.cs14
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.resx31
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs6
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs17
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj3
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs264
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs12
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SetLastErrorTests.cs1
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs5
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs6
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs256
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs4
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs1769
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ManualTypeMarshallingAnalyzerTests.cs1240
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs28
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs126
55 files changed, 5045 insertions, 2941 deletions
diff --git a/src/libraries/Common/src/Interop/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Interop.Ldap.cs
index a48640d1e46..423973b759d 100644
--- a/src/libraries/Common/src/Interop/Interop.Ldap.cs
+++ b/src/libraries/Common/src/Interop/Interop.Ldap.cs
@@ -44,6 +44,9 @@ namespace System.DirectoryServices.Protocols
public string packageList;
public int packageListLength;
+#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(SEC_WINNT_AUTH_IDENTITY_EX), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
+#endif
[StructLayout(LayoutKind.Sequential)]
internal struct Native
{
@@ -173,6 +176,7 @@ namespace System.DirectoryServices.Protocols
public IntPtr bv_val = IntPtr.Zero;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(BerVal), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
internal unsafe struct PinningMarshaller
{
private readonly BerVal _managed;
@@ -183,7 +187,7 @@ namespace System.DirectoryServices.Protocols
public ref int GetPinnableReference() => ref (_managed is null ? ref Unsafe.NullRef<int>() : ref _managed.bv_len);
- public void* Value => Unsafe.AsPointer(ref GetPinnableReference());
+ public void* ToNativeValue() => Unsafe.AsPointer(ref GetPinnableReference());
}
#endif
}
@@ -211,6 +215,7 @@ namespace System.DirectoryServices.Protocols
#if NET7_0_OR_GREATER
public static readonly unsafe int Size = sizeof(Marshaller.Native);
+ [CustomTypeMarshaller(typeof(LdapReferralCallback), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)]
public unsafe struct Marshaller
{
public unsafe struct Native
@@ -234,11 +239,9 @@ namespace System.DirectoryServices.Protocols
_native.dereference = managed.dereference is not null ? Marshal.GetFunctionPointerForDelegate(managed.dereference) : IntPtr.Zero;
}
- public Native Value
- {
- get => _native;
- set => _native = value;
- }
+ public Native ToNativeValue() => _native;
+
+ public void FromNativeValue(Native value) => _native = value;
public LdapReferralCallback ToManaged()
{
diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.LsaLookupNames2.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.LsaLookupNames2.cs
index 50be738d918..94dd8bc4360 100644
--- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.LsaLookupNames2.cs
+++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.LsaLookupNames2.cs
@@ -26,6 +26,7 @@ internal static partial class Interop
internal ushort MaximumLength;
internal string Buffer;
+ [CustomTypeMarshaller(typeof(MARSHALLED_UNICODE_STRING), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
public struct Native
{
internal ushort Length;
diff --git a/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs b/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs
index 4bdd0880f52..ce07eea1841 100644
--- a/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs
+++ b/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs
@@ -37,6 +37,7 @@ internal static partial class Interop
internal uint nStartPage;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
internal unsafe struct Native
{
private uint dwSize;
@@ -139,6 +140,7 @@ internal static partial class Interop
internal IntPtr hSelectedCertStore;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(CRYPTUI_SELECTCERTIFICATE_STRUCTW), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
internal unsafe struct Native
{
private uint dwSize;
diff --git a/src/libraries/Common/src/Interop/Windows/WebSocket/Interop.Structs.cs b/src/libraries/Common/src/Interop/Windows/WebSocket/Interop.Structs.cs
index 26c0dd93fd3..a4219658a3a 100644
--- a/src/libraries/Common/src/Interop/Windows/WebSocket/Interop.Structs.cs
+++ b/src/libraries/Common/src/Interop/Windows/WebSocket/Interop.Structs.cs
@@ -49,6 +49,7 @@ internal static partial class Interop
internal string Value;
internal uint ValueLength;
+ [CustomTypeMarshaller(typeof(HttpHeader), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
internal struct Native
{
private IntPtr Name;
diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs
index 7074ad6cdc0..b7e40e77b99 100644
--- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs
+++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs
@@ -53,6 +53,7 @@ internal static partial class Interop
uint modifiers);
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(StringBuilder), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)]
private unsafe struct SimpleStringBufferMarshaller
{
public SimpleStringBufferMarshaller(StringBuilder builder)
@@ -64,7 +65,9 @@ internal static partial class Interop
builder.CopyTo(0, buffer, length - 1);
}
- public void* Value { get; }
+ private void* Value { get; }
+
+ public void* ToNativeValue() => Value;
public void FreeNative()
{
diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs
index 47f105b6c3f..0a0c24292ca 100644
--- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs
+++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs
@@ -259,6 +259,7 @@ internal static partial class Interop
[MarshalAs(UnmanagedType.Bool)]
public bool AutoLoginIfChallenged;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(WINHTTP_AUTOPROXY_OPTIONS), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
public struct Native
{
private uint Flags;
diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs
index 28478031eb3..b19cd8dba06 100644
--- a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs
+++ b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs
@@ -74,6 +74,7 @@ internal static partial class Interop
internal byte[] MulticastAddress; // IP address of group.
internal int InterfaceIndex; // Local interface index.
+ [CustomTypeMarshaller(typeof(IPv6MulticastRequest))]
public unsafe struct Native
{
private const int MulticastAddressLength = 16;
diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/ArrayMarshaller.cs b/src/libraries/Common/src/System/Runtime/InteropServices/ArrayMarshaller.cs
index d28dba25b39..f5c5277a7d3 100644
--- a/src/libraries/Common/src/System/Runtime/InteropServices/ArrayMarshaller.cs
+++ b/src/libraries/Common/src/System/Runtime/InteropServices/ArrayMarshaller.cs
@@ -12,6 +12,10 @@ using System.Runtime.CompilerServices;
namespace System.Runtime.InteropServices.GeneratedMarshalling
{
+ // 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(CustomTypeMarshallerAttribute.GenericPlaceholder[]), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
@@ -58,44 +62,24 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
}
}
- /// <summary>
- /// 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.
- /// </summary>
- public const int BufferSize = 0x200;
- public const bool RequiresStackBuffer = true;
+ public ReadOnlySpan<T> GetManagedValuesSource() => _managedArray;
+ public Span<T> GetManagedValuesDestination(int length) => _allocatedMemory == IntPtr.Zero ? null : _managedArray = new T[length];
+ public Span<byte> GetNativeValuesDestination() => NativeValueStorage;
- public Span<T> ManagedValues => _managedArray;
-
- public Span<byte> NativeValueStorage { get; private set; }
+ public ReadOnlySpan<byte> GetNativeValuesSource(int length)
+ {
+ return _allocatedMemory == IntPtr.Zero ? default : NativeValueStorage = new Span<byte>((void*)_allocatedMemory, length * _sizeOfNativeElement);
+ }
+ private Span<byte> NativeValueStorage { get; set; }
public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(NativeValueStorage);
- public void SetUnmarshalledCollectionLength(int length)
- {
- _managedArray = new T[length];
- }
- public byte* Value
+ public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference());
+
+ public void FromNativeValue(byte* value)
{
- get
- {
- return (byte*)Unsafe.AsPointer(ref GetPinnableReference());
- }
- set
- {
- if (value == null)
- {
- _managedArray = null;
- NativeValueStorage = default;
- }
- else
- {
- _allocatedMemory = (IntPtr)value;
- NativeValueStorage = new Span<byte>(value, (_managedArray?.Length ?? 0) * _sizeOfNativeElement);
- }
- }
+ _allocatedMemory = (IntPtr)value;
}
public T[]? ToManaged() => _managedArray;
@@ -106,6 +90,10 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
}
}
+ // 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(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
@@ -152,45 +140,22 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
}
}
- /// <summary>
- /// 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.
- /// </summary>
- public const int BufferSize = 0x200;
- public const bool RequiresStackBuffer = true;
-
- public Span<IntPtr> ManagedValues => Unsafe.As<IntPtr[]>(_managedArray);
+ public ReadOnlySpan<IntPtr> GetManagedValuesSource() => Unsafe.As<IntPtr[]>(_managedArray);
+ public Span<IntPtr> GetManagedValuesDestination(int length) => _allocatedMemory == IntPtr.Zero ? null : Unsafe.As<IntPtr[]>(_managedArray = new T*[length]);
+ public Span<byte> GetNativeValuesDestination() => NativeValueStorage;
- public Span<byte> NativeValueStorage { get; private set; }
-
- public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(NativeValueStorage);
-
- public void SetUnmarshalledCollectionLength(int length)
+ public ReadOnlySpan<byte> GetNativeValuesSource(int length)
{
- _managedArray = new T*[length];
+ return _allocatedMemory == IntPtr.Zero ? default : NativeValueStorage = new Span<byte>((void*)_allocatedMemory, length * _sizeOfNativeElement);
}
+ private Span<byte> NativeValueStorage { get; set; }
- public byte* Value
- {
- get
- {
- return (byte*)Unsafe.AsPointer(ref GetPinnableReference());
- }
- set
- {
- if (value == null)
- {
- _managedArray = null;
- NativeValueStorage = default;
- }
- else
- {
- _allocatedMemory = (IntPtr)value;
- NativeValueStorage = new Span<byte>(value, (_managedArray?.Length ?? 0) * _sizeOfNativeElement);
- }
+ public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(NativeValueStorage);
+ public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference());
- }
+ public void FromNativeValue(byte* value)
+ {
+ _allocatedMemory = (IntPtr)value;
}
public T*[]? ToManaged() => _managedArray;
diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerDirection.cs b/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerDirection.cs
new file mode 100644
index 00000000000..0ee347d72b9
--- /dev/null
+++ b/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerDirection.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.ComponentModel;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// A direction of marshalling data into or out of the managed environment
+ /// </summary>
+ [Flags]
+#if LIBRARYIMPORT_GENERATOR_TEST
+ public
+#else
+ internal
+#endif
+ enum CustomTypeMarshallerDirection
+ {
+ /// <summary>
+ /// No marshalling direction
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ None = 0,
+ /// <summary>
+ /// Marshalling from a managed environment to an unmanaged environment
+ /// </summary>
+ In = 0x1,
+ /// <summary>
+ /// Marshalling from an unmanaged environment to a managed environment
+ /// </summary>
+ Out = 0x2,
+ /// <summary>
+ /// Marshalling to and from managed and unmanaged environments
+ /// </summary>
+ Ref = In | Out,
+ }
+}
diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerFeatures.cs b/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerFeatures.cs
new file mode 100644
index 00000000000..fe58f386f72
--- /dev/null
+++ b/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerFeatures.cs
@@ -0,0 +1,34 @@
+// 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
+{
+ /// <summary>
+ /// Optional features supported by custom type marshallers.
+ /// </summary>
+ [Flags]
+#if LIBRARYIMPORT_GENERATOR_TEST
+ public
+#else
+ internal
+#endif
+ enum CustomTypeMarshallerFeatures
+ {
+ /// <summary>
+ /// No optional features supported
+ /// </summary>
+ None = 0,
+ /// <summary>
+ /// The marshaller owns unmanaged resources that must be freed
+ /// </summary>
+ UnmanagedResources = 0x1,
+ /// <summary>
+ /// The marshaller can use a caller-allocated buffer instead of allocating in some scenarios
+ /// </summary>
+ CallerAllocatedBuffer = 0x2,
+ /// <summary>
+ /// The marshaller uses the two-stage marshalling design for its <see cref="CustomTypeMarshallerKind"/> instead of the one-stage design.
+ /// </summary>
+ TwoStageMarshalling = 0x4
+ }
+}
diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerKind.cs b/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerKind.cs
new file mode 100644
index 00000000000..06c73cdf7b6
--- /dev/null
+++ b/src/libraries/Common/src/System/Runtime/InteropServices/CustomTypeMarshallerKind.cs
@@ -0,0 +1,28 @@
+// 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
+{
+ /// <summary>
+ /// The shape of a custom type marshaller for usage in source-generated interop scenarios.
+ /// </summary>
+ /// <remarks>
+ /// <seealso cref="LibraryImportAttribute"/>
+ /// </remarks>
+#if LIBRARYIMPORT_GENERATOR_TEST
+ public
+#else
+ internal
+#endif
+ enum CustomTypeMarshallerKind
+ {
+ /// <summary>
+ /// This custom type marshaller represents a single value.
+ /// </summary>
+ Value,
+ /// <summary>
+ /// This custom type marshaller represents a container of values that are placed sequentially in memory.
+ /// </summary>
+ LinearCollection
+ }
+}
diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/GeneratedMarshallingAttribute.cs b/src/libraries/Common/src/System/Runtime/InteropServices/GeneratedMarshallingAttribute.cs
index 1ea2799beaa..4a0aaf99e23 100644
--- a/src/libraries/Common/src/System/Runtime/InteropServices/GeneratedMarshallingAttribute.cs
+++ b/src/libraries/Common/src/System/Runtime/InteropServices/GeneratedMarshallingAttribute.cs
@@ -8,17 +8,7 @@
//
namespace System.Runtime.InteropServices
{
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
-#if LIBRARYIMPORT_GENERATOR_TEST
- public
-#else
- internal
-#endif
- sealed class GeneratedMarshallingAttribute : Attribute
- {
- }
-
- [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
+ [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Delegate)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
@@ -34,7 +24,7 @@ namespace System.Runtime.InteropServices
public Type NativeType { get; }
}
- [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.Field, AllowMultiple = true)]
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
@@ -59,20 +49,64 @@ namespace System.Runtime.InteropServices
public int ConstantElementCount { get; set; }
- public int ElementIndirectionLevel { get; set; }
+ public int ElementIndirectionDepth { get; set; }
public const string ReturnsCountValue = "return-value";
}
- [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
+ /// <summary>
+ /// Attribute used to indicate that the type can be used to convert a value of the provided <see cref="ManagedType"/> to a native representation.
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// <seealso cref="LibraryImportAttribute"/>
+ /// </remarks>
+ [AttributeUsage(AttributeTargets.Struct)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
- sealed class GenericContiguousCollectionMarshallerAttribute : Attribute
+ sealed class CustomTypeMarshallerAttribute : Attribute
{
- public GenericContiguousCollectionMarshallerAttribute()
+ public CustomTypeMarshallerAttribute(Type managedType, CustomTypeMarshallerKind marshallerKind = CustomTypeMarshallerKind.Value)
+ {
+ ManagedType = managedType;
+ MarshallerKind = marshallerKind;
+ }
+
+ /// <summary>
+ /// The managed type for which the attributed type is a marshaller
+ /// </summary>
+ public Type ManagedType { get; }
+
+ /// <summary>
+ /// The required shape of the attributed type
+ /// </summary>
+ public CustomTypeMarshallerKind MarshallerKind { get; }
+
+ /// <summary>
+ /// When the <see cref="CustomTypeMarshallerFeatures.CallerAllocatedBuffer"/> flag is set on <see cref="Features"/> the size of the caller-allocated buffer in number of elements.
+ /// </summary>
+ public int BufferSize { get; set; }
+
+ /// <summary>
+ /// The marshalling directions this custom type marshaller supports.
+ /// </summary>
+ /// <remarks>Default is <see cref="CustomTypeMarshallerDirection.Ref"/></remarks>
+ public CustomTypeMarshallerDirection Direction { get; set; } = CustomTypeMarshallerDirection.Ref;
+
+ /// <summary>
+ /// The optional features for the <see cref="MarshallerKind"/> that the marshaller supports.
+ /// </summary>
+ public CustomTypeMarshallerFeatures Features { get; set; }
+
+ /// <summary>
+ /// 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[])
+ /// </summary>
+ public struct GenericPlaceholder
{
}
}
diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/HandleRefMarshaller.cs b/src/libraries/Common/src/System/Runtime/InteropServices/HandleRefMarshaller.cs
index 5278e31ae0e..d5b0a308bc6 100644
--- a/src/libraries/Common/src/System/Runtime/InteropServices/HandleRefMarshaller.cs
+++ b/src/libraries/Common/src/System/Runtime/InteropServices/HandleRefMarshaller.cs
@@ -6,6 +6,7 @@
namespace System.Runtime.InteropServices.GeneratedMarshalling
{
+ [CustomTypeMarshaller(typeof(HandleRef), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)]
internal struct HandleRefMarshaller
{
private HandleRef _handle;
@@ -15,7 +16,7 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
_handle = handle;
}
- public IntPtr Value => _handle.Handle;
+ public IntPtr ToNativeValue() => _handle.Handle;
public void FreeNative() => GC.KeepAlive(_handle.Wrapper);
}
diff --git a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs
index a9b92a3bca4..a4d40ab0cc4 100644
--- a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs
+++ b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs
@@ -353,6 +353,7 @@ namespace Microsoft.Win32
public CoTaskMemUnicodeSafeHandle Password;
public int Flags;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(EvtRpcLogin), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)]
public struct Marshaller
{
public struct Native
@@ -380,18 +381,16 @@ namespace Microsoft.Win32
_value.Flags = managed.Flags;
}
- public Native Value
+ public Native ToNativeValue() => _value;
+
+ public void FromNativeValue(Native value)
{
- get => _value;
- set
+ // SafeHandle fields cannot change the underlying handle value during marshalling.
+ if (_value.Password != value.Password)
{
- // SafeHandle fields cannot change the underlying handle value during marshalling.
- if (_value.Password != value.Password)
- {
- throw new InvalidOperationException();
- }
- _value = value;
+ throw new InvalidOperationException();
}
+ _value = value;
}
public EvtRpcLogin ToManaged()
@@ -701,6 +700,7 @@ namespace Microsoft.Win32
public uint Type;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(EvtStringVariant), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
[StructLayout(LayoutKind.Explicit)]
public struct Native
{
diff --git a/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs b/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs
index 545856dad96..0e01c1e57e2 100644
--- a/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs
+++ b/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs
@@ -188,6 +188,7 @@ internal static partial class Interop
internal int fwType;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(DOCINFO), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
internal struct Native
{
internal int cbSize;
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/BitmapData.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/BitmapData.cs
index c5a728914bc..4817da34d12 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/BitmapData.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/BitmapData.cs
@@ -98,6 +98,7 @@ namespace System.Drawing.Imaging
internal ref int GetPinnableReference() => ref _width;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(BitmapData), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
internal unsafe struct PinningMarshaller
{
private readonly BitmapData _managed;
@@ -108,7 +109,7 @@ namespace System.Drawing.Imaging
public ref int GetPinnableReference() => ref (_managed is null ? ref Unsafe.NullRef<int>() : ref _managed.GetPinnableReference());
- public void* Value => Unsafe.AsPointer(ref GetPinnableReference());
+ public void* ToNativeValue() => Unsafe.AsPointer(ref GetPinnableReference());
}
#endif
}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/ColorMatrix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/ColorMatrix.cs
index 707ff687216..336d6c68a0f 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/ColorMatrix.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/ColorMatrix.cs
@@ -396,6 +396,7 @@ namespace System.Drawing.Imaging
internal ref float GetPinnableReference() => ref _matrix00;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(ColorMatrix), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
internal unsafe struct PinningMarshaller
{
private readonly ColorMatrix _managed;
@@ -406,7 +407,7 @@ namespace System.Drawing.Imaging
public ref float GetPinnableReference() => ref (_managed is null ? ref Unsafe.NullRef<float>() : ref _managed.GetPinnableReference());
- public void* Value => Unsafe.AsPointer(ref GetPinnableReference());
+ public void* ToNativeValue() => Unsafe.AsPointer(ref GetPinnableReference());
}
#endif
}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderEmf.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderEmf.cs
index dfce8751ec4..55575087df7 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderEmf.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderEmf.cs
@@ -34,6 +34,7 @@ namespace System.Drawing.Imaging
internal ref byte GetPinnableReference() => ref Unsafe.As<MetafileType, byte>(ref type);
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(MetafileHeaderEmf), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
internal unsafe struct PinningMarshaller
{
private readonly MetafileHeaderEmf _managed;
@@ -44,7 +45,7 @@ namespace System.Drawing.Imaging
public ref byte GetPinnableReference() => ref (_managed is null ? ref Unsafe.NullRef<byte>() : ref _managed.GetPinnableReference());
- public void* Value => Unsafe.AsPointer(ref GetPinnableReference());
+ public void* ToNativeValue() => Unsafe.AsPointer(ref GetPinnableReference());
}
#endif
}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderWmf.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderWmf.cs
index 6825f2d007b..3295b5ca554 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderWmf.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/MetafileHeaderWmf.cs
@@ -55,6 +55,7 @@ namespace System.Drawing.Imaging
public int LogicalDpiY;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(MetafileHeaderWmf), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
internal unsafe struct InPlaceMarshaller
{
[StructLayout(LayoutKind.Sequential, Pack = 8)]
@@ -120,11 +121,9 @@ namespace System.Drawing.Imaging
_native.LogicalDpiY = managed.LogicalDpiY;
}
- public Native Value
- {
- get => _native;
- set => _native = value;
- }
+ public Native ToNativeValue() => _native;
+
+ public void FromNativeValue(Native value) => _native = value;
public MetafileHeaderWmf ToManaged()
{
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/WmfPlaceableFileHeader.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/WmfPlaceableFileHeader.cs
index ab26edfdb1a..1f7d7cdfd70 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/WmfPlaceableFileHeader.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/WmfPlaceableFileHeader.cs
@@ -106,6 +106,7 @@ namespace System.Drawing.Imaging
internal ref int GetPinnableReference() => ref _key;
#if NET7_0_OR_GREATER
+ [CustomTypeMarshaller(typeof(WmfPlaceableFileHeader), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
internal unsafe struct PinningMarshaller
{
private readonly WmfPlaceableFileHeader _managed;
@@ -116,7 +117,7 @@ namespace System.Drawing.Imaging
public ref int GetPinnableReference() => ref (_managed is null ? ref Unsafe.NullRef<int>() : ref _managed.GetPinnableReference());
- public void* Value => Unsafe.AsPointer(ref GetPinnableReference());
+ public void* ToNativeValue() => Unsafe.AsPointer(ref GetPinnableReference());
}
#endif
}
diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs
index 7b894cb803f..f19e664fa21 100644
--- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs
+++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs
@@ -97,6 +97,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
internal string AppName;
internal QUIC_EXECUTION_PROFILE ExecutionProfile;
+ [CustomTypeMarshaller(typeof(RegistrationConfig), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
[StructLayout(LayoutKind.Sequential)]
public struct Native
{
@@ -250,6 +251,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
// TODO: define delegate for AsyncHandler and make proper use of it.
internal IntPtr AsyncHandler;
+ [CustomTypeMarshaller(typeof(CredentialConfig), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
[StructLayout(LayoutKind.Sequential)]
public struct Native
{
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AnalyzerDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AnalyzerDiagnostics.cs
index e22c7799ce0..e365435b742 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AnalyzerDiagnostics.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AnalyzerDiagnostics.cs
@@ -14,25 +14,21 @@ namespace Microsoft.Interop.Analyzers
{
public const string Prefix = "DLLIMPORTGENANALYZER";
+ // Migration from DllImport to LibraryImport
+ public const string ConvertToLibraryImport = Prefix + "001";
+
// ManualTypeMarshalling
- public const string BlittableTypeMustBeBlittable = Prefix + "001";
- public const string CannotHaveMultipleMarshallingAttributes = Prefix + "002";
- public const string NativeTypeMustBeNonNull = Prefix + "003";
- public const string NativeTypeMustBeBlittable = Prefix + "004";
+ public const string MarshallerTypeMustSpecifyManagedType = Prefix + "002";
+ public const string CustomTypeMarshallerAttributeMustBeValid = Prefix + "003";
+ public const string InvalidNativeType = Prefix + "004";
public const string GetPinnableReferenceReturnTypeBlittable = Prefix + "005";
- public const string NativeTypeMustBePointerSized = Prefix + "006";
- public const string NativeTypeMustHaveRequiredShape = Prefix + "007";
- public const string ValuePropertyMustHaveSetter = Prefix + "008";
- public const string ValuePropertyMustHaveGetter = Prefix + "009";
- public const string GetPinnableReferenceShouldSupportAllocatingMarshallingFallback = Prefix + "010";
- public const string CallerAllocMarshallingShouldSupportAllocatingMarshallingFallback = Prefix + "011";
- public const string CallerAllocConstructorMustHaveStackBufferSizeConstant = Prefix + "012";
- public const string RefValuePropertyUnsupported = Prefix + "014";
- public const string NativeGenericTypeMustBeClosedOrMatchArity = Prefix + "016";
- public const string MarshallerGetPinnableReferenceRequiresValueProperty = Prefix + "018";
-
- // Migration from DllImport to LibraryImport
- public const string ConvertToLibraryImport = Prefix + "015";
+ public const string CustomMarshallerTypeMustHaveRequiredShape = Prefix + "006";
+ public const string CustomMarshallerTypeMustSupportDirection = Prefix + "007";
+ public const string ProvidedMethodsNotSpecifiedInShape = Prefix + "008";
+ public const string MissingAllocatingMarshallingFallback = Prefix + "009";
+ public const string CallerAllocConstructorMustHaveBufferSize = Prefix + "010";
+ public const string InvalidSignaturesInMarshallerShape = Prefix + "011";
+ public const string MarshallerGetPinnableReferenceRequiresTwoStageMarshalling = Prefix + "012";
}
internal static LocalizableResourceString GetResourceString(string resourceName)
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs
new file mode 100644
index 00000000000..d9889c941c8
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs
@@ -0,0 +1,909 @@
+// 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.Immutable;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics;
+
+namespace Microsoft.Interop.Analyzers
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+ 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 =
+ new DiagnosticDescriptor(
+ Ids.MarshallerTypeMustSpecifyManagedType,
+ "MarshallerTypeMustSpecifyManagedType",
+ GetResourceString(nameof(Resources.MarshallerTypeMustSpecifyManagedTypeMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.MarshallerTypeMustSpecifyManagedTypeDescription)));
+
+ public static readonly DiagnosticDescriptor CustomTypeMarshallerAttributeMustBeValidRule =
+ new DiagnosticDescriptor(
+ Ids.CustomTypeMarshallerAttributeMustBeValid,
+ "CustomTypeMarshallerAttributeMustBeValid",
+ GetResourceString(nameof(Resources.CustomTypeMarshallerAttributeMustBeValidMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.CustomTypeMarshallerAttributeMustBeValidDescription)));
+
+ public static readonly DiagnosticDescriptor MarshallerKindMustBeValidRule =
+ new DiagnosticDescriptor(
+ Ids.CustomTypeMarshallerAttributeMustBeValid,
+ "CustomTypeMarshallerAttributeMustBeValid",
+ GetResourceString(nameof(Resources.MarshallerKindMustBeValidMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.MarshallerKindMustBeValidDescription)));
+
+ public static readonly DiagnosticDescriptor MarshallerDirectionMustBeValidRule =
+ new DiagnosticDescriptor(
+ Ids.CustomTypeMarshallerAttributeMustBeValid,
+ "CustomTypeMarshallerAttributeMustBeValid",
+ GetResourceString(nameof(Resources.MarshallerDirectionMustBeValidMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.MarshallerDirectionMustBeValidDescription)));
+
+ public static readonly DiagnosticDescriptor NativeTypeMustHaveCustomTypeMarshallerAttributeRule =
+ new DiagnosticDescriptor(
+ Ids.InvalidNativeType,
+ "InvalidNativeType",
+ GetResourceString(nameof(Resources.NativeTypeMustHaveCustomTypeMarshallerAttributeMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.NativeTypeMustHaveCustomTypeMarshallerAttributeDescription)));
+
+ public static readonly DiagnosticDescriptor NativeTypeMustBeBlittableRule =
+ new DiagnosticDescriptor(
+ Ids.InvalidNativeType,
+ "InvalidNativeType",
+ GetResourceString(nameof(Resources.NativeTypeMustBeBlittableMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.NativeTypeMustBeBlittableDescription)));
+
+ public static readonly DiagnosticDescriptor GetPinnableReferenceReturnTypeBlittableRule =
+ new DiagnosticDescriptor(
+ Ids.GetPinnableReferenceReturnTypeBlittable,
+ "GetPinnableReferenceReturnTypeBlittable",
+ GetResourceString(nameof(Resources.GetPinnableReferenceReturnTypeBlittableMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.GetPinnableReferenceReturnTypeBlittableDescription)));
+
+ public static readonly DiagnosticDescriptor NativeTypeMustBePointerSizedRule =
+ new DiagnosticDescriptor(
+ Ids.InvalidNativeType,
+ "InvalidNativeType",
+ GetResourceString(nameof(Resources.NativeTypeMustBePointerSizedMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.NativeTypeMustBePointerSizedDescription)));
+
+ public static readonly DiagnosticDescriptor CustomMarshallerTypeMustSupportDirectionRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustSupportDirection,
+ "CustomMarshallerTypeMustSupportDirection",
+ GetResourceString(nameof(Resources.CustomMarshallerTypeMustSupportDirectionMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.CustomMarshallerTypeMustSupportDirectionDescription)));
+
+ public static readonly DiagnosticDescriptor ValueInRequiresOneParameterConstructorRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.ValueInRequiresOneParameterConstructorMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.ValueInRequiresOneParameterConstructorDescription)));
+
+ public static readonly DiagnosticDescriptor LinearCollectionInRequiresTwoParameterConstructorRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.LinearCollectionInRequiresTwoParameterConstructorMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.LinearCollectionInRequiresTwoParameterConstructorDescription)));
+
+ public static readonly DiagnosticDescriptor ValueInCallerAllocatedBufferRequiresSpanConstructorRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.ValueInCallerAllocatedBufferRequiresSpanConstructorMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.ValueInCallerAllocatedBufferRequiresSpanConstructorDescription)));
+
+ public static readonly DiagnosticDescriptor LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorDescription)));
+
+ public static readonly DiagnosticDescriptor OutRequiresToManagedRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.OutRequiresToManagedMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.OutRequiresToManagedDescription)));
+
+ public static readonly DiagnosticDescriptor LinearCollectionInRequiresCollectionMethodsRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.LinearCollectionInRequiresCollectionMethodsMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.LinearCollectionInRequiresCollectionMethodsDescription)));
+
+ public static readonly DiagnosticDescriptor LinearCollectionOutRequiresCollectionMethodsRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.LinearCollectionOutRequiresCollectionMethodsMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.LinearCollectionOutRequiresCollectionMethodsDescription)));
+
+ public static readonly DiagnosticDescriptor LinearCollectionOutRequiresIntConstructorRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.LinearCollectionOutRequiresIntConstructorMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.LinearCollectionOutRequiresIntConstructorDescription)));
+
+ public static readonly DiagnosticDescriptor UnmanagedResourcesRequiresFreeNativeRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.UnmanagedResourcesRequiresFreeNativeMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.UnmanagedResourcesRequiresFreeNativeDescription)));
+
+ public static readonly DiagnosticDescriptor OutTwoStageMarshallingRequiresFromNativeValueRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.OutTwoStageMarshallingRequiresFromNativeValueMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.OutTwoStageMarshallingRequiresFromNativeValueDescription)));
+
+ public static readonly DiagnosticDescriptor InTwoStageMarshallingRequiresToNativeValueRule =
+ new DiagnosticDescriptor(
+ Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ "CustomMarshallerTypeMustHaveRequiredShape",
+ GetResourceString(nameof(Resources.InTwoStageMarshallingRequiresToNativeValueMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.InTwoStageMarshallingRequiresToNativeValueDescription)));
+
+ public static readonly DiagnosticDescriptor GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule =
+ new DiagnosticDescriptor(
+ Ids.MissingAllocatingMarshallingFallback,
+ "GetPinnableReferenceShouldSupportAllocatingMarshallingFallback",
+ GetResourceString(nameof(Resources.GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackDescription)));
+
+ public static readonly DiagnosticDescriptor CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule =
+ new DiagnosticDescriptor(
+ Ids.MissingAllocatingMarshallingFallback,
+ "CallerAllocMarshallingShouldSupportAllocatingMarshallingFallback",
+ GetResourceString(nameof(Resources.CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackDescription)));
+
+ public static readonly DiagnosticDescriptor CallerAllocConstructorMustHaveBufferSizeRule =
+ new DiagnosticDescriptor(
+ Ids.CallerAllocConstructorMustHaveBufferSize,
+ "CallerAllocConstructorMustHaveBufferSize",
+ GetResourceString(nameof(Resources.CallerAllocConstructorMustHaveBufferSizeMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.CallerAllocConstructorMustHaveBufferSizeDescription)));
+
+ public static readonly DiagnosticDescriptor RefNativeValueUnsupportedRule =
+ new DiagnosticDescriptor(
+ Ids.InvalidSignaturesInMarshallerShape,
+ "InvalidSignaturesInMarshallerShape",
+ GetResourceString(nameof(Resources.RefNativeValueUnsupportedMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.RefNativeValueUnsupportedDescription)));
+
+ public static readonly DiagnosticDescriptor NativeGenericTypeMustBeClosedOrMatchArityRule =
+ new DiagnosticDescriptor(
+ Ids.InvalidNativeType,
+ "NativeGenericTypeMustBeClosedOrMatchArity",
+ GetResourceString(nameof(Resources.NativeGenericTypeMustBeClosedOrMatchArityMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.NativeGenericTypeMustBeClosedOrMatchArityDescription)));
+
+ public static readonly DiagnosticDescriptor MarshallerGetPinnableReferenceRequiresTwoStageMarshallingRule =
+ new DiagnosticDescriptor(
+ Ids.MarshallerGetPinnableReferenceRequiresTwoStageMarshalling,
+ "MarshallerGetPinnableReferenceRequiresTwoStageMarshalling",
+ GetResourceString(nameof(Resources.MarshallerGetPinnableReferenceRequiresTwoStageMarshallingMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.MarshallerGetPinnableReferenceRequiresTwoStageMarshallingDescription)));
+
+ public static readonly DiagnosticDescriptor FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule =
+ new DiagnosticDescriptor(
+ Ids.ProvidedMethodsNotSpecifiedInShape,
+ "ProvidedMethodsNotSpecifiedInShape",
+ GetResourceString(nameof(Resources.FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureDescription)));
+
+ public static readonly DiagnosticDescriptor ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule =
+ new DiagnosticDescriptor(
+ Ids.ProvidedMethodsNotSpecifiedInShape,
+ "ProvidedMethodsNotSpecifiedInShape",
+ GetResourceString(nameof(Resources.ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription)));
+
+ public static readonly DiagnosticDescriptor FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule =
+ new DiagnosticDescriptor(
+ Ids.ProvidedMethodsNotSpecifiedInShape,
+ "ProvidedMethodsNotSpecifiedInShape",
+ GetResourceString(nameof(Resources.FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription)));
+
+ public static readonly DiagnosticDescriptor CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureRule =
+ new DiagnosticDescriptor(
+ Ids.ProvidedMethodsNotSpecifiedInShape,
+ "ProvidedMethodsNotSpecifiedInShape",
+ GetResourceString(nameof(Resources.CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureDescription)));
+
+ public static readonly DiagnosticDescriptor TwoStageMarshallingNativeTypesMustMatchRule =
+ new DiagnosticDescriptor(
+ Ids.InvalidSignaturesInMarshallerShape,
+ "InvalidSignaturesInMarshallerShape",
+ GetResourceString(nameof(Resources.TwoStageMarshallingNativeTypesMustMatchMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.TwoStageMarshallingNativeTypesMustMatchDescription)));
+
+ public static readonly DiagnosticDescriptor LinearCollectionElementTypesMustMatchRule =
+ new DiagnosticDescriptor(
+ Ids.InvalidSignaturesInMarshallerShape,
+ "InvalidSignaturesInMarshallerShape",
+ GetResourceString(nameof(Resources.LinearCollectionElementTypesMustMatchMessage)),
+ Category,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(Resources.LinearCollectionElementTypesMustMatchDescription)));
+
+ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
+ ImmutableArray.Create(
+ MarshallerTypeMustSpecifyManagedTypeRule,
+ CustomTypeMarshallerAttributeMustBeValidRule,
+ MarshallerKindMustBeValidRule,
+ MarshallerDirectionMustBeValidRule,
+ NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
+ NativeTypeMustBeBlittableRule,
+ GetPinnableReferenceReturnTypeBlittableRule,
+ NativeTypeMustBePointerSizedRule,
+ ValueInRequiresOneParameterConstructorRule,
+ LinearCollectionInRequiresTwoParameterConstructorRule,
+ OutRequiresToManagedRule,
+ LinearCollectionInRequiresCollectionMethodsRule,
+ LinearCollectionOutRequiresCollectionMethodsRule,
+ LinearCollectionOutRequiresIntConstructorRule,
+ CustomMarshallerTypeMustSupportDirectionRule,
+ OutTwoStageMarshallingRequiresFromNativeValueRule,
+ InTwoStageMarshallingRequiresToNativeValueRule,
+ GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule,
+ CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule,
+ CallerAllocConstructorMustHaveBufferSizeRule,
+ RefNativeValueUnsupportedRule,
+ NativeGenericTypeMustBeClosedOrMatchArityRule,
+ MarshallerGetPinnableReferenceRequiresTwoStageMarshallingRule,
+ FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule,
+ ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule,
+ FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule,
+ CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureRule,
+ TwoStageMarshallingNativeTypesMustMatchRule,
+ LinearCollectionElementTypesMustMatchRule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ // Don't analyze generated code
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterCompilationStartAction(PrepareForAnalysis);
+ }
+
+ private void PrepareForAnalysis(CompilationStartAnalysisContext context)
+ {
+ INamedTypeSymbol? spanOfT = context.Compilation.GetTypeByMetadataName(TypeNames.System_Span_Metadata);
+ INamedTypeSymbol? spanOfByte = spanOfT?.Construct(context.Compilation.GetSpecialType(SpecialType.System_Byte));
+ INamedTypeSymbol? readOnlySpanOfT = context.Compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata);
+ INamedTypeSymbol? readOnlySpanOfByte = readOnlySpanOfT?.Construct(context.Compilation.GetSpecialType(SpecialType.System_Byte));
+
+ if (spanOfT is not null && readOnlySpanOfT is not null)
+ {
+ var perCompilationAnalyzer = new PerCompilationAnalyzer(spanOfT, spanOfByte, readOnlySpanOfT, readOnlySpanOfByte);
+
+ // Analyze NativeMarshalling/MarshalUsing for correctness
+ context.RegisterSymbolAction(perCompilationAnalyzer.AnalyzeTypeDefinition, SymbolKind.NamedType);
+ context.RegisterSymbolAction(perCompilationAnalyzer.AnalyzeElement, SymbolKind.Parameter, SymbolKind.Field);
+ context.RegisterSymbolAction(perCompilationAnalyzer.AnalyzeReturnType, SymbolKind.Method);
+
+ // Analyze marshaller type to validate shape.
+ context.RegisterSymbolAction(perCompilationAnalyzer.AnalyzeMarshallerType, SymbolKind.NamedType);
+ }
+ }
+
+ private class PerCompilationAnalyzer
+ {
+ private readonly INamedTypeSymbol _spanOfT;
+ private readonly INamedTypeSymbol _readOnlySpanOfT;
+ private readonly INamedTypeSymbol _spanOfByte;
+ private readonly INamedTypeSymbol _readOnlySpanOfByte;
+
+ public PerCompilationAnalyzer(INamedTypeSymbol spanOfT, INamedTypeSymbol? spanOfByte, INamedTypeSymbol readOnlySpanOfT, INamedTypeSymbol? readOnlySpanOfByte)
+ {
+ _spanOfT = spanOfT;
+ _spanOfByte = spanOfByte;
+ _readOnlySpanOfT = readOnlySpanOfT;
+ _readOnlySpanOfByte = readOnlySpanOfByte;
+ }
+
+ public void AnalyzeTypeDefinition(SymbolAnalysisContext context)
+ {
+ INamedTypeSymbol type = (INamedTypeSymbol)context.Symbol;
+
+ (AttributeData? attributeData, INamedTypeSymbol? marshallerType) = ManualTypeMarshallingHelper.GetDefaultMarshallerInfo(type);
+
+ if (attributeData is null)
+ {
+ return;
+ }
+
+ AnalyzeManagedTypeMarshallingInfo(context, type, attributeData, marshallerType);
+ }
+
+ public void AnalyzeElement(SymbolAnalysisContext context)
+ {
+ ITypeSymbol managedType = context.Symbol switch
+ {
+ IParameterSymbol param => param.Type,
+ IFieldSymbol field => field.Type,
+ _ => throw new InvalidOperationException()
+ };
+ AttributeData? attributeData = context.Symbol.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.MarshalUsingAttribute);
+ if (attributeData is null || attributeData.ConstructorArguments.Length == 0)
+ {
+ return;
+ }
+ AnalyzeManagedTypeMarshallingInfo(context, managedType, attributeData, attributeData.ConstructorArguments[0].Value as INamedTypeSymbol);
+ }
+
+ public void AnalyzeReturnType(SymbolAnalysisContext context)
+ {
+ IMethodSymbol method = (IMethodSymbol)context.Symbol;
+ ITypeSymbol managedType = method.ReturnType;
+ AttributeData? attributeData = method.GetReturnTypeAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.MarshalUsingAttribute);
+ if (attributeData is null || attributeData.ConstructorArguments.Length == 0)
+ {
+ return;
+ }
+ AnalyzeManagedTypeMarshallingInfo(context, managedType, attributeData, attributeData.ConstructorArguments[0].Value as INamedTypeSymbol);
+ }
+
+ private static void AnalyzeManagedTypeMarshallingInfo(SymbolAnalysisContext context, ITypeSymbol type, AttributeData attributeData, INamedTypeSymbol? marshallerType)
+ {
+ if (marshallerType is null)
+ {
+ context.ReportDiagnostic(
+ attributeData.CreateDiagnostic(
+ NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
+ type.ToDisplayString()));
+ return;
+ }
+
+ if (marshallerType.IsUnboundGenericType)
+ {
+ context.ReportDiagnostic(
+ attributeData.CreateDiagnostic(
+ NativeGenericTypeMustBeClosedOrMatchArityRule,
+ marshallerType.ToDisplayString(),
+ type.ToDisplayString()));
+ }
+
+ (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? marshallerManagedType, _) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(marshallerType);
+
+ marshallerManagedType = ManualTypeMarshallingHelper.ResolveManagedType(marshallerManagedType, marshallerType, context.Compilation);
+
+ if (!hasCustomTypeMarshallerAttribute)
+ {
+ context.ReportDiagnostic(
+ attributeData.CreateDiagnostic(
+ NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
+ type.ToDisplayString()));
+ return;
+ }
+
+ if (marshallerManagedType is null)
+ {
+ context.ReportDiagnostic(
+ attributeData.CreateDiagnostic(
+ NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
+ type.ToDisplayString()));
+ return;
+ }
+
+ if (!TypeSymbolsConstructedFromEqualTypes(type, marshallerManagedType))
+ {
+ context.ReportDiagnostic(
+ attributeData.CreateDiagnostic(
+ NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
+ type.ToDisplayString()));
+ 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)
+ };
+ }
+
+ public void AnalyzeMarshallerType(SymbolAnalysisContext context)
+ {
+ INamedTypeSymbol marshallerType = (INamedTypeSymbol)context.Symbol;
+ (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? type, CustomTypeMarshallerData? marshallerDataMaybe) = ManualTypeMarshallingHelper.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.IsManagedToNativeConstructor(ctor, type, marshallerData.Kind))
+ {
+ inConstructor = ctor;
+ }
+
+ if (callerAllocatedSpanConstructor is null && ManualTypeMarshallingHelper.IsCallerAllocatedSpanConstructor(ctor, type, _spanOfByte, marshallerData.Kind))
+ {
+ 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<string, string>.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<string, string>.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<string, string>.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.HasToManagedMethod(marshallerType, type))
+ {
+ context.ReportDiagnostic(
+ marshallerType.CreateDiagnostic(
+ OutRequiresToManagedRule,
+ ImmutableDictionary<string, string>.Empty.Add(
+ MissingMemberNames.Key,
+ ShapeMemberNames.Value.ToManaged),
+ marshallerType.ToDisplayString()));
+ }
+
+ if (marshallerData.Kind == CustomTypeMarshallerKind.LinearCollection)
+ {
+ IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper.FindGetManagedValuesSourceMethod(marshallerType, _readOnlySpanOfT);
+ IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper.FindGetManagedValuesDestinationMethod(marshallerType, _spanOfT);
+ IMethodSymbol? getNativeValuesSourceMethod = ManualTypeMarshallingHelper.FindGetNativeValuesSourceMethod(marshallerType, _readOnlySpanOfByte);
+ IMethodSymbol? getNativeValuesDestinationMethod = ManualTypeMarshallingHelper.FindGetNativeValuesDestinationMethod(marshallerType, _spanOfByte);
+ if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.In) && (getManagedValuesSourceMethod is null || getNativeValuesDestinationMethod is null))
+ {
+ var missingMembers = (getManagedValuesSourceMethod, getNativeValuesDestinationMethod) switch
+ {
+ (null, not null) => ShapeMemberNames.LinearCollection.GetManagedValuesSource,
+ (not null, null) => ShapeMemberNames.LinearCollection.GetNativeValuesDestination,
+ (null, null) => $"{ShapeMemberNames.LinearCollection.GetManagedValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames.LinearCollection.GetNativeValuesDestination}",
+ (not null, not null) => string.Empty
+ };
+ context.ReportDiagnostic(
+ marshallerType.CreateDiagnostic(
+ LinearCollectionInRequiresCollectionMethodsRule,
+ ImmutableDictionary<string, string>.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.LinearCollection.GetNativeValuesSource,
+ (null, not null) => ShapeMemberNames.LinearCollection.GetManagedValuesDestination,
+ (null, null) => $"{ShapeMemberNames.LinearCollection.GetNativeValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames.LinearCollection.GetManagedValuesDestination}",
+ (not null, not null) => string.Empty
+ };
+ context.ReportDiagnostic(
+ marshallerType.CreateDiagnostic(
+ LinearCollectionOutRequiresCollectionMethodsRule,
+ ImmutableDictionary<string, string>.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<string, string>.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.HasFreeNativeMethod(marshallerType))
+ {
+ context.ReportDiagnostic(
+ marshallerType.CreateDiagnostic(
+ UnmanagedResourcesRequiresFreeNativeRule,
+ ImmutableDictionary<string, string>.Empty.Add(
+ MissingMemberNames.Key,
+ ShapeMemberNames.Value.FreeNative),
+ marshallerType.ToDisplayString(),
+ type.ToDisplayString()));
+ }
+ else if (!marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources) && ManualTypeMarshallingHelper.HasFreeNativeMethod(marshallerType))
+ {
+ context.ReportDiagnostic(
+ marshallerType.CreateDiagnostic(
+ FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureRule,
+ ImmutableDictionary<string, string>.Empty.Add(
+ MissingFeaturesKey,
+ nameof(CustomTypeMarshallerFeatures.UnmanagedResources)),
+ marshallerType.ToDisplayString()));
+ }
+
+ IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper.FindToNativeValueMethod(marshallerType);
+ IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper.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<string, string>.Empty.Add(
+ MissingMemberNames.Key,
+ ShapeMemberNames.Value.ToNativeValue),
+ marshallerType.ToDisplayString()));
+ }
+ if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && fromNativeValueMethod is null)
+ {
+ context.ReportDiagnostic(marshallerType.CreateDiagnostic(
+ OutTwoStageMarshallingRequiresFromNativeValueRule,
+ ImmutableDictionary<string, string>.Empty.Add(
+ MissingMemberNames.Key,
+ ShapeMemberNames.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<string, string>.Empty.Add(
+ MissingFeaturesKey,
+ nameof(CustomTypeMarshallerFeatures.TwoStageMarshalling)),
+ marshallerType.ToDisplayString()));
+ }
+ else if (toNativeValueMethod is not null)
+ {
+ context.ReportDiagnostic(
+ marshallerType.CreateDiagnostic(
+ ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureRule,
+ ImmutableDictionary<string, string>.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.GetDefaultMarshallerInfo(type).marshallerType, 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()));
+ }
+ }
+ }
+
+ private DiagnosticDescriptor GetInConstructorShapeRule(CustomTypeMarshallerKind kind) => kind switch
+ {
+ CustomTypeMarshallerKind.Value => ValueInRequiresOneParameterConstructorRule,
+ CustomTypeMarshallerKind.LinearCollection => LinearCollectionInRequiresTwoParameterConstructorRule,
+ _ => throw new UnreachableException()
+ };
+ private string GetInConstructorMissingMemberName(CustomTypeMarshallerKind kind) => kind switch
+ {
+ CustomTypeMarshallerKind.Value => MissingMemberNames.ValueManagedToNativeConstructor,
+ CustomTypeMarshallerKind.LinearCollection => MissingMemberNames.CollectionManagedToNativeConstructor,
+ _ => throw new UnreachableException()
+ };
+ private DiagnosticDescriptor GetCallerAllocatedBufferConstructorShapeRule(CustomTypeMarshallerKind kind) => kind switch
+ {
+ CustomTypeMarshallerKind.Value => ValueInCallerAllocatedBufferRequiresSpanConstructorRule,
+ CustomTypeMarshallerKind.LinearCollection => LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorRule,
+ _ => throw new UnreachableException()
+ };
+ private 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
new file mode 100644
index 00000000000..08cc2550ed4
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs
@@ -0,0 +1,404 @@
+// 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.Composition;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.Interop.Analyzers
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared]
+ public class CustomTypeMarshallerFixer : CodeFixProvider
+ {
+ private const string AddMissingCustomTypeMarshallerMembersKey = nameof(AddMissingCustomTypeMarshallerMembersKey);
+ private const string AddMissingCustomTypeMarshallerFeaturesKey = nameof(AddMissingCustomTypeMarshallerFeaturesKey);
+
+ private class CustomFixAllProvider : DocumentBasedFixAllProvider
+ {
+ protected override async Task<Document> FixAllAsync(FixAllContext fixAllContext, Document document, ImmutableArray<Diagnostic> diagnostics)
+ {
+ SyntaxNode? root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
+ if (root == null)
+ return document;
+
+ DocumentEditor editor = await DocumentEditor.CreateAsync(document, fixAllContext.CancellationToken).ConfigureAwait(false);
+
+ switch (fixAllContext.CodeActionEquivalenceKey)
+ {
+ case AddMissingCustomTypeMarshallerMembersKey:
+ foreach (IGrouping<TextSpan, Diagnostic> diagnosticsBySpan in diagnostics.GroupBy(d => d.Location.SourceSpan))
+ {
+ SyntaxNode node = root.FindNode(diagnosticsBySpan.Key);
+
+ AddMissingMembers(fixAllContext, editor, diagnosticsBySpan, node);
+ }
+ break;
+ case AddMissingCustomTypeMarshallerFeaturesKey:
+ foreach (IGrouping<TextSpan, Diagnostic> diagnosticsBySpan in diagnostics.GroupBy(d => d.Location.SourceSpan))
+ {
+ SyntaxNode node = root.FindNode(diagnosticsBySpan.Key);
+
+ await AddMissingFeatures(fixAllContext, editor, diagnosticsBySpan, node).ConfigureAwait(false);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return editor.GetChangedDocument();
+ }
+
+ private static void AddMissingMembers(FixAllContext fixAllContext, DocumentEditor editor, IEnumerable<Diagnostic> diagnostics, SyntaxNode node)
+ {
+ var (missingMemberNames, _) = GetRequiredShapeMissingMemberNames(diagnostics);
+ ITypeSymbol marshallerType = (ITypeSymbol)editor.SemanticModel.GetDeclaredSymbol(node);
+ editor.ReplaceNode(
+ node,
+ (node, gen) =>
+ CustomTypeMarshallerFixer.AddMissingMembers(
+ node,
+ marshallerType,
+ missingMemberNames,
+ editor.SemanticModel.Compilation,
+ gen));
+ }
+
+ private static async Task AddMissingFeatures(FixAllContext fixAllContext, DocumentEditor editor, IEnumerable<Diagnostic> 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();
+
+ public override ImmutableArray<string> FixableDiagnosticIds { get; } =
+ ImmutableArray.Create(
+ AnalyzerDiagnostics.Ids.CustomMarshallerTypeMustHaveRequiredShape,
+ AnalyzerDiagnostics.Ids.MissingAllocatingMarshallingFallback,
+ AnalyzerDiagnostics.Ids.ProvidedMethodsNotSpecifiedInShape);
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ Document doc = context.Document;
+ SyntaxNode? root = await doc.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ if (root == null)
+ return;
+
+ SyntaxNode node = root.FindNode(context.Span);
+ var (missingMemberNames, missingMembersDiagnostics) = GetRequiredShapeMissingMemberNames(context.Diagnostics);
+
+ if (missingMembersDiagnostics.Count > 0)
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ Resources.AddMissingCustomTypeMarshallerMembers,
+ ct => AddMissingMembers(doc, node, missingMemberNames, ct),
+ AddMissingCustomTypeMarshallerMembersKey),
+ missingMembersDiagnostics);
+ }
+
+ var (featuresToAdd, featuresToAddDiagnostics) = GetFeaturesToAdd(context.Diagnostics);
+
+ if (featuresToAddDiagnostics.Count > 0 && featuresToAdd != CustomTypeMarshallerFeatures.None)
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ Resources.AddMissingFeaturesToCustomTypeMarshaller,
+ ct => AddMissingFeatures(doc, node, featuresToAdd, ct),
+ AddMissingCustomTypeMarshallerFeaturesKey),
+ featuresToAddDiagnostics);
+ }
+ }
+
+ private static (List<string> missingMembers, List<Diagnostic> fixedDiagnostics) GetRequiredShapeMissingMemberNames(IEnumerable<Diagnostic> diagnostics)
+ {
+ List<string> missingMemberNames = new();
+ List<Diagnostic> requiredShapeDiagnostics = new();
+ foreach (var diagnostic in diagnostics)
+ {
+ if (diagnostic.Id == AnalyzerDiagnostics.Ids.CustomMarshallerTypeMustHaveRequiredShape)
+ {
+ requiredShapeDiagnostics.Add(diagnostic);
+ if (diagnostic.Properties.TryGetValue(CustomTypeMarshallerAnalyzer.MissingMemberNames.Key, out string missingMembers))
+ {
+ missingMemberNames.AddRange(missingMembers.Split(CustomTypeMarshallerAnalyzer.MissingMemberNames.Delimiter));
+ }
+ }
+ }
+
+ return (missingMemberNames, requiredShapeDiagnostics);
+ }
+ private static (CustomTypeMarshallerFeatures featuresToAdd, List<Diagnostic> fixedDiagnostics) GetFeaturesToAdd(IEnumerable<Diagnostic> diagnostics)
+ {
+ List<Diagnostic> featuresToAddDiagnostics = new();
+ CustomTypeMarshallerFeatures featuresToAdd = CustomTypeMarshallerFeatures.None;
+ foreach (var diagnostic in diagnostics)
+ {
+ if (diagnostic.Id == AnalyzerDiagnostics.Ids.ProvidedMethodsNotSpecifiedInShape)
+ {
+ 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<Document> 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.CustomMarshallerAttributeFields.Features).OfType<IPropertySymbol>().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<Document> AddMissingMembers(Document doc, SyntaxNode node, List<string> missingMemberNames, CancellationToken ct)
+ {
+ var editor = await DocumentEditor.CreateAsync(doc, ct).ConfigureAwait(false);
+ var gen = editor.Generator;
+
+ SyntaxNode updatedDeclaration = AddMissingMembers(node, (ITypeSymbol)editor.SemanticModel.GetDeclaredSymbol(node, ct), missingMemberNames, editor.SemanticModel.Compilation, gen);
+
+ editor.ReplaceNode(node, updatedDeclaration);
+
+ return editor.GetChangedDocument();
+ }
+
+ private static SyntaxNode AddMissingMembers(SyntaxNode node, ITypeSymbol
+ marshallerType, List<string> 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.GetMarshallerShapeInfo(marshallerType);
+
+ IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper.FindFromNativeValueMethod(marshallerType);
+ IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper.FindToNativeValueMethod(marshallerType);
+ IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper.FindGetManagedValuesSourceMethod(marshallerType, readOnlySpanOfT);
+ IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper.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.Value.ToManaged:
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
+ ShapeMemberNames.Value.ToManaged,
+ returnType: gen.TypeExpression(managedType),
+ accessibility: Accessibility.Public,
+ statements: throwNotImplementedStatements));
+ break;
+ case ShapeMemberNames.Value.FreeNative:
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(ShapeMemberNames.Value.FreeNative,
+ accessibility: Accessibility.Public,
+ statements: throwNotImplementedStatements));
+ break;
+ case ShapeMemberNames.Value.FromNativeValue:
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
+ ShapeMemberNames.Value.FromNativeValue,
+ parameters: new[]
+ {
+ gen.ParameterDeclaration("value",
+ type: gen.TypeExpression(toNativeValueMethod?.ReturnType ?? @byte))
+ },
+ accessibility: Accessibility.Public,
+ statements: throwNotImplementedStatements));
+ break;
+ case ShapeMemberNames.Value.ToNativeValue:
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
+ ShapeMemberNames.Value.ToNativeValue,
+ returnType: gen.TypeExpression(fromNativeValueMethod?.Parameters[0].Type ?? @byte),
+ accessibility: Accessibility.Public,
+ statements: throwNotImplementedStatements));
+ break;
+ case ShapeMemberNames.LinearCollection.GetManagedValuesSource:
+ INamedTypeSymbol? getManagedValuesDestinationReturnType = (INamedTypeSymbol?)getManagedValuesDestinationMethod?.ReturnType;
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
+ ShapeMemberNames.LinearCollection.GetManagedValuesSource,
+ returnType: gen.TypeExpression(
+ readOnlySpanOfT.Construct(
+ getManagedValuesDestinationReturnType?.TypeArguments[0] ?? @object)),
+ accessibility: Accessibility.Public,
+ statements: throwNotImplementedStatements));
+ break;
+ case ShapeMemberNames.LinearCollection.GetNativeValuesDestination:
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
+ ShapeMemberNames.LinearCollection.GetNativeValuesDestination,
+ returnType: gen.TypeExpression(spanOfByte),
+ accessibility: Accessibility.Public,
+ statements: throwNotImplementedStatements));
+ break;
+ case ShapeMemberNames.LinearCollection.GetNativeValuesSource:
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
+ ShapeMemberNames.LinearCollection.GetNativeValuesSource,
+ parameters: new[]
+ {
+ gen.ParameterDeclaration("numElements", type: gen.TypeExpression(int32))
+ },
+ returnType: gen.TypeExpression(readOnlySpanOfByte),
+ accessibility: Accessibility.Public,
+ statements: throwNotImplementedStatements));
+ break;
+ case ShapeMemberNames.LinearCollection.GetManagedValuesDestination:
+ INamedTypeSymbol? getManagedValuesSourceReturnType = (INamedTypeSymbol?)getManagedValuesSourceMethod?.ReturnType;
+ updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
+ ShapeMemberNames.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;
+ }
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ManualTypeMarshallingAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ManualTypeMarshallingAnalyzer.cs
deleted file mode 100644
index 00abe866653..00000000000
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ManualTypeMarshallingAnalyzer.cs
+++ /dev/null
@@ -1,535 +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.Collections.Immutable;
-using System.Linq;
-
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Diagnostics;
-
-using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics;
-
-namespace Microsoft.Interop.Analyzers
-{
- [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
- public class ManualTypeMarshallingAnalyzer : DiagnosticAnalyzer
- {
- private const string Category = "Usage";
-
- public static readonly DiagnosticDescriptor BlittableTypeMustBeBlittableRule =
- new DiagnosticDescriptor(
- Ids.BlittableTypeMustBeBlittable,
- "BlittableTypeMustBeBlittable",
- GetResourceString(nameof(Resources.BlittableTypeMustBeBlittableMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.BlittableTypeMustBeBlittableDescription)));
-
- public static readonly DiagnosticDescriptor CannotHaveMultipleMarshallingAttributesRule =
- new DiagnosticDescriptor(
- Ids.CannotHaveMultipleMarshallingAttributes,
- "CannotHaveMultipleMarshallingAttributes",
- GetResourceString(nameof(Resources.CannotHaveMultipleMarshallingAttributesMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.CannotHaveMultipleMarshallingAttributesDescription)));
-
- public static readonly DiagnosticDescriptor NativeTypeMustBeNonNullRule =
- new DiagnosticDescriptor(
- Ids.NativeTypeMustBeNonNull,
- "NativeTypeMustBeNonNull",
- GetResourceString(nameof(Resources.NativeTypeMustBeNonNullMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.NativeTypeMustBeNonNullDescription)));
-
- public static readonly DiagnosticDescriptor NativeTypeMustBeBlittableRule =
- new DiagnosticDescriptor(
- Ids.NativeTypeMustBeBlittable,
- "NativeTypeMustBeBlittable",
- GetResourceString(nameof(Resources.NativeTypeMustBeBlittableMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.NativeTypeMustBeBlittableDescription)));
-
- public static readonly DiagnosticDescriptor GetPinnableReferenceReturnTypeBlittableRule =
- new DiagnosticDescriptor(
- Ids.GetPinnableReferenceReturnTypeBlittable,
- "GetPinnableReferenceReturnTypeBlittable",
- GetResourceString(nameof(Resources.GetPinnableReferenceReturnTypeBlittableMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.GetPinnableReferenceReturnTypeBlittableDescription)));
-
- public static readonly DiagnosticDescriptor NativeTypeMustBePointerSizedRule =
- new DiagnosticDescriptor(
- Ids.NativeTypeMustBePointerSized,
- "NativeTypeMustBePointerSized",
- GetResourceString(nameof(Resources.NativeTypeMustBePointerSizedMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.NativeTypeMustBePointerSizedDescription)));
-
- public static readonly DiagnosticDescriptor NativeTypeMustHaveRequiredShapeRule =
- new DiagnosticDescriptor(
- Ids.NativeTypeMustHaveRequiredShape,
- "NativeTypeMustHaveRequiredShape",
- GetResourceString(nameof(Resources.NativeTypeMustHaveRequiredShapeMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.NativeTypeMustHaveRequiredShapeDescription)));
-
- public static readonly DiagnosticDescriptor CollectionNativeTypeMustHaveRequiredShapeRule =
- new DiagnosticDescriptor(
- Ids.NativeTypeMustHaveRequiredShape,
- "NativeTypeMustHaveRequiredShape",
- GetResourceString(nameof(Resources.CollectionNativeTypeMustHaveRequiredShapeMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.CollectionNativeTypeMustHaveRequiredShapeDescription)));
-
- public static readonly DiagnosticDescriptor ValuePropertyMustHaveSetterRule =
- new DiagnosticDescriptor(
- Ids.ValuePropertyMustHaveSetter,
- "ValuePropertyMustHaveSetter",
- GetResourceString(nameof(Resources.ValuePropertyMustHaveSetterMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.ValuePropertyMustHaveSetterDescription)));
-
- public static readonly DiagnosticDescriptor ValuePropertyMustHaveGetterRule =
- new DiagnosticDescriptor(
- Ids.ValuePropertyMustHaveGetter,
- "ValuePropertyMustHaveGetter",
- GetResourceString(nameof(Resources.ValuePropertyMustHaveGetterMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.ValuePropertyMustHaveGetterDescription)));
-
- public static readonly DiagnosticDescriptor GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule =
- new DiagnosticDescriptor(
- Ids.GetPinnableReferenceShouldSupportAllocatingMarshallingFallback,
- "GetPinnableReferenceShouldSupportAllocatingMarshallingFallback",
- GetResourceString(nameof(Resources.GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackMessage)),
- Category,
- DiagnosticSeverity.Warning,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackDescription)));
-
- public static readonly DiagnosticDescriptor CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule =
- new DiagnosticDescriptor(
- Ids.CallerAllocMarshallingShouldSupportAllocatingMarshallingFallback,
- "CallerAllocMarshallingShouldSupportAllocatingMarshallingFallback",
- GetResourceString(nameof(Resources.CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackMessage)),
- Category,
- DiagnosticSeverity.Warning,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackDescription)));
-
- public static readonly DiagnosticDescriptor CallerAllocConstructorMustHaveBufferSizeConstantRule =
- new DiagnosticDescriptor(
- Ids.CallerAllocConstructorMustHaveStackBufferSizeConstant,
- "CallerAllocConstructorMustHaveBufferSizeConstant",
- GetResourceString(nameof(Resources.CallerAllocConstructorMustHaveBufferSizeConstantMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.CallerAllocConstructorMustHaveBufferSizeConstantDescription)));
-
- public static readonly DiagnosticDescriptor RefValuePropertyUnsupportedRule =
- new DiagnosticDescriptor(
- Ids.RefValuePropertyUnsupported,
- "RefValuePropertyUnsupported",
- GetResourceString(nameof(Resources.RefValuePropertyUnsupportedMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.RefValuePropertyUnsupportedDescription)));
-
- public static readonly DiagnosticDescriptor NativeGenericTypeMustBeClosedOrMatchArityRule =
- new DiagnosticDescriptor(
- Ids.NativeGenericTypeMustBeClosedOrMatchArity,
- "NativeGenericTypeMustBeClosedOrMatchArity",
- GetResourceString(nameof(Resources.NativeGenericTypeMustBeClosedOrMatchArityMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.NativeGenericTypeMustBeClosedOrMatchArityDescription)));
-
- public static readonly DiagnosticDescriptor MarshallerGetPinnableReferenceRequiresValuePropertyRule =
- new DiagnosticDescriptor(
- Ids.MarshallerGetPinnableReferenceRequiresValueProperty,
- "MarshallerGetPinnableReferenceRequiresValueProperty",
- GetResourceString(nameof(Resources.MarshallerGetPinnableReferenceRequiresValuePropertyMessage)),
- Category,
- DiagnosticSeverity.Error,
- isEnabledByDefault: true,
- description: GetResourceString(nameof(Resources.MarshallerGetPinnableReferenceRequiresValuePropertyDescription)));
-
- public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
- ImmutableArray.Create(
- BlittableTypeMustBeBlittableRule,
- CannotHaveMultipleMarshallingAttributesRule,
- NativeTypeMustBeNonNullRule,
- NativeTypeMustBeBlittableRule,
- GetPinnableReferenceReturnTypeBlittableRule,
- NativeTypeMustBePointerSizedRule,
- NativeTypeMustHaveRequiredShapeRule,
- CollectionNativeTypeMustHaveRequiredShapeRule,
- ValuePropertyMustHaveSetterRule,
- ValuePropertyMustHaveGetterRule,
- GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule,
- CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule,
- CallerAllocConstructorMustHaveBufferSizeConstantRule,
- RefValuePropertyUnsupportedRule,
- NativeGenericTypeMustBeClosedOrMatchArityRule,
- MarshallerGetPinnableReferenceRequiresValuePropertyRule);
-
- public override void Initialize(AnalysisContext context)
- {
- // Don't analyze generated code
- context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
- context.EnableConcurrentExecution();
- context.RegisterCompilationStartAction(PrepareForAnalysis);
- }
-
- private void PrepareForAnalysis(CompilationStartAnalysisContext context)
- {
- INamedTypeSymbol? generatedMarshallingAttribute = context.Compilation.GetTypeByMetadataName(TypeNames.GeneratedMarshallingAttribute);
- INamedTypeSymbol? nativeMarshallingAttribute = context.Compilation.GetTypeByMetadataName(TypeNames.NativeMarshallingAttribute);
- INamedTypeSymbol? marshalUsingAttribute = context.Compilation.GetTypeByMetadataName(TypeNames.MarshalUsingAttribute);
- INamedTypeSymbol? genericContiguousCollectionMarshallerAttribute = context.Compilation.GetTypeByMetadataName(TypeNames.GenericContiguousCollectionMarshallerAttribute);
- INamedTypeSymbol? spanOfByte = context.Compilation.GetTypeByMetadataName(TypeNames.System_Span_Metadata)!.Construct(context.Compilation.GetSpecialType(SpecialType.System_Byte));
-
- if (generatedMarshallingAttribute is not null
- && nativeMarshallingAttribute is not null
- && marshalUsingAttribute is not null
- && genericContiguousCollectionMarshallerAttribute is not null
- && spanOfByte is not null)
- {
- var perCompilationAnalyzer = new PerCompilationAnalyzer(
- generatedMarshallingAttribute,
- nativeMarshallingAttribute,
- marshalUsingAttribute,
- genericContiguousCollectionMarshallerAttribute,
- spanOfByte,
- context.Compilation.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_StructLayoutAttribute)!);
- context.RegisterSymbolAction(context => perCompilationAnalyzer.AnalyzeTypeDefinition(context), SymbolKind.NamedType);
- context.RegisterSymbolAction(context => perCompilationAnalyzer.AnalyzeElement(context), SymbolKind.Parameter, SymbolKind.Field);
- context.RegisterSymbolAction(context => perCompilationAnalyzer.AnalyzeReturnType(context), SymbolKind.Method);
- }
- }
-
- private class PerCompilationAnalyzer
- {
- private readonly INamedTypeSymbol _generatedMarshallingAttribute;
- private readonly INamedTypeSymbol _nativeMarshallingAttribute;
- private readonly INamedTypeSymbol _marshalUsingAttribute;
- private readonly INamedTypeSymbol _genericContiguousCollectionMarshallerAttribute;
- private readonly INamedTypeSymbol _spanOfByte;
- private readonly INamedTypeSymbol _structLayoutAttribute;
-
- public PerCompilationAnalyzer(INamedTypeSymbol generatedMarshallingAttribute,
- INamedTypeSymbol nativeMarshallingAttribute,
- INamedTypeSymbol marshalUsingAttribute,
- INamedTypeSymbol genericContiguousCollectionMarshallerAttribute,
- INamedTypeSymbol spanOfByte,
- INamedTypeSymbol structLayoutAttribute)
- {
- _generatedMarshallingAttribute = generatedMarshallingAttribute;
- _nativeMarshallingAttribute = nativeMarshallingAttribute;
- _marshalUsingAttribute = marshalUsingAttribute;
- _genericContiguousCollectionMarshallerAttribute = genericContiguousCollectionMarshallerAttribute;
- _spanOfByte = spanOfByte;
- _structLayoutAttribute = structLayoutAttribute;
- }
-
- public void AnalyzeTypeDefinition(SymbolAnalysisContext context)
- {
- INamedTypeSymbol type = (INamedTypeSymbol)context.Symbol;
-
- foreach (AttributeData attr in type.GetAttributes())
- {
- if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, _generatedMarshallingAttribute))
- {
- // If the type has the GeneratedMarshallingAttribute,
- // we let the source generator handle error checking.
- return;
- }
- else if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, _nativeMarshallingAttribute))
- {
- AnalyzeNativeMarshalerType(context, type, attr, isNativeMarshallingAttribute: true);
- return;
- }
- }
- }
-
- public void AnalyzeElement(SymbolAnalysisContext context)
- {
- AttributeData? attrData = context.Symbol.GetAttributes().FirstOrDefault(attr => SymbolEqualityComparer.Default.Equals(_marshalUsingAttribute, attr.AttributeClass));
- if (attrData is not null)
- {
- if (context.Symbol is IParameterSymbol param)
- {
- AnalyzeNativeMarshalerType(context, param.Type, attrData, isNativeMarshallingAttribute: false);
- }
- else if (context.Symbol is IFieldSymbol field)
- {
- AnalyzeNativeMarshalerType(context, field.Type, attrData, isNativeMarshallingAttribute: false);
- }
- }
- }
-
- public void AnalyzeReturnType(SymbolAnalysisContext context)
- {
- var method = (IMethodSymbol)context.Symbol;
- AttributeData? attrData = method.GetReturnTypeAttributes().FirstOrDefault(attr => SymbolEqualityComparer.Default.Equals(_marshalUsingAttribute, attr.AttributeClass));
- if (attrData is not null)
- {
- AnalyzeNativeMarshalerType(context, method.ReturnType, attrData, isNativeMarshallingAttribute: false);
- }
- }
-
- private void AnalyzeNativeMarshalerType(SymbolAnalysisContext context, ITypeSymbol type, AttributeData nativeMarshalerAttributeData, bool isNativeMarshallingAttribute)
- {
- if (nativeMarshalerAttributeData.ConstructorArguments.Length == 0)
- {
- // This is a MarshalUsing with just count information.
- return;
- }
-
- if (nativeMarshalerAttributeData.ConstructorArguments[0].IsNull)
- {
- context.ReportDiagnostic(
- nativeMarshalerAttributeData.CreateDiagnostic(
- NativeTypeMustBeNonNullRule,
- type.ToDisplayString()));
- return;
- }
-
- ITypeSymbol nativeType = (ITypeSymbol)nativeMarshalerAttributeData.ConstructorArguments[0].Value!;
- ISymbol nativeTypeDiagnosticsTargetSymbol = nativeType;
-
- if (nativeType is not INamedTypeSymbol marshalerType)
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, nativeType, nativeMarshalerAttributeData).CreateDiagnostic(
- NativeTypeMustHaveRequiredShapeRule,
- nativeType.ToDisplayString(),
- type.ToDisplayString()));
- return;
- }
-
- DiagnosticDescriptor requiredShapeRule = NativeTypeMustHaveRequiredShapeRule;
-
- ManualTypeMarshallingHelper.NativeTypeMarshallingVariant variant = ManualTypeMarshallingHelper.NativeTypeMarshallingVariant.Standard;
- if (marshalerType.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(_genericContiguousCollectionMarshallerAttribute, a.AttributeClass)))
- {
- variant = ManualTypeMarshallingHelper.NativeTypeMarshallingVariant.ContiguousCollection;
- requiredShapeRule = CollectionNativeTypeMustHaveRequiredShapeRule;
- if (!ManualTypeMarshallingHelper.TryGetManagedValuesProperty(marshalerType, out _)
- || !ManualTypeMarshallingHelper.HasNativeValueStorageProperty(marshalerType, _spanOfByte))
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, marshalerType, nativeMarshalerAttributeData).CreateDiagnostic(
- requiredShapeRule,
- nativeType.ToDisplayString(),
- type.ToDisplayString()));
- return;
- }
- }
-
- if (!nativeType.IsValueType)
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, nativeType, nativeMarshalerAttributeData).CreateDiagnostic(
- requiredShapeRule,
- nativeType.ToDisplayString(),
- type.ToDisplayString()));
- return;
- }
-
- if (marshalerType.IsUnboundGenericType)
- {
- if (!isNativeMarshallingAttribute)
- {
- context.ReportDiagnostic(
- nativeMarshalerAttributeData.CreateDiagnostic(
- NativeGenericTypeMustBeClosedOrMatchArityRule,
- nativeType.ToDisplayString(),
- type.ToDisplayString()));
- return;
- }
- if (type is not INamedTypeSymbol namedType || marshalerType.TypeArguments.Length != namedType.TypeArguments.Length)
- {
- context.ReportDiagnostic(
- nativeMarshalerAttributeData.CreateDiagnostic(
- NativeGenericTypeMustBeClosedOrMatchArityRule,
- nativeType.ToDisplayString(),
- type.ToDisplayString()));
- return;
- }
- // Construct the marshaler type around the same type arguments as the managed type.
- nativeType = marshalerType = marshalerType.ConstructedFrom.Construct(namedType.TypeArguments, namedType.TypeArgumentNullableAnnotations);
- }
-
- bool hasConstructor = false;
- bool hasCallerAllocSpanConstructor = false;
- foreach (IMethodSymbol ctor in marshalerType.Constructors)
- {
- if (ctor.IsStatic)
- {
- continue;
- }
-
- hasConstructor = hasConstructor || ManualTypeMarshallingHelper.IsManagedToNativeConstructor(ctor, type, variant);
-
- if (!hasCallerAllocSpanConstructor && ManualTypeMarshallingHelper.IsCallerAllocatedSpanConstructor(ctor, type, _spanOfByte, variant))
- {
- hasCallerAllocSpanConstructor = true;
- IFieldSymbol bufferSizeField = nativeType.GetMembers(ManualTypeMarshallingHelper.BufferSizeFieldName).OfType<IFieldSymbol>().FirstOrDefault();
- if (bufferSizeField is null or { DeclaredAccessibility: not Accessibility.Public } or { IsConst: false } or { Type: not { SpecialType: SpecialType.System_Int32 } })
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, ctor, nativeMarshalerAttributeData).CreateDiagnostic(
- CallerAllocConstructorMustHaveBufferSizeConstantRule,
- nativeType.ToDisplayString()));
- }
- }
- }
-
- bool hasToManaged = ManualTypeMarshallingHelper.HasToManagedMethod(marshalerType, type);
-
- // Validate that the native type has at least one marshalling method (either managed to native or native to managed)
- if (!hasConstructor && !hasCallerAllocSpanConstructor && !hasToManaged)
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, marshalerType, nativeMarshalerAttributeData).CreateDiagnostic(
- requiredShapeRule,
- marshalerType.ToDisplayString(),
- type.ToDisplayString()));
- }
-
- // Validate that this type can support marshalling when stackalloc is not usable.
- if (isNativeMarshallingAttribute && hasCallerAllocSpanConstructor && !hasConstructor)
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, marshalerType, nativeMarshalerAttributeData).CreateDiagnostic(
- CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule,
- marshalerType.ToDisplayString()));
- }
-
- IPropertySymbol? valueProperty = ManualTypeMarshallingHelper.FindValueProperty(nativeType);
- bool valuePropertyIsRefReturn = valueProperty is { ReturnsByRef: true } or { ReturnsByRefReadonly: true };
-
- if (valueProperty is not null)
- {
- if (valuePropertyIsRefReturn)
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, valueProperty, nativeMarshalerAttributeData).CreateDiagnostic(
- RefValuePropertyUnsupportedRule,
- marshalerType.ToDisplayString()));
- }
-
- nativeType = valueProperty.Type;
- nativeTypeDiagnosticsTargetSymbol = valueProperty;
-
- // Validate that we don't have partial implementations.
- // We error if either of the conditions below are partially met but not fully met:
- // - a constructor and a Value property getter
- // - a ToManaged method and a Value property setter
- if ((hasConstructor || hasCallerAllocSpanConstructor) && valueProperty.GetMethod is null)
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, valueProperty, nativeMarshalerAttributeData).CreateDiagnostic(
- ValuePropertyMustHaveGetterRule,
- marshalerType.ToDisplayString()));
- }
- if (hasToManaged && valueProperty.SetMethod is null)
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, valueProperty, nativeMarshalerAttributeData).CreateDiagnostic(
- ValuePropertyMustHaveSetterRule,
- marshalerType.ToDisplayString()));
- }
- }
- else if (ManualTypeMarshallingHelper.FindGetPinnableReference(marshalerType) is IMethodSymbol marshallerGetPinnableReferenceMethod)
- {
- // If we don't have a Value property, 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(
- MarshallerGetPinnableReferenceRequiresValuePropertyRule,
- nativeType.ToDisplayString()));
- }
-
- if (!nativeType.IsConsideredBlittable())
- {
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, nativeTypeDiagnosticsTargetSymbol, nativeMarshalerAttributeData).CreateDiagnostic(
- NativeTypeMustBeBlittableRule,
- nativeType.ToDisplayString(),
- type.ToDisplayString()));
- }
-
- if (isNativeMarshallingAttribute && 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 (isNativeMarshallingAttribute && (!hasConstructor || valueProperty is { GetMethod: null }))
- {
- context.ReportDiagnostic(
- nativeMarshalerAttributeData.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 (!valuePropertyIsRefReturn // 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 }))
- {
- IMethodSymbol getPinnableReferenceMethodToMention = managedGetPinnableReferenceMethod;
-
- context.ReportDiagnostic(
- GetDiagnosticLocations(context, nativeTypeDiagnosticsTargetSymbol, nativeMarshalerAttributeData).CreateDiagnostic(
- NativeTypeMustBePointerSizedRule,
- nativeType.ToDisplayString(),
- getPinnableReferenceMethodToMention.ContainingType.ToDisplayString()));
- }
- }
- }
-
- private ImmutableArray<Location> GetDiagnosticLocations(SymbolAnalysisContext context, ISymbol targetSymbol, AttributeData marshallingAttribute)
- {
- // If we're using a compilation that references another compilation, the symbol locations can be in source in the wrong compilation,
- // which can cause exceptions when reporting diagnostics. Make sure the symbol is defined in the current Compilation's source module before using its locations.
- // If the symbol is not defined in the current Compilation's source module, report the diagnostic at the marshalling attribute's location.
- if (SymbolEqualityComparer.Default.Equals(context.Compilation.SourceModule, targetSymbol.ContainingModule))
- {
- return targetSymbol.Locations;
- }
- return ImmutableArray.Create(marshallingAttribute.ApplicationSyntaxReference?.GetSyntax().GetLocation() ?? Location.None);
- }
- }
- }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxGeneratorExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxGeneratorExtensions.cs
new file mode 100644
index 00000000000..1bda8e4cc77
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxGeneratorExtensions.cs
@@ -0,0 +1,67 @@
+// 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.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Editing;
+
+namespace Microsoft.Interop.Analyzers
+{
+ internal static class SyntaxGeneratorExtensions
+ {
+ public static SyntaxNode GetEnumValueAsFlagsExpression(this SyntaxGenerator gen, ITypeSymbol enumType, object value, bool includeZeroValueFlags)
+ {
+ if (enumType.TypeKind != TypeKind.Enum)
+ {
+ throw new ArgumentException(nameof(enumType));
+ }
+
+ SpecialType underlyingType = ((INamedTypeSymbol)enumType).EnumUnderlyingType.SpecialType;
+
+ if (!underlyingType.IsIntegralType())
+ {
+ return gen.CastExpression(gen.TypeExpression(underlyingType), gen.LiteralExpression(value));
+ }
+
+ ulong valueToMatch = GetNumericValue(value);
+
+ ulong currentlyMatchedFlags = 0;
+ SyntaxNode? enumValueSyntax = null;
+ foreach (ISymbol member in enumType.GetMembers())
+ {
+ if (member is IFieldSymbol { HasConstantValue: true } enumValue)
+ {
+ ulong fieldNumericValue = GetNumericValue(enumValue.ConstantValue);
+ if (fieldNumericValue == 0 && !includeZeroValueFlags)
+ {
+ continue;
+ }
+ if ((fieldNumericValue & valueToMatch) == fieldNumericValue)
+ {
+ currentlyMatchedFlags |= fieldNumericValue;
+ enumValueSyntax = enumValueSyntax is null
+ ? gen.MemberAccessExpression(gen.TypeExpression(enumType), enumValue.Name)
+ : gen.BitwiseOrExpression(enumValueSyntax, gen.MemberAccessExpression(gen.TypeExpression(enumType), enumValue.Name));
+ }
+ }
+ }
+
+ // Unable to represent the value as the enum flags. Just use the literal value cast as the enum type.
+ if (currentlyMatchedFlags != valueToMatch)
+ {
+ return gen.CastExpression(gen.TypeExpression(underlyingType), gen.LiteralExpression(value));
+ }
+
+ return enumValueSyntax;
+
+ static ulong GetNumericValue(object value) => value switch
+ {
+ byte or ushort or uint or ulong => Convert.ToUInt64(value),
+ sbyte or short or int or long => (ulong)Convert.ToInt64(value),
+ _ => throw new UnreachableException()
+ };
+ }
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs
index fc0baa4b2d0..ec7a770472a 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs
@@ -145,7 +145,7 @@ namespace Microsoft.Interop
//
// [LibraryImport(NativeExportsNE_Binary, EntryPoint = "transpose_matrix")]
// [return: MarshalUsing(CountElementName = "numColumns")]
- // [return: MarshalUsing(CountElementName = "numRows", ElementIndirectionLevel = 1)]
+ // [return: MarshalUsing(CountElementName = "numRows", ElementIndirectionDepth = 1)]
// public static partial int[][] TransposeMatrix(
// int[][] matrix,
// [MarshalUsing(CountElementName="numColumns")] ref int[] numRows,
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.Designer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.Designer.cs
index fcad506c635..5e4628b58dd 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.Designer.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.Designer.cs
@@ -10,8 +10,8 @@
namespace Microsoft.Interop {
using System;
-
-
+
+
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
@@ -23,15 +23,15 @@ namespace Microsoft.Interop {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
-
+
private static global::System.Resources.ResourceManager resourceMan;
-
+
private static global::System.Globalization.CultureInfo resourceCulture;
-
+
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
-
+
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
@@ -45,7 +45,7 @@ namespace Microsoft.Interop {
return resourceMan;
}
}
-
+
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
@@ -59,43 +59,61 @@ namespace Microsoft.Interop {
resourceCulture = value;
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to A type marked with &apos;BlittableTypeAttribute&apos; must be blittable..
+ /// Looks up a localized string similar to Add missing custom type marshaller members.
/// </summary>
- internal static string BlittableTypeMustBeBlittableDescription {
+ internal static string AddMissingCustomTypeMarshallerMembers {
get {
- return ResourceManager.GetString("BlittableTypeMustBeBlittableDescription", resourceCulture);
+ return ResourceManager.GetString("AddMissingCustomTypeMarshallerMembers", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to Type &apos;{0}&apos; is marked with &apos;BlittableTypeAttribute&apos; but is not blittable.
+ /// Looks up a localized string similar to Add missing features to the &apos;CustomTypeMarshallerAttribute&apos; attribute.
/// </summary>
- internal static string BlittableTypeMustBeBlittableMessage {
+ internal static string AddMissingFeaturesToCustomTypeMarshaller {
get {
- return ResourceManager.GetString("BlittableTypeMustBeBlittableMessage", resourceCulture);
+ return ResourceManager.GetString("AddMissingFeaturesToCustomTypeMarshaller", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to When a constructor taking a Span&lt;byte&gt; is specified on the native type, the type must also have a public integer constant named BufferSize to provide the size of the caller-allocated buffer..
+ /// Looks up a localized string similar to A marshaller type that provides a constructor taking a caller-allocated &apos;Span&lt;byte&gt;&apos; should specify that it supports the &apos;CallerAllocatedBuffer&apos; feature..
/// </summary>
- internal static string CallerAllocConstructorMustHaveBufferSizeConstantDescription {
+ internal static string CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureDescription {
get {
- return ResourceManager.GetString("CallerAllocConstructorMustHaveBufferSizeConstantDescription", resourceCulture);
+ return ResourceManager.GetString("CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type &apos;{0}&apos; must have a &apos;public const int BufferSize&apos; field that specifies the size of the stack buffer because it has a constructor that takes a caller-allocated Span&lt;byte&gt;.
+ /// Looks up a localized string similar to The type &apos;{0}&apos; provides a constructor taking a caller-allocated &apos;Span&lt;byte&gt;&apos; but does not specify that it supports the &apos;CallerAllocatedBuffer&apos; feature. The constructor will not be used unless the feature is specified..
/// </summary>
- internal static string CallerAllocConstructorMustHaveBufferSizeConstantMessage {
+ internal static string CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureMessage {
get {
- return ResourceManager.GetString("CallerAllocConstructorMustHaveBufferSizeConstantMessage", resourceCulture);
+ return ResourceManager.GetString("CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureMessage", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to When a constructor taking a &apos;Span&lt;byte&gt;&apos; is specified on the native type, the type must set the BufferSize field on the &apos;System.Runtime.InteropServices.CustomTypeMarshallerAttribute&apos; to provide the size of the caller-allocated buffer..
+ /// </summary>
+ internal static string CallerAllocConstructorMustHaveBufferSizeDescription {
+ get {
+ return ResourceManager.GetString("CallerAllocConstructorMustHaveBufferSizeDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The native type &apos;{0}&apos; must set the &apos;BufferSize&apos; field on the applied &apos;System.Runtime.InteropServices.CustomTypeMarshallerAttribute&apos; to specify the size of the caller-allocated buffer because it has a constructor that takes a caller-allocated &apos;Span&lt;byte&gt;&apos;.
+ /// </summary>
+ internal static string CallerAllocConstructorMustHaveBufferSizeMessage {
+ get {
+ return ResourceManager.GetString("CallerAllocConstructorMustHaveBufferSizeMessage", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to A type that supports marshalling from managed to native using a caller-allocated buffer should also support marshalling from managed to native where using a caller-allocated buffer is impossible..
/// </summary>
@@ -104,7 +122,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Native type &apos;{0}&apos; has a constructor taking a caller-allocated buffer, but does not support marshalling in scenarios where using a caller-allocated buffer is impossible.
/// </summary>
@@ -113,7 +131,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The generated &apos;DllImportAttribute&apos; will not have a value corresponding to &apos;{0}&apos;..
/// </summary>
@@ -122,7 +140,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("CannotForwardToDllImportDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos; has no equivalent in &apos;DllImportAtttribute&apos; and will not be forwarded.
/// </summary>
@@ -131,7 +149,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("CannotForwardToDllImportMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Specified &apos;LibraryImportAttribute&apos; arguments cannot be forwarded to &apos;DllImportAttribute&apos;.
/// </summary>
@@ -140,43 +158,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("CannotForwardToDllImportTitle", resourceCulture);
}
}
-
- /// <summary>
- /// Looks up a localized string similar to The &apos;BlittableTypeAttribute&apos; and &apos;NativeMarshallingAttribute&apos; attributes are mutually exclusive..
- /// </summary>
- internal static string CannotHaveMultipleMarshallingAttributesDescription {
- get {
- return ResourceManager.GetString("CannotHaveMultipleMarshallingAttributesDescription", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to Type &apos;{0}&apos; is marked with &apos;BlittableTypeAttribute&apos; and &apos;NativeMarshallingAttribute&apos;. A type can only have one of these two attributes..
- /// </summary>
- internal static string CannotHaveMultipleMarshallingAttributesMessage {
- get {
- return ResourceManager.GetString("CannotHaveMultipleMarshallingAttributesMessage", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to A native type with the &apos;GenericContiguousCollectionMarshallerAttribute&apos; must have at least one of the two marshalling methods as well as a &apos;ManagedValues&apos; property of type &apos;Span&lt;T&gt;&apos; for some &apos;T&apos; and a &apos;NativeValueStorage&apos; property of type &apos;Span&lt;byte&gt;&apos; to enable marshalling the managed type..
- /// </summary>
- internal static string CollectionNativeTypeMustHaveRequiredShapeDescription {
- get {
- return ResourceManager.GetString("CollectionNativeTypeMustHaveRequiredShapeDescription", resourceCulture);
- }
- }
-
- /// <summary>
- /// Looks up a localized string similar to The native type &apos;{0}&apos; must be a value type and have a constructor that takes two parameters, one of type &apos;{1}&apos; and an &apos;int&apos;, or have a parameterless instance method named &apos;ToManaged&apos; that returns &apos;{1}&apos; as well as a &apos;ManagedValues&apos; property of type &apos;Span&lt;T&gt;&apos; for some &apos;T&apos; and a &apos;NativeValueStorage&apos; property of type &apos;Span&lt;byte&gt;&apos;.
- /// </summary>
- internal static string CollectionNativeTypeMustHaveRequiredShapeMessage {
- get {
- return ResourceManager.GetString("CollectionNativeTypeMustHaveRequiredShapeMessage", resourceCulture);
- }
- }
-
+
/// <summary>
/// Looks up a localized string similar to Source-generated P/Invokes will ignore any configuration that is not supported..
/// </summary>
@@ -185,7 +167,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConfigurationNotSupportedDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The &apos;{0}&apos; configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead..
/// </summary>
@@ -194,7 +176,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConfigurationNotSupportedMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The specified marshalling configuration is not supported by source-generated P/Invokes. {0}..
/// </summary>
@@ -203,7 +185,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConfigurationNotSupportedMessageMarshallingInfo", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The specified &apos;{0}&apos; configuration for parameter &apos;{1}&apos; is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead..
/// </summary>
@@ -212,7 +194,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConfigurationNotSupportedMessageParameter", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The specified &apos;{0}&apos; configuration for the return value of method &apos;{1}&apos; is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead..
/// </summary>
@@ -221,7 +203,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConfigurationNotSupportedMessageReturn", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The specified value &apos;{0}&apos; for &apos;{1}&apos; is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead..
/// </summary>
@@ -230,7 +212,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConfigurationNotSupportedMessageValue", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Specified configuration is not supported by source-generated P/Invokes..
/// </summary>
@@ -239,16 +221,16 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConfigurationNotSupportedTitle", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to Only one of &apos;ConstantElementCount&apos; or &apos;ElementCountInfo&apos; may be used in a &apos;MarshalUsingAttribute&apos; for a given &apos;ElementIndirectionLevel&apos;.
+ /// Looks up a localized string similar to Only one of &apos;ConstantElementCount&apos; or &apos;ElementCountInfo&apos; may be used in a &apos;MarshalUsingAttribute&apos; for a given &apos;ElementIndirectionDepth&apos;.
/// </summary>
internal static string ConstantAndElementCountInfoDisallowed {
get {
return ResourceManager.GetString("ConstantAndElementCountInfoDisallowed", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Automatically converting a P/Invoke with &apos;PreserveSig&apos; set to &apos;false&apos; to a source-generated P/Invoke may produce invalid code.
/// </summary>
@@ -257,7 +239,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConvertNoPreserveSigDllImportToGeneratedMayProduceInvalidCode", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Convert to &apos;LibraryImport&apos;.
/// </summary>
@@ -266,7 +248,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConvertToLibraryImport", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Use &apos;LibraryImportAttribute&apos; instead of &apos;DllImportAttribute&apos; to generate P/Invoke marshalling code at compile time.
/// </summary>
@@ -275,7 +257,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConvertToLibraryImportDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Mark the method &apos;{0}&apos; with &apos;LibraryImportAttribute&apos; instead of &apos;DllImportAttribute&apos; to generate P/Invoke marshalling code at compile time.
/// </summary>
@@ -284,7 +266,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConvertToLibraryImportMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Use &apos;LibraryImportAttribute&apos; instead of &apos;DllImportAttribute&apos; to generate P/Invoke marshalling code at compile time.
/// </summary>
@@ -293,7 +275,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConvertToLibraryImportTitle", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Conversion to &apos;LibraryImport&apos; may change behavior and compatibility. See {0} for more information..
/// </summary>
@@ -302,7 +284,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConvertToLibraryImportWarning", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Convert to &apos;LibraryImport&apos; with &apos;{0}&apos; suffix.
/// </summary>
@@ -311,7 +293,43 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("ConvertToLibraryImportWithSuffix", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to A native must set the &apos;Direction&apos; property on the &apos;CustomTypeMarshallerAttribute&apos; to a value that sets at least one known flag value on the &apos;CustomTypeMarshallerDirection&apos; enum.
+ /// </summary>
+ internal static string CustomMarshallerTypeMustSupportDirectionDescription {
+ get {
+ return ResourceManager.GetString("CustomMarshallerTypeMustSupportDirectionDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The native type &apos;{0}&apos; must set the &apos;Direction&apos; property on the &apos;CustomTypeMarshallerAttribute&apos; to a value that sets at least one known flag value on the &apos;CustomTypeMarshallerDirection&apos; enum.
+ /// </summary>
+ internal static string CustomMarshallerTypeMustSupportDirectionMessage {
+ get {
+ return ResourceManager.GetString("CustomMarshallerTypeMustSupportDirectionMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The &apos;CustomTypeMarshallerAttribute&apos; attribute must be semantically valid.
+ /// </summary>
+ internal static string CustomTypeMarshallerAttributeMustBeValidDescription {
+ get {
+ return ResourceManager.GetString("CustomTypeMarshallerAttributeMustBeValidDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The &apos;CustomTypeMarshallerAttribute&apos; on &apos;{0}&apos; is semantically invalid.
+ /// </summary>
+ internal static string CustomTypeMarshallerAttributeMustBeValidMessage {
+ get {
+ return ResourceManager.GetString("CustomTypeMarshallerAttributeMustBeValidMessage", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to The specified parameter needs to be marshalled from managed to native, but the native type &apos;{0}&apos; does not support it..
/// </summary>
@@ -320,7 +338,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("CustomTypeMarshallingManagedToNativeUnsupported", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The specified parameter needs to be marshalled from native to managed, but the native type &apos;{0}&apos; does not support it..
/// </summary>
@@ -329,7 +347,43 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("CustomTypeMarshallingNativeToManagedUnsupported", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to A marshaller type that provides a &apos;FreeNative&apos; method should specify that it supports the &apos;UnmanagedResources&apos; feature..
+ /// </summary>
+ internal static string FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureDescription {
+ get {
+ return ResourceManager.GetString("FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; provides a &apos;FreeNative&apos; method but does not specify that it supports the &apos;UnmanagedResources&apos; feature. The method will not be used unless the feature is specified..
+ /// </summary>
+ internal static string FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureMessage {
+ get {
+ return ResourceManager.GetString("FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A marshaller type that provides a &apos;FromNativeValue&apos; method should specify that it supports the &apos;TwoStageMarshalling&apos; feature..
+ /// </summary>
+ internal static string FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription {
+ get {
+ return ResourceManager.GetString("FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; provides a &apos;FromNativeValue&apos; method but does not specify that it supports the &apos;TwoStageMarshalling&apos; feature. The method will not be used unless the feature is specified..
+ /// </summary>
+ internal static string FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage {
+ get {
+ return ResourceManager.GetString("FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to The return type of &apos;GetPinnableReference&apos; (after accounting for &apos;ref&apos;) must be blittable..
/// </summary>
@@ -338,7 +392,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("GetPinnableReferenceReturnTypeBlittableDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The dereferenced type of the return type of the &apos;GetPinnableReference&apos; method must be blittable.
/// </summary>
@@ -347,7 +401,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("GetPinnableReferenceReturnTypeBlittableMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to A type that supports marshalling from managed to native by pinning should also support marshalling from managed to native where pinning is impossible..
/// </summary>
@@ -356,7 +410,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Type &apos;{0}&apos; has a &apos;GetPinnableReference&apos; method but its native type does not support marshalling in scenarios where pinning is impossible.
/// </summary>
@@ -365,7 +419,25 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackMessage", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to The &apos;TwoStageMarshalling&apos; feature requires a &apos;TNativeType ToNativeValue()&apos; method for the &apos;In&apos; direction..
+ /// </summary>
+ internal static string InTwoStageMarshallingRequiresToNativeValueDescription {
+ get {
+ return ResourceManager.GetString("InTwoStageMarshallingRequiresToNativeValueDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The marshaller type &apos;{0}&apos; supports marshalling in the &apos;In&apos; direction with the &apos;TwoStageMarshalling&apos; feature must provide a &apos;ToNativeValue&apos; instance method that returns the native value.
+ /// </summary>
+ internal static string InTwoStageMarshallingRequiresToNativeValueMessage {
+ get {
+ return ResourceManager.GetString("InTwoStageMarshallingRequiresToNativeValueMessage", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to Method &apos;{0}&apos; is contained in a type &apos;{1}&apos; that is not marked &apos;partial&apos;. P/Invoke source generation will ignore method &apos;{0}&apos;..
/// </summary>
@@ -374,7 +446,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidAttributedMethodContainingTypeMissingModifiersMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Methods marked with &apos;LibraryImportAttribute&apos; should be &apos;static&apos;, &apos;partial&apos;, and non-generic. P/Invoke source generation will ignore methods that are non-&apos;static&apos;, non-&apos;partial&apos;, or generic..
/// </summary>
@@ -383,7 +455,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidAttributedMethodDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Method &apos;{0}&apos; should be &apos;static&apos;, &apos;partial&apos;, and non-generic when marked with &apos;LibraryImportAttribute&apos;. P/Invoke source generation will ignore method &apos;{0}&apos;..
/// </summary>
@@ -392,7 +464,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidAttributedMethodSignatureMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Invalid &apos;LibraryImportAttribute&apos; usage.
/// </summary>
@@ -401,7 +473,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidLibraryImportAttributeUsageTitle", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The configuration of &apos;StringMarshalling&apos; and &apos;StringMarshallingCustomType&apos; is invalid..
/// </summary>
@@ -410,7 +482,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidStringMarshallingConfigurationDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The configuration of &apos;StringMarshalling&apos; and &apos;StringMarshallingCustomType&apos; on method &apos;{0}&apos; is invalid. {1}.
/// </summary>
@@ -419,7 +491,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidStringMarshallingConfigurationMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to &apos;StringMarshallingCustomType&apos; must be specified when &apos;StringMarshalling&apos; is set to &apos;StringMarshalling.Custom&apos;..
/// </summary>
@@ -428,7 +500,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidStringMarshallingConfigurationMissingCustomType", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to &apos;StringMarshalling&apos; should be set to &apos;StringMarshalling.Custom&apos; when &apos;StringMarshallingCustomType&apos; is specified..
/// </summary>
@@ -437,34 +509,187 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("InvalidStringMarshallingConfigurationNotCustom", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The use cases for &apos;GetPinnableReference&apos; are not applicable in any scenarios where a &apos;Value&apos; property is not also required..
+ /// Looks up a localized string similar to The element type of the &apos;ReadOnlySpan&apos; returned by &apos;GetManagedValuesSource&apos; must be the same as the element type returned by &apos;GetManagedValuesDestination&apos;..
/// </summary>
- internal static string MarshallerGetPinnableReferenceRequiresValuePropertyDescription {
+ internal static string LinearCollectionElementTypesMustMatchDescription {
get {
- return ResourceManager.GetString("MarshallerGetPinnableReferenceRequiresValuePropertyDescription", resourceCulture);
+ return ResourceManager.GetString("LinearCollectionElementTypesMustMatchDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The &apos;GetPinnableReference&apos; method cannot be provided on the native type &apos;{0}&apos; unless a &apos;Value&apos; property is also provided.
+ /// Looks up a localized string similar to The element type of the &apos;ReadOnlySpan&apos; returned by &apos;GetManagedValuesSource&apos; must be the same as the element type returned by &apos;GetManagedValuesDestination&apos;.
/// </summary>
- internal static string MarshallerGetPinnableReferenceRequiresValuePropertyMessage {
+ internal static string LinearCollectionElementTypesMustMatchMessage {
get {
- return ResourceManager.GetString("MarshallerGetPinnableReferenceRequiresValuePropertyMessage", resourceCulture);
+ return ResourceManager.GetString("LinearCollectionElementTypesMustMatchMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type &apos;{0}&apos; must be a closed generic so the emitted code can use a specific instantiation..
+ /// Looks up a localized string similar to A &apos;LinearCollection&apos;-kind native type that supports the &apos;CallerAllocatedBuffer&apos; feature must provide a three-parameter constructor taking the managed type as the first parameter, a &apos;Span&lt;byte&gt;&apos; as the second parameter, and the native size of the element as the third parameter.
/// </summary>
- internal static string NativeGenericTypeMustBeClosedDescription {
+ internal static string LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorDescription {
get {
- return ResourceManager.GetString("NativeGenericTypeMustBeClosedDescription", resourceCulture);
+ return ResourceManager.GetString("LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorDescription", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies that it supports &apos;In&apos; marshalling with the &apos;CallerAllocatedBuffer&apos; feature for &apos;{1}&apos; but does not provide a three-parameter constructor that takes a &apos;{1}&apos; , a &apos;Span&lt;byte&gt;&apos;, and an &apos;int&apos;.
+ /// </summary>
+ internal static string LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorMessage {
+ get {
+ return ResourceManager.GetString("LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A &apos;LinearCollection&apos;-kind native type that supports marshalling in the &apos;In&apos; direction must provide a &apos;GetManagedValuesSource&apos; that returns a &apos;ReadOnlySpan&lt;&gt;&apos; and a &apos;GetNativeValuesDestination&apos; method that returns a &apos;Span&lt;byte&gt;&apos;..
+ /// </summary>
+ internal static string LinearCollectionInRequiresCollectionMethodsDescription {
+ get {
+ return ResourceManager.GetString("LinearCollectionInRequiresCollectionMethodsDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies that is supports marshalling in the &apos;In&apos; direction, but it does not provide a &apos;GetManagedValuesSource&apos; that returns a &apos;ReadOnlySpan&lt;&gt;&apos; and a &apos;GetNativeValuesDestination&apos; method that returns a &apos;Span&lt;byte&gt;&apos;.
+ /// </summary>
+ internal static string LinearCollectionInRequiresCollectionMethodsMessage {
+ get {
+ return ResourceManager.GetString("LinearCollectionInRequiresCollectionMethodsMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A &apos;LinearCollection&apos;-kind native type must provide a two-parameter constructor taking the managed type as the first parameter and the native size of the element as the second parameter.
+ /// </summary>
+ internal static string LinearCollectionInRequiresTwoParameterConstructorDescription {
+ get {
+ return ResourceManager.GetString("LinearCollectionInRequiresTwoParameterConstructorDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies that it supports &apos;In&apos; marshalling of &apos;{1}&apos; but does not provide a two-parameter constructor that takes a &apos;{1}&apos; as the first parameter and an &apos;int&apos; as the second parameter.
+ /// </summary>
+ internal static string LinearCollectionInRequiresTwoParameterConstructorMessage {
+ get {
+ return ResourceManager.GetString("LinearCollectionInRequiresTwoParameterConstructorMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A &apos;LinearCollection&apos;-kind native type that supports marshalling in the &apos;Out&apos; direction must provide a &apos;GetManagedValuesDestination&apos; that takes an &apos;int&apos; and returns a &apos;Span&lt;&gt;&apos; and a &apos;GetNativeValuesSource&apos; method that takes an &apos;int&apos; and rreturns a &apos;ReadOnlySpan&lt;byte&gt;&apos;..
+ /// </summary>
+ internal static string LinearCollectionOutRequiresCollectionMethodsDescription {
+ get {
+ return ResourceManager.GetString("LinearCollectionOutRequiresCollectionMethodsDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies that it supports marshalling in the &apos;Out&apos; direction, but it does not provide a &apos;GetManagedValuesDestination&apos; that takes an &apos;int&apos; and returns a &apos;Span&lt;&gt;&apos; and a &apos;GetNativeValuesSource&apos; method that takes an &apos;int&apos; and rreturns a &apos;ReadOnlySpan&lt;byte&gt;&apos;.
+ /// </summary>
+ internal static string LinearCollectionOutRequiresCollectionMethodsMessage {
+ get {
+ return ResourceManager.GetString("LinearCollectionOutRequiresCollectionMethodsMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A &apos;LinearCollection&apos;-kind native type that supports marshalling in the &apos;Out&apos; direction must provide a constructor that takes the size of the native element as an &apos;int&apos;..
+ /// </summary>
+ internal static string LinearCollectionOutRequiresIntConstructorDescription {
+ get {
+ return ResourceManager.GetString("LinearCollectionOutRequiresIntConstructorDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies that it supports marshalling in the &apos;Out&apos; direction, but it does not provide a constructor that takes the size of the native element as an &apos;int&apos;..
+ /// </summary>
+ internal static string LinearCollectionOutRequiresIntConstructorMessage {
+ get {
+ return ResourceManager.GetString("LinearCollectionOutRequiresIntConstructorMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The specified marshaller direction must be a valid value of the &apos;System.Runtime.InteropServices.CustomMarshallerDirection&apos; enum..
+ /// </summary>
+ internal static string MarshallerDirectionMustBeValidDescription {
+ get {
+ return ResourceManager.GetString("MarshallerDirectionMustBeValidDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The specified custom marshaller direction for &apos;{0}&apos; is invalid.
+ /// </summary>
+ internal static string MarshallerDirectionMustBeValidMessage {
+ get {
+ return ResourceManager.GetString("MarshallerDirectionMustBeValidMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The use cases for &apos;GetPinnableReference&apos; are not applicable in any scenarios where &apos;TwoStageMarshalling&apos; is not also required..
+ /// </summary>
+ internal static string MarshallerGetPinnableReferenceRequiresTwoStageMarshallingDescription {
+ get {
+ return ResourceManager.GetString("MarshallerGetPinnableReferenceRequiresTwoStageMarshallingDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The &apos;GetPinnableReference&apos; method cannot be provided on the native type &apos;{0}&apos; unless the &apos;TwoStageMarshalling&apos; feature is also supported.
+ /// </summary>
+ internal static string MarshallerGetPinnableReferenceRequiresTwoStageMarshallingMessage {
+ get {
+ return ResourceManager.GetString("MarshallerGetPinnableReferenceRequiresTwoStageMarshallingMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The specified marshaller kind must be a valid value of the &apos;System.Runtime.InteropServices.CustomMarshallerKind&apos; enum..
+ /// </summary>
+ internal static string MarshallerKindMustBeValidDescription {
+ get {
+ return ResourceManager.GetString("MarshallerKindMustBeValidDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The specified custom marshaller kind for &apos;{0}&apos; is invalid.
+ /// </summary>
+ internal static string MarshallerKindMustBeValidMessage {
+ get {
+ return ResourceManager.GetString("MarshallerKindMustBeValidMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A type with a &apos;System.Runtime.InteropServices.CustomTypeMarshallerAttribute&apos; must specify a managed type.
+ /// </summary>
+ internal static string MarshallerTypeMustSpecifyManagedTypeDescription {
+ get {
+ return ResourceManager.GetString("MarshallerTypeMustSpecifyManagedTypeDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; does not specify a managed type in the &apos;System.Runtime.InteropServices.CustomTypeMarshallerAttribute&apos; applied to the type.
+ /// </summary>
+ internal static string MarshallerTypeMustSpecifyManagedTypeMessage {
+ get {
+ return ResourceManager.GetString("MarshallerTypeMustSpecifyManagedTypeMessage", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to The native type &apos;{0}&apos; must be a closed generic or have the same number of generic parameters as the managed type so the emitted code can use a specific instantiation..
/// </summary>
@@ -473,7 +698,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("NativeGenericTypeMustBeClosedOrMatchArityDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The native type &apos;{0}&apos; for managed type &apos;{1}&apos; must be a closed generic type or have the same arity as the managed type..
/// </summary>
@@ -482,106 +707,115 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("NativeGenericTypeMustBeClosedOrMatchArityMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to A native type for a given type must be blittable..
+ /// Looks up a localized string similar to A native type must be blittable..
/// </summary>
internal static string NativeTypeMustBeBlittableDescription {
get {
return ResourceManager.GetString("NativeTypeMustBeBlittableDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type &apos;{0}&apos; for the type &apos;{1}&apos; is not blittable.
+ /// Looks up a localized string similar to The native type &apos;{0}&apos; for type &apos;{1}&apos; must be blittable.
/// </summary>
internal static string NativeTypeMustBeBlittableMessage {
get {
return ResourceManager.GetString("NativeTypeMustBeBlittableMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to A native type for a given type must be non-null..
+ /// Looks up a localized string similar to The native type must be pointer sized so the pinned result of &apos;GetPinnableReference&apos; can be cast to the native type..
/// </summary>
- internal static string NativeTypeMustBeNonNullDescription {
+ internal static string NativeTypeMustBePointerSizedDescription {
get {
- return ResourceManager.GetString("NativeTypeMustBeNonNullDescription", resourceCulture);
+ return ResourceManager.GetString("NativeTypeMustBePointerSizedDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type for the type &apos;{0}&apos; is null.
+ /// Looks up a localized string similar to The native type &apos;{0}&apos; must be pointer sized because the managed type &apos;{1}&apos; has a &apos;GetPinnableReference&apos; method.
/// </summary>
- internal static string NativeTypeMustBeNonNullMessage {
+ internal static string NativeTypeMustBePointerSizedMessage {
get {
- return ResourceManager.GetString("NativeTypeMustBeNonNullMessage", resourceCulture);
+ return ResourceManager.GetString("NativeTypeMustBePointerSizedMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type must be pointer sized so the pinned result of &apos;GetPinnableReference&apos; can be cast to the native type..
+ /// Looks up a localized string similar to A native type for a given type must have the &apos;System.Runtime.InteropServices.CustomTypeMarshallerAttribute&apos; that specifies this type as the managed type..
/// </summary>
- internal static string NativeTypeMustBePointerSizedDescription {
+ internal static string NativeTypeMustHaveCustomTypeMarshallerAttributeDescription {
get {
- return ResourceManager.GetString("NativeTypeMustBePointerSizedDescription", resourceCulture);
+ return ResourceManager.GetString("NativeTypeMustHaveCustomTypeMarshallerAttributeDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type &apos;{0}&apos; must be pointer sized because the managed type &apos;{1}&apos; has a &apos;GetPinnableReference&apos; method.
+ /// Looks up a localized string similar to The native type for the type &apos;{0}&apos; must be a type with the &apos;System.Runtime.InteropServices.CustomTypeMarshallerAttribute&apos; that specifies this type as the managed type.
/// </summary>
- internal static string NativeTypeMustBePointerSizedMessage {
+ internal static string NativeTypeMustHaveCustomTypeMarshallerAttributeMessage {
get {
- return ResourceManager.GetString("NativeTypeMustBePointerSizedMessage", resourceCulture);
+ return ResourceManager.GetString("NativeTypeMustHaveCustomTypeMarshallerAttributeMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type must have at least one of the two marshalling methods to enable marshalling the managed type..
+ /// Looks up a localized string similar to A &apos;Value&apos; or &apos;LinearCollection&apos;-kind native type that supports marshalling in the &apos;Out&apos; direction must provide a &apos;ToManaged&apos; method that returns the managed type..
/// </summary>
- internal static string NativeTypeMustHaveRequiredShapeDescription {
+ internal static string OutRequiresToManagedDescription {
get {
- return ResourceManager.GetString("NativeTypeMustHaveRequiredShapeDescription", resourceCulture);
+ return ResourceManager.GetString("OutRequiresToManagedDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type &apos;{0}&apos; must be a value type and have a constructor that takes one parameter of type &apos;{1}&apos; or a parameterless instance method named &apos;ToManaged&apos; that returns &apos;{1}&apos;.
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies it supports marshalling in the &apos;Out&apos; direction, but it does not provide a &apos;ToManaged&apos; method that returns the managed type.
/// </summary>
- internal static string NativeTypeMustHaveRequiredShapeMessage {
+ internal static string OutRequiresToManagedMessage {
get {
- return ResourceManager.GetString("NativeTypeMustHaveRequiredShapeMessage", resourceCulture);
+ return ResourceManager.GetString("OutRequiresToManagedMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The &apos;Value&apos; property must not be a &apos;ref&apos; or &apos;readonly ref&apos; property..
+ /// Looks up a localized string similar to The &apos;TwoStageMarshalling&apos; feature requires a &apos;void FromNativeValue(TNativeType value)&apos; method for the &apos;Out&apos; direction..
/// </summary>
- internal static string RefValuePropertyUnsupportedDescription {
+ internal static string OutTwoStageMarshallingRequiresFromNativeValueDescription {
get {
- return ResourceManager.GetString("RefValuePropertyUnsupportedDescription", resourceCulture);
+ return ResourceManager.GetString("OutTwoStageMarshallingRequiresFromNativeValueDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The &apos;Value&apos; property on the native type &apos;{0}&apos; must not be a &apos;ref&apos; or &apos;readonly ref&apos; property..
+ /// Looks up a localized string similar to The marshaller type &apos;{0}&apos; supports marshalling in the &apos;Out&apos; direction with the &apos;TwoStageMarshalling&apos; feature, but it does not provide a &apos;FromNativeValue&apos; instance method that returns &apos;void&apos; and takes one parameter..
/// </summary>
- internal static string RefValuePropertyUnsupportedMessage {
+ internal static string OutTwoStageMarshallingRequiresFromNativeValueMessage {
get {
- return ResourceManager.GetString("RefValuePropertyUnsupportedMessage", resourceCulture);
+ return ResourceManager.GetString("OutTwoStageMarshallingRequiresFromNativeValueMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to .
+ /// Looks up a localized string similar to The &apos;Value&apos; property must not be a &apos;ref&apos; or &apos;readonly ref&apos; property..
/// </summary>
- internal static string RuntimeMarshallingMustBeDisabled {
+ internal static string RefNativeValueUnsupportedDescription {
get {
- return ResourceManager.GetString("RuntimeMarshallingMustBeDisabled", resourceCulture);
+ return ResourceManager.GetString("RefNativeValueUnsupportedDescription", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to The &apos;Value&apos; property on the native type &apos;{0}&apos; must not be a &apos;ref&apos; or &apos;readonly ref&apos; property..
+ /// </summary>
+ internal static string RefNativeValueUnsupportedMessage {
+ get {
+ return ResourceManager.GetString("RefNativeValueUnsupportedMessage", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to An abstract type derived from &apos;SafeHandle&apos; cannot be marshalled by reference. The provided type must be concrete..
/// </summary>
@@ -590,7 +824,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("SafeHandleByRefMustBeConcrete", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to P/Invoke source generation is not supported on unknown target framework v{0}. The generated source will not be compatible with other frameworks..
/// </summary>
@@ -599,7 +833,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TargetFrameworkNotSupportedDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to &apos;LibraryImportAttribute&apos; cannot be used for source-generated P/Invokes on an unknown target framework v{0}..
/// </summary>
@@ -608,7 +842,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TargetFrameworkNotSupportedMessage", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Current target framework is not supported by source-generated P/Invokes.
/// </summary>
@@ -617,7 +851,43 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TargetFrameworkNotSupportedTitle", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to A marshaller type that provides a &apos;ToNativeValue&apos; method should specify that it supports the &apos;TwoStageMarshalling&apos; feature..
+ /// </summary>
+ internal static string ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription {
+ get {
+ return ResourceManager.GetString("ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; provides a &apos;ToNativeValue&apos; method but does not specify that it supports the &apos;TwoStageMarshalling&apos; feature. The method will not be used unless the feature is specified..
+ /// </summary>
+ internal static string ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage {
+ get {
+ return ResourceManager.GetString("ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The return type of &apos;ToNativeValue&apos; and the parameter type of &apos;FromNativeValue&apos; must be the same..
+ /// </summary>
+ internal static string TwoStageMarshallingNativeTypesMustMatchDescription {
+ get {
+ return ResourceManager.GetString("TwoStageMarshallingNativeTypesMustMatchDescription", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The return type of &apos;ToNativeValue&apos; and the parameter type of &apos;FromNativeValue&apos; must be the same.
+ /// </summary>
+ internal static string TwoStageMarshallingNativeTypesMustMatchMessage {
+ get {
+ return ResourceManager.GetString("TwoStageMarshallingNativeTypesMustMatchMessage", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type..
/// </summary>
@@ -626,7 +896,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TypeNotSupportedDescription", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The type &apos;{0}&apos; is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter &apos;{1}&apos;..
/// </summary>
@@ -635,7 +905,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TypeNotSupportedMessageParameter", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to {0} The generated source will not handle marshalling of parameter &apos;{1}&apos;..
/// </summary>
@@ -644,7 +914,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TypeNotSupportedMessageParameterWithDetails", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to The type &apos;{0}&apos; is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method &apos;{1}&apos;..
/// </summary>
@@ -653,7 +923,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TypeNotSupportedMessageReturn", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to {0} The generated source will not handle marshalling of the return value of method &apos;{1}&apos;..
/// </summary>
@@ -662,7 +932,7 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TypeNotSupportedMessageReturnWithDetails", resourceCulture);
}
}
-
+
/// <summary>
/// Looks up a localized string similar to Specified type is not supported by source-generated P/Invokes.
/// </summary>
@@ -671,40 +941,58 @@ namespace Microsoft.Interop {
return ResourceManager.GetString("TypeNotSupportedTitle", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type&apos;s &apos;Value&apos; property must have a getter to support marshalling from managed to native..
+ /// Looks up a localized string similar to The &apos;UnmanagedResources&apos; feature requires a &apos;void FreeNative()&apos; method..
/// </summary>
- internal static string ValuePropertyMustHaveGetterDescription {
+ internal static string UnmanagedResourcesRequiresFreeNativeDescription {
get {
- return ResourceManager.GetString("ValuePropertyMustHaveGetterDescription", resourceCulture);
+ return ResourceManager.GetString("UnmanagedResourcesRequiresFreeNativeDescription", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The &apos;Value&apos; property on the native type &apos;{0}&apos; must have a getter.
+ /// Looks up a localized string similar to The marshaller type &apos;{0}&apos; supports marshalling with the &apos;UnmanagedResources&apos; feature, but it does not provide a parameterless &apos;FreeNative&apos; instance method that returns &apos;void&apos;.
/// </summary>
- internal static string ValuePropertyMustHaveGetterMessage {
+ internal static string UnmanagedResourcesRequiresFreeNativeMessage {
get {
- return ResourceManager.GetString("ValuePropertyMustHaveGetterMessage", resourceCulture);
+ return ResourceManager.GetString("UnmanagedResourcesRequiresFreeNativeMessage", resourceCulture);
}
}
-
+
/// <summary>
- /// Looks up a localized string similar to The native type&apos;s &apos;Value&apos; property must have a setter to support marshalling from native to managed..
+ /// Looks up a localized string similar to A &apos;Value&apos;-kind native type that supports the &apos;CallerAllocatedBuffer&apos; feature must provide a two-parameter constructor taking the managed type and a &apos;Span&lt;byte&gt;&apos; as parameters.
/// </summary>
- internal static string ValuePropertyMustHaveSetterDescription {
+ internal static string ValueInCallerAllocatedBufferRequiresSpanConstructorDescription {
get {
- return ResourceManager.GetString("ValuePropertyMustHaveSetterDescription", resourceCulture);
+ return ResourceManager.GetString("ValueInCallerAllocatedBufferRequiresSpanConstructorDescription", resourceCulture);
}
}
-
+
+ /// <summary>
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies that it supports &apos;In&apos; marshalling with the &apos;CallerAllocatedBuffer&apos; feature for &apos;{1}&apos; but does not provide a one-parameter constructor that takes a &apos;{1}&apos; and &apos;Span&lt;byte&gt;&apos; as parameters.
+ /// </summary>
+ internal static string ValueInCallerAllocatedBufferRequiresSpanConstructorMessage {
+ get {
+ return ResourceManager.GetString("ValueInCallerAllocatedBufferRequiresSpanConstructorMessage", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A &apos;Value&apos;-kind native type must provide a one-parameter constructor taking the managed type as a parameter.
+ /// </summary>
+ internal static string ValueInRequiresOneParameterConstructorDescription {
+ get {
+ return ResourceManager.GetString("ValueInRequiresOneParameterConstructorDescription", resourceCulture);
+ }
+ }
+
/// <summary>
- /// Looks up a localized string similar to The &apos;Value&apos; property on the native type &apos;{0}&apos; must have a setter.
+ /// Looks up a localized string similar to The type &apos;{0}&apos; specifies that it supports &apos;In&apos; marshalling of &apos;{1}&apos; but does not provide a one-parameter constructor that takes a &apos;{1}&apos; as a parameter.
/// </summary>
- internal static string ValuePropertyMustHaveSetterMessage {
+ internal static string ValueInRequiresOneParameterConstructorMessage {
get {
- return ResourceManager.GetString("ValuePropertyMustHaveSetterMessage", resourceCulture);
+ return ResourceManager.GetString("ValueInRequiresOneParameterConstructorMessage", resourceCulture);
}
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.resx b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.resx
index 1d6467f5daa..cb1b973807d 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.resx
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Resources.resx
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
- <!--
- Microsoft ResX Schema
-
+ <!--
+ Microsoft ResX Schema
+
Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
associated with the data types.
-
+
Example:
-
+
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
-
- There are any number of "resheader" rows that contain simple
+
+ There are any number of "resheader" rows that contain simple
name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
-
+
mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
-
+
mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
+ value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -117,17 +117,11 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
- <data name="BlittableTypeMustBeBlittableDescription" xml:space="preserve">
- <value>A type marked with 'BlittableTypeAttribute' must be blittable.</value>
- </data>
- <data name="BlittableTypeMustBeBlittableMessage" xml:space="preserve">
- <value>Type '{0}' is marked with 'BlittableTypeAttribute' but is not blittable</value>
- </data>
- <data name="CallerAllocConstructorMustHaveBufferSizeConstantDescription" xml:space="preserve">
- <value>When a constructor taking a Span&lt;byte&gt; is specified on the native type, the type must also have a public integer constant named BufferSize to provide the size of the caller-allocated buffer.</value>
+ <data name="CallerAllocConstructorMustHaveBufferSizeDescription" xml:space="preserve">
+ <value>When a constructor taking a 'Span&lt;byte&gt;' is specified on the native type, the type must set the BufferSize field on the 'System.Runtime.InteropServices.CustomTypeMarshallerAttribute' to provide the size of the caller-allocated buffer.</value>
</data>
- <data name="CallerAllocConstructorMustHaveBufferSizeConstantMessage" xml:space="preserve">
- <value>The native type '{0}' must have a 'public const int BufferSize' field that specifies the size of the stack buffer because it has a constructor that takes a caller-allocated Span&lt;byte&gt;</value>
+ <data name="CallerAllocConstructorMustHaveBufferSizeMessage" xml:space="preserve">
+ <value>The native type '{0}' must set the 'BufferSize' field on the applied 'System.Runtime.InteropServices.CustomTypeMarshallerAttribute' to specify the size of the caller-allocated buffer because it has a constructor that takes a caller-allocated 'Span&lt;byte&gt;'</value>
</data>
<data name="CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackDescription" xml:space="preserve">
<value>A type that supports marshalling from managed to native using a caller-allocated buffer should also support marshalling from managed to native where using a caller-allocated buffer is impossible.</value>
@@ -144,18 +138,6 @@
<data name="CannotForwardToDllImportTitle" xml:space="preserve">
<value>Specified 'LibraryImportAttribute' arguments cannot be forwarded to 'DllImportAttribute'</value>
</data>
- <data name="CannotHaveMultipleMarshallingAttributesDescription" xml:space="preserve">
- <value>The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive.</value>
- </data>
- <data name="CannotHaveMultipleMarshallingAttributesMessage" xml:space="preserve">
- <value>Type '{0}' is marked with 'BlittableTypeAttribute' and 'NativeMarshallingAttribute'. A type can only have one of these two attributes.</value>
- </data>
- <data name="CollectionNativeTypeMustHaveRequiredShapeDescription" xml:space="preserve">
- <value>A native type with the 'GenericContiguousCollectionMarshallerAttribute' must have at least one of the two marshalling methods as well as a 'ManagedValues' property of type 'Span&lt;T&gt;' for some 'T' and a 'NativeValueStorage' property of type 'Span&lt;byte&gt;' to enable marshalling the managed type.</value>
- </data>
- <data name="CollectionNativeTypeMustHaveRequiredShapeMessage" xml:space="preserve">
- <value>The native type '{0}' must be a value type and have a constructor that takes two parameters, one of type '{1}' and an 'int', or have a parameterless instance method named 'ToManaged' that returns '{1}' as well as a 'ManagedValues' property of type 'Span&lt;T&gt;' for some 'T' and a 'NativeValueStorage' property of type 'Span&lt;byte&gt;'</value>
- </data>
<data name="ConfigurationNotSupportedDescription" xml:space="preserve">
<value>Source-generated P/Invokes will ignore any configuration that is not supported.</value>
</data>
@@ -178,7 +160,7 @@
<value>Specified configuration is not supported by source-generated P/Invokes.</value>
</data>
<data name="ConstantAndElementCountInfoDisallowed" xml:space="preserve">
- <value>Only one of 'ConstantElementCount' or 'ElementCountInfo' may be used in a 'MarshalUsingAttribute' for a given 'ElementIndirectionLevel'</value>
+ <value>Only one of 'ConstantElementCount' or 'ElementCountInfo' may be used in a 'MarshalUsingAttribute' for a given 'ElementIndirectionDepth'</value>
</data>
<data name="ConvertNoPreserveSigDllImportToGeneratedMayProduceInvalidCode" xml:space="preserve">
<value>Automatically converting a P/Invoke with 'PreserveSig' set to 'false' to a source-generated P/Invoke may produce invalid code</value>
@@ -245,14 +227,23 @@
<data name="InvalidStringMarshallingConfigurationNotCustom" xml:space="preserve">
<value>'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified.</value>
</data>
- <data name="MarshallerGetPinnableReferenceRequiresValuePropertyDescription" xml:space="preserve">
- <value>The use cases for 'GetPinnableReference' are not applicable in any scenarios where a 'Value' property is not also required.</value>
+ <data name="MarshallerGetPinnableReferenceRequiresTwoStageMarshallingDescription" xml:space="preserve">
+ <value>The use cases for 'GetPinnableReference' are not applicable in any scenarios where 'TwoStageMarshalling' is not also required.</value>
+ </data>
+ <data name="MarshallerGetPinnableReferenceRequiresTwoStageMarshallingMessage" xml:space="preserve">
+ <value>The 'GetPinnableReference' method cannot be provided on the native type '{0}' unless the 'TwoStageMarshalling' feature is also supported</value>
+ </data>
+ <data name="MarshallerKindMustBeValidDescription" xml:space="preserve">
+ <value>The specified marshaller kind must be a valid value of the 'System.Runtime.InteropServices.CustomMarshallerKind' enum.</value>
+ </data>
+ <data name="MarshallerKindMustBeValidMessage" xml:space="preserve">
+ <value>The specified custom marshaller kind for '{0}' is invalid</value>
</data>
- <data name="MarshallerGetPinnableReferenceRequiresValuePropertyMessage" xml:space="preserve">
- <value>The 'GetPinnableReference' method cannot be provided on the native type '{0}' unless a 'Value' property is also provided</value>
+ <data name="MarshallerTypeMustSpecifyManagedTypeDescription" xml:space="preserve">
+ <value>A type with a 'System.Runtime.InteropServices.CustomTypeMarshallerAttribute' must specify a managed type</value>
</data>
- <data name="NativeGenericTypeMustBeClosedDescription" xml:space="preserve">
- <value>The native type '{0}' must be a closed generic so the emitted code can use a specific instantiation.</value>
+ <data name="MarshallerTypeMustSpecifyManagedTypeMessage" xml:space="preserve">
+ <value>The type '{0}' does not specify a managed type in the 'System.Runtime.InteropServices.CustomTypeMarshallerAttribute' applied to the type</value>
</data>
<data name="NativeGenericTypeMustBeClosedOrMatchArityDescription" xml:space="preserve">
<value>The native type '{0}' must be a closed generic or have the same number of generic parameters as the managed type so the emitted code can use a specific instantiation.</value>
@@ -261,16 +252,10 @@
<value>The native type '{0}' for managed type '{1}' must be a closed generic type or have the same arity as the managed type.</value>
</data>
<data name="NativeTypeMustBeBlittableDescription" xml:space="preserve">
- <value>A native type for a given type must be blittable.</value>
+ <value>A native type must be blittable.</value>
</data>
<data name="NativeTypeMustBeBlittableMessage" xml:space="preserve">
- <value>The native type '{0}' for the type '{1}' is not blittable</value>
- </data>
- <data name="NativeTypeMustBeNonNullDescription" xml:space="preserve">
- <value>A native type for a given type must be non-null.</value>
- </data>
- <data name="NativeTypeMustBeNonNullMessage" xml:space="preserve">
- <value>The native type for the type '{0}' is null</value>
+ <value>The native type '{0}' for type '{1}' must be blittable</value>
</data>
<data name="NativeTypeMustBePointerSizedDescription" xml:space="preserve">
<value>The native type must be pointer sized so the pinned result of 'GetPinnableReference' can be cast to the native type.</value>
@@ -278,21 +263,24 @@
<data name="NativeTypeMustBePointerSizedMessage" xml:space="preserve">
<value>The native type '{0}' must be pointer sized because the managed type '{1}' has a 'GetPinnableReference' method</value>
</data>
- <data name="NativeTypeMustHaveRequiredShapeDescription" xml:space="preserve">
- <value>The native type must have at least one of the two marshalling methods to enable marshalling the managed type.</value>
+ <data name="NativeTypeMustHaveCustomTypeMarshallerAttributeDescription" xml:space="preserve">
+ <value>A native type for a given type must have the 'System.Runtime.InteropServices.CustomTypeMarshallerAttribute' that specifies this type as the managed type.</value>
+ </data>
+ <data name="NativeTypeMustHaveCustomTypeMarshallerAttributeMessage" xml:space="preserve">
+ <value>The native type for the type '{0}' must be a type with the 'System.Runtime.InteropServices.CustomTypeMarshallerAttribute' that specifies this type as the managed type</value>
+ </data>
+ <data name="CustomMarshallerTypeMustSupportDirectionDescription" xml:space="preserve">
+ <value>A native must set the 'Direction' property on the 'CustomTypeMarshallerAttribute' to a value that sets at least one known flag value on the 'CustomTypeMarshallerDirection' enum</value>
</data>
- <data name="NativeTypeMustHaveRequiredShapeMessage" xml:space="preserve">
- <value>The native type '{0}' must be a value type and have a constructor that takes one parameter of type '{1}' or a parameterless instance method named 'ToManaged' that returns '{1}'</value>
+ <data name="CustomMarshallerTypeMustSupportDirectionMessage" xml:space="preserve">
+ <value>The native type '{0}' must set the 'Direction' property on the 'CustomTypeMarshallerAttribute' to a value that sets at least one known flag value on the 'CustomTypeMarshallerDirection' enum</value>
</data>
- <data name="RefValuePropertyUnsupportedDescription" xml:space="preserve">
+ <data name="RefNativeValueUnsupportedDescription" xml:space="preserve">
<value>The 'Value' property must not be a 'ref' or 'readonly ref' property.</value>
</data>
- <data name="RefValuePropertyUnsupportedMessage" xml:space="preserve">
+ <data name="RefNativeValueUnsupportedMessage" xml:space="preserve">
<value>The 'Value' property on the native type '{0}' must not be a 'ref' or 'readonly ref' property.</value>
</data>
- <data name="RuntimeMarshallingMustBeDisabled" xml:space="preserve">
- <value />
- </data>
<data name="SafeHandleByRefMustBeConcrete" xml:space="preserve">
<value>An abstract type derived from 'SafeHandle' cannot be marshalled by reference. The provided type must be concrete.</value>
</data>
@@ -329,16 +317,124 @@
<data name="TypeNotSupportedTitle" xml:space="preserve">
<value>Specified type is not supported by source-generated P/Invokes</value>
</data>
- <data name="ValuePropertyMustHaveGetterDescription" xml:space="preserve">
- <value>The native type's 'Value' property must have a getter to support marshalling from managed to native.</value>
+ <data name="InTwoStageMarshallingRequiresToNativeValueDescription" xml:space="preserve">
+ <value>The 'TwoStageMarshalling' feature requires a 'TNativeType ToNativeValue()' method for the 'In' direction.</value>
+ </data>
+ <data name="InTwoStageMarshallingRequiresToNativeValueMessage" xml:space="preserve">
+ <value>The marshaller type '{0}' supports marshalling in the 'In' direction with the 'TwoStageMarshalling' feature must provide a 'ToNativeValue' instance method that returns the native value</value>
+ </data>
+ <data name="OutTwoStageMarshallingRequiresFromNativeValueDescription" xml:space="preserve">
+ <value>The 'TwoStageMarshalling' feature requires a 'void FromNativeValue(TNativeType value)' method for the 'Out' direction.</value>
+ </data>
+ <data name="OutTwoStageMarshallingRequiresFromNativeValueMessage" xml:space="preserve">
+ <value>The marshaller type '{0}' supports marshalling in the 'Out' direction with the 'TwoStageMarshalling' feature, but it does not provide a 'FromNativeValue' instance method that returns 'void' and takes one parameter.</value>
+ </data>
+ <data name="CustomTypeMarshallerAttributeMustBeValidDescription" xml:space="preserve">
+ <value>The 'CustomTypeMarshallerAttribute' attribute must be semantically valid</value>
+ </data>
+ <data name="CustomTypeMarshallerAttributeMustBeValidMessage" xml:space="preserve">
+ <value>The 'CustomTypeMarshallerAttribute' on '{0}' is semantically invalid</value>
+ </data>
+ <data name="LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorDescription" xml:space="preserve">
+ <value>A 'LinearCollection'-kind native type that supports the 'CallerAllocatedBuffer' feature must provide a three-parameter constructor taking the managed type as the first parameter, a 'Span&lt;byte&gt;' as the second parameter, and the native size of the element as the third parameter</value>
+ </data>
+ <data name="LinearCollectionInCallerAllocatedBufferRequiresSpanConstructorMessage" xml:space="preserve">
+ <value>The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a three-parameter constructor that takes a '{1}' , a 'Span&lt;byte&gt;', and an 'int'</value>
+ </data>
+ <data name="LinearCollectionInRequiresTwoParameterConstructorDescription" xml:space="preserve">
+ <value>A 'LinearCollection'-kind native type must provide a two-parameter constructor taking the managed type as the first parameter and the native size of the element as the second parameter</value>
+ </data>
+ <data name="LinearCollectionInRequiresTwoParameterConstructorMessage" xml:space="preserve">
+ <value>The type '{0}' specifies that it supports 'In' marshalling of '{1}' but does not provide a two-parameter constructor that takes a '{1}' as the first parameter and an 'int' as the second parameter</value>
+ </data>
+ <data name="MarshallerDirectionMustBeValidDescription" xml:space="preserve">
+ <value>The specified marshaller direction must be a valid value of the 'System.Runtime.InteropServices.CustomMarshallerDirection' enum.</value>
+ </data>
+ <data name="MarshallerDirectionMustBeValidMessage" xml:space="preserve">
+ <value>The specified custom marshaller direction for '{0}' is invalid</value>
+ </data>
+ <data name="ValueInCallerAllocatedBufferRequiresSpanConstructorDescription" xml:space="preserve">
+ <value>A 'Value'-kind native type that supports the 'CallerAllocatedBuffer' feature must provide a two-parameter constructor taking the managed type and a 'Span&lt;byte&gt;' as parameters</value>
+ </data>
+ <data name="ValueInCallerAllocatedBufferRequiresSpanConstructorMessage" xml:space="preserve">
+ <value>The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span&lt;byte&gt;' as parameters</value>
+ </data>
+ <data name="ValueInRequiresOneParameterConstructorDescription" xml:space="preserve">
+ <value>A 'Value'-kind native type must provide a one-parameter constructor taking the managed type as a parameter</value>
+ </data>
+ <data name="ValueInRequiresOneParameterConstructorMessage" xml:space="preserve">
+ <value>The type '{0}' specifies that it supports 'In' marshalling of '{1}' but does not provide a one-parameter constructor that takes a '{1}' as a parameter</value>
+ </data>
+ <data name="LinearCollectionInRequiresCollectionMethodsDescription" xml:space="preserve">
+ <value>A 'LinearCollection'-kind native type that supports marshalling in the 'In' direction must provide a 'GetManagedValuesSource' that returns a 'ReadOnlySpan&lt;&gt;' and a 'GetNativeValuesDestination' method that returns a 'Span&lt;byte&gt;'.</value>
+ </data>
+ <data name="LinearCollectionInRequiresCollectionMethodsMessage" xml:space="preserve">
+ <value>The type '{0}' specifies that is supports marshalling in the 'In' direction, but it does not provide a 'GetManagedValuesSource' that returns a 'ReadOnlySpan&lt;&gt;' and a 'GetNativeValuesDestination' method that returns a 'Span&lt;byte&gt;'</value>
+ </data>
+ <data name="OutRequiresToManagedDescription" xml:space="preserve">
+ <value>A 'Value' or 'LinearCollection'-kind native type that supports marshalling in the 'Out' direction must provide a 'ToManaged' method that returns the managed type.</value>
+ </data>
+ <data name="OutRequiresToManagedMessage" xml:space="preserve">
+ <value>The type '{0}' specifies it supports marshalling in the 'Out' direction, but it does not provide a 'ToManaged' method that returns the managed type</value>
+ </data>
+ <data name="LinearCollectionOutRequiresCollectionMethodsDescription" xml:space="preserve">
+ <value>A 'LinearCollection'-kind native type that supports marshalling in the 'Out' direction must provide a 'GetManagedValuesDestination' that takes an 'int' and returns a 'Span&lt;&gt;' and a 'GetNativeValuesSource' method that takes an 'int' and rreturns a 'ReadOnlySpan&lt;byte&gt;'.</value>
+ </data>
+ <data name="LinearCollectionOutRequiresCollectionMethodsMessage" xml:space="preserve">
+ <value>The type '{0}' specifies that it supports marshalling in the 'Out' direction, but it does not provide a 'GetManagedValuesDestination' that takes an 'int' and returns a 'Span&lt;&gt;' and a 'GetNativeValuesSource' method that takes an 'int' and rreturns a 'ReadOnlySpan&lt;byte&gt;'</value>
+ </data>
+ <data name="LinearCollectionOutRequiresIntConstructorDescription" xml:space="preserve">
+ <value>A 'LinearCollection'-kind native type that supports marshalling in the 'Out' direction must provide a constructor that takes the size of the native element as an 'int'.</value>
+ </data>
+ <data name="LinearCollectionOutRequiresIntConstructorMessage" xml:space="preserve">
+ <value>The type '{0}' specifies that it supports marshalling in the 'Out' direction, but it does not provide a constructor that takes the size of the native element as an 'int'.</value>
+ </data>
+ <data name="UnmanagedResourcesRequiresFreeNativeDescription" xml:space="preserve">
+ <value>The 'UnmanagedResources' feature requires a 'void FreeNative()' method.</value>
+ </data>
+ <data name="UnmanagedResourcesRequiresFreeNativeMessage" xml:space="preserve">
+ <value>The marshaller type '{0}' supports marshalling with the 'UnmanagedResources' feature, but it does not provide a parameterless 'FreeNative' instance method that returns 'void'</value>
+ </data>
+ <data name="AddMissingCustomTypeMarshallerMembers" xml:space="preserve">
+ <value>Add missing custom type marshaller members</value>
+ </data>
+ <data name="AddMissingFeaturesToCustomTypeMarshaller" xml:space="preserve">
+ <value>Add missing features to the 'CustomTypeMarshallerAttribute' attribute</value>
+ </data>
+ <data name="CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureDescription" xml:space="preserve">
+ <value>A marshaller type that provides a constructor taking a caller-allocated 'Span&lt;byte&gt;' should specify that it supports the 'CallerAllocatedBuffer' feature.</value>
+ </data>
+ <data name="CallerAllocatedBufferConstructorProvidedShouldSpecifyFeatureMessage" xml:space="preserve">
+ <value>The type '{0}' provides a constructor taking a caller-allocated 'Span&lt;byte&gt;' but does not specify that it supports the 'CallerAllocatedBuffer' feature. The constructor will not be used unless the feature is specified.</value>
+ </data>
+ <data name="FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureDescription" xml:space="preserve">
+ <value>A marshaller type that provides a 'FreeNative' method should specify that it supports the 'UnmanagedResources' feature.</value>
+ </data>
+ <data name="FreeNativeMethodProvidedShouldSpecifyUnmanagedResourcesFeatureMessage" xml:space="preserve">
+ <value>The type '{0}' provides a 'FreeNative' method but does not specify that it supports the 'UnmanagedResources' feature. The method will not be used unless the feature is specified.</value>
+ </data>
+ <data name="FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription" xml:space="preserve">
+ <value>A marshaller type that provides a 'FromNativeValue' method should specify that it supports the 'TwoStageMarshalling' feature.</value>
+ </data>
+ <data name="FromNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage" xml:space="preserve">
+ <value>The type '{0}' provides a 'FromNativeValue' method but does not specify that it supports the 'TwoStageMarshalling' feature. The method will not be used unless the feature is specified.</value>
+ </data>
+ <data name="LinearCollectionElementTypesMustMatchDescription" xml:space="preserve">
+ <value>The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'.</value>
+ </data>
+ <data name="LinearCollectionElementTypesMustMatchMessage" xml:space="preserve">
+ <value>The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'</value>
+ </data>
+ <data name="ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureDescription" xml:space="preserve">
+ <value>A marshaller type that provides a 'ToNativeValue' method should specify that it supports the 'TwoStageMarshalling' feature.</value>
</data>
- <data name="ValuePropertyMustHaveGetterMessage" xml:space="preserve">
- <value>The 'Value' property on the native type '{0}' must have a getter</value>
+ <data name="ToNativeValueMethodProvidedShouldSpecifyTwoStageMarshallingFeatureMessage" xml:space="preserve">
+ <value>The type '{0}' provides a 'ToNativeValue' method but does not specify that it supports the 'TwoStageMarshalling' feature. The method will not be used unless the feature is specified.</value>
</data>
- <data name="ValuePropertyMustHaveSetterDescription" xml:space="preserve">
- <value>The native type's 'Value' property must have a setter to support marshalling from native to managed.</value>
+ <data name="TwoStageMarshallingNativeTypesMustMatchDescription" xml:space="preserve">
+ <value>The return type of 'ToNativeValue' and the parameter type of 'FromNativeValue' must be the same.</value>
</data>
- <data name="ValuePropertyMustHaveSetterMessage" xml:space="preserve">
- <value>The 'Value' property on the native type '{0}' must have a setter</value>
+ <data name="TwoStageMarshallingNativeTypesMustMatchMessage" xml:space="preserve">
+ <value>The return type of 'ToNativeValue' and the parameter type of 'FromNativeValue' must be the same</value>
</data>
</root> \ No newline at end of file
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs
index f1df80186c8..3af27467e7f 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs
@@ -38,7 +38,7 @@ namespace Microsoft.Interop
{
SyntaxReference? syntaxReference = attributeData.ApplicationSyntaxReference;
Location location = syntaxReference is not null
- ? syntaxReference.GetSyntax().GetLocation()
+ ? syntaxReference.SyntaxTree.GetLocation(syntaxReference.Span)
: Location.None;
return location.CreateDiagnostic(descriptor, args);
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ContiguousCollectionElementMarshallingCodeContext.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/LinearCollectionElementMarshallingCodeContext.cs
index 02d965c9f29..442c3ab55e3 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ContiguousCollectionElementMarshallingCodeContext.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/LinearCollectionElementMarshallingCodeContext.cs
@@ -3,8 +3,9 @@
namespace Microsoft.Interop
{
- internal sealed class ContiguousCollectionElementMarshallingCodeContext : StubCodeContext
+ internal sealed class LinearCollectionElementMarshallingCodeContext : StubCodeContext
{
+ private readonly string _managedSpanIdentifier;
private readonly string _nativeSpanIdentifier;
public override bool SingleFrameSpansNativeContext => false;
@@ -20,13 +21,15 @@ namespace Microsoft.Interop
/// <param name="indexerIdentifier">The indexer in the loop to get the element to marshal from the collection.</param>
/// <param name="nativeSpanIdentifier">The identifier of the native value storage cast to the target element type.</param>
/// <param name="parentContext">The parent context.</param>
- public ContiguousCollectionElementMarshallingCodeContext(
+ public LinearCollectionElementMarshallingCodeContext(
Stage currentStage,
+ string managedSpanIdentifier,
string nativeSpanIdentifier,
StubCodeContext parentContext)
{
CurrentStage = currentStage;
IndexerIdentifier = CalculateIndexerIdentifierBasedOnParentContext(parentContext);
+ _managedSpanIdentifier = managedSpanIdentifier;
_nativeSpanIdentifier = nativeSpanIdentifier;
ParentContext = parentContext;
}
@@ -38,9 +41,8 @@ namespace Microsoft.Interop
/// <returns>Managed and native identifiers</returns>
public override (string managed, string native) GetIdentifiers(TypePositionInfo info)
{
- (string _, string native) = ParentContext!.GetIdentifiers(info);
return (
- $"{native}.ManagedValues[{IndexerIdentifier}]",
+ $"{_managedSpanIdentifier}[{IndexerIdentifier}]",
$"{_nativeSpanIdentifier}[{IndexerIdentifier}]"
);
}
@@ -55,7 +57,7 @@ namespace Microsoft.Interop
int i = 0;
while (parentContext is StubCodeContext context)
{
- if (context is ContiguousCollectionElementMarshallingCodeContext)
+ if (context is LinearCollectionElementMarshallingCodeContext)
{
i++;
}
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 b6343bb5d23..3b190b6ad04 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
@@ -2,39 +2,172 @@
// 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(CustomTypeMarshallerKind Kind, CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures Features, int? BufferSize);
+
+ public static class ShapeMemberNames
+ {
+ 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
{
- public const string ValuePropertyName = "Value";
- public const string GetPinnableReferenceName = "GetPinnableReference";
- public const string BufferSizeFieldName = "BufferSize";
- public const string RequiresStackBufferFieldName = "RequiresStackBuffer";
- public const string ToManagedMethodName = "ToManaged";
- public const string FreeNativeMethodName = "FreeNative";
- public const string ManagedValuesPropertyName = "ManagedValues";
- public const string NativeValueStoragePropertyName = "NativeValueStorage";
- public const string SetUnmarshalledCollectionLengthMethodName = "SetUnmarshalledCollectionLength";
+ public static class CustomMarshallerAttributeFields
+ {
+ public const string BufferSize = nameof(BufferSize);
+ public const string Direction = nameof(Direction);
+ public const string Features = nameof(Features);
+ }
public static class MarshalUsingProperties
{
- public const string ElementIndirectionLevel = nameof(ElementIndirectionLevel);
+ public const string ElementIndirectionDepth = nameof(ElementIndirectionDepth);
public const string CountElementName = nameof(CountElementName);
public const string ConstantElementCount = nameof(ConstantElementCount);
}
- public enum NativeTypeMarshallingVariant
+ public static (bool hasAttribute, ITypeSymbol? managedType, CustomTypeMarshallerData? kind) GetMarshallerShapeInfo(ITypeSymbol marshallerType)
{
- Standard,
- ContiguousCollection
+ 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(kind, direction, features, bufferSize));
+ }
+
+ /// <summary>
+ /// Resolve a non-<see cref="INamedTypeSymbol"/> <paramref name="managedType"/> to the correct managed type if <paramref name="marshallerType"/> is generic and <paramref name="managedType"/> is using any placeholder types.
+ /// </summary>
+ /// <param name="managedType">The non-named managed type.</param>
+ /// <param name="marshallerType">The marshaller type.</param>
+ /// <param name="compilation">The compilation to use to make new type symbols.</param>
+ /// <returns>The resolved managed type, or <paramref name="managedType"/> if the provided type did not have any placeholders.</returns>
+ public static ITypeSymbol? ResolveManagedType(ITypeSymbol? managedType, INamedTypeSymbol marshallerType, Compilation compilation)
+ {
+ if (managedType is null || !marshallerType.IsGenericType)
+ {
+ return managedType;
+ }
+ Stack<ITypeSymbol> typeStack = new();
+ ITypeSymbol? innerType = managedType;
+ while (innerType.TypeKind is TypeKind.Array or TypeKind.Pointer)
+ {
+ if (innerType is IArrayTypeSymbol array)
+ {
+ typeStack.Push(innerType);
+ innerType = array.ElementType;
+ }
+ else if (innerType is IPointerTypeSymbol pointerType)
+ {
+ typeStack.Push(innerType);
+ innerType = pointerType.PointedAtType;
+ }
+ }
+
+ if (innerType.ToDisplayString() != TypeNames.CustomTypeMarshallerAttributeGenericPlaceholder)
+ {
+ return managedType;
+ }
+
+ ITypeSymbol resultType = marshallerType.TypeArguments[0];
+
+ while (typeStack.Count > 0)
+ {
+ ITypeSymbol wrapperType = typeStack.Pop();
+ if (wrapperType.TypeKind == TypeKind.Pointer)
+ {
+ resultType = compilation.CreatePointerTypeSymbol(resultType);
+ }
+ else if (wrapperType.TypeKind == TypeKind.Array)
+ {
+ IArrayTypeSymbol arrayType = (IArrayTypeSymbol)wrapperType;
+ if (arrayType.IsSZArray)
+ {
+ resultType = compilation.CreateArrayTypeSymbol(resultType, arrayType.Rank);
+ }
+ }
+ }
+ return resultType;
+ }
+
+ public static (AttributeData? attribute, INamedTypeSymbol? marshallerType) GetDefaultMarshallerInfo(ITypeSymbol managedType)
+ {
+ AttributeData? attr = managedType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.NativeMarshallingAttribute);
+ if (attr is null)
+ {
+ return (attr, null);
+ }
+ INamedTypeSymbol? marshallerType = null;
+ if (attr.ConstructorArguments.Length == 0)
+ {
+ return (attr, null);
+ }
+
+ marshallerType = attr.ConstructorArguments[0].Value as INamedTypeSymbol;
+ if (managedType is not INamedTypeSymbol namedType || marshallerType is null)
+ {
+ return (attr, null);
+ }
+ if (namedType.TypeArguments.Length == 0)
+ {
+ return (attr, marshallerType);
+ }
+ else if (marshallerType.TypeArguments.Length != namedType.TypeArguments.Length)
+ {
+ return (attr, null);
+ }
+ else if (marshallerType.IsGenericType)
+ {
+ // Construct the marshaler type around the same type arguments as the managed type.
+ return (attr, marshallerType.ConstructedFrom.Construct(namedType.TypeArguments, namedType.TypeArgumentNullableAnnotations));
+ }
+
+ return (attr, marshallerType);
}
public static bool HasToManagedMethod(ITypeSymbol nativeType, ITypeSymbol managedType)
{
- return nativeType.GetMembers(ToManagedMethodName)
+ return nativeType.GetMembers(ShapeMemberNames.Value.ToManaged)
.OfType<IMethodSymbol>()
.Any(m => m.Parameters.IsEmpty
&& !m.ReturnsByRef
@@ -46,9 +179,9 @@ namespace Microsoft.Interop
public static bool IsManagedToNativeConstructor(
IMethodSymbol ctor,
ITypeSymbol managedType,
- NativeTypeMarshallingVariant variant)
+ CustomTypeMarshallerKind variant)
{
- if (variant == NativeTypeMarshallingVariant.ContiguousCollection)
+ if (variant == CustomTypeMarshallerKind.LinearCollection)
{
return ctor.Parameters.Length == 2
&& SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type)
@@ -62,9 +195,9 @@ namespace Microsoft.Interop
IMethodSymbol ctor,
ITypeSymbol managedType,
ITypeSymbol spanOfByte,
- NativeTypeMarshallingVariant variant)
+ CustomTypeMarshallerKind variant)
{
- if (variant == NativeTypeMarshallingVariant.ContiguousCollection)
+ if (variant == CustomTypeMarshallerKind.LinearCollection)
{
return ctor.Parameters.Length == 3
&& SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type)
@@ -82,66 +215,81 @@ namespace Microsoft.Interop
// fixed statement. We aren't supporting a GetPinnableReference extension method
// (which is apparently supported in the compiler).
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/pattern-based-fixed
- return type.GetMembers(GetPinnableReferenceName)
+ return type.GetMembers(ShapeMemberNames.Value.GetPinnableReference)
.OfType<IMethodSymbol>()
- .FirstOrDefault(m => m is { Parameters: { Length: 0 } } and
+ .FirstOrDefault(m => m is { Parameters.Length: 0 } and
({ ReturnsByRef: true } or { ReturnsByRefReadonly: true }));
}
- public static IPropertySymbol? FindValueProperty(ITypeSymbol type)
+ public static bool HasFreeNativeMethod(ITypeSymbol type)
{
- return type.GetMembers(ValuePropertyName)
- .OfType<IPropertySymbol>()
- .FirstOrDefault(p => !p.IsStatic);
+ return type.GetMembers(ShapeMemberNames.Value.FreeNative)
+ .OfType<IMethodSymbol>()
+ .Any(m => m is { IsStatic: false, Parameters.Length: 0, ReturnType.SpecialType: SpecialType.System_Void });
}
- public static bool HasFreeNativeMethod(ITypeSymbol type)
+ public static IMethodSymbol? FindToNativeValueMethod(ITypeSymbol type)
{
- return type.GetMembers(FreeNativeMethodName)
+ return type.GetMembers(ShapeMemberNames.Value.ToNativeValue)
.OfType<IMethodSymbol>()
- .Any(m => m is { IsStatic: false, Parameters: { Length: 0 }, ReturnType: { SpecialType: SpecialType.System_Void } });
+ .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0 });
}
- public static bool TryGetManagedValuesProperty(ITypeSymbol type, out IPropertySymbol managedValuesProperty)
+ public static IMethodSymbol? FindFromNativeValueMethod(ITypeSymbol type)
{
- managedValuesProperty = type
- .GetMembers(ManagedValuesPropertyName)
- .OfType<IPropertySymbol>()
- .FirstOrDefault(p => p is { IsStatic: false, GetMethod: not null, ReturnsByRef: false, ReturnsByRefReadonly: false });
- return managedValuesProperty is not null;
+ return type.GetMembers(ShapeMemberNames.Value.FromNativeValue)
+ .OfType<IMethodSymbol>()
+ .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 1, ReturnType.SpecialType: SpecialType.System_Void });
}
- public static bool TryGetElementTypeFromContiguousCollectionMarshaller(ITypeSymbol type, out ITypeSymbol elementType)
+ public static bool TryGetElementTypeFromLinearCollectionMarshaller(ITypeSymbol type, ITypeSymbol readOnlySpanOfT, out ITypeSymbol elementType)
{
- if (!TryGetManagedValuesProperty(type, out IPropertySymbol managedValuesProperty))
+ if (FindGetManagedValuesSourceMethod(type, readOnlySpanOfT) is not IMethodSymbol managedValuesSourceMethod)
{
elementType = null!;
return false;
}
- elementType = ((INamedTypeSymbol)managedValuesProperty.Type).TypeArguments[0];
+ elementType = ((INamedTypeSymbol)managedValuesSourceMethod.ReturnType).TypeArguments[0];
return true;
}
- public static bool HasSetUnmarshalledCollectionLengthMethod(ITypeSymbol type)
+ public static IMethodSymbol? FindGetManagedValuesSourceMethod(ITypeSymbol type, ITypeSymbol readOnlySpanOfT)
{
- return type.GetMembers(SetUnmarshalledCollectionLengthMethodName)
+ return type
+ .GetMembers(ShapeMemberNames.LinearCollection.GetManagedValuesSource)
.OfType<IMethodSymbol>()
- .Any(m => m is
- {
- IsStatic: false,
- Parameters: { Length: 1 },
- ReturnType: { SpecialType: SpecialType.System_Void }
- } && m.Parameters[0].Type.SpecialType == SpecialType.System_Int32);
+ .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 bool HasNativeValueStorageProperty(ITypeSymbol type, ITypeSymbol spanOfByte)
+ public static IMethodSymbol? FindGetManagedValuesDestinationMethod(ITypeSymbol type, ITypeSymbol spanOfT)
{
return type
- .GetMembers(NativeValueStoragePropertyName)
- .OfType<IPropertySymbol>()
- .Any(p => p is { IsStatic: false, GetMethod: not null, ReturnsByRef: false, ReturnsByRefReadonly: false }
- && SymbolEqualityComparer.Default.Equals(p.Type, spanOfByte));
+ .GetMembers(ShapeMemberNames.LinearCollection.GetManagedValuesDestination)
+ .OfType<IMethodSymbol>()
+ .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.LinearCollection.GetNativeValuesDestination)
+ .OfType<IMethodSymbol>()
+ .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.LinearCollection.GetNativeValuesSource)
+ .OfType<IMethodSymbol>()
+ .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/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs
index 7b28fa14f2a..f3aac5de6a7 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
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -47,8 +48,8 @@ namespace Microsoft.Interop
return info.MarshallingAttributeInfo switch
{
NativeMarshallingAttributeInfo marshalInfo when Options.RuntimeMarshallingDisabled => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
- NativeMarshallingAttributeInfo { ValuePropertyType: SpecialTypeInfo specialType } marshalInfo when specialType.SpecialType.IsAlwaysBlittable() => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
- NativeMarshallingAttributeInfo { ValuePropertyType: PointerTypeInfo } marshalInfo => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
+ NativeMarshallingAttributeInfo { NativeValueType: SpecialTypeInfo specialType } marshalInfo when specialType.SpecialType.IsAlwaysBlittable() => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
+ NativeMarshallingAttributeInfo { NativeValueType: PointerTypeInfo } marshalInfo => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
UnmanagedBlittableMarshallingInfo when Options.RuntimeMarshallingDisabled => s_blittable,
UnmanagedBlittableMarshallingInfo or NativeMarshallingAttributeInfo when !Options.RuntimeMarshallingDisabled =>
throw new MarshallingNotSupportedException(info, context)
@@ -93,7 +94,7 @@ namespace Microsoft.Interop
for (int i = 0; i < numIndirectionLevels; i++)
{
- if (marshallingInfo is NativeContiguousCollectionMarshallingInfo collectionInfo)
+ if (marshallingInfo is NativeLinearCollectionMarshallingInfo collectionInfo)
{
type = collectionInfo.ElementType;
marshallingInfo = collectionInfo.ElementMarshallingInfo;
@@ -129,7 +130,7 @@ namespace Microsoft.Interop
while (currentContext is not null)
{
- if (currentContext is ContiguousCollectionElementMarshallingCodeContext collectionContext)
+ if (currentContext is LinearCollectionElementMarshallingCodeContext collectionContext)
{
indexerStack.Push(collectionContext.IndexerIdentifier);
}
@@ -157,30 +158,34 @@ namespace Microsoft.Interop
ICustomNativeTypeMarshallingStrategy marshallingStrategy = new SimpleCustomNativeTypeMarshalling(marshalInfo.NativeMarshallingType.Syntax);
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNativeStackalloc) != 0)
+ if ((marshalInfo.MarshallingFeatures & CustomTypeMarshallerFeatures.CallerAllocatedBuffer) != 0)
{
- marshallingStrategy = new StackallocOptimizationMarshalling(marshallingStrategy);
+ if (marshalInfo.BufferSize is null)
+ {
+ throw new MarshallingNotSupportedException(info, context);
+ }
+ marshallingStrategy = new StackallocOptimizationMarshalling(marshallingStrategy, marshalInfo.BufferSize.Value);
}
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.FreeNativeResources) != 0)
+ if ((marshalInfo.MarshallingFeatures & CustomTypeMarshallerFeatures.UnmanagedResources) != 0)
{
marshallingStrategy = new FreeNativeCleanupStrategy(marshallingStrategy);
}
// Collections have extra configuration, so handle them here.
- if (marshalInfo is NativeContiguousCollectionMarshallingInfo collectionMarshallingInfo)
+ if (marshalInfo is NativeLinearCollectionMarshallingInfo collectionMarshallingInfo)
{
return CreateNativeCollectionMarshaller(info, context, collectionMarshallingInfo, marshallingStrategy);
}
- if (marshalInfo.ValuePropertyType is not null)
+ if (marshalInfo.NativeValueType is not null)
{
- marshallingStrategy = DecorateWithValuePropertyStrategy(marshalInfo, marshallingStrategy);
+ marshallingStrategy = DecorateWithTwoStageMarshallingStrategy(marshalInfo, marshallingStrategy);
}
IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false);
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedTypePinning) != 0)
+ if (marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.ManagedType))
{
return new PinnableManagedValueMarshaller(marshallingGenerator);
}
@@ -193,7 +198,7 @@ namespace Microsoft.Interop
// 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.MarshallingFeatures & CustomMarshallingFeatures.NativeToManaged) == 0)
+ && !marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.Out))
{
throw new MarshallingNotSupportedException(info, context)
{
@@ -203,8 +208,10 @@ namespace Microsoft.Interop
// 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.
else if (!info.IsByRef
- && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0
- && (context.SingleFrameSpansNativeContext && (marshalInfo.MarshallingFeatures & (CustomMarshallingFeatures.ManagedTypePinning | CustomMarshallingFeatures.ManagedToNativeStackalloc)) == 0))
+ && context.SingleFrameSpansNativeContext
+ && !(marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.ManagedType)
+ || marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.CallerAllocatedBuffer)
+ || marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.In)))
{
throw new MarshallingNotSupportedException(info, context)
{
@@ -215,8 +222,8 @@ namespace Microsoft.Interop
// but our scenario requires marshalling from managed to native by reference.
// "in" byref supports stack marshalling.
else if (info.RefKind == RefKind.In
- && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0
- && !(context.SingleFrameSpansNativeContext && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNativeStackalloc) != 0))
+ && !(context.SingleFrameSpansNativeContext && marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.CallerAllocatedBuffer))
+ && !marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.In))
{
throw new MarshallingNotSupportedException(info, context)
{
@@ -226,8 +233,9 @@ namespace Microsoft.Interop
// 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
else if (info.RefKind == RefKind.Ref
- && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0)
+ && !marshalInfo.Direction.HasFlag(CustomTypeMarshallerDirection.In))
{
throw new MarshallingNotSupportedException(info, context)
{
@@ -236,57 +244,57 @@ namespace Microsoft.Interop
}
}
- private ICustomNativeTypeMarshallingStrategy DecorateWithValuePropertyStrategy(NativeMarshallingAttributeInfo marshalInfo, ICustomNativeTypeMarshallingStrategy nativeTypeMarshaller)
+ private ICustomNativeTypeMarshallingStrategy DecorateWithTwoStageMarshallingStrategy(NativeMarshallingAttributeInfo marshalInfo, ICustomNativeTypeMarshallingStrategy nativeTypeMarshaller)
{
- TypeSyntax valuePropertyTypeSyntax = marshalInfo.ValuePropertyType!.Syntax;
+ TypeSyntax valuePropertyTypeSyntax = marshalInfo.NativeValueType!.Syntax;
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.NativeTypePinning) != 0)
+ if (marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.NativeType) && marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.TwoStageMarshalling))
{
return new PinnableMarshallerTypeMarshalling(nativeTypeMarshaller, valuePropertyTypeSyntax);
}
- return new CustomNativeTypeWithValuePropertyMarshalling(nativeTypeMarshaller, valuePropertyTypeSyntax);
+ return new CustomNativeTypeWithToFromNativeValueMarshalling(nativeTypeMarshaller, valuePropertyTypeSyntax);
}
private IMarshallingGenerator CreateNativeCollectionMarshaller(
TypePositionInfo info,
StubCodeContext context,
- NativeContiguousCollectionMarshallingInfo collectionInfo,
+ NativeLinearCollectionMarshallingInfo collectionInfo,
ICustomNativeTypeMarshallingStrategy marshallingStrategy)
{
var elementInfo = new TypePositionInfo(collectionInfo.ElementType, collectionInfo.ElementMarshallingInfo) { ManagedIndex = info.ManagedIndex };
IMarshallingGenerator elementMarshaller = _elementMarshallingGenerator.Create(
elementInfo,
- new ContiguousCollectionElementMarshallingCodeContext(StubCodeContext.Stage.Setup, string.Empty, context));
+ new LinearCollectionElementMarshallingCodeContext(StubCodeContext.Stage.Setup, string.Empty, string.Empty, context));
TypeSyntax elementType = elementMarshaller.AsNativeType(elementInfo);
+
+ 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 isBlittable = elementMarshaller is BlittableMarshaller;
if (isBlittable)
{
- marshallingStrategy = new ContiguousBlittableElementCollectionMarshalling(marshallingStrategy, collectionInfo.ElementType.Syntax);
+ marshallingStrategy = new LinearCollectionWithBlittableElementsMarshalling(marshallingStrategy, collectionInfo.ElementType.Syntax, numElementsExpression);
}
else
{
- marshallingStrategy = new ContiguousNonBlittableElementCollectionMarshalling(marshallingStrategy, elementMarshaller, elementInfo);
+ marshallingStrategy = new LinearCollectionWithNonBlittableElementsMarshalling(marshallingStrategy, elementMarshaller, elementInfo, numElementsExpression);
}
// Explicitly insert the Value property handling here (before numElements handling) so that the numElements handling will be emitted before the Value property handling in unmarshalling.
- if (collectionInfo.ValuePropertyType is not null)
- {
- marshallingStrategy = DecorateWithValuePropertyStrategy(collectionInfo, marshallingStrategy);
- }
-
- ExpressionSyntax numElementsExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0));
- if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In))
+ if (collectionInfo.NativeValueType is not null)
{
- // In this case, we need a numElementsExpression supplied from metadata, so we'll calculate it here.
- numElementsExpression = GetNumElementsExpressionFromMarshallingInfo(info, collectionInfo.ElementCountInfo, context);
+ marshallingStrategy = DecorateWithTwoStageMarshallingStrategy(collectionInfo, marshallingStrategy);
}
- marshallingStrategy = new NumElementsExpressionMarshalling(
+ marshallingStrategy = new SizeOfElementMarshalling(
marshallingStrategy,
- numElementsExpression,
SizeOfExpression(elementType));
if (collectionInfo.UseDefaultMarshalling && info.ManagedType is SzArrayType)
@@ -299,7 +307,7 @@ namespace Microsoft.Interop
IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false);
- if ((collectionInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedTypePinning) != 0)
+ if (collectionInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.ManagedType))
{
return new PinnableManagedValueMarshaller(marshallingGenerator);
}
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
index 2160d9f1be3..cb617994e3b 100644
--- 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
@@ -89,7 +89,7 @@ namespace Microsoft.Interop
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nativeIdentifier),
- IdentifierName(ManualTypeMarshallingHelper.ToManagedMethodName)))));
+ IdentifierName(ShapeMemberNames.Value.ToManaged)))));
}
public IEnumerable<ArgumentSyntax> GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context)
@@ -111,9 +111,9 @@ namespace Microsoft.Interop
/// <summary>
/// A context that redefines the 'native' identifier for a TypePositionInfo to be the marshaller identifier.
/// </summary>
- internal class CustomNativeTypeWithValuePropertyStubContext : StubCodeContext
+ internal class CustomNativeTypeWithToFromNativeValueContext : StubCodeContext
{
- public CustomNativeTypeWithValuePropertyStubContext(StubCodeContext parentContext)
+ public CustomNativeTypeWithToFromNativeValueContext(StubCodeContext parentContext)
{
ParentContext = parentContext;
CurrentStage = parentContext.CurrentStage;
@@ -130,22 +130,22 @@ namespace Microsoft.Interop
}
/// <summary>
- /// Marshaller that enables support of a Value property on a native type.
+ /// Marshaller that enables support of ToNativeValue/FromNativeValue methods on a native type.
/// </summary>
- internal sealed class CustomNativeTypeWithValuePropertyMarshalling : ICustomNativeTypeMarshallingStrategy
+ internal sealed class CustomNativeTypeWithToFromNativeValueMarshalling : ICustomNativeTypeMarshallingStrategy
{
private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller;
- private readonly TypeSyntax _valuePropertyType;
+ private readonly TypeSyntax _nativeValueTypeSyntax;
- public CustomNativeTypeWithValuePropertyMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax valuePropertyType)
+ public CustomNativeTypeWithToFromNativeValueMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax nativeValueTypeSyntax)
{
_innerMarshaller = innerMarshaller;
- _valuePropertyType = valuePropertyType;
+ _nativeValueTypeSyntax = nativeValueTypeSyntax;
}
public TypeSyntax AsNativeType(TypePositionInfo info)
{
- return _valuePropertyType;
+ return _nativeValueTypeSyntax;
}
public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context)
@@ -155,14 +155,14 @@ namespace Microsoft.Interop
public IEnumerable<StatementSyntax> GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(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 GenerateValuePropertyAssignment(info, context, subContext);
+ yield return GenerateFromNativeValueInvocation(info, context, subContext);
}
foreach (StatementSyntax statement in _innerMarshaller.GenerateCleanupStatements(info, subContext))
@@ -173,41 +173,42 @@ namespace Microsoft.Interop
public IEnumerable<StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable<ArgumentSyntax> nativeTypeConstructorArguments)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, subContext, nativeTypeConstructorArguments))
{
yield return statement;
}
- // <nativeIdentifier> = <marshalerIdentifier>.Value;
+ // <nativeIdentifier> = <marshalerIdentifier>.ToNativeValue();
yield return ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(context.GetIdentifiers(info).native),
- MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(subContext.GetIdentifiers(info).native),
- IdentifierName(ManualTypeMarshallingHelper.ValuePropertyName))));
+ InvocationExpression(
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(subContext.GetIdentifiers(info).native),
+ IdentifierName(ShapeMemberNames.Value.ToNativeValue)),
+ ArgumentList())));
}
- private StatementSyntax GenerateValuePropertyAssignment(TypePositionInfo info, StubCodeContext context, CustomNativeTypeWithValuePropertyStubContext subContext)
+ private StatementSyntax GenerateFromNativeValueInvocation(TypePositionInfo info, StubCodeContext context, CustomNativeTypeWithToFromNativeValueContext subContext)
{
- // <marshalerIdentifier>.Value = <nativeIdentifier>;
+ // <marshalerIdentifier>.FromNativeValue(<nativeIdentifier>);
return ExpressionStatement(
- AssignmentExpression(
- SyntaxKind.SimpleAssignmentExpression,
+ InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(subContext.GetIdentifiers(info).native),
- IdentifierName(ManualTypeMarshallingHelper.ValuePropertyName)),
- IdentifierName(context.GetIdentifiers(info).native)));
+ IdentifierName(ShapeMemberNames.Value.FromNativeValue)),
+ ArgumentList(SingletonSeparatedList(Argument(IdentifierName(context.GetIdentifiers(info).native))))));
}
public IEnumerable<StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In))
{
- yield return GenerateValuePropertyAssignment(info, context, subContext);
+ yield return GenerateFromNativeValueInvocation(info, context, subContext);
}
foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, subContext))
@@ -218,13 +219,13 @@ namespace Microsoft.Interop
public IEnumerable<ArgumentSyntax> GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
return _innerMarshaller.GetNativeTypeConstructorArguments(info, subContext);
}
public IEnumerable<StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
yield return LocalDeclarationStatement(
VariableDeclaration(
_innerMarshaller.AsNativeType(info),
@@ -240,7 +241,7 @@ namespace Microsoft.Interop
public IEnumerable<StatementSyntax> GeneratePinStatements(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
return _innerMarshaller.GeneratePinStatements(info, subContext);
}
}
@@ -251,10 +252,12 @@ namespace Microsoft.Interop
internal sealed class StackallocOptimizationMarshalling : ICustomNativeTypeMarshallingStrategy
{
private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller;
+ private readonly int _bufferSize;
- public StackallocOptimizationMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller)
+ public StackallocOptimizationMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, int bufferSize)
{
_innerMarshaller = innerMarshaller;
+ _bufferSize = bufferSize;
}
public TypeSyntax AsNativeType(TypePositionInfo info)
@@ -271,7 +274,7 @@ namespace Microsoft.Interop
{
if (StackAllocOptimizationValid(info, context))
{
- // byte* <managedIdentifier>__stackptr = stackalloc byte[<_nativeLocalType>.BufferSize];
+ // byte* <managedIdentifier>__stackptr = stackalloc byte[<_bufferSize>];
yield return LocalDeclarationStatement(
VariableDeclaration(
PointerType(PredefinedType(Token(SyntaxKind.ByteKeyword))),
@@ -282,9 +285,7 @@ namespace Microsoft.Interop
ArrayType(
PredefinedType(Token(SyntaxKind.ByteKeyword)),
SingletonList(ArrayRankSpecifier(SingletonSeparatedList<ExpressionSyntax>(
- MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
- AsNativeType(info),
- IdentifierName(ManualTypeMarshallingHelper.BufferSizeFieldName))
+ LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(_bufferSize))
))))))))));
}
@@ -336,9 +337,7 @@ namespace Microsoft.Interop
ArgumentList(SeparatedList(new ArgumentSyntax[]
{
Argument(IdentifierName(GetStackAllocPointerIdentifier(info, context))),
- Argument(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
- AsNativeType(info),
- IdentifierName(ManualTypeMarshallingHelper.BufferSizeFieldName)))
+ Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(_bufferSize)))
}))));
}
}
@@ -378,7 +377,7 @@ namespace Microsoft.Interop
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(context.GetIdentifiers(info).native),
- IdentifierName(ManualTypeMarshallingHelper.FreeNativeMethodName))));
+ IdentifierName(ShapeMemberNames.Value.FreeNative))));
}
public IEnumerable<StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable<ArgumentSyntax> nativeTypeConstructorArguments)
@@ -413,17 +412,17 @@ namespace Microsoft.Interop
}
/// <summary>
- /// Marshaller that calls the GetPinnableReference method on the marshaller value and enables support for the Value property.
+ /// Marshaller that calls the GetPinnableReference method on the marshaller value and enables support for the ToNativeValue and FromNativeValue methods.
/// </summary>
internal sealed class PinnableMarshallerTypeMarshalling : ICustomNativeTypeMarshallingStrategy
{
private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller;
- private readonly TypeSyntax _valuePropertyType;
+ private readonly TypeSyntax _nativeValueType;
- public PinnableMarshallerTypeMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax valuePropertyType)
+ public PinnableMarshallerTypeMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax nativeValueType)
{
_innerMarshaller = innerMarshaller;
- _valuePropertyType = valuePropertyType;
+ _nativeValueType = nativeValueType;
}
private bool CanPinMarshaller(TypePositionInfo info, StubCodeContext context)
@@ -433,17 +432,17 @@ namespace Microsoft.Interop
public TypeSyntax AsNativeType(TypePositionInfo info)
{
- return _valuePropertyType;
+ return _nativeValueType;
}
public IEnumerable<StatementSyntax> GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
if (!context.AdditionalTemporaryStateLivesAcrossStages)
{
// <marshalerIdentifier>.Value = <nativeIdentifier>;
- yield return GenerateValuePropertyAssignment(info, context, subContext);
+ yield return GenerateFromNativeValueInvocation(info, context, subContext);
}
foreach (StatementSyntax statement in _innerMarshaller.GenerateCleanupStatements(info, subContext))
@@ -454,46 +453,48 @@ namespace Microsoft.Interop
public IEnumerable<StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable<ArgumentSyntax> nativeTypeConstructorArguments)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, subContext, nativeTypeConstructorArguments))
{
yield return statement;
}
if (!CanPinMarshaller(info, context))
- yield return GenerateNativeAssignmentFromValueProperty(info, context, subContext);
+ yield return GenerateToNativeValueInvocation(info, context, subContext);
}
- private static StatementSyntax GenerateNativeAssignmentFromValueProperty(TypePositionInfo info, StubCodeContext context, CustomNativeTypeWithValuePropertyStubContext subContext)
+ private static StatementSyntax GenerateToNativeValueInvocation(TypePositionInfo info, StubCodeContext context, CustomNativeTypeWithToFromNativeValueContext subContext)
{
- // <nativeIdentifier> = <marshalerIdentifier>.Value;
+ // <nativeIdentifier> = <marshalerIdentifier>.ToNativeValue();
return ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(context.GetIdentifiers(info).native),
- MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(subContext.GetIdentifiers(info).native),
- IdentifierName(ManualTypeMarshallingHelper.ValuePropertyName))));
+ InvocationExpression(
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(subContext.GetIdentifiers(info).native),
+ IdentifierName(ShapeMemberNames.Value.ToNativeValue)),
+ ArgumentList())));
}
public IEnumerable<StatementSyntax> GeneratePinStatements(TypePositionInfo info, StubCodeContext context)
{
// fixed (<_nativeTypeSyntax> <ignoredIdentifier> = &<marshalerIdentifier>)
// <assignment to Value property>
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
yield return FixedStatement(
VariableDeclaration(
- _valuePropertyType,
+ _nativeValueType,
SingletonSeparatedList(
VariableDeclarator(Identifier(context.GetAdditionalIdentifier(info, "ignored")))
.WithInitializer(EqualsValueClause(
IdentifierName(subContext.GetIdentifiers(info).native))))),
- GenerateNativeAssignmentFromValueProperty(info, context, subContext));
+ GenerateToNativeValueInvocation(info, context, subContext));
}
public IEnumerable<StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
yield return LocalDeclarationStatement(
VariableDeclaration(
_innerMarshaller.AsNativeType(info),
@@ -507,26 +508,25 @@ namespace Microsoft.Interop
}
}
- private StatementSyntax GenerateValuePropertyAssignment(TypePositionInfo info, StubCodeContext context, CustomNativeTypeWithValuePropertyStubContext subContext)
+ private StatementSyntax GenerateFromNativeValueInvocation(TypePositionInfo info, StubCodeContext context, CustomNativeTypeWithToFromNativeValueContext subContext)
{
- // <marshalerIdentifier>.Value = <nativeIdentifier>;
+ // <marshalerIdentifier>.FromNativeValue(<nativeIdentifier>);
return ExpressionStatement(
- AssignmentExpression(
- SyntaxKind.SimpleAssignmentExpression,
+ InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(subContext.GetIdentifiers(info).native),
- IdentifierName(ManualTypeMarshallingHelper.ValuePropertyName)),
- IdentifierName(context.GetIdentifiers(info).native)));
+ IdentifierName(ShapeMemberNames.Value.FromNativeValue)),
+ ArgumentList(SingletonSeparatedList(Argument(IdentifierName(context.GetIdentifiers(info).native))))));
}
public IEnumerable<StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In))
{
// <marshalerIdentifier>.Value = <nativeIdentifier>;
- yield return GenerateValuePropertyAssignment(info, context, subContext);
+ yield return GenerateFromNativeValueInvocation(info, context, subContext);
}
foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, subContext))
@@ -537,7 +537,7 @@ namespace Microsoft.Interop
public IEnumerable<ArgumentSyntax> GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context)
{
- var subContext = new CustomNativeTypeWithValuePropertyStubContext(context);
+ var subContext = new CustomNativeTypeWithToFromNativeValueContext(context);
return _innerMarshaller.GetNativeTypeConstructorArguments(info, subContext);
}
@@ -548,18 +548,16 @@ namespace Microsoft.Interop
}
/// <summary>
- /// Marshaller that enables support for native types with the constructor variants that take a sizeOfElement int parameter and that have a SetUnmarshalledCollectionLength method.
+ /// Marshaller that enables support for native types with the constructor variants that take a sizeOfElement int parameter.
/// </summary>
- internal sealed class NumElementsExpressionMarshalling : ICustomNativeTypeMarshallingStrategy
+ internal sealed class SizeOfElementMarshalling : ICustomNativeTypeMarshallingStrategy
{
private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller;
- private readonly ExpressionSyntax _numElementsExpression;
private readonly ExpressionSyntax _sizeOfElementExpression;
- public NumElementsExpressionMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, ExpressionSyntax numElementsExpression, ExpressionSyntax sizeOfElementExpression)
+ public SizeOfElementMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, ExpressionSyntax sizeOfElementExpression)
{
_innerMarshaller = innerMarshaller;
- _numElementsExpression = numElementsExpression;
_sizeOfElementExpression = sizeOfElementExpression;
}
@@ -611,17 +609,6 @@ namespace Microsoft.Interop
IdentifierName(marshalerIdentifier),
ImplicitObjectCreationExpression().AddArgumentListArguments(Argument(_sizeOfElementExpression))));
}
-
- if (info.IsByRef || !info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out))
- {
- yield return ExpressionStatement(
- InvocationExpression(
- MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(marshalerIdentifier),
- IdentifierName(ManualTypeMarshallingHelper.SetUnmarshalledCollectionLengthMethodName)))
- .AddArgumentListArguments(Argument(_numElementsExpression)));
- }
}
public IEnumerable<StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
@@ -658,17 +645,19 @@ namespace Microsoft.Interop
}
/// <summary>
- /// Marshaller that enables support for marshalling blittable elements of a contiguous collection via a native type that implements the contiguous collection marshalling spec.
+ /// Marshaller that enables support for marshalling blittable elements of a collection via a native type that implements the LinearCollection marshalling spec.
/// </summary>
- internal sealed class ContiguousBlittableElementCollectionMarshalling : ICustomNativeTypeMarshallingStrategy
+ internal sealed class LinearCollectionWithBlittableElementsMarshalling : ICustomNativeTypeMarshallingStrategy
{
private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller;
private readonly TypeSyntax _elementType;
+ private readonly ExpressionSyntax _numElementsExpression;
- public ContiguousBlittableElementCollectionMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax elementType)
+ public LinearCollectionWithBlittableElementsMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller, TypeSyntax elementType, ExpressionSyntax numElementsExpression)
{
_innerMarshaller = innerMarshaller;
_elementType = elementType;
+ _numElementsExpression = numElementsExpression;
}
public TypeSyntax AsNativeType(TypePositionInfo info)
@@ -695,15 +684,17 @@ namespace Microsoft.Interop
yield break;
}
- // <nativeIdentifier>.ManagedValues.CopyTo(MemoryMarshal.Cast<byte, <elementType>>(<nativeIdentifier>.NativeValueStorage));
+ // <nativeIdentifier>.GetManagedValuesSource().CopyTo(MemoryMarshal.Cast<byte, <elementType>>(<nativeIdentifier>.GetNativeValuesDestination()));
yield return ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
- MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(nativeIdentifier),
- IdentifierName(ManualTypeMarshallingHelper.ManagedValuesPropertyName)),
+ InvocationExpression(
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(nativeIdentifier),
+ IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource)),
+ ArgumentList()),
IdentifierName("CopyTo")))
.AddArgumentListArguments(
Argument(
@@ -723,10 +714,12 @@ namespace Microsoft.Interop
})))))
.AddArgumentListArguments(
Argument(
- MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(nativeIdentifier),
- IdentifierName(ManualTypeMarshallingHelper.NativeValueStoragePropertyName)))))));
+ InvocationExpression(
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(nativeIdentifier),
+ IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesDestination)),
+ ArgumentList()))))));
}
public IEnumerable<StatementSyntax> GeneratePinStatements(TypePositionInfo info, StubCodeContext context)
@@ -742,7 +735,13 @@ namespace Microsoft.Interop
public IEnumerable<StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
{
string nativeIdentifier = context.GetIdentifiers(info).native;
- // MemoryMarshal.Cast<byte, <elementType>>(<nativeIdentifier>.NativeValueStorage).CopyTo(<nativeIdentifier>.ManagedValues);
+ string numElementsIdentifier = context.GetAdditionalIdentifier(info, "numElements");
+ yield return LocalDeclarationStatement(
+ VariableDeclaration(
+ PredefinedType(Token(SyntaxKind.IntKeyword)),
+ SingletonSeparatedList(
+ VariableDeclarator(numElementsIdentifier).WithInitializer(EqualsValueClause(_numElementsExpression)))));
+ // MemoryMarshal.Cast<byte, <elementType>>(<nativeIdentifier>.GetNativeValuesSource(<numElements>)).CopyTo(<nativeIdentifier>.GetManagedValuesDestination(<numElements>));
yield return ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
@@ -763,17 +762,21 @@ namespace Microsoft.Interop
})))))
.AddArgumentListArguments(
Argument(
- MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(nativeIdentifier),
- IdentifierName(ManualTypeMarshallingHelper.NativeValueStoragePropertyName)))),
+ InvocationExpression(
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(nativeIdentifier),
+ IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesSource)),
+ ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier))))))),
IdentifierName("CopyTo")))
.AddArgumentListArguments(
Argument(
- MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(nativeIdentifier),
- IdentifierName(ManualTypeMarshallingHelper.ManagedValuesPropertyName)))));
+ InvocationExpression(
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(nativeIdentifier),
+ IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesDestination)),
+ ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier))))))));
foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, context))
{
@@ -793,24 +796,27 @@ namespace Microsoft.Interop
}
/// <summary>
- /// Marshaller that enables support for marshalling non-blittable elements of a contiguous collection via a native type that implements the contiguous collection marshalling spec.
+ /// Marshaller that enables support for marshalling non-blittable elements of a collection via a native type that implements the LinearCollection marshalling spec.
/// </summary>
- internal sealed class ContiguousNonBlittableElementCollectionMarshalling : ICustomNativeTypeMarshallingStrategy
+ internal sealed class LinearCollectionWithNonBlittableElementsMarshalling : ICustomNativeTypeMarshallingStrategy
{
private readonly ICustomNativeTypeMarshallingStrategy _innerMarshaller;
private readonly IMarshallingGenerator _elementMarshaller;
private readonly TypePositionInfo _elementInfo;
+ private readonly ExpressionSyntax _numElementsExpression;
- public ContiguousNonBlittableElementCollectionMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller,
+ public LinearCollectionWithNonBlittableElementsMarshalling(ICustomNativeTypeMarshallingStrategy innerMarshaller,
IMarshallingGenerator elementMarshaller,
- TypePositionInfo elementInfo)
+ TypePositionInfo elementInfo,
+ ExpressionSyntax numElementsExpression)
{
_innerMarshaller = innerMarshaller;
_elementMarshaller = elementMarshaller;
_elementInfo = elementInfo;
+ _numElementsExpression = numElementsExpression;
}
- private LocalDeclarationStatementSyntax GenerateNativeSpanDeclaration(TypePositionInfo info, StubCodeContext context)
+ private LocalDeclarationStatementSyntax GenerateNativeValuesDestinationDeclaration(TypePositionInfo info, StubCodeContext context)
{
string nativeIdentifier = context.GetIdentifiers(info).native;
string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context);
@@ -838,28 +844,105 @@ namespace Microsoft.Interop
_elementMarshaller.AsNativeType(_elementInfo).GetCompatibleGenericTypeParameterSyntax()
})))))
.AddArgumentListArguments(
- Argument(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ Argument(
+ InvocationExpression(
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(nativeIdentifier),
+ IdentifierName(ShapeMemberNames.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.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(ManualTypeMarshallingHelper.NativeValueStoragePropertyName)))))))));
+ IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource)),
+ ArgumentList()))))));
}
- private StatementSyntax GenerateContentsMarshallingStatement(TypePositionInfo info, StubCodeContext context, bool useManagedSpanForLength)
+ 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.LinearCollection.GetManagedValuesDestination)),
+ ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier))))))))));
+ }
+
+ private StatementSyntax GenerateContentsMarshallingStatement(TypePositionInfo info, StubCodeContext context, ExpressionSyntax lengthExpression)
+ {
+ string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context);
string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context);
- var elementSetupSubContext = new ContiguousCollectionElementMarshallingCodeContext(
+ var elementSetupSubContext = new LinearCollectionElementMarshallingCodeContext(
StubCodeContext.Stage.Setup,
+ managedSpanIdentifier,
nativeSpanIdentifier,
context);
- var elementSubContext = new ContiguousCollectionElementMarshallingCodeContext(
+ var elementSubContext = new LinearCollectionElementMarshallingCodeContext(
context.CurrentStage,
+ managedSpanIdentifier,
nativeSpanIdentifier,
context);
- string collectionIdentifierForLength = useManagedSpanForLength
- ? $"{nativeIdentifier}.{ManualTypeMarshallingHelper.ManagedValuesPropertyName}"
- : nativeSpanIdentifier;
-
TypePositionInfo localElementInfo = _elementInfo with
{
InstanceIdentifier = info.InstanceIdentifier,
@@ -883,10 +966,8 @@ namespace Microsoft.Interop
}
// Iterate through the elements of the native collection to unmarshal them
- return Block(
- GenerateNativeSpanDeclaration(info, context),
- MarshallerHelpers.GetForLoop(collectionIdentifierForLength, elementSubContext.IndexerIdentifier)
- .WithStatement(marshallingStatement));
+ return MarshallerHelpers.GetForLoop(lengthExpression, elementSubContext.IndexerIdentifier)
+ .WithStatement(marshallingStatement);
}
return EmptyStatement();
}
@@ -898,7 +979,18 @@ namespace Microsoft.Interop
public IEnumerable<StatementSyntax> GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context)
{
- yield return GenerateContentsMarshallingStatement(info, context, useManagedSpanForLength: false);
+ StatementSyntax contentsCleanupStatements = GenerateContentsMarshallingStatement(info, context,
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(MarshallerHelpers.GetNativeSpanIdentifier(info, context)),
+ IdentifierName("Length")));
+
+ if (!contentsCleanupStatements.IsKind(SyntaxKind.EmptyStatement))
+ {
+ yield return Block(
+ GenerateNativeValuesDestinationDeclaration(info, context),
+ contentsCleanupStatements);
+ }
+
foreach (StatementSyntax statement in _innerMarshaller.GenerateCleanupStatements(info, context))
{
yield return statement;
@@ -916,21 +1008,29 @@ namespace Microsoft.Interop
{
// 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.
- // <nativeIdentifier>.NativeValueStorage.Clear();
+ // <nativeIdentifier>.GetNativeValuesDestination().Clear();
string nativeIdentifier = context.GetIdentifiers(info).native;
yield return ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
- MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(nativeIdentifier),
- IdentifierName(ManualTypeMarshallingHelper.NativeValueStoragePropertyName)),
+ InvocationExpression(
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(nativeIdentifier),
+ IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesDestination)),
+ ArgumentList()),
IdentifierName("Clear"))));
yield break;
}
- yield return GenerateContentsMarshallingStatement(info, context, useManagedSpanForLength: true);
+ yield return Block(
+ GeneratedManagedValuesSourceDeclaration(info, context),
+ GenerateNativeValuesDestinationDeclaration(info, context),
+ GenerateContentsMarshallingStatement(info, context,
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(MarshallerHelpers.GetManagedSpanIdentifier(info, context)),
+ IdentifierName("Length"))));
}
public IEnumerable<StatementSyntax> GeneratePinStatements(TypePositionInfo info, StubCodeContext context)
@@ -943,9 +1043,101 @@ namespace Microsoft.Interop
return _innerMarshaller.GenerateSetupStatements(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 <numElements> = <nativeIdentifier>.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.LinearCollection.GetManagedValuesSource)),
+ ArgumentList()),
+ IdentifierName("Length")))))));
+
+ string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context);
+ // Span<TElement> <managedSpan> = MemoryMarshal.CreateSpan(ref Unsafe.AsRef(ref <nativeIdentifier>.GetManagedValuesSource().GetPinnableReference(), <numElements>));
+ 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.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)));
+ }
+
public IEnumerable<StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
{
- yield return GenerateContentsMarshallingStatement(info, context, useManagedSpanForLength: false);
+ 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)));
+ }
+
foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, context))
{
yield return statement;
@@ -992,6 +1184,16 @@ namespace Microsoft.Interop
return node;
}
+
+ public override SyntaxNode? VisitArgument(ArgumentSyntax node)
+ {
+ if (node.Expression.ToString() == _nativeIdentifier)
+ {
+ return node.WithExpression(
+ CastExpression(_nativeType, node.Expression));
+ }
+ return node;
+ }
}
}
}
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 01b0c4aae2b..dc1a04c6981 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
@@ -22,9 +22,9 @@ namespace Microsoft.Interop
public static readonly TypeSyntax SystemIntPtrType = ParseTypeName(TypeNames.System_IntPtr);
- public static ForStatementSyntax GetForLoop(string collectionIdentifier, string indexerIdentifier)
+ public static ForStatementSyntax GetForLoop(ExpressionSyntax lengthExpression, string indexerIdentifier)
{
- // for(int <indexerIdentifier> = 0; <indexerIdentifier> < <collectionIdentifier>.Length; ++<indexerIdentifier>)
+ // for(int <indexerIdentifier> = 0; <indexerIdentifier> < <lengthIdentifier>; ++<indexerIdentifier>)
// ;
return ForStatement(EmptyStatement())
.WithDeclaration(
@@ -32,7 +32,7 @@ namespace Microsoft.Interop
PredefinedType(
Token(SyntaxKind.IntKeyword)))
.WithVariables(
- SingletonSeparatedList<VariableDeclaratorSyntax>(
+ SingletonSeparatedList(
VariableDeclarator(
Identifier(indexerIdentifier))
.WithInitializer(
@@ -44,10 +44,7 @@ namespace Microsoft.Interop
BinaryExpression(
SyntaxKind.LessThanExpression,
IdentifierName(indexerIdentifier),
- MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(collectionIdentifier),
- IdentifierName("Length"))))
+ lengthExpression))
.WithIncrementors(
SingletonSeparatedList<ExpressionSyntax>(
PrefixUnaryExpression(
@@ -102,6 +99,11 @@ namespace Microsoft.Interop
return context.GetAdditionalIdentifier(info, "marshaller");
}
+ public static string GetManagedSpanIdentifier(TypePositionInfo info, StubCodeContext context)
+ {
+ return context.GetAdditionalIdentifier(info, "managedSpan");
+ }
+
public static string GetNativeSpanIdentifier(TypePositionInfo info, StubCodeContext context)
{
return context.GetAdditionalIdentifier(info, "nativeSpan");
@@ -232,7 +234,7 @@ namespace Microsoft.Interop
public static IEnumerable<TypePositionInfo> GetDependentElementsOfMarshallingInfo(
MarshallingInfo elementMarshallingInfo)
{
- if (elementMarshallingInfo is NativeContiguousCollectionMarshallingInfo nestedCollection)
+ if (elementMarshallingInfo is NativeLinearCollectionMarshallingInfo nestedCollection)
{
if (nestedCollection.ElementCountInfo is CountElementCountInfo { ElementInfo: TypePositionInfo nestedCountElement })
{
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs
index 6cd7da3f430..8de5682ac01 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs
@@ -118,7 +118,7 @@ namespace Microsoft.Interop
{
CountInfo countInfo;
MarshallingInfo elementMarshallingInfo;
- if (info.MarshallingAttributeInfo is NativeContiguousCollectionMarshallingInfo collectionMarshalling
+ if (info.MarshallingAttributeInfo is NativeLinearCollectionMarshallingInfo collectionMarshalling
&& collectionMarshalling.UseDefaultMarshalling
&& collectionMarshalling.ElementCountInfo is NoCountInfo or SizeAndParamIndexInfo
&& collectionMarshalling.ElementMarshallingInfo is NoMarshallingInfo or MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler }
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 0000772d544..86bab61b220 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
@@ -98,15 +98,11 @@ namespace Microsoft.Interop
public sealed record UnmanagedBlittableMarshallingInfo : MarshallingInfo;
[Flags]
- public enum CustomMarshallingFeatures
+ public enum CustomTypeMarshallerPinning
{
None = 0,
- ManagedToNative = 0x1,
- NativeToManaged = 0x2,
- ManagedToNativeStackalloc = 0x4,
- ManagedTypePinning = 0x8,
- NativeTypePinning = 0x10,
- FreeNativeResources = 0x20,
+ ManagedType = 0x1,
+ NativeType = 0x2
}
public abstract record CountInfo
@@ -142,9 +138,12 @@ namespace Microsoft.Interop
/// </summary>
public record NativeMarshallingAttributeInfo(
ManagedTypeInfo NativeMarshallingType,
- ManagedTypeInfo? ValuePropertyType,
- CustomMarshallingFeatures MarshallingFeatures,
- bool UseDefaultMarshalling) : MarshallingInfo;
+ ManagedTypeInfo? NativeValueType,
+ CustomTypeMarshallerDirection Direction,
+ CustomTypeMarshallerFeatures MarshallingFeatures,
+ CustomTypeMarshallerPinning PinningFeatures,
+ bool UseDefaultMarshalling,
+ int? BufferSize) : MarshallingInfo;
/// <summary>
/// User-applied System.Runtime.InteropServices.GeneratedMarshallingAttribute
@@ -162,18 +161,24 @@ namespace Microsoft.Interop
/// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute
/// with a contiguous collection marshaller
/// </summary>
- public sealed record NativeContiguousCollectionMarshallingInfo(
+ public sealed record NativeLinearCollectionMarshallingInfo(
ManagedTypeInfo NativeMarshallingType,
- ManagedTypeInfo? ValuePropertyType,
- CustomMarshallingFeatures MarshallingFeatures,
+ ManagedTypeInfo? NativeValueType,
+ CustomTypeMarshallerDirection Direction,
+ CustomTypeMarshallerFeatures MarshallingFeatures,
+ CustomTypeMarshallerPinning PinningFeatures,
bool UseDefaultMarshalling,
+ int? BufferSize,
CountInfo ElementCountInfo,
ManagedTypeInfo ElementType,
MarshallingInfo ElementMarshallingInfo) : NativeMarshallingAttributeInfo(
NativeMarshallingType,
- ValuePropertyType,
+ NativeValueType,
+ Direction,
MarshallingFeatures,
- UseDefaultMarshalling
+ PinningFeatures,
+ UseDefaultMarshalling,
+ BufferSize
);
@@ -223,36 +228,36 @@ namespace Microsoft.Interop
IEnumerable<AttributeData> useSiteAttributes,
ImmutableHashSet<string> inspectedElements)
{
- Dictionary<int, AttributeData> marshallingAttributesByIndirectionLevel = new();
+ Dictionary<int, AttributeData> marshallingAttributesByIndirectionDepth = new();
int maxIndirectionLevelDataProvided = 0;
foreach (AttributeData attribute in useSiteAttributes)
{
if (TryGetAttributeIndirectionLevel(attribute, out int indirectionLevel))
{
- if (marshallingAttributesByIndirectionLevel.ContainsKey(indirectionLevel))
+ if (marshallingAttributesByIndirectionDepth.ContainsKey(indirectionLevel))
{
_diagnostics.ReportInvalidMarshallingAttributeInfo(attribute, nameof(Resources.DuplicateMarshallingInfo), indirectionLevel.ToString());
return NoMarshallingInfo.Instance;
}
- marshallingAttributesByIndirectionLevel.Add(indirectionLevel, attribute);
+ marshallingAttributesByIndirectionDepth.Add(indirectionLevel, attribute);
maxIndirectionLevelDataProvided = Math.Max(maxIndirectionLevelDataProvided, indirectionLevel);
}
}
- int maxIndirectionLevelUsed = 0;
+ int maxIndirectionDepthUsed = 0;
MarshallingInfo info = GetMarshallingInfo(
managedType,
- marshallingAttributesByIndirectionLevel,
+ marshallingAttributesByIndirectionDepth,
indirectionLevel: 0,
inspectedElements,
- ref maxIndirectionLevelUsed);
- if (maxIndirectionLevelUsed < maxIndirectionLevelDataProvided)
+ ref maxIndirectionDepthUsed);
+ if (maxIndirectionDepthUsed < maxIndirectionLevelDataProvided)
{
_diagnostics.ReportInvalidMarshallingAttributeInfo(
- marshallingAttributesByIndirectionLevel[maxIndirectionLevelDataProvided],
+ marshallingAttributesByIndirectionDepth[maxIndirectionLevelDataProvided],
nameof(Resources.ExtraneousMarshallingInfo),
maxIndirectionLevelDataProvided.ToString(),
- maxIndirectionLevelUsed.ToString());
+ maxIndirectionDepthUsed.ToString());
}
return info;
}
@@ -262,9 +267,9 @@ namespace Microsoft.Interop
Dictionary<int, AttributeData> useSiteAttributes,
int indirectionLevel,
ImmutableHashSet<string> inspectedElements,
- ref int maxIndirectionLevelUsed)
+ ref int maxIndirectionDepthUsed)
{
- maxIndirectionLevelUsed = Math.Max(indirectionLevel, maxIndirectionLevelUsed);
+ maxIndirectionDepthUsed = Math.Max(indirectionLevel, maxIndirectionDepthUsed);
CountInfo parsedCountInfo = NoCountInfo.Instance;
if (useSiteAttributes.TryGetValue(indirectionLevel, out AttributeData useSiteAttribute))
@@ -275,7 +280,7 @@ namespace Microsoft.Interop
&& SymbolEqualityComparer.Default.Equals(_compilation.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute), attributeClass))
{
// https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.marshalasattribute
- return CreateInfoFromMarshalAs(type, useSiteAttribute, inspectedElements, ref maxIndirectionLevelUsed);
+ return CreateInfoFromMarshalAs(type, useSiteAttribute, inspectedElements, ref maxIndirectionDepthUsed);
}
else if (SymbolEqualityComparer.Default.Equals(_compilation.GetTypeByMetadataName(TypeNames.MarshalUsingAttribute), attributeClass))
{
@@ -296,7 +301,7 @@ namespace Microsoft.Interop
parsedCountInfo,
useSiteAttributes,
inspectedElements,
- ref maxIndirectionLevelUsed);
+ ref maxIndirectionDepthUsed);
}
}
}
@@ -318,7 +323,7 @@ namespace Microsoft.Interop
parsedCountInfo,
useSiteAttributes,
inspectedElements,
- ref maxIndirectionLevelUsed);
+ ref maxIndirectionDepthUsed);
}
else if (attributeClass.ToDisplayString() == TypeNames.GeneratedMarshallingAttribute)
{
@@ -334,7 +339,7 @@ namespace Microsoft.Interop
indirectionLevel,
useSiteAttributes,
inspectedElements,
- ref maxIndirectionLevelUsed,
+ ref maxIndirectionDepthUsed,
out MarshallingInfo infoMaybe))
{
return infoMaybe;
@@ -467,7 +472,7 @@ namespace Microsoft.Interop
ITypeSymbol type,
AttributeData attrData,
ImmutableHashSet<string> inspectedElements,
- ref int maxIndirectionLevelUsed)
+ ref int maxIndirectionDepthUsed)
{
object unmanagedTypeObj = attrData.ConstructorArguments[0].Value!;
UnmanagedType unmanagedType = unmanagedTypeObj is short unmanagedTypeAsShort
@@ -547,8 +552,8 @@ namespace Microsoft.Interop
}
else
{
- maxIndirectionLevelUsed = 1;
- elementMarshallingInfo = GetMarshallingInfo(elementType, new Dictionary<int, AttributeData>(), 1, ImmutableHashSet<string>.Empty, ref maxIndirectionLevelUsed);
+ maxIndirectionDepthUsed = 1;
+ elementMarshallingInfo = GetMarshallingInfo(elementType, new Dictionary<int, AttributeData>(), 1, ImmutableHashSet<string>.Empty, ref maxIndirectionDepthUsed);
}
INamedTypeSymbol? arrayMarshaller;
@@ -568,13 +573,20 @@ namespace Microsoft.Interop
return new MissingSupportCollectionMarshallingInfo(arraySizeInfo, elementMarshallingInfo);
}
- ITypeSymbol? valuePropertyType = ManualTypeMarshallingHelper.FindValueProperty(arrayMarshaller)?.Type;
+ var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(arrayMarshaller);
+
+ Debug.Assert(customTypeMarshallerData is not null);
- return new NativeContiguousCollectionMarshallingInfo(
+ ITypeSymbol? nativeValueType = ManualTypeMarshallingHelper.FindToNativeValueMethod(arrayMarshaller)?.ReturnType;
+
+ return new NativeLinearCollectionMarshallingInfo(
NativeMarshallingType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller),
- ValuePropertyType: valuePropertyType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(valuePropertyType) : null,
- MarshallingFeatures: ~CustomMarshallingFeatures.ManagedTypePinning,
+ NativeValueType: nativeValueType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeValueType) : null,
+ Direction: customTypeMarshallerData.Value.Direction,
+ MarshallingFeatures: customTypeMarshallerData.Value.Features,
+ PinningFeatures: CustomTypeMarshallerPinning.NativeType,
UseDefaultMarshalling: true,
+ BufferSize: customTypeMarshallerData.Value.BufferSize,
ElementCountInfo: arraySizeInfo,
ElementType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType),
ElementMarshallingInfo: elementMarshallingInfo);
@@ -589,16 +601,9 @@ namespace Microsoft.Interop
CountInfo parsedCountInfo,
Dictionary<int, AttributeData> useSiteAttributes,
ImmutableHashSet<string> inspectedElements,
- ref int maxIndirectionLevelUsed)
+ ref int maxIndirectionDepthUsed)
{
- CustomMarshallingFeatures features = CustomMarshallingFeatures.None;
-
- if (!isMarshalUsingAttribute && ManualTypeMarshallingHelper.FindGetPinnableReference(type) is not null)
- {
- features |= CustomMarshallingFeatures.ManagedTypePinning;
- }
-
- ITypeSymbol spanOfByte = _compilation.GetTypeByMetadataName(TypeNames.System_Span_Metadata)!.Construct(_compilation.GetSpecialType(SpecialType.System_Byte));
+ INamedTypeSymbol readOnlySpanOfT = _compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata)!;
if (nativeType.IsUnboundGenericType)
{
@@ -626,93 +631,55 @@ namespace Microsoft.Interop
}
}
- ITypeSymbol contiguousCollectionMarshalerAttribute = _compilation.GetTypeByMetadataName(TypeNames.GenericContiguousCollectionMarshallerAttribute)!;
-
- bool isContiguousCollectionMarshaller = nativeType.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, contiguousCollectionMarshalerAttribute));
- IPropertySymbol? valueProperty = ManualTypeMarshallingHelper.FindValueProperty(nativeType);
-
- ManualTypeMarshallingHelper.NativeTypeMarshallingVariant marshallingVariant = isContiguousCollectionMarshaller
- ? ManualTypeMarshallingHelper.NativeTypeMarshallingVariant.ContiguousCollection
- : ManualTypeMarshallingHelper.NativeTypeMarshallingVariant.Standard;
-
- bool hasInt32Constructor = false;
- foreach (IMethodSymbol ctor in nativeType.Constructors)
- {
- if (ManualTypeMarshallingHelper.IsManagedToNativeConstructor(ctor, type, marshallingVariant) && (valueProperty is null or { GetMethod: not null }))
- {
- features |= CustomMarshallingFeatures.ManagedToNative;
- }
- else if (ManualTypeMarshallingHelper.IsCallerAllocatedSpanConstructor(ctor, type, spanOfByte, marshallingVariant)
- && (valueProperty is null or { GetMethod: not null }))
- {
- features |= CustomMarshallingFeatures.ManagedToNativeStackalloc;
- }
- else if (ctor.Parameters.Length == 1 && ctor.Parameters[0].Type.SpecialType == SpecialType.System_Int32)
- {
- hasInt32Constructor = true;
- }
- }
-
- // The constructor that takes only the native element size is required for collection marshallers
- // in the native-to-managed scenario.
- if ((!isContiguousCollectionMarshaller
- || (hasInt32Constructor && ManualTypeMarshallingHelper.HasSetUnmarshalledCollectionLengthMethod(nativeType)))
- && ManualTypeMarshallingHelper.HasToManagedMethod(nativeType, type)
- && (valueProperty is null or { SetMethod: not null }))
+ var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(nativeType);
+ if (customTypeMarshallerData is null)
{
- features |= CustomMarshallingFeatures.NativeToManaged;
- }
-
- if (features == CustomMarshallingFeatures.None)
- {
- _diagnostics.ReportInvalidMarshallingAttributeInfo(
- attrData,
- isContiguousCollectionMarshaller
- ? nameof(Resources.CollectionNativeTypeMustHaveRequiredShapeMessage)
- : nameof(Resources.NativeTypeMustHaveRequiredShapeMessage),
- nativeType.ToDisplayString());
return NoMarshallingInfo.Instance;
}
- if (ManualTypeMarshallingHelper.HasFreeNativeMethod(nativeType))
+ CustomTypeMarshallerPinning pinning = CustomTypeMarshallerPinning.None;
+
+ if (!isMarshalUsingAttribute && ManualTypeMarshallingHelper.FindGetPinnableReference(type) is not null)
{
- features |= CustomMarshallingFeatures.FreeNativeResources;
+ pinning |= CustomTypeMarshallerPinning.ManagedType;
}
if (ManualTypeMarshallingHelper.FindGetPinnableReference(nativeType) is not null)
{
- features |= CustomMarshallingFeatures.NativeTypePinning;
+ pinning |= CustomTypeMarshallerPinning.NativeType;
}
- if (isContiguousCollectionMarshaller)
- {
- if (!ManualTypeMarshallingHelper.HasNativeValueStorageProperty(nativeType, spanOfByte))
- {
- _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(Resources.CollectionNativeTypeMustHaveRequiredShapeMessage), nativeType.ToDisplayString());
- return NoMarshallingInfo.Instance;
- }
+ IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper.FindToNativeValueMethod(nativeType);
- if (!ManualTypeMarshallingHelper.TryGetElementTypeFromContiguousCollectionMarshaller(nativeType, out ITypeSymbol elementType))
+ if (customTypeMarshallerData.Value.Kind == CustomTypeMarshallerKind.LinearCollection)
+ {
+ if (!ManualTypeMarshallingHelper.TryGetElementTypeFromLinearCollectionMarshaller(nativeType, readOnlySpanOfT, out ITypeSymbol elementType))
{
_diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(Resources.CollectionNativeTypeMustHaveRequiredShapeMessage), nativeType.ToDisplayString());
return NoMarshallingInfo.Instance;
}
- return new NativeContiguousCollectionMarshallingInfo(
+ return new NativeLinearCollectionMarshallingInfo(
ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeType),
- valueProperty is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(valueProperty.Type) : null,
- features,
+ toNativeValueMethod is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(toNativeValueMethod.ReturnType) : null,
+ customTypeMarshallerData.Value.Direction,
+ customTypeMarshallerData.Value.Features,
+ pinning,
UseDefaultMarshalling: !isMarshalUsingAttribute,
+ customTypeMarshallerData.Value.BufferSize,
parsedCountInfo,
ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType),
- GetMarshallingInfo(elementType, useSiteAttributes, indirectionLevel + 1, inspectedElements, ref maxIndirectionLevelUsed));
+ GetMarshallingInfo(elementType, useSiteAttributes, indirectionLevel + 1, inspectedElements, ref maxIndirectionDepthUsed));
}
return new NativeMarshallingAttributeInfo(
ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeType),
- valueProperty is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(valueProperty.Type) : null,
- features,
- UseDefaultMarshalling: !isMarshalUsingAttribute);
+ toNativeValueMethod is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(toNativeValueMethod.ReturnType) : null,
+ customTypeMarshallerData.Value.Direction,
+ customTypeMarshallerData.Value.Features,
+ pinning,
+ UseDefaultMarshalling: !isMarshalUsingAttribute,
+ customTypeMarshallerData.Value.BufferSize);
}
private bool TryCreateTypeBasedMarshallingInfo(
@@ -721,7 +688,7 @@ namespace Microsoft.Interop
int indirectionLevel,
Dictionary<int, AttributeData> useSiteAttributes,
ImmutableHashSet<string> inspectedElements,
- ref int maxIndirectionLevelUsed,
+ ref int maxIndirectionDepthUsed,
out MarshallingInfo marshallingInfo)
{
// Check for an implicit SafeHandle conversion.
@@ -767,20 +734,24 @@ namespace Microsoft.Interop
if (arrayMarshaller is null)
{
// If the array marshaler type is not available, then we cannot marshal arrays but indicate it is missing.
- marshallingInfo = new MissingSupportCollectionMarshallingInfo(parsedCountInfo, GetMarshallingInfo(elementType, useSiteAttributes, indirectionLevel + 1, inspectedElements, ref maxIndirectionLevelUsed));
+ marshallingInfo = new MissingSupportCollectionMarshallingInfo(parsedCountInfo, GetMarshallingInfo(elementType, useSiteAttributes, indirectionLevel + 1, inspectedElements, ref maxIndirectionDepthUsed));
return true;
}
- ITypeSymbol? valuePropertyType = ManualTypeMarshallingHelper.FindValueProperty(arrayMarshaller)?.Type;
+ var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(arrayMarshaller);
+ ITypeSymbol? valuePropertyType = ManualTypeMarshallingHelper.FindToNativeValueMethod(arrayMarshaller)?.ReturnType;
- marshallingInfo = new NativeContiguousCollectionMarshallingInfo(
+ marshallingInfo = new NativeLinearCollectionMarshallingInfo(
NativeMarshallingType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller),
- ValuePropertyType: valuePropertyType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(valuePropertyType) : null,
- MarshallingFeatures: ~CustomMarshallingFeatures.ManagedTypePinning,
+ NativeValueType: valuePropertyType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(valuePropertyType) : null,
+ Direction: CustomTypeMarshallerDirection.Ref,
+ MarshallingFeatures: CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer,
+ PinningFeatures: CustomTypeMarshallerPinning.NativeType,
UseDefaultMarshalling: true,
+ customTypeMarshallerData.Value.BufferSize,
ElementCountInfo: parsedCountInfo,
ElementType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType),
- ElementMarshallingInfo: GetMarshallingInfo(elementType, useSiteAttributes, indirectionLevel + 1, inspectedElements, ref maxIndirectionLevelUsed));
+ ElementMarshallingInfo: GetMarshallingInfo(elementType, useSiteAttributes, indirectionLevel + 1, inspectedElements, ref maxIndirectionDepthUsed));
return true;
}
@@ -793,7 +764,7 @@ namespace Microsoft.Interop
AttributeData attrData = _contextSymbol is IMethodSymbol
? _contextSymbol.GetAttributes().First(a => a.AttributeClass.ToDisplayString() == TypeNames.LibraryImportAttribute)
: default;
- marshallingInfo = CreateNativeMarshallingInfo(type, _defaultInfo.StringMarshallingCustomType, attrData, true, indirectionLevel, parsedCountInfo, useSiteAttributes, inspectedElements, ref maxIndirectionLevelUsed);
+ marshallingInfo = CreateNativeMarshallingInfo(type, _defaultInfo.StringMarshallingCustomType, attrData, true, indirectionLevel, parsedCountInfo, useSiteAttributes, inspectedElements, ref maxIndirectionDepthUsed);
return true;
}
@@ -862,7 +833,7 @@ namespace Microsoft.Interop
foreach (KeyValuePair<string, TypedConstant> arg in attrData.NamedArguments)
{
- if (arg.Key == ManualTypeMarshallingHelper.MarshalUsingProperties.ElementIndirectionLevel)
+ if (arg.Key == ManualTypeMarshallingHelper.MarshalUsingProperties.ElementIndirectionDepth)
{
indirectionLevel = (int)arg.Value.Value!;
return true;
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 a542f34e721..8c9dbccb9f1 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
@@ -5,6 +5,7 @@
<Nullable>enable</Nullable>
<RootNamespace>Microsoft.Interop</RootNamespace>
<RunAnalyzers>true</RunAnalyzers>
+ <DefineConstants>$(DefineConstants);LIBRARYIMPORT_GENERATOR_TEST</DefineConstants>
</PropertyGroup>
<ItemGroup>
@@ -12,6 +13,12 @@
DependentUpon="Resources.resx"
DesignTime="True"
AutoGen="True" />
+ <Compile Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerKind.cs"
+ Link="Common\System\Runtime\InteropServices\CustomTypeMarshallerKind.cs" />
+ <Compile Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerDirection.cs"
+ Link="Common\System\Runtime\InteropServices\CustomTypeMarshallerDirection.cs" />
+ <Compile Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerFeatures.cs"
+ Link="Common\System\Runtime\InteropServices\CustomTypeMarshallerFeatures.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.Designer.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.Designer.cs
index 90e95ecef5c..626e683b776 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.Designer.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.Designer.cs
@@ -124,7 +124,7 @@ namespace Microsoft.Interop {
}
/// <summary>
- /// Looks up a localized string similar to Only one of &apos;ConstantElementCount&apos; or &apos;ElementCountInfo&apos; may be used in a &apos;MarshalUsingAttribute&apos; for a given &apos;ElementIndirectionLevel&apos;.
+ /// Looks up a localized string similar to Only one of &apos;ConstantElementCount&apos; or &apos;ElementCountInfo&apos; may be used in a &apos;MarshalUsingAttribute&apos; for a given &apos;ElementIndirectionDepth&apos;.
/// </summary>
internal static string ConstantAndElementCountInfoDisallowed {
get {
@@ -178,7 +178,7 @@ namespace Microsoft.Interop {
}
/// <summary>
- /// Looks up a localized string similar to Marshalling info was specified for &apos;ElementIndirectionLevel&apos; {0}, but marshalling info was only needed for {1} level(s) of indirection.
+ /// Looks up a localized string similar to Marshalling info was specified for &apos;ElementIndirectionDepth&apos; {0}, but marshalling info was only needed for {1} level(s) of indirection.
/// </summary>
internal static string ExtraneousMarshallingInfo {
get {
@@ -223,7 +223,7 @@ namespace Microsoft.Interop {
}
/// <summary>
- /// Marshalling bool without explicit marshalling information is not supported. Specify either &apos;MarshalUsingAttribute&apos; or &apos;MarshalAsAttribute&apos;..
+ /// Looks up a localized string similar to Marshalling bool without explicit marshalling information is not supported. Specify either &apos;MarshalUsingAttribute&apos; or &apos;MarshalAsAttribute&apos;..
/// </summary>
internal static string MarshallingBoolAsUndefinedNotSupported {
get {
@@ -297,18 +297,18 @@ namespace Microsoft.Interop {
/// <summary>
/// Looks up a localized string similar to The &apos;Value&apos; property must not be a &apos;ref&apos; or &apos;readonly ref&apos; property..
/// </summary>
- internal static string RefValuePropertyUnsupportedDescription {
+ internal static string RefNativeValueUnsupportedDescription {
get {
- return ResourceManager.GetString("RefValuePropertyUnsupportedDescription", resourceCulture);
+ return ResourceManager.GetString("RefNativeValueUnsupportedDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The &apos;Value&apos; property on the native type &apos;{0}&apos; must not be a &apos;ref&apos; or &apos;readonly ref&apos; property..
/// </summary>
- internal static string RefValuePropertyUnsupportedMessage {
+ internal static string RefNativeValueUnsupportedMessage {
get {
- return ResourceManager.GetString("RefValuePropertyUnsupportedMessage", resourceCulture);
+ return ResourceManager.GetString("RefNativeValueUnsupportedMessage", resourceCulture);
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.resx b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.resx
index abac39ff660..2097f8a82ec 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.resx
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources.resx
@@ -165,33 +165,12 @@
<data name="OutByValueNotSupportedMessage" xml:space="preserve">
<value>The '[Out]' attribute is not supported on the '{0}' parameter.</value>
</data>
- <data name="RefValuePropertyUnsupportedDescription" xml:space="preserve">
- <value>The 'Value' property must not be a 'ref' or 'readonly ref' property.</value>
- </data>
- <data name="RefValuePropertyUnsupportedMessage" xml:space="preserve">
- <value>The 'Value' property on the native type '{0}' must not be a 'ref' or 'readonly ref' property.</value>
- </data>
<data name="SafeHandleByRefMustBeConcrete" xml:space="preserve">
<value>An abstract type derived from 'SafeHandle' cannot be marshalled by reference. The provided type must be concrete.</value>
</data>
<data name="TypeNotSupportedTitle" xml:space="preserve">
<value>Specified type is not supported by source-generated P/Invokes</value>
</data>
- <data name="ValuePropertyMarshallingRequiresAdditionalState" xml:space="preserve">
- <value>Marshalling a value between managed and native with a native type with a 'Value' property requires extra state, which is not supported in this context.</value>
- </data>
- <data name="ValuePropertyMustHaveGetterDescription" xml:space="preserve">
- <value>The native type's 'Value' property must have a getter to support marshalling from managed to native.</value>
- </data>
- <data name="ValuePropertyMustHaveGetterMessage" xml:space="preserve">
- <value>The 'Value' property on the native type '{0}' must have a getter</value>
- </data>
- <data name="ValuePropertyMustHaveSetterDescription" xml:space="preserve">
- <value>The native type's 'Value' property must have a setter to support marshalling from native to managed.</value>
- </data>
- <data name="ValuePropertyMustHaveSetterMessage" xml:space="preserve">
- <value>The 'Value' property on the native type '{0}' must have a setter</value>
- </data>
<data name="CyclicalCountInfo" xml:space="preserve">
<value>This element cannot depend on '{0}' for collection size information without creating a dependency cycle</value>
</data>
@@ -202,17 +181,11 @@
<value>Multiple marshalling attributes per element per indirection level is unsupported, but duplicate information was provided for indirection level {0}</value>
</data>
<data name="ExtraneousMarshallingInfo" xml:space="preserve">
- <value>Marshalling info was specified for 'ElementIndirectionLevel' {0}, but marshalling info was only needed for {1} level(s) of indirection</value>
+ <value>Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection</value>
</data>
<data name="NativeGenericTypeMustBeClosedOrMatchArityMessage" xml:space="preserve">
<value>The native type '{0}' for managed type '{1}' must be a closed generic type or have the same arity as the managed type.</value>
</data>
- <data name="NativeTypeMustHaveRequiredShapeDescription" xml:space="preserve">
- <value>The native type must have at least one of the two marshalling methods to enable marshalling the managed type.</value>
- </data>
- <data name="NativeTypeMustHaveRequiredShapeMessage" xml:space="preserve">
- <value>The native type '{0}' must be a value type and have a constructor that takes one parameter of type '{1}' or a parameterless instance method named 'ToManaged' that returns '{1}'</value>
- </data>
<data name="CollectionNativeTypeMustHaveRequiredShapeDescription" xml:space="preserve">
<value>A native type with the 'GenericContiguousCollectionMarshallerAttribute' must have at least one of the two marshalling methods as well as a 'ManagedValues' property of type 'Span&lt;T&gt;' for some 'T' and a 'NativeValueStorage' property of type 'Span&lt;byte&gt;' to enable marshalling the managed type.</value>
</data>
@@ -220,7 +193,7 @@
<value>The native type '{0}' must be a value type and have a constructor that takes two parameters, one of type '{1}' and an 'int', or have a parameterless instance method named 'ToManaged' that returns '{1}' as well as a 'ManagedValues' property of type 'Span&lt;T&gt;' for some 'T' and a 'NativeValueStorage' property of type 'Span&lt;byte&gt;'</value>
</data>
<data name="ConstantAndElementCountInfoDisallowed" xml:space="preserve">
- <value>Only one of 'ConstantElementCount' or 'ElementCountInfo' may be used in a 'MarshalUsingAttribute' for a given 'ElementIndirectionLevel'</value>
+ <value>Only one of 'ConstantElementCount' or 'ElementCountInfo' may be used in a 'MarshalUsingAttribute' for a given 'ElementIndirectionDepth'</value>
</data>
<data name="RuntimeMarshallingMustBeDisabled" xml:space="preserve">
<value>Runtime marshalling must be disabled in this project by applying the 'System.Runtime.InteropServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.</value>
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 1a812d49696..ba09ebee867 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
@@ -15,7 +15,9 @@ namespace Microsoft.Interop
public const string MarshalUsingAttribute = "System.Runtime.InteropServices.MarshalUsingAttribute";
- public const string GenericContiguousCollectionMarshallerAttribute = "System.Runtime.InteropServices.GenericContiguousCollectionMarshallerAttribute";
+ public const string CustomTypeMarshallerAttribute = "System.Runtime.InteropServices.CustomTypeMarshallerAttribute";
+
+ public const string CustomTypeMarshallerAttributeGenericPlaceholder = "System.Runtime.InteropServices.CustomTypeMarshallerAttribute.GenericPlaceholder";
public const string LCIDConversionAttribute = "System.Runtime.InteropServices.LCIDConversionAttribute";
@@ -24,6 +26,8 @@ namespace Microsoft.Interop
public const string UnmanagedCallConvAttribute = "System.Runtime.InteropServices.UnmanagedCallConvAttribute";
public const string System_Span_Metadata = "System.Span`1";
public const string System_Span = "System.Span";
+ public const string System_ReadOnlySpan_Metadata = "System.ReadOnlySpan`1";
+ public const string System_ReadOnlySpan = "System.ReadOnlySpan";
public const string System_IntPtr = "System.IntPtr";
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
index c03e880f124..bb10cf31c12 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
@@ -28,16 +28,7 @@ namespace Microsoft.Interop
{
if (!field.IsStatic)
{
- bool fieldBlittable = field switch
- {
- // Assume that type parameters that can be blittable are blittable.
- // We'll re-evaluate blittability for generic fields of generic types at instantation time.
- { Type: ITypeParameterSymbol { IsReferenceType: false } } => true,
- { Type.IsUnmanagedType: false } => false,
- _ => IsConsideredBlittable(field.Type, seenTypes.Add(type))
- };
-
- if (!fieldBlittable)
+ if (!IsConsideredBlittable(field.Type, seenTypes.Add(type)))
{
return false;
}
@@ -51,6 +42,12 @@ namespace Microsoft.Interop
private static bool IsConsideredBlittable(this ITypeSymbol type, ImmutableHashSet<ITypeSymbol> seenTypes)
{
+ // Assume that type parameters that can be blittable are blittable.
+ // We'll re-evaluate blittability for generic fields of generic types at instantation time.
+ if (type.TypeKind == TypeKind.TypeParameter && !type.IsReferenceType)
+ {
+ return true;
+ }
if (!type.IsUnmanagedType || type.IsAutoLayout())
{
return false;
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj
index 710d935b82f..a1c0dd27574 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj
+++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj
@@ -12,6 +12,9 @@
<ItemGroup>
<Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/GeneratedMarshallingAttribute.cs" Link="GeneratedMarshallingAttribute.cs" />
+ <Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/CustomTypeMarshallerKind.cs" Link="CustomTypeMarshallerKind.cs" />
+ <Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/CustomTypeMarshallerDirection.cs" Link="CustomTypeMarshallerDirection.cs" />
+ <Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/CustomTypeMarshallerFeatures.cs" Link="CustomTypeMarshallerFeatures.cs" />
<Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/ArrayMarshaller.cs" Link="ArrayMarshaller.cs" />
</ItemGroup>
</Project>
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs
index 46cd7302fbf..358fc92cf6b 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/SpanMarshallers.cs
@@ -6,7 +6,10 @@ using System.Runtime.CompilerServices;
namespace System.Runtime.InteropServices.GeneratedMarshalling
{
- [GenericContiguousCollectionMarshaller]
+ // 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<T>
{
private ReadOnlySpan<T> _managedSpan;
@@ -47,47 +50,15 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
}
}
- /// <summary>
- /// 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.
- /// </summary>
- public const int BufferSize = 0x200;
- public const bool RequiresStackBuffer = true;
+ public ReadOnlySpan<T> GetManagedValuesSource() => _managedSpan;
- public Span<T> ManagedValues => MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(_managedSpan), _managedSpan.Length);
+ public Span<byte> GetNativeValuesDestination() => NativeValueStorage;
- public Span<byte> NativeValueStorage { get; private set; }
+ private Span<byte> NativeValueStorage { get; }
public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(NativeValueStorage);
- public void SetUnmarshalledCollectionLength(int length)
- {
- _managedSpan = new T[length];
- }
-
- public byte* Value
- {
- get
- {
- return (byte*)Unsafe.AsPointer(ref GetPinnableReference());
- }
- set
- {
- if (value == null)
- {
- _managedSpan = null;
- NativeValueStorage = default;
- }
- else
- {
- _allocatedMemory = (IntPtr)value;
- NativeValueStorage = new Span<byte>(value, _managedSpan.Length * _sizeOfNativeElement);
- }
- }
- }
-
- public ReadOnlySpan<T> ToManaged() => _managedSpan;
+ public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference());
public void FreeNative()
{
@@ -95,68 +66,69 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
}
}
- [GenericContiguousCollectionMarshaller]
+ [CustomTypeMarshaller(typeof(Span<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)]
public unsafe ref struct SpanMarshaller<T>
{
- private ReadOnlySpanMarshaller<T> _inner;
+ private Span<T> _managedSpan;
+ private readonly int _sizeOfNativeElement;
+ private IntPtr _allocatedMemory;
public SpanMarshaller(int sizeOfNativeElement)
: this()
{
- _inner = new ReadOnlySpanMarshaller<T>(sizeOfNativeElement);
+ _sizeOfNativeElement = sizeOfNativeElement;
}
public SpanMarshaller(Span<T> managed, int sizeOfNativeElement)
+ :this(managed, Span<byte>.Empty, sizeOfNativeElement)
{
- _inner = new ReadOnlySpanMarshaller<T>(managed, sizeOfNativeElement);
}
public SpanMarshaller(Span<T> managed, Span<byte> stackSpace, int sizeOfNativeElement)
{
- _inner = new ReadOnlySpanMarshaller<T>(managed, stackSpace, sizeOfNativeElement);
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- public const int BufferSize = ReadOnlySpanMarshaller<T>.BufferSize;
- public const bool RequiresStackBuffer = ReadOnlySpanMarshaller<T>.RequiresStackBuffer;
-
- public Span<T> ManagedValues => _inner.ManagedValues;
-
- public Span<byte> NativeValueStorage
- {
- get => _inner.NativeValueStorage;
+ _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<byte>((void*)_allocatedMemory, spaceToAllocate);
+ }
}
- public ref byte GetPinnableReference() => ref _inner.GetPinnableReference();
-
- public void SetUnmarshalledCollectionLength(int length)
- {
- _inner.SetUnmarshalledCollectionLength(length);
- }
+ private Span<byte> NativeValueStorage { get; set; }
- public byte* Value
- {
- get => _inner.Value;
- set => _inner.Value = value;
- }
+ public ReadOnlySpan<T> GetManagedValuesSource() => _managedSpan;
+ public Span<T> GetManagedValuesDestination(int length) => _managedSpan = new T[length];
+ public Span<byte> GetNativeValuesDestination() => NativeValueStorage;
+ public ReadOnlySpan<byte> GetNativeValuesSource(int length) => NativeValueStorage = new Span<byte>((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<T> ToManaged()
{
- ReadOnlySpan<T> managedInner = _inner.ToManaged();
- return MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(managedInner), managedInner.Length);
+ return _managedSpan;
}
public void FreeNative()
{
- _inner.FreeNative();
+ Marshal.FreeCoTaskMem(_allocatedMemory);
}
}
- [GenericContiguousCollectionMarshaller]
+ [CustomTypeMarshaller(typeof(Span<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)]
public unsafe ref struct NeverNullSpanMarshaller<T>
{
private SpanMarshaller<T> _inner;
@@ -177,47 +149,14 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
_inner = new SpanMarshaller<T>(managed, stackSpace, sizeOfNativeElement);
}
- /// <summary>
- /// Stack-alloc threshold set to 256 bytes to enable small spans to be passed on the stack.
- /// Number kept small to ensure that P/Invokes with a lot of span parameters doesn't
- /// blow the stack.
- /// </summary>
- public const int BufferSize = SpanMarshaller<T>.BufferSize;
-
- public Span<T> ManagedValues => _inner.ManagedValues;
-
- public Span<byte> NativeValueStorage
- {
- get => _inner.NativeValueStorage;
- }
-
- public ref byte GetPinnableReference()
- {
- if (_inner.ManagedValues.Length == 0)
- {
- return ref *(byte*)0xa5a5a5a5;
- }
- return ref _inner.GetPinnableReference();
- }
-
- public void SetUnmarshalledCollectionLength(int length)
- {
- _inner.SetUnmarshalledCollectionLength(length);
- }
- public byte* Value
- {
- get
- {
- if (_inner.ManagedValues.Length == 0)
- {
- return (byte*)0xa5a5a5a5;
- }
- return _inner.Value;
- }
-
- set => _inner.Value = value;
- }
+ public ReadOnlySpan<T> GetManagedValuesSource() => _inner.GetManagedValuesSource();
+ public Span<T> GetManagedValuesDestination(int length) => _inner.GetManagedValuesDestination(length);
+ public Span<byte> GetNativeValuesDestination() => _inner.GetNativeValuesDestination();
+ public ReadOnlySpan<byte> 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<T> ToManaged() => _inner.ToManaged();
@@ -227,7 +166,7 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
}
}
- [GenericContiguousCollectionMarshaller]
+ [CustomTypeMarshaller(typeof(ReadOnlySpan<>), CustomTypeMarshallerKind.LinearCollection, Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 0x200)]
public unsafe ref struct NeverNullReadOnlySpanMarshaller<T>
{
private ReadOnlySpanMarshaller<T> _inner;
@@ -248,50 +187,10 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
_inner = new ReadOnlySpanMarshaller<T>(managed, stackSpace, sizeOfNativeElement);
}
- /// <summary>
- /// Stack-alloc threshold set to 256 bytes to enable small spans to be passed on the stack.
- /// Number kept small to ensure that P/Invokes with a lot of span parameters doesn't
- /// blow the stack.
- /// </summary>
- public const int BufferSize = SpanMarshaller<T>.BufferSize;
- public const bool RequiresStackBuffer = SpanMarshaller<T>.RequiresStackBuffer;
-
- public Span<T> ManagedValues => _inner.ManagedValues;
-
- public Span<byte> NativeValueStorage
- {
- get => _inner.NativeValueStorage;
- }
-
- public ref byte GetPinnableReference()
- {
- if (_inner.ManagedValues.Length == 0)
- {
- return ref *(byte*)0xa5a5a5a5;
- }
- return ref _inner.GetPinnableReference();
- }
-
- public void SetUnmarshalledCollectionLength(int length)
- {
- _inner.SetUnmarshalledCollectionLength(length);
- }
-
- public byte* Value
- {
- get
- {
- if (_inner.ManagedValues.Length == 0)
- {
- return (byte*)0xa5a5a5a5;
- }
- return _inner.Value;
- }
-
- set => _inner.Value = value;
- }
-
- public ReadOnlySpan<T> ToManaged() => _inner.ToManaged();
+ public ReadOnlySpan<T> GetManagedValuesSource() => _inner.GetManagedValuesSource();
+ public Span<byte> 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()
{
@@ -299,22 +198,18 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
}
}
- [GenericContiguousCollectionMarshaller]
+ // 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<T>
where T : unmanaged
{
- private int _unmarshalledLength;
private T* _allocatedMemory;
+ private T* _nativeValue;
private Span<T> _data;
public DirectSpanMarshaller(int sizeOfNativeElement)
:this()
{
- // This check is not exhaustive, but it will catch the majority of cases.
- if (typeof(T) == typeof(bool) || typeof(T) == typeof(char) || Unsafe.SizeOf<T>() != sizeOfNativeElement)
- {
- throw new ArgumentException("This marshaller only supports blittable element types. The provided type parameter must be blittable", nameof(T));
- }
}
public DirectSpanMarshaller(Span<T> managed, int sizeOfNativeElement)
@@ -337,42 +232,29 @@ namespace System.Runtime.InteropServices.GeneratedMarshalling
_data = managed;
}
- /// <summary>
- /// 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.
- /// </summary>
- public const int BufferSize = 0;
-
- public Span<T> ManagedValues => _data;
-
- public Span<byte> NativeValueStorage => _allocatedMemory != null
+ public ReadOnlySpan<T> GetManagedValuesSource() => _data;
+ public Span<T> GetManagedValuesDestination(int length) => _data = new Span<T>(_nativeValue, length);
+ public Span<byte> GetNativeValuesDestination() => _allocatedMemory != null
? new Span<byte>(_allocatedMemory, _data.Length * Unsafe.SizeOf<T>())
: MemoryMarshal.Cast<T, byte>(_data);
+ public ReadOnlySpan<byte> GetNativeValuesSource(int length) => new ReadOnlySpan<byte>(_nativeValue, length * sizeof(T));
+
public ref T GetPinnableReference() => ref _data.GetPinnableReference();
- public void SetUnmarshalledCollectionLength(int length)
+ public T* ToNativeValue()
{
- _unmarshalledLength = length;
+ if (_allocatedMemory != null)
+ {
+ return _allocatedMemory;
+ }
+ return (T*)Unsafe.AsPointer(ref GetPinnableReference());
}
- public T* Value
+ public void FromNativeValue(T* value)
{
- get
- {
- if (_allocatedMemory != null)
- {
- return _allocatedMemory;
- }
- return (T*)Unsafe.AsPointer(ref GetPinnableReference());
- }
- set
- {
- // We don't save the pointer assigned here to be freed
- // since this marshaller passes back the actual memory span from native code
- // back to managed code.
- _allocatedMemory = null;
- _data = new Span<T>(value, _unmarshalledLength);
- }
+ _allocatedMemory = null;
+ _nativeValue = value;
}
public Span<T> ToManaged()
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 8fd114021a4..6075ce224ee 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs
@@ -77,7 +77,7 @@ namespace LibraryImportGenerator.IntegrationTests
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "transpose_matrix")]
[return: MarshalUsing(CountElementName = "numColumns")]
- [return: MarshalUsing(CountElementName = "numRows", ElementIndirectionLevel = 1)]
+ [return: MarshalUsing(CountElementName = "numRows", ElementIndirectionDepth = 1)]
public static partial int[][] TransposeMatrix(int[][] matrix, int[] numRows, int numColumns);
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs
index f8676d68e26..f77258710ca 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs
@@ -36,20 +36,20 @@ namespace LibraryImportGenerator.IntegrationTests
public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalUsing(typeof(ListMarshaller<int>), CountElementName = "numValues")] out List<int> res);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")]
- public static partial int SumStringLengths([MarshalUsing(typeof(ListMarshaller<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionLevel = 1)] List<string> strArray);
+ public static partial int SumStringLengths([MarshalUsing(typeof(ListMarshaller<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_replace")]
- public static partial void ReverseStrings_Ref([MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionLevel = 1)] ref List<string> strArray, out int numElements);
+ public static partial void ReverseStrings_Ref([MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] ref List<string> strArray, out int numElements);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_return")]
- [return: MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionLevel = 1)]
- public static partial List<string> ReverseStrings_Return([MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionLevel = 1)] List<string> strArray, out int numElements);
+ [return: MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)]
+ public static partial List<string> ReverseStrings_Return([MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray, out int numElements);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_out")]
public static partial void ReverseStrings_Out(
- [MarshalUsing(typeof(ListMarshaller<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionLevel = 1)] List<string> strArray,
+ [MarshalUsing(typeof(ListMarshaller<string>)), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] List<string> strArray,
out int numElements,
- [MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionLevel = 1)] out List<string> res);
+ [MarshalUsing(typeof(ListMarshaller<string>), CountElementName = "numElements"), MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)] out List<string> res);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")]
[return:MarshalUsing(typeof(ListMarshaller<byte>), ConstantElementCount = sizeof(long))]
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 057bef953c7..18a3ac4fc1a 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SetLastErrorTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SetLastErrorTests.cs
@@ -8,6 +8,7 @@ using Xunit;
namespace LibraryImportGenerator.IntegrationTests
{
+ [CustomTypeMarshaller(typeof(int))]
public struct SetLastErrorMarshaller
{
public int val;
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 e9a7f5c47b4..fa879e7d134 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs
@@ -31,6 +31,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
@@ -82,6 +83,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
@@ -172,6 +174,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
@@ -204,6 +207,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
@@ -236,6 +240,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
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 f876a914e0f..7edda25746c 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs
@@ -38,6 +38,7 @@ struct S
{{
}}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{{
public Native(S s) {{ }}
@@ -79,6 +80,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
@@ -122,6 +124,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
@@ -169,6 +172,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
@@ -220,6 +224,7 @@ struct S
{{
}}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{{
public Native(S s) {{ }}
@@ -268,6 +273,7 @@ struct S
{
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
public Native(S s) { }
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 93b822d6f7b..3312098bfe5 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
@@ -381,6 +381,7 @@ partial class Test
{
string typeName = typeof(T).ToString();
return BasicParametersAndModifiersWithStringMarshallingCustomType(typeName, "Native", DisableRuntimeMarshalling) + @$"
+[CustomTypeMarshaller(typeof({typeName}))]
struct Native
{{
public Native({typeName} s) {{ }}
@@ -636,6 +637,7 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
private int i;
@@ -655,6 +657,7 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S))]
struct Native
{
private int i;
@@ -674,6 +677,7 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 1)]
struct Native
{
private int i;
@@ -683,8 +687,6 @@ struct Native
}
public S ToManaged() => new S { b = i != 0 };
-
- public const int BufferSize = 1;
}
";
public static string CustomStructMarshallingStackallocOnlyRefParameter = BasicParameterWithByRefModifier("ref", "S", DisableRuntimeMarshalling) + @"
@@ -694,6 +696,7 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.Out, Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 1)]
struct Native
{
private int i;
@@ -703,9 +706,6 @@ struct Native
}
public S ToManaged() => new S { b = i != 0 };
-
- public const int BufferSize = 1;
- public const bool RequiresStackBuffer = false;
}
";
public static string CustomStructMarshallingOptionalStackallocParametersAndModifiers = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + @"
@@ -715,6 +715,7 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 1)]
struct Native
{
private int i;
@@ -728,9 +729,6 @@ struct Native
}
public S ToManaged() => new S { b = i != 0 };
-
- public const int BufferSize = 1;
- public const bool RequiresStackBuffer = true;
}
";
@@ -741,18 +739,17 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)]
struct Native
{
public Native(S s, System.Span<byte> b)
{
- Value = s.b ? 1 : 0;
}
- public S ToManaged() => new S { b = Value != 0 };
-
- public int Value { get; set; }
+ public S ToManaged() => new S { b = true };
- public const int BufferSize = 1;
+ public int ToNativeValue() => throw null;
+ public void FromNativeValue(int value) => throw null;
}
";
public static string CustomStructMarshallingValuePropertyParametersAndModifiers = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + @"
@@ -762,16 +759,17 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
struct Native
{
public Native(S s)
{
- Value = s.b ? 1 : 0;
}
- public S ToManaged() => new S { b = Value != 0 };
+ public S ToManaged() => new S { b = true };
- public int Value { get; set; }
+ public int ToNativeValue() => throw null;
+ public void FromNativeValue(int value) => throw null;
}
";
public static string CustomStructMarshallingPinnableParametersAndModifiers = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + @"
@@ -783,6 +781,7 @@ class S
public ref int GetPinnableReference() => ref i;
}
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
unsafe struct Native
{
private int* ptr;
@@ -794,15 +793,14 @@ unsafe struct Native
public S ToManaged() => new S { i = *ptr };
- public nint Value
- {
- get => (nint)ptr;
- set => ptr = (int*)value;
- }
+ public nint ToNativeValue() => (nint)ptr;
+
+ public void FromNativeValue(nint value) => ptr = (int*)value;
}
";
public static string CustomStructMarshallingNativeTypePinnable = @"
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System;
@@ -814,6 +812,7 @@ class S
public byte c;
}
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)]
unsafe ref struct Native
{
private byte* ptr;
@@ -823,6 +822,7 @@ unsafe ref struct Native
{
ptr = (byte*)Marshal.AllocCoTaskMem(sizeof(byte));
*ptr = s.c;
+ stackBuffer = new Span<byte>(ptr, 1);
}
public Native(S s, Span<byte> buffer) : this()
@@ -831,18 +831,16 @@ unsafe ref struct Native
stackBuffer[0] = s.c;
}
- public ref byte GetPinnableReference() => ref (ptr != null ? ref *ptr : ref stackBuffer.GetPinnableReference());
+ public ref byte GetPinnableReference() => ref stackBuffer.GetPinnableReference();
public S ToManaged()
{
return new S { c = *ptr };
}
- public byte* Value
- {
- get => ptr != null ? ptr : throw new InvalidOperationException();
- set => ptr = value;
- }
+ public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference());
+
+ public void FromNativeValue(byte* value) => ptr = value;
public void FreeNative()
{
@@ -851,8 +849,6 @@ unsafe ref struct Native
Marshal.FreeCoTaskMem((IntPtr)ptr);
}
}
-
- public const int BufferSize = 1;
}
partial class Test
@@ -871,6 +867,7 @@ class S
public byte c = 0;
}
+[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
unsafe struct Native
{
private S value;
@@ -880,7 +877,7 @@ unsafe struct Native
value = s;
}
- public ref byte Value { get => ref value.c; }
+ public ref byte ToNativeValue() => ref value.c;
}
";
@@ -921,6 +918,7 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In)]
struct Native
{
private int i;
@@ -939,6 +937,7 @@ struct S
public bool b;
}
+[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In)]
struct Native
{
private int i;
@@ -957,6 +956,7 @@ struct S
}
[StructLayout(LayoutKind.Sequential)]
+[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.Out)]
struct Native
{
private int i;
@@ -971,16 +971,17 @@ public struct IntStructWrapper
public int Value;
}
+[CustomTypeMarshaller(typeof(IntStructWrapper), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
public struct IntStructWrapperNative
{
public IntStructWrapperNative(IntStructWrapper managed)
{
- Value = managed.Value;
}
- public int Value { get; set; }
+ public int ToNativeValue() => throw null;
+ public void FromNativeValue(int value) => throw null;
- public IntStructWrapper ToManaged() => new IntStructWrapper { Value = Value };
+ public IntStructWrapper ToManaged() => new IntStructWrapper { Value = 1 };
}
";
@@ -991,6 +992,7 @@ public struct IntStructWrapper
public int Value;
}
+[CustomTypeMarshaller(typeof(IntStructWrapper))]
public struct IntStructWrapperNative
{
private int value;
@@ -1116,13 +1118,18 @@ struct RecursiveStruct2
[NativeMarshalling(typeof(Marshaller<>))]
class TestCollection<T> {}
-[GenericContiguousCollectionMarshaller]
+[CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
ref struct Marshaller<T>
{
+ public Marshaller(int nativeElementSize) : this() {}
public Marshaller(TestCollection<T> managed, int nativeElementSize) : this() {}
- public System.Span<T> ManagedValues { get; }
- public System.Span<byte> NativeValueStorage { get; }
- public System.IntPtr Value { get; }
+ public System.ReadOnlySpan<T> GetManagedValuesSource() => throw null;
+ public System.Span<T> GetManagedValuesDestination(int length) => throw null;
+ public System.ReadOnlySpan<byte> GetNativeValuesSource(int length) => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+ public void FromNativeValue(System.IntPtr value) => throw null;
+ public TestCollection<T> ToManaged() => throw null;
}
";
@@ -1150,15 +1157,17 @@ partial class Test
string nativeMarshallingAttribute = enableDefaultMarshalling ? "[NativeMarshalling(typeof(Marshaller<>))]" : string.Empty;
return nativeMarshallingAttribute + @"class TestCollection<T> {}
-[GenericContiguousCollectionMarshaller]
+[CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
ref struct Marshaller<T>
{
public Marshaller(int nativeElementSize) : this() {}
public Marshaller(TestCollection<T> managed, int nativeElementSize) : this() {}
- public System.Span<T> ManagedValues { get; }
- public System.Span<byte> NativeValueStorage { get; }
- public System.IntPtr Value { get; set; }
- public void SetUnmarshalledCollectionLength(int length) {}
+ public System.ReadOnlySpan<T> GetManagedValuesSource() => throw null;
+ public System.Span<T> GetManagedValuesDestination(int length) => throw null;
+ public System.ReadOnlySpan<byte> GetNativeValuesSource(int length) => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+ public void FromNativeValue(System.IntPtr value) => throw null;
public TestCollection<T> ToManaged() => throw null;
}";
}
@@ -1247,13 +1256,18 @@ partial class Test
[NativeMarshalling(typeof(Marshaller<,>))]
class TestCollection<T> {}
-[GenericContiguousCollectionMarshaller]
+[CustomTypeMarshaller(typeof(TestCollection<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
ref struct Marshaller<T, U>
{
public Marshaller(TestCollection<T> managed, int nativeElementSize) : this() {}
- public System.Span<T> ManagedValues { get; }
- public System.Span<byte> NativeValueStorage { get; }
- public System.IntPtr Value { get; }
+
+ public System.ReadOnlySpan<T> GetManagedValuesSource() => throw null;
+ public System.Span<T> GetManagedValuesDestination(int length) => throw null;
+ public System.ReadOnlySpan<byte> GetNativeValuesSource(int length) => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+ public void FromNativeValue(System.IntPtr value) => throw null;
+
public TestCollection<T> ToManaged() => throw null;
}";
@@ -1264,13 +1278,13 @@ partial class Test
{
[LibraryImport(""DoesNotExist"")]
[return:MarshalUsing(ConstantElementCount=10)]
- [return:MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 1)]
+ [return:MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)]
public static partial TestCollection<int> Method(
- [MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 1)] TestCollection<int> p,
- [MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 1)] in TestCollection<int> pIn,
+ [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] TestCollection<int> p,
+ [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] in TestCollection<int> pIn,
int pRefSize,
- [MarshalUsing(CountElementName = ""pRefSize""), MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 1)] ref TestCollection<int> pRef,
- [MarshalUsing(CountElementName = ""pOutSize"")][MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 1)] out TestCollection<int> pOut,
+ [MarshalUsing(CountElementName = ""pRefSize""), MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] ref TestCollection<int> pRef,
+ [MarshalUsing(CountElementName = ""pOutSize"")][MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] out TestCollection<int> pOut,
out int pOutSize
);
}
@@ -1283,14 +1297,14 @@ struct IntWrapper
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionLevel => @"
+ public static string GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth => @"
using System.Runtime.InteropServices;
[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
partial class Test
{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
- [MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 1)] [MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 1)] TestCollection<int> p);
+ [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] TestCollection<int> p);
}
struct IntWrapper
@@ -1301,14 +1315,14 @@ struct IntWrapper
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionLevel => @"
+ public static string GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth => @"
using System.Runtime.InteropServices;
[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
partial class Test
{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
- [MarshalUsing(typeof(IntWrapper), ElementIndirectionLevel = 2)] TestCollection<int> p);
+ [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 2)] TestCollection<int> p);
}
struct IntWrapper
@@ -1385,72 +1399,72 @@ partial class Test
{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]
- [MarshalUsing(CountElementName=""arr4"", ElementIndirectionLevel = 4)]
- [MarshalUsing(CountElementName=""arr5"", ElementIndirectionLevel = 5)]
- [MarshalUsing(CountElementName=""arr6"", ElementIndirectionLevel = 6)]
- [MarshalUsing(CountElementName=""arr7"", ElementIndirectionLevel = 7)]
- [MarshalUsing(CountElementName=""arr8"", ElementIndirectionLevel = 8)]
- [MarshalUsing(CountElementName=""arr9"", ElementIndirectionLevel = 9)]
- [MarshalUsing(CountElementName=""arr10"", ElementIndirectionLevel = 10)] ref int[][][][][][][][][][][] arr11,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]
- [MarshalUsing(CountElementName=""arr4"", ElementIndirectionLevel = 4)]
- [MarshalUsing(CountElementName=""arr5"", ElementIndirectionLevel = 5)]
- [MarshalUsing(CountElementName=""arr6"", ElementIndirectionLevel = 6)]
- [MarshalUsing(CountElementName=""arr7"", ElementIndirectionLevel = 7)]
- [MarshalUsing(CountElementName=""arr8"", ElementIndirectionLevel = 8)]
- [MarshalUsing(CountElementName=""arr9"", ElementIndirectionLevel = 9)]ref int[][][][][][][][][][] arr10,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]
- [MarshalUsing(CountElementName=""arr4"", ElementIndirectionLevel = 4)]
- [MarshalUsing(CountElementName=""arr5"", ElementIndirectionLevel = 5)]
- [MarshalUsing(CountElementName=""arr6"", ElementIndirectionLevel = 6)]
- [MarshalUsing(CountElementName=""arr7"", ElementIndirectionLevel = 7)]
- [MarshalUsing(CountElementName=""arr8"", ElementIndirectionLevel = 8)]ref int[][][][][][][][][] arr9,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]
- [MarshalUsing(CountElementName=""arr4"", ElementIndirectionLevel = 4)]
- [MarshalUsing(CountElementName=""arr5"", ElementIndirectionLevel = 5)]
- [MarshalUsing(CountElementName=""arr6"", ElementIndirectionLevel = 6)]
- [MarshalUsing(CountElementName=""arr7"", ElementIndirectionLevel = 7)]ref int[][][][][][][][][] arr8,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]
- [MarshalUsing(CountElementName=""arr4"", ElementIndirectionLevel = 4)]
- [MarshalUsing(CountElementName=""arr5"", ElementIndirectionLevel = 5)]
- [MarshalUsing(CountElementName=""arr6"", ElementIndirectionLevel = 6)]ref int[][][][][][][] arr7,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]
- [MarshalUsing(CountElementName=""arr4"", ElementIndirectionLevel = 4)]
- [MarshalUsing(CountElementName=""arr5"", ElementIndirectionLevel = 5)]ref int[][][][][][] arr6,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]
- [MarshalUsing(CountElementName=""arr4"", ElementIndirectionLevel = 4)]ref int[][][][][] arr5,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]
- [MarshalUsing(CountElementName=""arr3"", ElementIndirectionLevel = 3)]ref int[][][][] arr4,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]
- [MarshalUsing(CountElementName=""arr2"", ElementIndirectionLevel = 2)]ref int[][][] arr3,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]
- [MarshalUsing(CountElementName=""arr1"", ElementIndirectionLevel = 1)]ref int[][] arr2,
- [MarshalUsing(CountElementName=""arr0"", ElementIndirectionLevel = 0)]ref int[] arr1,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]
+ [MarshalUsing(CountElementName=""arr4"", ElementIndirectionDepth = 4)]
+ [MarshalUsing(CountElementName=""arr5"", ElementIndirectionDepth = 5)]
+ [MarshalUsing(CountElementName=""arr6"", ElementIndirectionDepth = 6)]
+ [MarshalUsing(CountElementName=""arr7"", ElementIndirectionDepth = 7)]
+ [MarshalUsing(CountElementName=""arr8"", ElementIndirectionDepth = 8)]
+ [MarshalUsing(CountElementName=""arr9"", ElementIndirectionDepth = 9)]
+ [MarshalUsing(CountElementName=""arr10"", ElementIndirectionDepth = 10)] ref int[][][][][][][][][][][] arr11,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]
+ [MarshalUsing(CountElementName=""arr4"", ElementIndirectionDepth = 4)]
+ [MarshalUsing(CountElementName=""arr5"", ElementIndirectionDepth = 5)]
+ [MarshalUsing(CountElementName=""arr6"", ElementIndirectionDepth = 6)]
+ [MarshalUsing(CountElementName=""arr7"", ElementIndirectionDepth = 7)]
+ [MarshalUsing(CountElementName=""arr8"", ElementIndirectionDepth = 8)]
+ [MarshalUsing(CountElementName=""arr9"", ElementIndirectionDepth = 9)]ref int[][][][][][][][][][][] arr10,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]
+ [MarshalUsing(CountElementName=""arr4"", ElementIndirectionDepth = 4)]
+ [MarshalUsing(CountElementName=""arr5"", ElementIndirectionDepth = 5)]
+ [MarshalUsing(CountElementName=""arr6"", ElementIndirectionDepth = 6)]
+ [MarshalUsing(CountElementName=""arr7"", ElementIndirectionDepth = 7)]
+ [MarshalUsing(CountElementName=""arr8"", ElementIndirectionDepth = 8)]ref int[][][][][][][][][][] arr9,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]
+ [MarshalUsing(CountElementName=""arr4"", ElementIndirectionDepth = 4)]
+ [MarshalUsing(CountElementName=""arr5"", ElementIndirectionDepth = 5)]
+ [MarshalUsing(CountElementName=""arr6"", ElementIndirectionDepth = 6)]
+ [MarshalUsing(CountElementName=""arr7"", ElementIndirectionDepth = 7)]ref int[][][][][][][][][] arr8,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]
+ [MarshalUsing(CountElementName=""arr4"", ElementIndirectionDepth = 4)]
+ [MarshalUsing(CountElementName=""arr5"", ElementIndirectionDepth = 5)]
+ [MarshalUsing(CountElementName=""arr6"", ElementIndirectionDepth = 6)]ref int[][][][][][][] arr7,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]
+ [MarshalUsing(CountElementName=""arr4"", ElementIndirectionDepth = 4)]
+ [MarshalUsing(CountElementName=""arr5"", ElementIndirectionDepth = 5)]ref int[][][][][][] arr6,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]
+ [MarshalUsing(CountElementName=""arr4"", ElementIndirectionDepth = 4)]ref int[][][][][] arr5,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]
+ [MarshalUsing(CountElementName=""arr3"", ElementIndirectionDepth = 3)]ref int[][][][] arr4,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]
+ [MarshalUsing(CountElementName=""arr2"", ElementIndirectionDepth = 2)]ref int[][][] arr3,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
+ [MarshalUsing(CountElementName=""arr1"", ElementIndirectionDepth = 1)]ref int[][] arr2,
+ [MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]ref int[] arr1,
ref int arr0
);
}
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 262072e940c..3a5403e70c3 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
@@ -110,8 +110,8 @@ namespace LibraryImportGenerator.UnitTests
yield return new object[] { CodeSnippets.GenericCollectionMarshallingArityMismatch, 2, 0 };
yield return new object[] { CodeSnippets.MarshalAsAndMarshalUsingOnReturnValue, 2, 0 };
- yield return new object[] { CodeSnippets.GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionLevel, 2, 0 };
- yield return new object[] { CodeSnippets.GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionLevel, 1, 0 };
+ yield return new object[] { CodeSnippets.GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth, 2, 0 };
+ yield return new object[] { CodeSnippets.GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth, 1, 0 };
yield return new object[] { CodeSnippets.RecursiveCountElementNameOnReturnValue, 2, 0 };
yield return new object[] { CodeSnippets.RecursiveCountElementNameOnParameter, 2, 0 };
yield return new object[] { CodeSnippets.MutuallyRecursiveCountElementNameOnParameter, 4, 0 };
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs
new file mode 100644
index 00000000000..9707345179c
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomTypeMarshallerFixerTests.cs
@@ -0,0 +1,1769 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Testing;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xunit;
+using static Microsoft.Interop.Analyzers.CustomTypeMarshallerAnalyzer;
+
+using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier<
+ Microsoft.Interop.Analyzers.CustomTypeMarshallerAnalyzer,
+ Microsoft.Interop.Analyzers.CustomTypeMarshallerFixer>;
+
+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;
+
+[{|#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;
+
+[{|#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;
+
+[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;
+
+[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;
+
+[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;
+
+[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;
+
+[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;
+
+[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;
+
+[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;
+
+[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<char>();
+
+ 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;
+
+[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<byte>();
+
+ 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;
+
+[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;
+
+[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;
+
+[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;
+
+[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;
+
+[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<byte>();
+}";
+
+ 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;
+
+[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<byte>();
+
+ public int ToNativeValue() => throw null;
+}";
+
+ await VerifyCS.VerifyCodeFixAsync(source, source);
+ }
+
+ [Fact]
+ public async Task NativeTypeWithNoMarshallingMethods_ReportsDiagnostic()
+ {
+ string source = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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;
+
+[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;
+
+[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<int> GetManagedValuesSource() => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+}";
+ string fixedSource = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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<int> GetManagedValuesSource() => throw null;
+ public System.Span<byte> 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;
+
+[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<int> GetManagedValuesSource() => throw null;
+ public System.Span<byte> 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;
+
+[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<byte> stackSpace) : this() {}
+
+ public System.ReadOnlySpan<int> GetManagedValuesSource() => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+}";
+ string fixedSource = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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<byte> stackSpace) : this() {}
+
+ public System.ReadOnlySpan<int> GetManagedValuesSource() => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+
+ public Native(S managed, int nativeElementSize)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Native(S managed, Span<byte> 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;
+
+[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<byte> stackSpace, int nativeElementSize) : this() {}
+
+ public System.ReadOnlySpan<int> GetManagedValuesSource() => throw null;
+ public System.Span<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+}";
+ string fixedSource = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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<byte> stackSpace, int nativeElementSize) : this() {}
+
+ public System.ReadOnlySpan<int> GetManagedValuesSource() => throw null;
+ public System.Span<byte> 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;
+
+[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<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+}";
+ string fixedSource = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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<byte> GetNativeValuesDestination() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+
+ public ReadOnlySpan<object> 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;
+
+[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<int> GetManagedValuesSource() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+}";
+ string fixedSource = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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<int> GetManagedValuesSource() => throw null;
+ public System.IntPtr ToNativeValue() => throw null;
+
+ public Span<byte> 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;
+
+[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<int> GetManagedValuesSource() => throw null;
+ public Span<byte> GetNativeValuesDestination() => throw null;
+ public ReadOnlySpan<byte> GetNativeValuesSource(int length) => throw null;
+ public Span<int> 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;
+
+[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<int> {|#0:GetManagedValuesSource|}() => throw null;
+ public Span<byte> GetNativeValuesDestination() => throw null;
+ public ReadOnlySpan<byte> GetNativeValuesSource(int length) => throw null;
+ public Span<long> 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;
+
+[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;
+
+[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 NativeTypeWithOnlyStackallocConstructor_ReportsDiagnostic()
+ {
+ string source = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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<byte> buffer) {}
+}";
+ string fixedSource = @"
+using System;
+using System.Runtime.InteropServices;
+
+[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<byte> 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;
+
+[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;
+
+[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;
+
+[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;
+
+[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;
+
+[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;
+
+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;
+
+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;
+
+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;
+
+[NativeMarshalling(typeof(Native<int>))]
+struct S
+{
+ public string s;
+}
+
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
+struct Native<T>
+ 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;
+
+[{|#0:NativeMarshalling(typeof(Native<>))|}]
+struct S
+{
+ public string s;
+}
+
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
+struct Native<T>
+ 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;
+
+struct S
+{
+ public string s;
+}
+
+[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
+struct Native<T>
+ 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;
+
+[{|#0:NativeMarshalling(typeof(Native<,>))|}]
+struct S<T>
+{
+ public string s;
+}
+
+[CustomTypeMarshaller(typeof(S<>), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
+struct {|#1:Native|}<T, U>
+ where T : new()
+{
+ public Native(S<T> s)
+ {
+ }
+
+ public S<T> ToManaged() => new S<T>();
+
+ public T ToNativeValue() => throw null;
+ public void FromNativeValue(T value) => throw null;
+}";
+ await VerifyCS.VerifyCodeFixAsync(source,
+ source,
+ VerifyCS.Diagnostic(NativeTypeMustHaveCustomTypeMarshallerAttributeRule).WithLocation(0).WithArguments("S<T>"),
+ VerifyCS.Diagnostic(NativeGenericTypeMustBeClosedOrMatchArityRule).WithLocation(1).WithArguments("Native<T, U>", "S<>"));
+ }
+
+ [Fact]
+ public async Task UninstantiatedGenericNativeTypeOnGenericWithArityMatch_DoesNotReportDiagnostic()
+ {
+ string source = @"
+using System.Runtime.InteropServices;
+
+[NativeMarshalling(typeof(Native<>))]
+struct S<T>
+{
+ public T t;
+}
+
+[CustomTypeMarshaller(typeof(S<>), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
+struct Native<T>
+ where T : new()
+{
+ public Native(S<T> s)
+ {
+ }
+
+ public S<T> ToManaged() => new S<T>();
+
+ 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;
+
+[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<byte> 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;
+
+[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder), Direction = CustomTypeMarshallerDirection.In)]
+struct Native<T>
+{
+ public Native(T a) {}
+}";
+
+ await VerifyCS.VerifyCodeFixAsync(source, source);
+ }
+
+ [Fact]
+ public async Task CustomTypeMarshallerForArrayTypeWithPlaceholder_DoesNotReportDiagnostic()
+ {
+ string source = @"
+using System;
+using System.Runtime.InteropServices;
+
+[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), Direction = CustomTypeMarshallerDirection.In)]
+struct Native<T>
+{
+ public Native(T[] a) {}
+}";
+
+ await VerifyCS.VerifyCodeFixAsync(source, source);
+ }
+
+ [Fact]
+ public async Task CustomTypeMarshallerForPointerTypeWithPlaceholder_DoesNotReportDiagnostic()
+ {
+ string source = @"
+using System;
+using System.Runtime.InteropServices;
+
+[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*), Direction = CustomTypeMarshallerDirection.In)]
+unsafe struct Native<T> 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;
+
+[CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), Direction = CustomTypeMarshallerDirection.In)]
+unsafe struct Native<T> 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;
+
+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;
+
+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;
+
+struct S { }
+
+[CustomTypeMarshaller(typeof(S), Direction = CustomTypeMarshallerDirection.In, BufferSize = 0x100)]
+unsafe struct {|#0:Native|}
+{
+ public Native(S s){}
+
+ public Native(S s, Span<byte> buffer) { }
+}";
+ string fixedSource = @"
+using System;
+using System.Runtime.InteropServices;
+
+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<byte> 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;
+
+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;
+
+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;
+
+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;
+
+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;
+
+[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 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/LibraryImportGenerator.UnitTests/ManualTypeMarshallingAnalyzerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ManualTypeMarshallingAnalyzerTests.cs
deleted file mode 100644
index bdc1eaf3625..00000000000
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ManualTypeMarshallingAnalyzerTests.cs
+++ /dev/null
@@ -1,1240 +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 Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Testing;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Xunit;
-using static Microsoft.Interop.Analyzers.ManualTypeMarshallingAnalyzer;
-
-using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpAnalyzerVerifier<Microsoft.Interop.Analyzers.ManualTypeMarshallingAnalyzer>;
-
-namespace LibraryImportGenerator.UnitTests
-{
- [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)]
- public class ManualTypeMarshallingAnalyzerTests
- {
- [Fact]
- public async Task NullNativeType_ReportsDiagnostic()
- {
- string source = @"
-using System.Runtime.InteropServices;
-
-[{|#0:NativeMarshalling(null)|}]
-struct S
-{
- public string s;
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustBeNonNullRule).WithLocation(0).WithArguments("S"));
- }
-
- [Fact]
- public async Task NonNamedNativeType_ReportsDiagnostic()
- {
- string source = @"
-using System.Runtime.InteropServices;
-
-[{|#0:NativeMarshalling(typeof(int*))|}]
-struct S
-{
- public string s;
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("int*", "S"));
- }
-
- [Fact]
- public async Task NonBlittableNativeType_ReportsDiagnostic()
- {
- string source = @"
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-struct S
-{
- public string s;
-}
-
-struct {|#0:Native|}
-{
- private string value;
-
- public Native(S s)
- {
- value = s.s;
- }
-
- public S ToManaged() => new S { s = value };
-}";
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task ClassNativeType_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-struct S
-{
- public string s;
-}
-
-class {|#0:Native|}
-{
- private IntPtr value;
-
- public Native(S s)
- {
- }
-
- public S ToManaged() => new S();
-}";
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task BlittableNativeType_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-struct S
-{
- public string s;
-}
-
-struct Native
-{
- private IntPtr value;
-
- public Native(S s)
- {
- value = IntPtr.Zero;
- }
-
- public S ToManaged() => new S();
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task BlittableNativeWithNonBlittableValueProperty_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-struct S
-{
- public string s;
-}
-
-struct Native
-{
- private IntPtr value;
-
- public Native(S s)
- {
- value = IntPtr.Zero;
- }
-
- public S ToManaged() => new S();
-
- public string {|#0:Value|} { get => null; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("string", "S"));
- }
-
- [Fact]
- public async Task NonBlittableNativeTypeWithBlittableValueProperty_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-struct S
-{
- public string s;
-}
-
-struct Native
-{
- private string value;
-
- public Native(S s)
- {
- value = s.s;
- }
-
- public S ToManaged() => new S() { s = value };
-
- public IntPtr Value { get => IntPtr.Zero; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task ClassNativeTypeWithValueProperty_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-struct S
-{
- public string s;
-}
-
-class {|#0:Native|}
-{
- private string value;
-
- public Native(S s)
- {
- value = s.s;
- }
-
- public S ToManaged() => new S() { s = value };
-
- public IntPtr Value { get => IntPtr.Zero; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task NonBlittableGetPinnableReferenceReturnType_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public string s;
-
- public ref string {|#0:GetPinnableReference|}() => ref s;
-}
-
-unsafe struct Native
-{
- private IntPtr value;
-
- public Native(S s)
- {
- value = IntPtr.Zero;
- }
-
- public S ToManaged() => new S();
-
- public IntPtr Value { get => IntPtr.Zero; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(GetPinnableReferenceReturnTypeBlittableRule).WithLocation(0));
- }
-
- [Fact]
- public async Task BlittableGetPinnableReferenceReturnType_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-
- public ref byte GetPinnableReference() => ref c;
-}
-
-unsafe struct Native
-{
- private IntPtr value;
-
- public Native(S s) : this()
- {
- value = IntPtr.Zero;
- }
-
- public S ToManaged() => new S();
-
- public IntPtr Value { get => IntPtr.Zero; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task NonBlittableMarshallerGetPinnableReferenceReturnType_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public char c;
-}
-
-unsafe struct Native
-{
- private IntPtr value;
-
- public Native(S s)
- {
- value = IntPtr.Zero;
- }
-
- public ref char GetPinnableReference() => ref System.Runtime.CompilerServices.Unsafe.NullRef<char>();
-
- public S ToManaged() => new S();
-
- public IntPtr Value { get => IntPtr.Zero; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task BlittableMarshallerGetPinnableReferenceReturnType_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-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<byte>();
-
- public IntPtr Value { get => IntPtr.Zero; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task TypeWithGetPinnableReferenceNonPointerReturnType_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-
- public ref byte GetPinnableReference() => ref c;
-}
-
-unsafe struct Native
-{
- private IntPtr value;
-
- public Native(S s) : this()
- {
- value = IntPtr.Zero;
- }
-
- public S ToManaged() => new S();
-
- public int {|#0:Value|} { get => 0; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustBePointerSizedRule).WithLocation(0).WithArguments("int", "S"));
- }
-
- [Fact]
- public async Task TypeWithGetPinnableReferencePointerReturnType_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-
- public ref byte GetPinnableReference() => ref c;
-}
-
-unsafe struct Native
-{
- private IntPtr value;
-
- public Native(S s) : this()
- {
- value = IntPtr.Zero;
- }
-
- public S ToManaged() => new S();
-
- public int* Value { get => null; set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task TypeWithGetPinnableReferenceByRefValuePropertyType_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-
- public ref byte GetPinnableReference() => ref c;
-}
-
-unsafe struct Native
-{
- private S value;
-
- public Native(S s) : this()
- {
- value = s;
- }
-
- public ref byte {|#0:Value|} { get => ref value.GetPinnableReference(); }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(RefValuePropertyUnsupportedRule).WithLocation(0).WithArguments("Native"));
- }
-
- [Fact]
- public async Task NativeTypeWithGetPinnableReferenceByRefValuePropertyType_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-unsafe struct Native
-{
- private S value;
-
- public Native(S s) : this()
- {
- value = s;
- }
-
- public ref byte GetPinnableReference() => ref value.c;
-
- public ref byte {|#0:Value|} { get => ref GetPinnableReference(); }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(RefValuePropertyUnsupportedRule).WithLocation(0).WithArguments("Native"));
- }
-
- [Fact]
- public async Task NativeTypeWithGetPinnableReferenceNoValueProperty_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-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<byte>();
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(MarshallerGetPinnableReferenceRequiresValuePropertyRule).WithLocation(0).WithArguments("Native"));
- }
-
- [Fact]
- public async Task NativeTypeWithGetPinnableReferenceWithNonPointerValueProperty_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-unsafe struct Native
-{
- private byte value;
-
- public Native(S s) : this()
- {
- value = s.c;
- }
-
- public ref byte GetPinnableReference() => ref System.Runtime.CompilerServices.Unsafe.NullRef<byte>();
-
- public int Value { get; set; }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task NativeTypeWithNoMarshallingMethods_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-struct {|#0:Native|}
-{
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task CollectionNativeTypeWithNoMarshallingMethods_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-[GenericContiguousCollectionMarshaller]
-struct {|#0:Native|}
-{
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CollectionNativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task CollectionNativeTypeWithWrongConstructor_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-[GenericContiguousCollectionMarshaller]
-ref struct {|#0:Native|}
-{
- public Native(S s) : this() {}
-
- public Span<int> ManagedValues { get; set; }
- public Span<byte> NativeValueStorage { get; set; }
-
- public IntPtr Value { get; }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CollectionNativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task CollectionNativeTypeWithCorrectConstructor_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-[GenericContiguousCollectionMarshaller]
-ref struct Native
-{
- public Native(S s, int nativeElementSize) : this() {}
-
- public Span<int> ManagedValues { get; set; }
- public Span<byte> NativeValueStorage { get; set; }
-
- public IntPtr Value { get; }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task CollectionNativeTypeWithIncorrectStackallocConstructor_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-[GenericContiguousCollectionMarshaller]
-ref struct {|#0:Native|}
-{
- public Native(S s, Span<byte> stackSpace) : this() {}
-
- public const int BufferSize = 1;
-
- public Span<int> ManagedValues { get; set; }
- public Span<byte> NativeValueStorage { get; set; }
-
- public IntPtr Value { get; }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CollectionNativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task CollectionNativeTypeWithOnlyStackallocConstructor_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-[GenericContiguousCollectionMarshaller]
-ref struct {|#0:Native|}
-{
- public Native(S s, Span<byte> stackSpace, int nativeElementSize) : this() {}
-
- public const int BufferSize = 1;
-
- public Span<int> ManagedValues { get; set; }
- public Span<byte> NativeValueStorage { get; set; }
-
- public IntPtr Value { get; }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task CollectionNativeTypeWithMissingManagedValuesProperty_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-[GenericContiguousCollectionMarshaller]
-ref struct {|#0:Native|}
-{
- public Native(S s, int nativeElementSize) : this() {}
-
- public Span<byte> NativeValueStorage { get; set; }
-
- public IntPtr Value { get; }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CollectionNativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task CollectionNativeTypeWithMissingNativeValueStorageProperty_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-[GenericContiguousCollectionMarshaller]
-ref struct {|#0:Native|}
-{
- public Native(S s, int nativeElementSize) : this() {}
-
- public Span<int> ManagedValues { get; set; }
-
- public IntPtr Value { get; }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CollectionNativeTypeMustHaveRequiredShapeRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task NativeTypeWithOnlyConstructor_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-struct Native
-{
- public Native(S s) {}
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task NativeTypeWithOnlyToManagedMethod_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-struct Native
-{
- public S ToManaged() => new S();
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task NativeTypeWithOnlyStackallocConstructor_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-struct {|#0:Native|}
-{
- public Native(S s, Span<byte> buffer) {}
-
- public const int BufferSize = 0x100;
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule).WithLocation(0).WithArguments("Native"));
- }
-
- [Fact]
- public async Task TypeWithOnlyNativeStackallocConstructorAndGetPinnableReference_ReportsDiagnostics()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[{|#0:NativeMarshalling(typeof(Native))|}]
-class S
-{
- public byte c;
- public ref byte GetPinnableReference() => ref c;
-}
-
-struct {|#1:Native|}
-{
- public Native(S s, Span<byte> buffer) {}
-
- public IntPtr Value => IntPtr.Zero;
-
- public const int BufferSize = 0x100;
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CallerAllocMarshallingShouldSupportAllocatingMarshallingFallbackRule).WithLocation(1).WithArguments("Native"),
- VerifyCS.Diagnostic(GetPinnableReferenceShouldSupportAllocatingMarshallingFallbackRule).WithLocation(0).WithArguments("S", "Native"));
- }
-
- [Fact]
- public async Task NativeTypeWithConstructorAndSetOnlyValueProperty_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-struct Native
-{
- public Native(S s) {}
-
- public IntPtr {|#0:Value|} { set {} }
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(ValuePropertyMustHaveGetterRule).WithLocation(0).WithArguments("Native"));
- }
-
- [Fact]
- public async Task NativeTypeWithToManagedAndGetOnlyValueProperty_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-struct Native
-{
- public S ToManaged() => new S();
-
- public IntPtr {|#0:Value|} => IntPtr.Zero;
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(ValuePropertyMustHaveSetterRule).WithLocation(0).WithArguments("Native"));
- }
-
- [Fact]
- public async Task BlittableNativeTypeOnMarshalUsingParameter_DoesNotReportDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-struct S
-{
- public string 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.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task NonBlittableNativeTypeOnMarshalUsingParameter_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-struct S
-{
- public string 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.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task NonBlittableNativeTypeOnMarshalUsingParameter_MultipleCompilations_ReportsDiagnostic_WithLocation()
- {
- string source1 = @"
-using System;
-using System.Runtime.InteropServices;
-
-public struct S
-{
- public string s;
-}
-
-public struct Native
-{
- private string value;
-
- public Native(S s) : this()
- {
- }
-
- public S ToManaged() => new S();
-}
-";
- Compilation compilation1 = await TestUtils.CreateCompilation(source1);
-
- string source2 = @"
-using System;
-using System.Runtime.InteropServices;
-
-static class Test
-{
- static void Foo([{|#0:MarshalUsing(typeof(Native))|}] S s)
- {}
-}
-";
- var test = new Verifiers.CSharpCodeFixVerifier<Microsoft.Interop.Analyzers.ManualTypeMarshallingAnalyzer, EmptyCodeFixProvider>.Test
- {
- ExpectedDiagnostics =
- {
- VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S")
- },
- SolutionTransforms =
- {
- (solution, projectId) => solution.AddMetadataReference(projectId, compilation1.ToMetadataReference())
- },
- TestCode = source2
- };
-
- await test.RunAsync();
- }
-
- [Fact]
- public async Task NonBlittableNativeTypeOnMarshalUsingReturn_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-struct S
-{
- public string 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.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task NonBlittableNativeTypeOnMarshalUsingField_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-struct S
-{
- public string s;
-}
-
-struct {|#0:Native|}
-{
- private string value;
-
- public Native(S s) : this()
- {
- }
-
- public S ToManaged() => new S();
-}
-
-
-struct Test
-{
- [MarshalUsing(typeof(Native))]
- S s;
-}
-";
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(NativeTypeMustBeBlittableRule).WithLocation(0).WithArguments("Native", "S"));
- }
-
- [Fact]
- public async Task GenericNativeTypeWithValueTypeValueProperty_DoesNotReportDiagnostic()
- {
- string source = @"
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native<S>))]
-struct S
-{
- public string s;
-}
-
-struct Native<T>
- where T : new()
-{
- public Native(T s)
- {
- Value = 0;
- }
-
- public T ToManaged() => new T();
-
- public int Value { get; set; }
-}";
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task GenericNativeTypeWithGenericMemberInstantiatedWithBlittable_DoesNotReportDiagnostic()
- {
-
- string source = @"
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native<int>))]
-struct S
-{
- public string s;
-}
-
-struct Native<T>
- where T : new()
-{
- public Native(S s)
- {
- Value = new T();
- }
-
- public S ToManaged() => new S();
-
- public T Value { get; set; }
-}";
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task UninstantiatedGenericNativeTypeOnNonGeneric_ReportsDiagnostic()
- {
-
- string source = @"
-using System.Runtime.InteropServices;
-
-[{|#0:NativeMarshalling(typeof(Native<>))|}]
-struct S
-{
- public string s;
-}
-
-struct Native<T>
- where T : new()
-{
- public Native(S s)
- {
- Value = new T();
- }
-
- public S ToManaged() => new S();
-
- public T Value { get; set; }
-}";
- await VerifyCS.VerifyAnalyzerAsync(source, VerifyCS.Diagnostic(NativeGenericTypeMustBeClosedOrMatchArityRule).WithLocation(0).WithArguments("Native<>", "S"));
- }
-
- [Fact]
- public async Task UninstantiatedGenericNativeTypeOnGenericWithArityMismatch_ReportsDiagnostic()
- {
- string source = @"
-using System.Runtime.InteropServices;
-
-[{|#0:NativeMarshalling(typeof(Native<,>))|}]
-struct S<T>
-{
- public string s;
-}
-
-struct Native<T, U>
- where T : new()
-{
- public Native(S<T> s)
- {
- Value = 0;
- }
-
- public S<T> ToManaged() => new S<T>();
-
- public int Value { get; set; }
-}";
- await VerifyCS.VerifyAnalyzerAsync(source, VerifyCS.Diagnostic(NativeGenericTypeMustBeClosedOrMatchArityRule).WithLocation(0).WithArguments("Native<,>", "S<T>"));
- }
-
- [Fact]
- public async Task UninstantiatedGenericNativeTypeOnGenericWithArityMatch_DoesNotReportDiagnostic()
- {
- string source = @"
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native<>))]
-struct S<T>
-{
- public T t;
-}
-
-struct Native<T>
- where T : new()
-{
- public Native(S<T> s)
- {
- Value = 0;
- }
-
- public S<T> ToManaged() => new S<T>();
-
- public int Value { get; set; }
-}";
- await VerifyCS.VerifyAnalyzerAsync(source);
- }
-
- [Fact]
- public async Task NativeTypeWithStackallocConstructorWithoutBufferSize_ReportsDiagnostic()
- {
- string source = @"
-using System;
-using System.Runtime.InteropServices;
-
-[NativeMarshalling(typeof(Native))]
-class S
-{
- public byte c;
-}
-
-struct Native
-{
- public Native(S s) {}
- public {|#0:Native|}(S s, Span<byte> buffer) {}
-}";
-
- await VerifyCS.VerifyAnalyzerAsync(source,
- VerifyCS.Diagnostic(CallerAllocConstructorMustHaveBufferSizeConstantRule).WithLocation(0).WithArguments("Native"));
- }
- }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs
index f56377d272e..dd30ab7a8c8 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs
@@ -66,6 +66,34 @@ namespace LibraryImportGenerator.UnitTests.Verifiers
await test.RunAsync(CancellationToken.None);
}
+ /// <inheritdoc cref="CodeFixVerifier{TAnalyzer, TCodeFix, TTest, TVerifier}.VerifyCodeFixAsync(string, DiagnosticResult[], string)"/>
+ public static async Task VerifyCodeFixAsync(string source, string fixedSource, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource,
+ int numIncrementalIterations, int numFixAllIterations)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ NumberOfIncrementalIterations = numIncrementalIterations,
+ NumberOfFixAllIterations = numFixAllIterations
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+
internal class Test : CSharpCodeFixTest<TAnalyzer, TCodeFix, XUnitVerifier>
{
public Test()
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 e1211664390..155edea1bc9 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs
@@ -17,6 +17,7 @@ namespace SharedTypes
public string str2;
}
+ [CustomTypeMarshaller(typeof(StringContainer), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
public struct StringContainerNative
{
public IntPtr str1;
@@ -44,6 +45,7 @@ namespace SharedTypes
}
}
+ [CustomTypeMarshaller(typeof(double), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
public struct DoubleToLongMarshaler
{
public long l;
@@ -55,11 +57,9 @@ namespace SharedTypes
public double ToManaged() => MemoryMarshal.Cast<long, double>(MemoryMarshal.CreateSpan(ref l, 1))[0];
- public long Value
- {
- get => l;
- set => l = value;
- }
+ public long ToNativeValue() => l;
+
+ public void FromNativeValue(long value) => l = value;
}
[NativeMarshalling(typeof(BoolStructNative))]
@@ -70,6 +70,7 @@ namespace SharedTypes
public bool b3;
}
+ [CustomTypeMarshaller(typeof(BoolStruct))]
public struct BoolStructNative
{
public byte b1;
@@ -101,6 +102,7 @@ namespace SharedTypes
public ref int GetPinnableReference() => ref i;
}
+ [CustomTypeMarshaller(typeof(IntWrapper), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)]
public unsafe struct IntWrapperMarshaler
{
public IntWrapperMarshaler(IntWrapper managed)
@@ -109,7 +111,10 @@ namespace SharedTypes
*Value = managed.i;
}
- public int* Value { get; set; }
+ private int* Value { get; set; }
+
+ public int* ToNativeValue() => Value;
+ public void FromNativeValue(int* value) => Value = value;
public IntWrapper ToManaged() => new IntWrapper { i = *Value };
@@ -119,6 +124,7 @@ namespace SharedTypes
}
}
+ [CustomTypeMarshaller(typeof(string), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x100)]
public unsafe ref struct Utf16StringMarshaller
{
private ushort* allocated;
@@ -160,24 +166,19 @@ namespace SharedTypes
return ref span.GetPinnableReference();
}
- public ushort* Value
+ public ushort* ToNativeValue() => (ushort*)Unsafe.AsPointer(ref GetPinnableReference());
+
+ public void FromNativeValue(ushort* value)
{
- get
- {
- return (ushort*)Unsafe.AsPointer(ref GetPinnableReference());
- }
- set
+ allocated = value;
+ span = new Span<ushort>(value, value == null ? 0 : FindStringLength(value));
+ isNullString = value == null;
+
+ static int FindStringLength(ushort* ptr)
{
- allocated = value;
- span = new Span<ushort>(value, value == null ? 0 : FindStringLength(value));
- isNullString = value == null;
-
- static int FindStringLength(ushort* ptr)
- {
- // Implemented similarly to string.wcslen as we can't access that outside of CoreLib
- var searchSpace = new Span<ushort>(ptr, int.MaxValue);
- return searchSpace.IndexOf((ushort)0);
- }
+ // Implemented similarly to string.wcslen as we can't access that outside of CoreLib
+ var searchSpace = new Span<ushort>(ptr, int.MaxValue);
+ return searchSpace.IndexOf((ushort)0);
}
}
@@ -190,11 +191,9 @@ namespace SharedTypes
{
Marshal.FreeCoTaskMem((IntPtr)allocated);
}
-
- public const int BufferSize = 0x100;
- public const bool RequiresStackBuffer = true;
}
+ [CustomTypeMarshaller(typeof(string), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x100)]
public unsafe ref struct Utf8StringMarshaller
{
private byte* allocated;
@@ -223,24 +222,13 @@ namespace SharedTypes
}
}
- public byte* Value
- {
- get
- {
- return allocated != null ? allocated : (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span));
- }
- set
- {
- allocated = value;
- }
- }
+ public byte* ToNativeValue() => allocated != null ? allocated : (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span));
- public string? ToManaged() => Marshal.PtrToStringUTF8((IntPtr)Value);
+ public void FromNativeValue(byte* value) => allocated = value;
- public void FreeNative() => Marshal.FreeCoTaskMem((IntPtr)allocated);
+ public string? ToManaged() => Marshal.PtrToStringUTF8((IntPtr)allocated);
- public const int BufferSize = 0x100;
- public const bool RequiresStackBuffer = true;
+ public void FreeNative() => Marshal.FreeCoTaskMem((IntPtr)allocated);
}
[NativeMarshalling(typeof(IntStructWrapperNative))]
@@ -249,6 +237,7 @@ namespace SharedTypes
public int Value;
}
+ [CustomTypeMarshaller(typeof(IntStructWrapper))]
public struct IntStructWrapperNative
{
public int value;
@@ -260,7 +249,7 @@ namespace SharedTypes
public IntStructWrapper ToManaged() => new IntStructWrapper { Value = value };
}
- [GenericContiguousCollectionMarshaller]
+ [CustomTypeMarshaller(typeof(List<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)]
public unsafe ref struct ListMarshaller<T>
{
private List<T> managedList;
@@ -302,48 +291,39 @@ namespace SharedTypes
}
}
- /// <summary>
- /// 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.
- /// </summary>
- public const int BufferSize = 0x200;
- public const bool RequiresStackBuffer = true;
-
- public Span<T> ManagedValues => CollectionsMarshal.AsSpan(managedList);
+ public ReadOnlySpan<T> GetManagedValuesSource() => CollectionsMarshal.AsSpan(managedList);
- public Span<byte> NativeValueStorage { get; private set; }
-
- public ref byte GetPinnableReference() => ref NativeValueStorage.GetPinnableReference();
-
- public void SetUnmarshalledCollectionLength(int length)
+ public Span<T> GetManagedValuesDestination(int length)
{
+ if (allocatedMemory == IntPtr.Zero)
+ {
+ managedList = null;
+ return default;
+ }
managedList = new List<T>(length);
for (int i = 0; i < length; i++)
{
managedList.Add(default);
}
+ return CollectionsMarshal.AsSpan(managedList);
}
- public byte* Value
+ private Span<byte> NativeValueStorage { get; set; }
+
+ public Span<byte> GetNativeValuesDestination() => NativeValueStorage;
+
+ public ReadOnlySpan<byte> GetNativeValuesSource(int length)
{
- get
- {
- return (byte*)Unsafe.AsPointer(ref GetPinnableReference());
- }
- set
- {
- if (value == null)
- {
- managedList = null;
- NativeValueStorage = default;
- }
- else
- {
- allocatedMemory = (IntPtr)value;
- NativeValueStorage = new Span<byte>(value, (managedList?.Count ?? 0) * sizeOfNativeElement);
- }
- }
+ return allocatedMemory == IntPtr.Zero ? default : NativeValueStorage = new Span<byte>((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<T> ToManaged() => managedList;