Use bidirectional marshallers for elements. (#90056)
authorJeremy Koritzinsky <jekoritz@microsoft.com>
Tue, 8 Aug 2023 16:28:09 +0000 (09:28 -0700)
committerGitHub <noreply@github.com>
Tue, 8 Aug 2023 16:28:09 +0000 (09:28 -0700)
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.LsaLookupNames2.cs
src/libraries/Common/src/Interop/Windows/WebSocket/Interop.Structs.cs
src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs
src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionMarshallingFails.cs
src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessLinearCollectionShapeValidation.cs
src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessValueShapeValidation.cs
src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/ComInterfaces/IStatelessCollectionStatelessElement.cs
src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/ComInterfaces/IStatelessMarshalling.cs

index bb65329..4213723 100644 (file)
@@ -31,6 +31,15 @@ internal static partial class Interop
             [CustomMarshaller(typeof(MARSHALLED_UNICODE_STRING), MarshalMode.ElementIn, typeof(Marshaller))]
             public static class Marshaller
             {
+                public static MARSHALLED_UNICODE_STRING ConvertToManaged(Native unmanaged)
+                {
+                    MARSHALLED_UNICODE_STRING m;
+                    m.Length = unmanaged.Length;
+                    m.MaximumLength = unmanaged.MaximumLength;
+                    m.Buffer = Marshal.PtrToStringUni(unmanaged.Buffer)!;
+                    return m;
+                }
+
                 public static Native ConvertToUnmanaged(MARSHALLED_UNICODE_STRING managed)
                 {
                     Native n;
index d5e7d2e..c243dab 100644 (file)
@@ -52,6 +52,14 @@ internal static partial class Interop
             [CustomMarshaller(typeof(HttpHeader), MarshalMode.ElementIn, typeof(Marshaller))]
             public static class Marshaller
             {
+                public static HttpHeader ConvertToManaged(WEB_SOCKET_HTTP_HEADER unmanaged)
+                {
+                    HttpHeader m;
+                    m.Name = Marshal.PtrToStringAnsi(unmanaged.Name, (int)unmanaged.NameLength);
+                    m.Value = Marshal.PtrToStringAnsi(unmanaged.Value, (int)unmanaged.ValueLength);
+                    return m;
+                }
+
                 public static WEB_SOCKET_HTTP_HEADER ConvertToUnmanaged(HttpHeader managed)
                 {
                     WEB_SOCKET_HTTP_HEADER n;
index 2f1e460..44f0c3a 100644 (file)
@@ -423,8 +423,9 @@ namespace Microsoft.Interop
         public static bool ModeUsesManagedToUnmanagedShape(MarshalMode mode)
             => mode is MarshalMode.Default
                 or MarshalMode.ManagedToUnmanagedIn
-                or MarshalMode.UnmanagedToManagedOut
                 or MarshalMode.ElementIn
+                or MarshalMode.UnmanagedToManagedOut
+                or MarshalMode.ElementOut
                 or MarshalMode.ManagedToUnmanagedRef
                 or MarshalMode.UnmanagedToManagedRef
                 or MarshalMode.ElementRef;
@@ -432,12 +433,23 @@ namespace Microsoft.Interop
         public static bool ModeUsesUnmanagedToManagedShape(MarshalMode mode)
             => mode is MarshalMode.Default
                 or MarshalMode.ManagedToUnmanagedOut
-                or MarshalMode.UnmanagedToManagedIn
                 or MarshalMode.ElementOut
+                or MarshalMode.UnmanagedToManagedIn
+                or MarshalMode.ElementIn
                 or MarshalMode.ManagedToUnmanagedRef
                 or MarshalMode.UnmanagedToManagedRef
                 or MarshalMode.ElementRef;
 
+        // These modes can be used with either shape,
+        // but we don't want to require that all marshallers implement both shapes.
+        // The CustomMarshallerAttributeAnalyzer will provide any enforcement we would like
+        // on these marshaller shapes.
+        private static bool ModeOptionallyMatchesShape(MarshalMode mode)
+            => mode is MarshalMode.Default
+                or MarshalMode.ElementIn
+                or MarshalMode.ElementRef
+                or MarshalMode.ElementOut;
+
         private static CustomTypeMarshallerData? GetStatelessMarshallerDataForType(ITypeSymbol marshallerType, MarshalMode mode, ITypeSymbol managedType, bool isLinearCollectionMarshaller, Compilation compilation, Func<ITypeSymbol, MarshallingInfo>? getMarshallingInfo)
         {
             (MarshallerShape shape, StatelessMarshallerShapeHelper.MarshallerMethods methods) = StatelessMarshallerShapeHelper.GetShapeForType(marshallerType, managedType, isLinearCollectionMarshaller, compilation);
@@ -446,7 +458,7 @@ namespace Microsoft.Interop
             ITypeSymbol? nativeType = null;
             if (ModeUsesManagedToUnmanagedShape(mode))
             {
-                if (mode != MarshalMode.Default && !shape.HasFlag(MarshallerShape.CallerAllocatedBuffer) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
+                if (!ModeOptionallyMatchesShape(mode) && !shape.HasFlag(MarshallerShape.CallerAllocatedBuffer) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
                     return null;
 
                 if (isLinearCollectionMarshaller && methods.ManagedValuesSource is not null)
@@ -469,7 +481,7 @@ namespace Microsoft.Interop
             if (ModeUsesUnmanagedToManagedShape(mode))
             {
                 // Unmanaged to managed requires ToManaged either with or without guaranteed unmarshal
-                if (mode != MarshalMode.Default && !shape.HasFlag(MarshallerShape.GuaranteedUnmarshal) && !shape.HasFlag(MarshallerShape.ToManaged))
+                if (!ModeOptionallyMatchesShape(mode) && !shape.HasFlag(MarshallerShape.GuaranteedUnmarshal) && !shape.HasFlag(MarshallerShape.ToManaged))
                     return null;
 
                 if (isLinearCollectionMarshaller)
@@ -501,7 +513,7 @@ namespace Microsoft.Interop
             }
 
             // Bidirectional requires ToUnmanaged without the caller-allocated buffer
-            if (mode != MarshalMode.Default && ModeUsesManagedToUnmanagedShape(mode) && ModeUsesUnmanagedToManagedShape(mode) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
+            if (!ModeOptionallyMatchesShape(mode) && ModeUsesManagedToUnmanagedShape(mode) && ModeUsesUnmanagedToManagedShape(mode) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
                 return null;
 
             if (nativeType is null)
index 3e51f40..9336f8c 100644 (file)
@@ -329,6 +329,8 @@ namespace LibraryImportGenerator.IntegrationTests
 
         public static IntStructWrapper ConvertToManaged(nint unmanaged) => s_IntStructWrapperMarshalling.ConvertToManaged(unmanaged);
 
+        public static nint ConvertToUnmanaged(IntStructWrapper managed) => throw new NotImplementedException();
+
         /// <summary>
         /// The number of elements that are expected to be cleaned up / freed.
         /// </summary>
@@ -366,6 +368,8 @@ namespace LibraryImportGenerator.IntegrationTests
 
         public static BoolStruct ConvertToManaged(nint unmanaged) => s_BoolStructMarshalling.ConvertToManaged(unmanaged);
 
+        public static nint ConvertToUnmanaged(BoolStruct managed) => throw new NotImplementedException();
+
         /// <summary>
         /// The number of elements that are expected to be cleaned up / freed.
         /// </summary>
@@ -390,10 +394,10 @@ namespace LibraryImportGenerator.IntegrationTests
     /// so the pinvoke should not be run if it will access marshalled objects. Make sure to call ThrowOnNthMarshalledElement such that marshalling
     /// the array will fail before the pinvoke is run.
     /// </summary>
+
     [CustomMarshaller(typeof(BoolStruct), MarshalMode.ElementIn, typeof(EnforceLastElementMarshalledCleanupBoolStruct))]
     [CustomMarshaller(typeof(BoolStruct), MarshalMode.ElementRef, typeof(EnforceLastElementMarshalledCleanupBoolStruct))]
     [CustomMarshaller(typeof(BoolStruct), MarshalMode.ElementOut, typeof(EnforceLastElementMarshalledCleanupBoolStruct))]
-    [CustomMarshaller(typeof(char), MarshalMode.ElementIn, typeof(EnforceLastElementMarshalledCleanupBoolStruct))]
     static class EnforceLastElementMarshalledCleanupBoolStruct
     {
         private static MarshallingExceptionManager<BoolStruct> s_BoolStructMarshalling = new(_dummyPtr, default);
@@ -410,8 +414,6 @@ namespace LibraryImportGenerator.IntegrationTests
                 s_BoolStructMarshalling.Throw($"Freed unmarshalled pointer: {obj}");
         }
 
-        public static nint ConvertToUnmanaged(char managed) => throw new NotImplementedException();
-
         public static BoolStruct ConvertToManaged(nint unmanaged) => throw new NotImplementedException();
     }
 
index f5d2299..fec16b2 100644 (file)
@@ -22,12 +22,11 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -36,12 +35,11 @@ namespace LibraryImportGenerator.UnitTests
 
             string fixedSource = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -67,10 +65,8 @@ namespace LibraryImportGenerator.UnitTests
                 fixedSource,
                 VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType").WithLocation(0),
                 VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType").WithLocation(1),
-                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsRule, "MarshallerType<T>", MarshalMode.ElementIn, "ManagedType").WithLocation(2),
                 VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionInRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType").WithLocation(0),
-                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionInRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType").WithLocation(1),
-                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionInRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.ElementIn, "ManagedType").WithLocation(2));
+                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionInRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType").WithLocation(1));
         }
 
         [Fact]
@@ -78,12 +74,11 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -93,12 +88,11 @@ namespace LibraryImportGenerator.UnitTests
 
             string fixedSource = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -120,8 +114,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(2).WithArguments("MarshallerType<T>", MarshalMode.ElementIn, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"));
         }
 
         [Fact]
@@ -130,12 +123,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -148,19 +140,18 @@ namespace LibraryImportGenerator.UnitTests
             string fixedSource = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static nint AllocateContainerForUnmanagedElements(ManagedType m, out int numElements) => throw null;
-                
+
                     public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numElements) => default;
-                
+
                     public static ReadOnlySpan<nint> GetManagedValuesSource(ManagedType managed)
                     {
                         throw new NotImplementedException();
@@ -172,8 +163,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(2).WithArguments("MarshallerType<T>", MarshalMode.ElementIn, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"));
         }
 
         [Fact]
@@ -182,12 +172,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -200,17 +189,16 @@ namespace LibraryImportGenerator.UnitTests
             string fixedSource = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static nint AllocateContainerForUnmanagedElements(ManagedType m, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<byte> GetManagedValuesSource(ManagedType m) => default;
 
                     public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numElements)
@@ -224,8 +212,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(2).WithArguments("MarshallerType<T>", MarshalMode.ElementIn, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"));
         }
 
         [Fact]
@@ -234,12 +221,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -254,8 +240,7 @@ namespace LibraryImportGenerator.UnitTests
             await VerifyCS.VerifyAnalyzerAsync(
                 source,
                 VerifyCS.Diagnostic(FirstParameterMustMatchReturnTypeRule).WithLocation(0).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(int, int)", "MarshallerType<T>.AllocateContainerForUnmanagedElements(ManagedType, out int)"),
-                VerifyCS.Diagnostic(FirstParameterMustMatchReturnTypeRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(int, int)", "MarshallerType<T>.AllocateContainerForUnmanagedElements(ManagedType, out int)"),
-                VerifyCS.Diagnostic(FirstParameterMustMatchReturnTypeRule).WithLocation(2).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(int, int)", "MarshallerType<T>.AllocateContainerForUnmanagedElements(ManagedType, out int)"));
+                VerifyCS.Diagnostic(FirstParameterMustMatchReturnTypeRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(int, int)", "MarshallerType<T>.AllocateContainerForUnmanagedElements(ManagedType, out int)"));
         }
 
         [Fact]
@@ -264,12 +249,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -292,12 +276,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -312,8 +295,7 @@ namespace LibraryImportGenerator.UnitTests
             await VerifyCS.VerifyAnalyzerAsync(
                 source,
                 VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(0).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(nint, int)", "System.Span<T>"),
-                VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(nint, int)", "System.Span<T>"),
-                VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(2).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(nint, int)", "System.Span<T>"));
+                VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesDestination(nint, int)", "System.Span<T>"));
         }
 
         [Fact]
@@ -321,12 +303,11 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -335,12 +316,11 @@ namespace LibraryImportGenerator.UnitTests
 
             string fixedSource = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -366,10 +346,8 @@ namespace LibraryImportGenerator.UnitTests
                 fixedSource,
                 VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType").WithLocation(0),
                 VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType").WithLocation(1),
-                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsRule, "MarshallerType<T>", MarshalMode.ElementOut, "ManagedType").WithLocation(2),
                 VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionOutRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType").WithLocation(0),
-                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionOutRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType").WithLocation(1),
-                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionOutRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.ElementOut, "ManagedType").WithLocation(2));
+                VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionOutRequiresCollectionMethodsRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType").WithLocation(1));
         }
 
         [Fact]
@@ -377,12 +355,11 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -392,12 +369,11 @@ namespace LibraryImportGenerator.UnitTests
 
             string fixedSource = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -419,8 +395,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(2).WithArguments("MarshallerType<T>", MarshalMode.ElementOut, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"));
         }
 
         [Fact]
@@ -429,12 +404,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -447,17 +421,16 @@ namespace LibraryImportGenerator.UnitTests
             string fixedSource = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static ManagedType AllocateContainerForManagedElements(nint m, int numElements) => throw null;
-                
+
                     public static Span<byte> GetManagedValuesDestination(ManagedType m) => default;
 
                     public static ReadOnlySpan<T> GetUnmanagedValuesSource(nint unmanaged, int numElements)
@@ -471,8 +444,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(2).WithArguments("MarshallerType<T>", MarshalMode.ElementOut, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"));
         }
 
         [Fact]
@@ -481,12 +453,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -499,12 +470,11 @@ namespace LibraryImportGenerator.UnitTests
             string fixedSource = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -523,8 +493,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(2).WithArguments("MarshallerType<T>", MarshalMode.ElementOut, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"));
         }
 
         [Fact]
@@ -533,12 +502,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -553,8 +521,7 @@ namespace LibraryImportGenerator.UnitTests
             await VerifyCS.VerifyAnalyzerAsync(
                 source,
                 VerifyCS.Diagnostic(FirstParametersMustMatchRule).WithLocation(0).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(int, int)", "MarshallerType<T>.AllocateContainerForManagedElements(nint, out int)"),
-                VerifyCS.Diagnostic(FirstParametersMustMatchRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(int, int)", "MarshallerType<T>.AllocateContainerForManagedElements(nint, out int)"),
-                VerifyCS.Diagnostic(FirstParametersMustMatchRule).WithLocation(2).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(int, int)", "MarshallerType<T>.AllocateContainerForManagedElements(nint, out int)"));
+                VerifyCS.Diagnostic(FirstParametersMustMatchRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(int, int)", "MarshallerType<T>.AllocateContainerForManagedElements(nint, out int)"));
         }
 
         [Fact]
@@ -563,12 +530,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType<>))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType<>))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -590,12 +556,11 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#2:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
@@ -610,8 +575,7 @@ namespace LibraryImportGenerator.UnitTests
             await VerifyCS.VerifyAnalyzerAsync(
                 source,
                 VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(0).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(nint, int)", "System.ReadOnlySpan<T>"),
-                VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(nint, int)", "System.ReadOnlySpan<T>"),
-                VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(2).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(nint, int)", "System.ReadOnlySpan<T>"));
+                VerifyCS.Diagnostic(ReturnTypeMustBeExpectedTypeRule).WithLocation(1).WithArguments("MarshallerType<T>.GetUnmanagedValuesSource(nint, int)", "System.ReadOnlySpan<T>"));
         }
 
         [Fact]
@@ -620,17 +584,17 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static nint AllocateContainerForUnmanagedElements(ManagedType m, Span<byte> b, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<int> GetManagedValuesSource(ManagedType m) => default;
-                
+
                     public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numElements) => default;
                 }
                 """;
@@ -638,19 +602,19 @@ namespace LibraryImportGenerator.UnitTests
             string fixedSource = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static nint AllocateContainerForUnmanagedElements(ManagedType m, Span<byte> b, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<int> GetManagedValuesSource(ManagedType m) => default;
-                
+
                     public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numElements) => default;
-                
+
                     public static int BufferSize
                     {
                         get
@@ -673,25 +637,27 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#2:MarshallerType<>|}))]
+
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof(MarshallerType<>))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof(MarshallerType<>))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType<>))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof(MarshallerType<>))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType<>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static nint AllocateContainerForUnmanagedElements(ManagedType m, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<int> GetManagedValuesSource(ManagedType m) => default;
-                
+
                     public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numElements) => default;
 
                     public static ManagedType AllocateContainerForManagedElements(nint unmanaged, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<T> GetUnmanagedValuesSource(nint unmanaged, int numElements) => default;
-                
+
                     public static Span<int> GetManagedValuesDestination(ManagedType m) => default;
                 }
                 """;
