Skip to content

Commit

Permalink
Add some basic marshalling tests to give some validation that we set …
Browse files Browse the repository at this point in the history
…up the marshalling generator correctly (E2E-style validation)
  • Loading branch information
jkoritzinsky committed May 12, 2022
1 parent 6d7327b commit b9f3597
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
)
.WithTrackingName(StepNames.CalculateStubInformation);

IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateSingleStub = generateStubInformation
IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateManagedToNativeStub = generateStubInformation
.Where(data => data.VtableIndexData.Direction.HasFlag(CustomTypeMarshallerDirection.In))
.Select(
static (data, ct) => GenerateManagedToNativeStub(data)
)
.WithComparer(Comparers.GeneratedSyntax)
.WithTrackingName(StepNames.GenerateManagedToNativeStub);

context.RegisterDiagnostics(generateSingleStub.SelectMany((stubInfo, ct) => stubInfo.Item2));
context.RegisterDiagnostics(generateManagedToNativeStub.SelectMany((stubInfo, ct) => stubInfo.Item2));

context.RegisterConcatenatedSyntaxOutputs(generateSingleStub.Select((data, ct) => data.Item1), "ManagedToNativeStubs.g.cs");
context.RegisterConcatenatedSyntaxOutputs(generateManagedToNativeStub.Select((data, ct) => data.Item1), "ManagedToNativeStubs.g.cs");

IncrementalValuesProvider<MemberDeclarationSyntax> generateNativeInterface = generateStubInformation
.Select(static (context, ct) => context.ContainingSyntaxContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,16 @@ static IEnumerable<int> GetInfoDependencies(TypePositionInfo info)

static int GetInfoIndex(TypePositionInfo info)
{
// A TypePositionInfo needs to have either a managed or native index.
// We use negative values of the native index to distinguish them from the managed index.
if (info.ManagedIndex == TypePositionInfo.UnsetIndex)
{
// A TypePositionInfo needs to have either a managed or native index.
// We use negative values of the native index to distinguish them from the managed index.
if (info.NativeIndex == 0)
{
// If we don't have a managed index and the native index is zero, use ReturnIndex + 1 as our
// index to avoid conflict with managed parameter 0.
return TypePositionInfo.ReturnIndex + 1;
}
return -info.NativeIndex;
}
return info.ManagedIndex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,90 @@ sealed class NativeAPI : IUnmanagedVirtualMethodTableProvider<NoCasting>, INativ
}
";

public static string BasicParametersAndModifiers(string typeName) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly:DisableRuntimeMarshalling]
readonly record struct NoCasting {{}}
partial interface INativeAPI
{{
public static readonly NoCasting TypeKey = default;
[VirtualMethodIndex(0)]
{typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
}}
// Try using the generated native interface
sealed class NativeAPI : IUnmanagedVirtualMethodTableProvider<NoCasting>, INativeAPI.Native
{{
public VirtualMethodTableInfo GetFunctionPointerForIndex(NoCasting typeKey) => throw null;
}}
";

public static string BasicParametersAndModifiers<T>() => BasicParametersAndModifiers(typeof(T).FullName!);

public const string CustomTypeMarshallingTestsTypeName = "S";

public static string SimpleCustomTypeMarshallingDeclaration = $@"
[NativeMarshalling(typeof(Marshaller))]
struct {CustomTypeMarshallingTestsTypeName} {{}}
[CustomTypeMarshaller(typeof({CustomTypeMarshallingTestsTypeName}))]
struct Marshaller
{{
public Marshaller({CustomTypeMarshallingTestsTypeName} managed) {{}}
public {CustomTypeMarshallingTestsTypeName} ToManaged() => throw null;
}}
";

public static string TwoStageCustomTypeMarshallingDeclaration = $@"
[NativeMarshalling(typeof(Marshaller))]
struct {CustomTypeMarshallingTestsTypeName} {{}}
[CustomTypeMarshaller(typeof({CustomTypeMarshallingTestsTypeName}), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)]
struct Marshaller
{{
public Marshaller({CustomTypeMarshallingTestsTypeName} managed) {{}}
public {CustomTypeMarshallingTestsTypeName} ToManaged() => throw null;
public int ToNativeValue() => throw null;
public void FromNativeValue(int i) => throw null;
}}
";

public static string OptionalCallerAllocatedBufferMarshallingDeclaration = $@"
[NativeMarshalling(typeof(Marshaller))]
struct {CustomTypeMarshallingTestsTypeName}
{{
}}
[CustomTypeMarshaller(typeof({CustomTypeMarshallingTestsTypeName}), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 1)]
struct Marshaller
{{
public Marshaller({CustomTypeMarshallingTestsTypeName} s, System.Span<byte> b) {{}}
public Marshaller({CustomTypeMarshallingTestsTypeName} managed) {{}}
public {CustomTypeMarshallingTestsTypeName} ToManaged() => throw null;
}}
";

public static string UnmanagedResourcesCustomTypeMarshallingDeclaration = $@"
[NativeMarshalling(typeof(Marshaller))]
struct {CustomTypeMarshallingTestsTypeName} {{}}
[CustomTypeMarshaller(typeof({CustomTypeMarshallingTestsTypeName}), Features = CustomTypeMarshallerFeatures.UnmanagedResources)]
struct Marshaller
{{
public Marshaller({CustomTypeMarshallingTestsTypeName} managed) {{}}
public {CustomTypeMarshallingTestsTypeName} ToManaged() => throw null;
public void FreeNative() {{}}
}}
";
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis;
Expand All @@ -16,6 +17,29 @@ public static IEnumerable<object[]> VTableIndexCodeSnippetsToCompile()
yield return new[] { CodeSnippets.SpecifiedMethodIndexNoExplicitParameters };
yield return new[] { CodeSnippets.SpecifiedMethodIndexNoExplicitParametersNoImplicitThis };
yield return new[] { CodeSnippets.SpecifiedMethodIndexNoExplicitParametersCallConvWithCallingConventions };

// Basic marshalling validation
yield return new[] { CodeSnippets.BasicParametersAndModifiers<byte>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<sbyte>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<short>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<ushort>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<int>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<uint>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<long>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<ulong>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<float>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<double>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<IntPtr>() };
yield return new[] { CodeSnippets.BasicParametersAndModifiers<UIntPtr>() };

// Attributed marshalling model validation
yield return new[] { CodeSnippets.BasicParametersAndModifiers(CodeSnippets.CustomTypeMarshallingTestsTypeName) + CodeSnippets.SimpleCustomTypeMarshallingDeclaration };
yield return new[] { CodeSnippets.BasicParametersAndModifiers(CodeSnippets.CustomTypeMarshallingTestsTypeName) + CodeSnippets.TwoStageCustomTypeMarshallingDeclaration };
yield return new[] { CodeSnippets.BasicParametersAndModifiers(CodeSnippets.CustomTypeMarshallingTestsTypeName) + CodeSnippets.OptionalCallerAllocatedBufferMarshallingDeclaration };
yield return new[] { CodeSnippets.BasicParametersAndModifiers(CodeSnippets.CustomTypeMarshallingTestsTypeName) + CodeSnippets.UnmanagedResourcesCustomTypeMarshallingDeclaration };

// SafeHandles
yield return new[] { CodeSnippets.BasicParametersAndModifiers("Microsoft.Win32.SafeHandles.SafeFileHandle") };
}

[Theory]
Expand Down

0 comments on commit b9f3597

Please sign in to comment.