未验证 提交 7e967b1a 编写于 作者: J Jeremy Koritzinsky 提交者: GitHub

Provide a code-fix to add missing stateful marshaller shape methods (#73186)

上级 5d4526d8
......@@ -164,7 +164,7 @@
<FsCheckVersion>2.14.3</FsCheckVersion>
<!-- Uncomment to set a fixed version, else the latest is used -->
<!--<SdkVersionForWorkloadTesting>7.0.100-rc.1.22402.35</SdkVersionForWorkloadTesting>-->
<CompilerPlatformTestingVersion>1.1.2-beta1.22205.2</CompilerPlatformTestingVersion>
<CompilerPlatformTestingVersion>1.1.2-beta1.22403.2</CompilerPlatformTestingVersion>
<!-- Docs -->
<MicrosoftPrivateIntellisenseVersion>7.0.0-preview-20220721.1</MicrosoftPrivateIntellisenseVersion>
<!-- ILLink -->
......
......@@ -468,7 +468,7 @@ public static class DefaultMarshalModeDiagnostics
description: GetResourceString(nameof(SR.StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsDescription)));
/// <inheritdoc cref="CustomMarshallerAttributeAnalyzer.StatefulMarshallerRequiresFromManagedRule" />
public static readonly DiagnosticDescriptor StatefulMarshallerRequiresFromManagedRule =
private static readonly DiagnosticDescriptor StatefulMarshallerRequiresFromManagedRule =
new DiagnosticDescriptor(
Ids.CustomMarshallerTypeMustHaveRequiredShape,
GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)),
......@@ -479,7 +479,7 @@ public static class DefaultMarshalModeDiagnostics
description: GetResourceString(nameof(SR.StatefulMarshallerRequiresFromManagedDescription)));
/// <inheritdoc cref="CustomMarshallerAttributeAnalyzer.StatefulMarshallerRequiresToUnmanagedRule" />
public static readonly DiagnosticDescriptor StatefulMarshallerRequiresToUnmanagedRule =
private static readonly DiagnosticDescriptor StatefulMarshallerRequiresToUnmanagedRule =
new DiagnosticDescriptor(
Ids.CustomMarshallerTypeMustHaveRequiredShape,
GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)),
......@@ -490,7 +490,7 @@ public static class DefaultMarshalModeDiagnostics
description: GetResourceString(nameof(SR.StatefulMarshallerRequiresToUnmanagedDescription)));
/// <inheritdoc cref="CustomMarshallerAttributeAnalyzer.StatefulMarshallerRequiresToManagedRule" />
public static readonly DiagnosticDescriptor StatefulMarshallerRequiresToManagedRule =
private static readonly DiagnosticDescriptor StatefulMarshallerRequiresToManagedRule =
new DiagnosticDescriptor(
Ids.CustomMarshallerTypeMustHaveRequiredShape,
GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)),
......@@ -501,7 +501,7 @@ public static class DefaultMarshalModeDiagnostics
description: GetResourceString(nameof(SR.StatefulMarshallerRequiresToManagedDescription)));
/// <inheritdoc cref="CustomMarshallerAttributeAnalyzer.StatefulMarshallerRequiresFromUnmanagedRule" />
public static readonly DiagnosticDescriptor StatefulMarshallerRequiresFromUnmanagedRule =
private static readonly DiagnosticDescriptor StatefulMarshallerRequiresFromUnmanagedRule =
new DiagnosticDescriptor(
Ids.CustomMarshallerTypeMustHaveRequiredShape,
GetResourceString(nameof(SR.CustomMarshallerTypeMustHaveRequiredShapeTitle)),
......@@ -511,7 +511,7 @@ public static class DefaultMarshalModeDiagnostics
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.StatefulMarshallerRequiresFromUnmanagedDescription)));
internal static DiagnosticDescriptor GetDefaultMarshalModeDiagnostic(DiagnosticDescriptor errorDescriptor)
public static DiagnosticDescriptor GetDefaultMarshalModeDiagnostic(DiagnosticDescriptor errorDescriptor)
{
if (ReferenceEquals(errorDescriptor, CustomMarshallerAttributeAnalyzer.StatelessValueInRequiresConvertToUnmanagedRule))
{
......
......@@ -200,6 +200,10 @@ private static ITypeSymbol GetManagedTypeInAttributeSyntax(Location locationInAt
{
AddMissingMembersToStatelessMarshaller(editor, declaringSyntax, marshallerType, managedType, missingMemberNames, isLinearCollectionMarshaller);
}
if (marshallerType.IsValueType)
{
AddMissingMembersToStatefulMarshaller(editor, declaringSyntax, marshallerType, managedType, missingMemberNames, isLinearCollectionMarshaller);
}
}
private static void AddMissingMembersToStatelessMarshaller(DocumentEditor editor, SyntaxNode declaringSyntax, INamedTypeSymbol marshallerType, ITypeSymbol managedType, HashSet<string> missingMemberNames, bool isLinearCollectionMarshaller)
......@@ -398,6 +402,173 @@ ITypeSymbol CreateManagedElementTypeSymbol()
}
}
private static void AddMissingMembersToStatefulMarshaller(DocumentEditor editor, SyntaxNode declaringSyntax, INamedTypeSymbol marshallerType, ITypeSymbol managedType, HashSet<string> missingMemberNames, bool isLinearCollectionMarshaller)
{
SyntaxGenerator gen = editor.Generator;
// Get the methods of the shape so we can use them to determine what types to use in signatures that are not obvious.
var (_, methods) = StatefulMarshallerShapeHelper.GetShapeForType(marshallerType, managedType, isLinearCollectionMarshaller, editor.SemanticModel.Compilation);
INamedTypeSymbol spanOfT = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.System_Span_Metadata)!;
INamedTypeSymbol readOnlySpanOfT = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata)!;
var (typeParameters, _) = marshallerType.GetAllTypeArgumentsIncludingInContainingTypes();
// Use a lazy factory for the type syntaxes to avoid re-checking the various methods and reconstructing the syntax.
Lazy<SyntaxNode> unmanagedTypeSyntax = new(CreateUnmanagedTypeSyntax, isThreadSafe: false);
Lazy<ITypeSymbol> managedElementTypeSymbol = new(CreateManagedElementTypeSymbol, isThreadSafe: false);
List<SyntaxNode> newMembers = new();
if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.FromManaged))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.Value.Stateful.FromManaged,
parameters: new[] { gen.ParameterDeclaration("managed", gen.TypeExpression(managedType)) },
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.ToUnmanaged))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.Value.Stateful.ToUnmanaged,
returnType: unmanagedTypeSyntax.Value,
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.FromUnmanaged))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.Value.Stateful.FromUnmanaged,
parameters: new[] { gen.ParameterDeclaration("unmanaged", unmanagedTypeSyntax.Value) },
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.ToManaged))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.Value.Stateful.ToManaged,
returnType: gen.TypeExpression(managedType),
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.BufferSize))
{
newMembers.Add(
gen.WithAccessorDeclarations(
gen.PropertyDeclaration(ShapeMemberNames.BufferSize,
gen.TypeExpression(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_Int32)),
Accessibility.Public,
DeclarationModifiers.Static),
gen.GetAccessorDeclaration(statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })));
}
if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesSource))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesSource,
returnType: gen.TypeExpression(readOnlySpanOfT.Construct(managedElementTypeSymbol.Value)),
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesDestination))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesDestination,
returnType: gen.TypeExpression(spanOfT.Construct(typeParameters[typeParameters.Length - 1])),
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesSource))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesSource,
parameters: new[]
{
gen.ParameterDeclaration("numElements", gen.TypeExpression(SpecialType.System_Int32))
},
returnType: gen.TypeExpression(readOnlySpanOfT.Construct(typeParameters[typeParameters.Length - 1])),
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesDestination))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesDestination,
parameters: new[]
{
gen.ParameterDeclaration("numElements", gen.TypeExpression(SpecialType.System_Int32))
},
returnType: gen.TypeExpression(spanOfT.Construct(managedElementTypeSymbol.Value)),
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
if (missingMemberNames.Contains(ShapeMemberNames.Free))
{
newMembers.Add(
gen.MethodDeclaration(
ShapeMemberNames.Value.Stateful.Free,
accessibility: Accessibility.Public,
statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
}
editor.ReplaceNode(declaringSyntax, (declaringSyntax, gen) => gen.AddMembers(declaringSyntax, newMembers));
SyntaxNode CreateUnmanagedTypeSyntax()
{
ITypeSymbol? unmanagedType = null;
if (methods.ToUnmanaged is not null)
{
unmanagedType = methods.ToUnmanaged.ReturnType;
}
else if (methods.FromUnmanaged is not null)
{
unmanagedType = methods.FromUnmanaged.Parameters[0].Type;
}
else if (methods.UnmanagedValuesSource is not null)
{
unmanagedType = methods.UnmanagedValuesSource.Parameters[0].Type;
}
else if (methods.UnmanagedValuesDestination is not null)
{
unmanagedType = methods.UnmanagedValuesDestination.Parameters[0].Type;
}
if (unmanagedType is not null)
{
return gen.TypeExpression(unmanagedType);
}
return gen.TypeExpression(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_IntPtr));
}
ITypeSymbol CreateManagedElementTypeSymbol()
{
if (methods.ManagedValuesSource is not null)
{
return ((INamedTypeSymbol)methods.ManagedValuesSource.ReturnType).TypeArguments[0];
}
if (methods.ManagedValuesDestination is not null)
{
return ((INamedTypeSymbol)methods.ManagedValuesDestination.ReturnType).TypeArguments[0];
}
return editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_IntPtr);
}
}
private static SyntaxNode DefaultMethodStatement(SyntaxGenerator generator, Compilation compilation)
{
return generator.ThrowStatement(generator.ObjectCreationExpression(
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using LibraryImportGenerator.UnitTests.Verifiers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.Interop.Analyzers;
using static Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer;
namespace LibraryImportGenerator.UnitTests
{
internal class CustomMarshallerAttributeFixerTest : CSharpCodeFixVerifier<CustomMarshallerAttributeAnalyzer, CustomMarshallerAttributeFixer>.Test
{
// Sort the diagnostics in a deterministic order even when they only differ by diagnostic message.
// In particular, sort the equivalent subgroups by their diagnostic descriptor in the order that the fixer's fix-all provider
// will add the methods.
// This ensures that the iterative code-fix test will produce the same (deterministic) output as the fix-all tests.
protected override ImmutableArray<(Project project, Diagnostic diagnostic)> SortDistinctDiagnostics(IEnumerable<(Project project, Diagnostic diagnostic)> diagnostics)
=> diagnostics.OrderBy(d => d.diagnostic.Location.GetLineSpan().Path, StringComparer.Ordinal)
.ThenBy(d => d.diagnostic.Location.SourceSpan.Start)
.ThenBy(d => d.diagnostic.Location.SourceSpan.End)
.ThenBy(d => d.diagnostic.Id)
.ThenBy(d => d.diagnostic.Descriptor, Comparer.Instance)
.ToImmutableArray();
private class Comparer : IComparer<DiagnosticDescriptor>
{
public static readonly Comparer Instance = new();
/// <summary>
/// Checks if the provided descriptor matches the expected descriptor or the default marshal mode equivalent of the expected descriptor.
/// </summary>
/// <param name="descriptor"></param>
/// <param name="expected"></param>
/// <returns></returns>
private static bool IsEquivalentDescriptor(DiagnosticDescriptor descriptor, DiagnosticDescriptor expected)
{
return descriptor.Equals(expected) || descriptor.Equals(DefaultMarshalModeDiagnostics.GetDefaultMarshalModeDiagnostic(expected));
}
private static int GetOrderIndexFromDescriptor(DiagnosticDescriptor descriptor)
{
// We'll order the descriptors in the following order for testing:
// - FromManaged/ConvertToUnmanaged
// - ToUnmanaged
// - FromUnmanaged/ConvertToManaged
// - ToManaged
// - BufferSize
// - AllocateContainerForUnmanagedElements
// - AllocateContainerForManagedElements
// - GetManagedValuesSource/GetUnmanagedValuesDestination
// - GetUnmanagedValuesSource/GetManagedValuesDestination
// - Free
// This order corresponds to the order that the fix-all provider will add the methods.
if (IsEquivalentDescriptor(descriptor, StatefulMarshallerRequiresFromManagedRule)
|| IsEquivalentDescriptor(descriptor, StatelessValueInRequiresConvertToUnmanagedRule)
|| IsEquivalentDescriptor(descriptor, StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsRule))
{
return 0;
}
if (IsEquivalentDescriptor(descriptor, StatefulMarshallerRequiresToUnmanagedRule))
{
return 1;
}
if (IsEquivalentDescriptor(descriptor, StatefulMarshallerRequiresFromUnmanagedRule)
|| IsEquivalentDescriptor(descriptor, StatelessRequiresConvertToManagedRule)
|| IsEquivalentDescriptor(descriptor, StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsRule))
{
return 2;
}
if (IsEquivalentDescriptor(descriptor, StatefulMarshallerRequiresToManagedRule))
{
return 3;
}
if (IsEquivalentDescriptor(descriptor, CallerAllocFromManagedMustHaveBufferSizeRule)
|| IsEquivalentDescriptor(descriptor, StatelessLinearCollectionCallerAllocFromManagedMustHaveBufferSizeRule))
{
return 4;
}
if (IsEquivalentDescriptor(descriptor, StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsRule))
{
return 5;
}
if (IsEquivalentDescriptor(descriptor, StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsRule))
{
return 6;
}
if (IsEquivalentDescriptor(descriptor, LinearCollectionInRequiresCollectionMethodsRule)
|| IsEquivalentDescriptor(descriptor, StatelessLinearCollectionInRequiresCollectionMethodsRule))
{
return 7;
}
if (IsEquivalentDescriptor(descriptor, LinearCollectionOutRequiresCollectionMethodsRule)
|| IsEquivalentDescriptor(descriptor, StatelessLinearCollectionOutRequiresCollectionMethodsRule))
{
return 8;
}
if (IsEquivalentDescriptor(descriptor, StatefulMarshallerRequiresFreeRule))
{
return 9;
}
// Sort all unknown diagnostic descriptors later.
return 10;
}
public int Compare(DiagnosticDescriptor? x, DiagnosticDescriptor? y)
{
// Sort null as less than non-null.
if (x is null)
{
return y is null ? 0 : -1;
}
if (y is null)
{
return 1;
}
return GetOrderIndexFromDescriptor(x) - GetOrderIndexFromDescriptor(y);
}
}
public static async Task VerifyCodeFixAsync(string source, string fixedSource, params DiagnosticResult[] diagnostics)
{
CustomMarshallerAttributeFixerTest test = new()
{
TestCode = source,
FixedCode = fixedSource,
};
test.ExpectedDiagnostics.AddRange(diagnostics);
await test.RunAsync();
}
}
}
......@@ -34,8 +34,46 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
[CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromManaged(ManagedType managed)
{
throw new System.NotImplementedException();
}
public nint ToUnmanaged()
{
throw new System.NotImplementedException();
}
public System.ReadOnlySpan<nint> GetManagedValuesSource()
{
throw new System.NotImplementedException();
}
public System.Span<T> GetUnmanagedValuesDestination()
{
throw new System.NotImplementedException();
}
public void Free()
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFreeRule, "MarshallerType<T>").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromManagedRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromManagedRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType").WithLocation(1),
......@@ -65,8 +103,35 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
[CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromManaged(ManagedType m) {}
public nint ToUnmanaged() => default;
public void Free() {}
public System.ReadOnlySpan<nint> GetManagedValuesSource()
{
throw new System.NotImplementedException();
}
public System.Span<T> GetUnmanagedValuesDestination()
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"));
}
......@@ -92,8 +157,32 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
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<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromManaged(ManagedType m) {}
public nint ToUnmanaged() => default;
public void Free() {}
public Span<T> GetUnmanagedValuesDestination() => default;
public ReadOnlySpan<nint> GetManagedValuesSource()
{
throw new NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"));
}
......@@ -119,8 +208,32 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
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<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromManaged(ManagedType m) {}
public nint ToUnmanaged() => default;
public void Free() {}
public ReadOnlySpan<byte> GetManagedValuesSource() => default;
public Span<T> GetUnmanagedValuesDestination()
{
throw new NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedOut, "ManagedType"),
VerifyCS.Diagnostic(LinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"));
}
......@@ -196,8 +309,46 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType<>))]
[CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromUnmanaged(nint unmanaged)
{
throw new System.NotImplementedException();
}
public ManagedType ToManaged()
{
throw new System.NotImplementedException();
}
public System.ReadOnlySpan<T> GetUnmanagedValuesSource(int numElements)
{
throw new System.NotImplementedException();
}
public System.Span<nint> GetManagedValuesDestination(int numElements)
{
throw new System.NotImplementedException();
}
public void Free()
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFreeRule, "MarshallerType<T>").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresToManagedRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresToManagedRule, "MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType").WithLocation(1),
......@@ -227,8 +378,35 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType<>))]
[CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromUnmanaged(int f) {}
public ManagedType ToManaged() => default;
public void Free() {}
public System.ReadOnlySpan<T> GetUnmanagedValuesSource(int numElements)
{
throw new System.NotImplementedException();
}
public System.Span<nint> GetManagedValuesDestination(int numElements)
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(LinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
VerifyCS.Diagnostic(LinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"));
}
......@@ -254,8 +432,32 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
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<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromUnmanaged(int f) {}
public ManagedType ToManaged() => default;
public void Free() {}
public Span<byte> GetManagedValuesDestination(int numElements) => default;
public ReadOnlySpan<T> GetUnmanagedValuesSource(int numElements)
{
throw new NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(LinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
VerifyCS.Diagnostic(LinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"));
}
......@@ -281,8 +483,32 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
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<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromUnmanaged(int f) {}
public ManagedType ToManaged() => default;
public void Free() {}
public ReadOnlySpan<T> GetUnmanagedValuesSource(int numElements) => default;
public Span<nint> GetManagedValuesDestination(int numElements)
{
throw new NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(LinearCollectionOutRequiresCollectionMethodsRule).WithLocation(1).WithArguments("MarshallerType<T>", MarshalMode.UnmanagedToManagedIn, "ManagedType"),
VerifyCS.Diagnostic(LinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"));
}
......@@ -362,8 +588,35 @@ struct MarshallerType<T>
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System;
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType<>))]
[ContiguousCollectionMarshaller]
struct MarshallerType<T>
{
public void FromManaged(ManagedType m, Span<byte> buffer) {}
public nint ToUnmanaged() => default;
public void Free() {}
public ReadOnlySpan<byte> GetManagedValuesSource() => default;
public Span<T> GetUnmanagedValuesDestination() => default;
public static int BufferSize
{
get
{
throw new NotImplementedException();
}
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(CallerAllocFromManagedMustHaveBufferSizeRule).WithLocation(0).WithArguments("MarshallerType<T>", "byte"));
}
......
......@@ -5,6 +5,7 @@
using Microsoft.CodeAnalysis.Testing;
using Microsoft.Interop;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using static Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer;
......@@ -33,8 +34,35 @@ struct MarshallerType
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof(MarshallerType))]
[CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedOut, typeof(MarshallerType))]
struct MarshallerType
{
public void FromManaged(ManagedType managed)
{
throw new System.NotImplementedException();
}
public nint ToUnmanaged()
{
throw new System.NotImplementedException();
}
public void Free()
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromManagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedIn, "ManagedType").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromManagedRule, "MarshallerType", MarshalMode.UnmanagedToManagedOut, "ManagedType").WithLocation(1),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresToUnmanagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedIn, "ManagedType").WithLocation(0),
......@@ -58,8 +86,35 @@ struct MarshallerType
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedOut, typeof(MarshallerType))]
[CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedIn, typeof(MarshallerType))]
struct MarshallerType
{
public void FromUnmanaged(nint unmanaged)
{
throw new System.NotImplementedException();
}
public ManagedType ToManaged()
{
throw new System.NotImplementedException();
}
public void Free()
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromUnmanagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedOut, "ManagedType").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromUnmanagedRule, "MarshallerType", MarshalMode.UnmanagedToManagedIn, "ManagedType").WithLocation(1),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresToManagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedOut, "ManagedType").WithLocation(0),
......@@ -106,8 +161,45 @@ struct MarshallerType
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedRef, typeof(MarshallerType))]
[CustomMarshaller(typeof(ManagedType), MarshalMode.UnmanagedToManagedRef, typeof(MarshallerType))]
struct MarshallerType
{
public void FromManaged(ManagedType managed)
{
throw new System.NotImplementedException();
}
public nint ToUnmanaged()
{
throw new System.NotImplementedException();
}
public void FromUnmanaged(nint unmanaged)
{
throw new System.NotImplementedException();
}
public ManagedType ToManaged()
{
throw new System.NotImplementedException();
}
public void Free()
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFreeRule, "MarshallerType").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromManagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedRef, "ManagedType").WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromManagedRule, "MarshallerType", MarshalMode.UnmanagedToManagedRef, "ManagedType").WithLocation(1),
......@@ -212,8 +304,44 @@ struct MarshallerType
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.Default, typeof(MarshallerType))]
struct MarshallerType
{
public void FromManaged(ManagedType managed)
{
throw new System.NotImplementedException();
}
public nint ToUnmanaged()
{
throw new System.NotImplementedException();
}
public void FromUnmanaged(nint unmanaged)
{
throw new System.NotImplementedException();
}
public ManagedType ToManaged()
{
throw new System.NotImplementedException();
}
public void Free()
{
throw new System.NotImplementedException();
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatefulMarshallerRequiresFreeRule).WithLocation(0).WithArguments("MarshallerType"),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresFromManagedRule, "MarshallerType", MarshalMode.Default, "ManagedType").WithSeverity(DiagnosticSeverity.Info).WithLocation(0),
VerifyCS.DiagnosticWithArguments(StatefulMarshallerRequiresToUnmanagedRule, "MarshallerType", MarshalMode.Default, "ManagedType").WithSeverity(DiagnosticSeverity.Info).WithLocation(0),
......@@ -241,8 +369,34 @@ struct MarshallerType
}
""";
await VerifyCS.VerifyAnalyzerAsync(
string fixedSource = """
using System;
using System.Runtime.InteropServices.Marshalling;
class ManagedType {}
[CustomMarshaller(typeof(ManagedType), MarshalMode.ManagedToUnmanagedIn, typeof({|#0:MarshallerType|}))]
struct MarshallerType
{
public void FromManaged(ManagedType m, Span<byte> b) {}
public int ToUnmanaged() => default;
public void Free() {}
public static int BufferSize
{
get
{
throw new NotImplementedException();
}
}
}
""";
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(CallerAllocFromManagedMustHaveBufferSizeRule).WithLocation(0).WithArguments("MarshallerType", "byte"));
}
}
......
......@@ -63,7 +63,7 @@ public static System.Span<T> GetUnmanagedValuesDestination(nint unmanaged, int n
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForUnmanagedElementsRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType").WithLocation(0),
......@@ -117,7 +117,7 @@ public static System.Span<T> GetUnmanagedValuesDestination(nint unmanaged, int n
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
......@@ -169,7 +169,7 @@ public static ReadOnlySpan<nint> GetManagedValuesSource(ManagedType managed)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
......@@ -221,7 +221,7 @@ public static Span<T> GetUnmanagedValuesDestination(nint unmanaged, int numEleme
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessLinearCollectionInRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
......@@ -362,7 +362,7 @@ public static System.Span<nint> GetManagedValuesDestination(ManagedType managed)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatelessLinearCollectionRequiresTwoParameterAllocateContainerForManagedElementsRule, "MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType").WithLocation(0),
......@@ -416,7 +416,7 @@ public static System.Span<nint> GetManagedValuesDestination(ManagedType managed)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
......@@ -468,7 +468,7 @@ public static ReadOnlySpan<T> GetUnmanagedValuesSource(nint unmanaged, int numEl
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
......@@ -520,7 +520,7 @@ public static Span<nint> GetManagedValuesDestination(ManagedType managed)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessLinearCollectionOutRequiresCollectionMethodsRule).WithLocation(0).WithArguments("MarshallerType<T>", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
......@@ -662,7 +662,7 @@ public static int BufferSize
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessLinearCollectionCallerAllocFromManagedMustHaveBufferSizeRule).WithLocation(0).WithArguments("MarshallerType<T>", "byte"));
......
......@@ -51,7 +51,7 @@ public static nint ConvertToUnmanaged(ManagedType managed)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithLocation(0).WithArguments("MarshallerType", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
......@@ -113,7 +113,7 @@ public static ManagedType ConvertToManaged(nint unmanaged)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessRequiresConvertToManagedRule).WithLocation(0).WithArguments("MarshallerType", MarshalMode.ManagedToUnmanagedOut, "ManagedType"),
......@@ -159,7 +159,7 @@ public static ManagedType ConvertToManaged(nint unmanaged)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.DiagnosticWithArguments(StatelessValueInRequiresConvertToUnmanagedRule, "MarshallerType", MarshalMode.ManagedToUnmanagedRef, "ManagedType").WithLocation(0),
......@@ -212,7 +212,7 @@ public static float ConvertToUnmanaged(ManagedType managed)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithLocation(0).WithArguments("MarshallerType", MarshalMode.ManagedToUnmanagedRef, "ManagedType"),
......@@ -262,7 +262,7 @@ public static ManagedType ConvertToManaged(float unmanaged)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessRequiresConvertToManagedRule).WithLocation(0).WithArguments("MarshallerType", MarshalMode.ManagedToUnmanagedRef, "ManagedType"),
......@@ -329,7 +329,7 @@ public static ManagedType ConvertToManaged(nint unmanaged)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithArguments("MarshallerType", MarshalMode.Default, "ManagedType"),
......@@ -373,7 +373,7 @@ public static int BufferSize
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(CallerAllocFromManagedMustHaveBufferSizeRule).WithLocation(0).WithArguments("MarshallerType", "byte"));
......@@ -422,14 +422,11 @@ public static nint ConvertToUnmanaged(ManagedType managed)
}
[Fact]
[ActiveIssue("https://github.com/dotnet/roslyn-sdk/issues/1000")]
public async Task ModeThatUsesManagedToUnmanagedShape_Missing_ConvertToUnmanagedMethod_Marshaller_DifferentProject_ReportsDiagnostic()
{
string entryPointTypeSource = """
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|}))]
......@@ -439,12 +436,14 @@ static class MarshallerType
""";
string otherMarshallerTypeOriginalSource = """
public class ManagedType {}
public static class OtherMarshallerType
{
}
""";
string otherMarshallerTypeFixedSource = """
public class ManagedType {}
public static class OtherMarshallerType
{
public static nint ConvertToUnmanaged(ManagedType managed)
......@@ -472,8 +471,10 @@ public static nint ConvertToUnmanaged(ManagedType managed)
test.FixedState.Sources.Add(entryPointTypeSource);
test.FixedState.AdditionalProjects.Add(otherProjectName, otherProjectFixedState);
test.FixedState.AdditionalProjectReferences.Add(otherProjectName);
test.MarkupOptions = MarkupOptions.UseFirstDescriptor;
test.FixedState.MarkupHandling = MarkupMode.IgnoreFixable;
test.NumberOfFixAllIterations = 1;
test.MarkupOptions = MarkupOptions.UseFirstDescriptor;
await test.RunAsync();
}
......@@ -515,7 +516,7 @@ public static nint ConvertToUnmanaged(ManagedType2 managed)
}
""";
await VerifyCS.VerifyCodeFixAsync(
await CustomMarshallerAttributeFixerTest.VerifyCodeFixAsync(
source,
fixedSource,
VerifyCS.Diagnostic(StatelessValueInRequiresConvertToUnmanagedRule).WithLocation(0).WithArguments("MarshallerType", MarshalMode.ManagedToUnmanagedIn, "ManagedType"),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册