@@ -705,25 +671,27 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType<>|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType<>|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#2:MarshallerType<>|}))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType<>|}))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#3:MarshallerType<>|}))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#4:MarshallerType<>|}))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static nint AllocateContainerForUnmanagedElements(ManagedType m, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<int> GetManagedValuesSource(ManagedType m) => default;
-                
+
                     public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numElements) => default;
 
                     public static ManagedType AllocateContainerForManagedElements(nint unmanaged, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<T> GetUnmanagedValuesSource(nint unmanaged, int numElements) => default;
-                
+
                     public static Span<byte> GetManagedValuesDestination(ManagedType m) => default;
                 }
                 """;
@@ -731,7 +699,9 @@ namespace LibraryImportGenerator.UnitTests
             await VerifyCS.VerifyAnalyzerAsync(source,
                 VerifyCS.Diagnostic(ElementTypesOfReturnTypesMustMatchRule).WithLocation(0).WithArguments("MarshallerType<T>.GetManagedValuesSource(ManagedType)", "MarshallerType<T>.GetManagedValuesDestination(ManagedType)"),
                 VerifyCS.Diagnostic(ElementTypesOfReturnTypesMustMatchRule).WithLocation(1).WithArguments("MarshallerType<T>.GetManagedValuesSource(ManagedType)", "MarshallerType<T>.GetManagedValuesDestination(ManagedType)"),
-                VerifyCS.Diagnostic(ElementTypesOfReturnTypesMustMatchRule).WithLocation(2).WithArguments("MarshallerType<T>.GetManagedValuesSource(ManagedType)", "MarshallerType<T>.GetManagedValuesDestination(ManagedType)"));
+                VerifyCS.Diagnostic(ElementTypesOfReturnTypesMustMatchRule).WithLocation(2).WithArguments("MarshallerType<T>.GetManagedValuesSource(ManagedType)", "MarshallerType<T>.GetManagedValuesDestination(ManagedType)"),
+                VerifyCS.Diagnostic(ElementTypesOfReturnTypesMustMatchRule).WithLocation(3).WithArguments("MarshallerType<T>.GetManagedValuesSource(ManagedType)", "MarshallerType<T>.GetManagedValuesDestination(ManagedType)"),
+                VerifyCS.Diagnostic(ElementTypesOfReturnTypesMustMatchRule).WithLocation(4).WithArguments("MarshallerType<T>.GetManagedValuesSource(ManagedType)", "MarshallerType<T>.GetManagedValuesDestination(ManagedType)"));
         }
 
         [Fact]
@@ -740,23 +710,25 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
-                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType<,>|}))]
-                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType<,>|}))]
-                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof({|#2:MarshallerType<,>|}))]
+
+                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(MarshallerType<,>))]
+                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(MarshallerType<,>))]
+                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(MarshallerType<,>))]
+                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(MarshallerType<,>))]
+                [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(MarshallerType<,>))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T, TNative>
                 {
                     public static nint AllocateContainerForUnmanagedElements(T[] m, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<int> GetManagedValuesSource(T[] m) => default;
-                
+
                     public static Span<TNative> GetUnmanagedValuesDestination(nint unmanaged, int numElements) => default;
 
                     public static T[] AllocateContainerForManagedElements(nint unmanaged, out int numElements) => throw null;
-                
+
                     public static ReadOnlySpan<TNative> GetUnmanagedValuesSource(nint unmanaged, int numElements) => default;
-                
+
                     public static Span<int> GetManagedValuesDestination(T[] m) => default;
                 }
                 """;
