Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add analyzer support to validate the stateless marshaller shapes #72643

Merged
merged 9 commits into from
Jul 26, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static class Ids
public const string CustomMarshallerTypeMustHaveRequiredShape = Prefix + "1057";
public const string InvalidNativeMarshallingAttributeUsage = Prefix + "1058";
public const string MissingAllocatingMarshallingFallback = Prefix + "1059";
public const string CallerAllocConstructorMustHaveBufferSize = Prefix + "1060";
public const string InvalidMarshallerType = Prefix + "1060";
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
public const string InvalidSignaturesInMarshallerShape = Prefix + "1061";
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ private static void AddMissingMembers(DocumentEditor editor, IEnumerable<Diagnos

public override ImmutableArray<string> FixableDiagnosticIds { get; } =
ImmutableArray.Create(
AnalyzerDiagnostics.Ids.CustomMarshallerTypeMustHaveRequiredShape,
AnalyzerDiagnostics.Ids.MissingAllocatingMarshallingFallback,
AnalyzerDiagnostics.Ids.InvalidNativeMarshallingAttributeUsage);
AnalyzerDiagnostics.Ids.CustomMarshallerTypeMustHaveRequiredShape);

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ public DiagnosticReporter(Action<DiagnosticDescriptor, ImmutableDictionary<strin
public static DiagnosticReporter CreateForLocation(Location location, Action<Diagnostic> reportDiagnostic) => new((descriptor, properties, args) => reportDiagnostic(location.CreateDiagnostic(descriptor, properties, args)));

public void CreateAndReportDiagnostic(DiagnosticDescriptor descriptor, params object[] messageArgs) => _diagnosticFactory(descriptor, ImmutableDictionary<string, string>.Empty, messageArgs);

public void CreateAndReportDiagnostic(DiagnosticDescriptor descriptor, ImmutableDictionary<string, string> properties, params object[] messageArgs) => _diagnosticFactory(descriptor, properties, messageArgs);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@
<data name="CallerAllocConstructorMustHaveBufferSizeMessage" xml:space="preserve">
<value>The marshaller type '{0}' must have a static read-only 'int' 'BufferSize' property to specify the size of the caller-allocated buffer because it has a FromManaged method that takes a caller-allocated 'Span&lt;{1}&gt;'</value>
</data>
<data name="StatelessLinearCollectionCallerAllocConstructorMustHaveBufferSizeDescription" xml:space="preserve">
<value>When the 'Managed to Unmanaged with Caller-Allocated Buffer' shape is used by providing an 'AllocateContainerForUnmanagedElements' method that takes a 'Span&lt;T&gt;' on the marshaller type, the type must provide a static 'BufferSize' property to provide the number of elements in the caller-allocated buffer.</value>
</data>
<data name="StatelessLinearCollectionCallerAllocConstructorMustHaveBufferSizeMessage" xml:space="preserve">
<value>The marshaller type '{0}' must have a static read-only 'int' 'BufferSize' property to specify the size of the caller-allocated buffer because it has an 'AllocateContainerForUnmanagedElements' method that takes a caller-allocated 'Span&lt;{1}&gt;'</value>
</data>
<data name="CannotForwardToDllImportDescription" xml:space="preserve">
<value>The generated 'DllImportAttribute' will not have a value corresponding to '{0}'.</value>
</data>
Expand Down Expand Up @@ -230,11 +236,11 @@
<data name="MarshallerTypeMustBeClosedOrMatchArityMessage" xml:space="preserve">
<value>The marshaller type '{0}' pointed to by the entry-point marshaller type '{1}' must be a closed generic type or have the same arity as the managed type</value>
</data>
<data name="TypeMustBeUnmanagedOrStrictlyBlittableDescription" xml:space="preserve">
<value>A native type must be blittable.</value>
<data name="TypeMustBeUnmanagedDescription" xml:space="preserve">
<value>An unmanaged type for a marshaller must be unmanaged.</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="TypeMustBeUnmanagedOrStrictlyBlittableMessage" xml:space="preserve">
<value>The type '{0}' must be unmanaged or strictly blittable</value>
<data name="TypeMustBeUnmanagedMessage" xml:space="preserve">
<value>The return type of '{0}' must be unmanaged</value>
</data>
<data name="TypeMustHaveExplicitCastFromVoidPointerDescription" xml:space="preserve">
<value>'void*' must be castable to the type so the pinned result of the static 'GetPinnableReference' method can be passed to the native context after being pinned.</value>
Expand Down Expand Up @@ -288,11 +294,17 @@
<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 name="StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsDescription" xml:space="preserve">
<value>A statelss contiguous collection marshaller that supports marshalling from managed to unmanaged must provide an 'AllocateContainerForUnmanagedElements' method taking the managed type as the first parameter and providing the number of elements as an 'out int' parameter</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsMessage" xml:space="preserve">
<value>The type '{0}' specifies that it supports the '{1}' marshal mode for '{2}' but does not provide a two-parameter 'AllocateContainerForUnmanagedElements' method that takes a '{2}' as the first parameter and an 'out int' as the second parameter</value>
</data>
<data name="StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsDescription" xml:space="preserve">
<value>A statelss contiguous collection marshaller that supports marshalling from managed to unmanaged must provide an 'AllocateContainerForManagedElements' method taking the unmanaged type as the first parameter and the number of elements as an 'int' parameter</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</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 name="StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsMessage" xml:space="preserve">
<value>The type '{0}' specifies that it supports the '{1}' marshal mode for '{2}' but does not provide a two-parameter 'AllocateContainerForManagedElements' method that takes the unmanaged type as the first parameter and an 'int' as the second parameter</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' of an 'unmanaged' type as parameters</value>
Expand All @@ -306,23 +318,47 @@
<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="StatelessValueInRequiresConvertToUnmanagedDescription" xml:space="preserve">
<value>A 'Value'-kind native type must provide a one-parameter constructor taking the managed type as a parameter</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="StatelessValueInRequiresConvertToUnmanagedMessage" xml:space="preserve">
<value>The type '{0}' specifies that it supports the '{1}' marshal mode of '{2}' but does not provide a one-parameter 'ConvertToUnmanaged' that takes a '{2}' as a parameter and returns a value of an 'unmanaged' type.</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</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>
<value>A contiguous collection marshaller that supports marshalling from managed to unmanaged must provide a 'GetManagedValuesSource' that returns a 'ReadOnlySpan&lt;&gt;' and a 'GetNativeValuesDestination' method that returns a 'Span&lt;&gt;'.</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</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>
<value>The type '{0}' specifies that it supports the '{1}' marshal mode, but it does not provide a 'GetManagedValuesSource' that returns a 'ReadOnlySpan&lt;&gt;' and a 'GetNativeValuesDestination' method that returns a 'Span&lt;&gt;'</value>
</data>
<data name="StatelessLinearCollectionInRequiresCollectionMethodsDescription" xml:space="preserve">
<value>A contiguous collection marshaller that supports marshalling from managed to unmanaged must provide a 'GetManagedValuesSource' that takes the managed value as a parameter and returns a 'ReadOnlySpan&lt;&gt;' and a 'GetNativeValuesDestination' method that takes the unmanaged value as a parameter and returns a 'Span&lt;&gt;'</value>
</data>
<data name="StatelessLinearCollectionInRequiresCollectionMethodsMessage" xml:space="preserve">
<value>The type '{0}' specifies that it supports the '{1}' marshal mode, but it does not provide a 'GetManagedValuesSource' that takes '{2}' as a parameter and returns a 'ReadOnlySpan&lt;&gt;' and a 'GetNativeValuesDestination' method that takes the unmanaged value as a parameter and returns a 'Span&lt;&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="StatelessRequiresConvertToManagedDescription" xml:space="preserve">
<value>A stateless value marshaller that supports marshalling from unmanaged to managed must provide a 'ConvertToManaged' method that takes the unmanaged type as a parameter and returns the the managed type.</value>
</data>
<data name="StatelessRequiresConvertToManagedMessage" xml:space="preserve">
<value>The type '{0}' specifies it supports the '{1}' marshal mode, but it does not provide a 'ConvertToManaged' method that takes the unmanaged type as a parameter and returns '{2}'</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>
<value>A contiguous collection marshaller that supports marshalling from unmanaged to managed must provide a 'GetManagedValuesDestination' that takes an 'int' and returns a 'Span&lt;&gt;' and a 'GetNativeValuesSource' method that takes an 'int' and returns a 'ReadOnlySpan&lt;&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>
<value>The type '{0}' specifies that it supports the '{1}' marshal mode, 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 returns a 'ReadOnlySpan&lt;&gt;'</value>
</data>
<data name="StatelessLinearCollectionOutRequiresCollectionMethodsDescription" xml:space="preserve">
<value>A contiguous collection marshaller that supports marshalling from unmanaged to managed must provide a 'GetManagedValuesDestination' that takes the unmanaged value and an 'int' and returns a 'Span&lt;&gt;' and a 'GetNativeValuesSource' method that takes the unmanaged value and an 'int' and returns a 'ReadOnlySpan&lt;&gt;'.</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="StatelessLinearCollectionOutRequiresCollectionMethodsMessage" xml:space="preserve">
<value>The type '{0}' specifies that it supports the '{1}' marshal mode, but it does not provide a 'GetManagedValuesDestination' that takes '{2}' and an 'int' and returns a 'Span&lt;&gt;' and a 'GetNativeValuesSource' method that takes the unmanaged value and an 'int' and returns a 'ReadOnlySpan&lt;&gt;'</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="AddMissingCustomTypeMarshallerMembers" xml:space="preserve">
<value>Add missing custom type marshaller members</value>
Expand Down Expand Up @@ -351,9 +387,6 @@
<data name="ToUnmanagedFromManagedTypesMustMatchMessage" xml:space="preserve">
<value>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same</value>
</data>
<data name="CallerAllocConstructorMustHaveBufferSizeTitle" xml:space="preserve">
<value>'BufferSize' should be set on 'CustomTypeMarshallerAttribute'</value>
</data>
<data name="CustomMarshallerTypeMustHaveRequiredShapeTitle" xml:space="preserve">
<value>Marshaller type does not have the required shape</value>
</data>
Expand All @@ -375,4 +408,40 @@
<data name="MarshallerTypeMustBeNonNullMessage" xml:space="preserve">
<value>The 'marshallerType' parameter in the 'System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute' cannot be 'null'</value>
</data>
<data name="MarshallerTypeMustBeStaticClassOrStructDescription" xml:space="preserve">
<value>A marshaller type must either be a stateless static class or a stateful value type. A non-static class is not allowed.</value>
</data>
<data name="MarshallerTypeMustBeStaticClassOrStructMessage" xml:space="preserve">
<value>The type '{0}' must be a static class or a value type</value>
</data>
<data name="ReturnTypesMustMatchDescription" xml:space="preserve">
<value>The return types of the two methods must be the same type.</value>
</data>
<data name="ReturnTypesMustMatchMessage" xml:space="preserve">
<value>The return type of '{0}' must be the same type as the return type of '{1}'</value>
</data>
<data name="ReturnTypeMustBeExpectedTypeDescription" xml:space="preserve">
<value>The return type the two method must be the expected type.</value>
</data>
<data name="ReturnTypeMustBeExpectedTypeMessage" xml:space="preserve">
<value>The return type of '{0}' must be '{1}'</value>
</data>
<data name="FirstParameterMustMatchReturnTypeDescription" xml:space="preserve">
<value>The first parameter of the first method must be the same type as the return types of the second method.</value>
</data>
<data name="FirstParameterMustMatchReturnTypeMessage" xml:space="preserve">
<value>The first parameter of '{0}' must be the same type as the return type of '{1}'</value>
</data>
<data name="FirstParametersMustMatchDescription" xml:space="preserve">
<value>The first parameters of the two methods must be the same type.</value>
</data>
<data name="FirstParametersMustMatchMessage" xml:space="preserve">
<value>The first parameter of '{0}' and '{1}' must be the same type</value>
</data>
<data name="ElementTypesOfReturnTypesMustMatchDescription" xml:space="preserve">
<value>The element type of the span returned by the first method must be the same type as the element type of the span returned by the second type.</value>
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="ElementTypesOfReturnTypesMustMatchMessage" xml:space="preserve">
<value>The element type of the span returned by '{0}' must be the same type as the element type of the span returned by '{1}'.</value>
</data>
</root>
Loading