@@ -770,27 +742,29 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType<>.Nested|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType<>.Nested|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#2:MarshallerType<>.Nested|}))]
+
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof(MarshallerType<>.Nested))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof(MarshallerType<>.Nested))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType<>.Nested))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof(MarshallerType<>.Nested))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType<>.Nested))]
                 [ContiguousCollectionMarshaller]
                 static class MarshallerType<T>
                 {
                     public static class Nested
                     {
                         public static nint AllocateContainerForUnmanagedElements(ManagedType m, out int numElements) => throw null;
-                    
+
                         public static ReadOnlySpan<int> GetManagedValuesSource(ManagedType m) => default;
-                    
+
                         public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numElements) => default;
 
                         public static ManagedType AllocateContainerForManagedElements(nint unmanaged, out int numElements) => throw null;
-                    
+
                         public static ReadOnlySpan<T> GetUnmanagedValuesSource(nint unmanaged, int numElements) => default;
-                    
+
                         public static Span<int> GetManagedValuesDestination(ManagedType m) => default;
                     }
                 }
index 6087288..7d94afb 100644 (file)
@@ -22,12 +22,11 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|#1:MarshallerType|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType|}))]
                 static class MarshallerType
                 {
                 }
@@ -37,10 +36,9 @@ namespace LibraryImportGenerator.UnitTests
                 using System.Runtime.InteropServices.Marshalling;
 
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType))]
                 static class MarshallerType
                 {
                     public static nint ConvertToUnmanaged(ManagedType managed)
@@ -54,8 +52,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithLocation(0).WithArguments("MarshallerType", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithLocation(1).WithArguments("MarshallerType", MarshalMode.UnmanagedToManagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithLocation(2).WithArguments("MarshallerType", MarshalMode.ElementIn, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithLocation(1).WithArguments("MarshallerType", MarshalMode.UnmanagedToManagedOut, "ManagedType"));
         }
 
         [Fact]
@@ -64,9 +61,9 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType))]
                 static class MarshallerType
                 {
@@ -84,12 +81,11 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof({|#0:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof({|#1:MarshallerType|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#2:MarshallerType|}))]
                 static class MarshallerType
                 {
                 }
@@ -99,10 +95,9 @@ namespace LibraryImportGenerator.UnitTests
                 using System.Runtime.InteropServices.Marshalling;
 
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType))]
                 static class MarshallerType
                 {
                     public static ManagedType ConvertToManaged(nint unmanaged)
@@ -116,8 +111,7 @@ namespace LibraryImportGenerator.UnitTests
                 source,
                 fixedSource,
                 VerifyCS.Diagnostic(StatelessRequiresConvertToManagedRule).WithLocation(0).WithArguments("MarshallerType", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessRequiresConvertToManagedRule).WithLocation(1).WithArguments("MarshallerType", MarshalMode.UnmanagedToManagedIn, "ManagedType"),
-                VerifyCS.Diagnostic(StatelessRequiresConvertToManagedRule).WithLocation(2).WithArguments("MarshallerType", MarshalMode.ElementOut, "ManagedType"));
+                VerifyCS.Diagnostic(StatelessRequiresConvertToManagedRule).WithLocation(1).WithArguments("MarshallerType", MarshalMode.UnmanagedToManagedIn, "ManagedType"));
         }
 
         [Fact]
@@ -125,12 +119,14 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#2:MarshallerType|}))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|#2:MarshallerType|}))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#3:MarshallerType|}))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof({|#4:MarshallerType|}))]
                 static class MarshallerType
                 {
                 }
@@ -140,17 +136,19 @@ namespace LibraryImportGenerator.UnitTests
                 using System.Runtime.InteropServices.Marshalling;
 
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof(MarshallerType))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof(MarshallerType))]
+                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementOut, typeof(MarshallerType))]
                 static class MarshallerType
                 {
                     public static nint ConvertToUnmanaged(ManagedType managed)
                     {
                         throw new System.NotImplementedException();
                     }
-                
+
                     public static ManagedType ConvertToManaged(nint unmanaged)
                     {
                         throw new System.NotImplementedException();
@@ -163,10 +161,14 @@ namespace LibraryImportGenerator.UnitTests
                 fixedSource,
                 VerifyCS.DiagnosticWithArguments(StatelessValueInRequiresConvertToUnmanagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedRef, "ManagedType").WithLocation(0),
                 VerifyCS.DiagnosticWithArguments(StatelessValueInRequiresConvertToUnmanagedRule, "MarshallerType", MarshalMode.UnmanagedToManagedRef, "ManagedType").WithLocation(1),
-                VerifyCS.DiagnosticWithArguments(StatelessValueInRequiresConvertToUnmanagedRule, "MarshallerType", MarshalMode.ElementRef, "ManagedType").WithLocation(2),
+                VerifyCS.DiagnosticWithArguments(StatelessValueInRequiresConvertToUnmanagedRule, "MarshallerType", MarshalMode.ElementIn, "ManagedType").WithLocation(2),
+                VerifyCS.DiagnosticWithArguments(StatelessValueInRequiresConvertToUnmanagedRule, "MarshallerType", MarshalMode.ElementRef, "ManagedType").WithLocation(3),
+                VerifyCS.DiagnosticWithArguments(StatelessValueInRequiresConvertToUnmanagedRule, "MarshallerType", MarshalMode.ElementOut, "ManagedType").WithLocation(4),
                 VerifyCS.DiagnosticWithArguments(StatelessRequiresConvertToManagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedRef, "ManagedType").WithLocation(0),
                 VerifyCS.DiagnosticWithArguments(StatelessRequiresConvertToManagedRule, "MarshallerType", MarshalMode.UnmanagedToManagedRef, "ManagedType").WithLocation(1),
-                VerifyCS.DiagnosticWithArguments(StatelessRequiresConvertToManagedRule, "MarshallerType", MarshalMode.ElementRef, "ManagedType").WithLocation(2));
+                VerifyCS.DiagnosticWithArguments(StatelessRequiresConvertToManagedRule, "MarshallerType", MarshalMode.ElementIn, "ManagedType").WithLocation(2),
+                VerifyCS.DiagnosticWithArguments(StatelessRequiresConvertToManagedRule, "MarshallerType", MarshalMode.ElementRef, "ManagedType").WithLocation(3),
+                VerifyCS.DiagnosticWithArguments(StatelessRequiresConvertToManagedRule, "MarshallerType", MarshalMode.ElementOut, "ManagedType").WithLocation(4));
         }
 
         [Fact]
@@ -174,9 +176,9 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#2:MarshallerType|}))]
@@ -193,7 +195,7 @@ namespace LibraryImportGenerator.UnitTests
                 using System.Runtime.InteropServices.Marshalling;
 
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof(MarshallerType))]
@@ -224,9 +226,9 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#2:MarshallerType|}))]
@@ -243,7 +245,7 @@ namespace LibraryImportGenerator.UnitTests
                 using System.Runtime.InteropServices.Marshalling;
 
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof(MarshallerType))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof(MarshallerType))]
@@ -274,9 +276,9 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof({|#0:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof({|#1:MarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementRef, typeof({|#2:MarshallerType|}))]
@@ -299,9 +301,9 @@ namespace LibraryImportGenerator.UnitTests
         {
             string source = """
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.Default, typeof({|#0:MarshallerType|}))]
                 static class MarshallerType
                 {
@@ -312,7 +314,7 @@ namespace LibraryImportGenerator.UnitTests
                 using System.Runtime.InteropServices.Marshalling;
 
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.Default, typeof(MarshallerType))]
                 static class MarshallerType
                 {
@@ -320,7 +322,7 @@ namespace LibraryImportGenerator.UnitTests
                     {
                         throw new System.NotImplementedException();
                     }
-                
+
                     public static ManagedType ConvertToManaged(nint unmanaged)
                     {
                         throw new System.NotImplementedException();
@@ -341,9 +343,9 @@ namespace LibraryImportGenerator.UnitTests
             string source = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType|}))]
                 static class MarshallerType
                 {
@@ -354,9 +356,9 @@ namespace LibraryImportGenerator.UnitTests
             string fixedSource = """
                 using System;
                 using System.Runtime.InteropServices.Marshalling;
-                
+
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType))]
                 static class MarshallerType
                 {
@@ -385,10 +387,9 @@ namespace LibraryImportGenerator.UnitTests
                 using System.Runtime.InteropServices.Marshalling;
 
                 class ManagedType {}
-                
+
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|SYSLIB1057:OtherMarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|SYSLIB1057:OtherMarshallerType|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|SYSLIB1057:OtherMarshallerType|}))]
                 static class MarshallerType
                 {
                 }
@@ -428,7 +429,6 @@ namespace LibraryImportGenerator.UnitTests
 
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|SYSLIB1057:OtherMarshallerType|}))]
                 [CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof({|SYSLIB1057:OtherMarshallerType|}))]
-                [CustomMarshaller(typeof(ManagedType), MarshalMode.ElementIn, typeof({|SYSLIB1057:OtherMarshallerType|}))]
                 static class MarshallerType
                 {
                 }
index 7ab2245..0b03eee 100644 (file)
@@ -47,10 +47,10 @@ namespace SharedTypes.ComInterfaces
     [ContiguousCollectionMarshaller]
     [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(StatelessCollectionMarshaller<,>.ManagedToUnmanaged))]
     [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.UnmanagedToManagedOut, typeof(StatelessCollectionMarshaller<,>.ManagedToUnmanaged))]
-    [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementIn, typeof(StatelessCollectionMarshaller<,>.ManagedToUnmanaged))]
+    [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementIn, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
     [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ManagedToUnmanagedOut, typeof(StatelessCollectionMarshaller<,>.UnmanagedToManaged))]
     [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.UnmanagedToManagedIn, typeof(StatelessCollectionMarshaller<,>.UnmanagedToManaged))]
-    [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementOut, typeof(StatelessCollectionMarshaller<,>.UnmanagedToManaged))]
+    [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementOut, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
     [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.UnmanagedToManagedRef, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
     [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ManagedToUnmanagedRef, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
     [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementRef, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
index 325064a..12c98b6 100644 (file)
@@ -39,10 +39,10 @@ namespace SharedTypes.ComInterfaces
 
     [CustomMarshaller(typeof(StatelessType), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToUnmanaged))]
     [CustomMarshaller(typeof(StatelessType), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToUnmanaged))]
-    [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementIn, typeof(ManagedToUnmanaged))]
+    [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementIn, typeof(Bidirectional))]
     [CustomMarshaller(typeof(StatelessType), MarshalMode.ManagedToUnmanagedOut, typeof(UnmanagedToManaged))]
     [CustomMarshaller(typeof(StatelessType), MarshalMode.UnmanagedToManagedIn, typeof(UnmanagedToManaged))]
-    [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementOut, typeof(UnmanagedToManaged))]
+    [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementOut, typeof(Bidirectional))]
     [CustomMarshaller(typeof(StatelessType), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
     [CustomMarshaller(typeof(StatelessType), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
     [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementRef, typeof(Bidirectional))]