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

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/design/libraries/LibraryImportGenerator/StructMarshalling.md18
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs59
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs21
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj1
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs100
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs276
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs28
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs37
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/TestUtils.cs47
10 files changed, 376 insertions, 213 deletions
diff --git a/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md b/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md
index b3d08539a5e..c865ae2bae9 100644
--- a/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md
+++ b/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md
@@ -246,7 +246,23 @@ As an alternative design, we can use a different definition of "does not require
For the auto-layout clause, we have one small issue; today, our ref-assemblies do not expose if a value type is marked as `[StructLayout(LayoutKind.Auto)]`, so we'd still have some cases where we might have runtime failures. However, we can update the tooling used in dotnet/runtime, GenAPI, to expose this information if we so desire. Once that case is handled, we have a mechanism that we can safely use to determine, at compile time, which types will not require marshalling. If we decide to not cover this case (as cases where users mark types as `LayoutKind.Auto` manually are exceptionally rare), we still have a solid design as Roslyn will automatically determine for us if a type is `unmanaged`, so we don't need to do any additional work.
-As `unmanaged` is a C# language concept, we can use Roslyn's APIs to determine if a type is `unmanaged` to determine if it does not require marshalling without needing to define any new attributes and reshape the ecosystem. However, to enable this work, the LibraryImportGenerator, as well as any other source generators that generate calls to native code using the interop team's infrastructure, will need to require that the user applies the `DisableRuntimeMarshallingAttribute` to their assembly when custom user-defined types are used. As we believe that users should be able to move over their assemblies to the new source-generated interop world as a whole assembly, we do not believe that this will cause any serious issues in adoption. To help support users in this case, the interop team will provide a code-fix that will generate the `DisableRuntimeMarshallingAttribute` for users when they use the source generator.
+As `unmanaged` is a C# language concept, we can use Roslyn's APIs to determine if a type is `unmanaged` to determine if it does not require marshalling without needing to define any new attributes and reshape the ecosystem. However, to enable this work, the LibraryImportGenerator, as well as any other source generators that generate calls to native code using the interop team's infrastructure, will need to require that the user applies the `DisableRuntimeMarshallingAttribute` to their assembly when non-trivial custom user-defined types are used. To help support users in this case, the interop team will provide a code-fix that will generate the `DisableRuntimeMarshallingAttribute` for users when they use the source generator. New codebases that adopt the source-generated interop world should immediately apply `DisableRuntimeMarshallingAttribute`.
+
+Applying `DisableRuntimeMarshallingAttribute` can impact existing codebases depending on what interop APIs are used. Along with the potential difficultly in tracking down these places there is also an argument to made around the UX of the source-generator. Users are permitted to rely upon the runtime's definition of blittable and not apply `DisableRuntimeMarshallingAttribute` if all the types to be marshalled adhere to the following constraints, termed "strictly blittable" in code:
+
+1) Is always blittable (for example, `int` or `double`, but not `char`).
+2) Is a value type defined in the source project the current source generator is running on.
+3) Is a type composed of types adhering to (1) and (2).
+
+For example, the following value type would require the consumer of the source generator to apply `DisableRuntimeMarshallingAttribute` if the above was not permitted.
+
+```csharp
+struct S
+{
+ public short A;
+ public short B;
+}
+```
### Usage
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs
index 5cd08a37f28..d8a5ca227cb 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs
@@ -51,22 +51,51 @@ namespace Microsoft.Interop
public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context)
{
- return info.MarshallingAttributeInfo switch
+ if (info.MarshallingAttributeInfo is NativeMarshallingAttributeInfo marshalInfo)
{
- NativeMarshallingAttributeInfo marshalInfo when Options.RuntimeMarshallingDisabled => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
- NativeMarshallingAttributeInfo { NativeValueType: SpecialTypeInfo specialType } marshalInfo when specialType.SpecialType.IsAlwaysBlittable() => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
- NativeMarshallingAttributeInfo { NativeValueType: PointerTypeInfo } marshalInfo => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
- UnmanagedBlittableMarshallingInfo when Options.RuntimeMarshallingDisabled => s_blittable,
- UnmanagedBlittableMarshallingInfo or NativeMarshallingAttributeInfo when !Options.RuntimeMarshallingDisabled =>
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = SR.RuntimeMarshallingMustBeDisabled,
- DiagnosticProperties = AddDisableRuntimeMarshallingAttributeProperties
- },
- GeneratedNativeMarshallingAttributeInfo => s_forwarder,
- MissingSupportMarshallingInfo => s_forwarder,
- _ => _innerMarshallingGenerator.Create(info, context)
- };
+ if (Options.RuntimeMarshallingDisabled || marshalInfo.IsStrictlyBlittable)
+ {
+ return CreateCustomNativeTypeMarshaller(info, context, marshalInfo);
+ }
+
+ if (marshalInfo.NativeValueType is SpecialTypeInfo specialType
+ && specialType.SpecialType.IsAlwaysBlittable())
+ {
+ return CreateCustomNativeTypeMarshaller(info, context, marshalInfo);
+ }
+
+ if (marshalInfo.NativeValueType is PointerTypeInfo)
+ {
+ return CreateCustomNativeTypeMarshaller(info, context, marshalInfo);
+ }
+
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = SR.RuntimeMarshallingMustBeDisabled,
+ DiagnosticProperties = AddDisableRuntimeMarshallingAttributeProperties
+ };
+ }
+
+ if (info.MarshallingAttributeInfo is UnmanagedBlittableMarshallingInfo blittableInfo)
+ {
+ if (Options.RuntimeMarshallingDisabled || blittableInfo.IsStrictlyBlittable)
+ {
+ return s_blittable;
+ }
+
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = SR.RuntimeMarshallingMustBeDisabled,
+ DiagnosticProperties = AddDisableRuntimeMarshallingAttributeProperties
+ };
+ }
+
+ if (info.MarshallingAttributeInfo is MissingSupportMarshallingInfo)
+ {
+ return s_forwarder;
+ }
+
+ return _innerMarshallingGenerator.Create(info, context);
}
private static ExpressionSyntax GetNumElementsExpressionFromMarshallingInfo(TypePositionInfo info, CountInfo count, StubCodeContext context)
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
index 803f57e4495..795a49642c0 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
@@ -99,7 +99,10 @@ namespace Microsoft.Interop
/// <summary>
/// The provided type was determined to be an "unmanaged" type that can be passed as-is to native code.
/// </summary>
- public sealed record UnmanagedBlittableMarshallingInfo : MarshallingInfo;
+ /// <param name="IsStrictlyBlittable">Indicates if the type is blittable as defined by the built-in .NET marshallers.</param>
+ public sealed record UnmanagedBlittableMarshallingInfo(
+ bool IsStrictlyBlittable
+ ) : MarshallingInfo;
[Flags]
public enum CustomTypeMarshallerPinning
@@ -147,17 +150,11 @@ namespace Microsoft.Interop
CustomTypeMarshallerFeatures MarshallingFeatures,
CustomTypeMarshallerPinning PinningFeatures,
bool UseDefaultMarshalling,
+ bool IsStrictlyBlittable,
ManagedTypeInfo? BufferElementType,
int? BufferSize) : MarshallingInfo;
/// <summary>
- /// User-applied System.Runtime.InteropServices.GeneratedMarshallingAttribute
- /// on a non-blittable type in source in this compilation.
- /// </summary>
- public sealed record GeneratedNativeMarshallingAttributeInfo(
- string NativeMarshallingFullyQualifiedTypeName) : MarshallingInfo;
-
- /// <summary>
/// The type of the element is a SafeHandle-derived type with no marshalling attributes.
/// </summary>
public sealed record SafeHandleMarshallingInfo(bool AccessibleDefaultConstructor, bool IsAbstract) : MarshallingInfo;
@@ -183,6 +180,7 @@ namespace Microsoft.Interop
MarshallingFeatures,
PinningFeatures,
UseDefaultMarshalling,
+ IsStrictlyBlittable: false,
SpecialTypeInfo.Byte,
BufferSize
);
@@ -331,10 +329,6 @@ namespace Microsoft.Interop
inspectedElements,
ref maxIndirectionDepthUsed);
}
- else if (attributeClass.ToDisplayString() == TypeNames.GeneratedMarshallingAttribute)
- {
- return type.IsConsideredBlittable() ? GetBlittableMarshallingInfo(type) : new GeneratedNativeMarshallingAttributeInfo(null! /* TODO: determine naming convention */);
- }
}
// If the type doesn't have custom attributes that dictate marshalling,
@@ -697,6 +691,7 @@ namespace Microsoft.Interop
customTypeMarshallerData.Features,
pinning,
useDefaultMarshalling,
+ nativeType.IsStrictlyBlittable(),
bufferElementTypeInfo,
customTypeMarshallerData.BufferSize);
}
@@ -904,7 +899,7 @@ namespace Microsoft.Interop
}
else
{
- return new UnmanagedBlittableMarshallingInfo();
+ return new UnmanagedBlittableMarshallingInfo(type.IsStrictlyBlittable());
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj
index a169234d97a..ad1891b04fa 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj
@@ -5,6 +5,7 @@
<Nullable>enable</Nullable>
<RootNamespace>Microsoft.Interop</RootNamespace>
<RunAnalyzers>true</RunAnalyzers>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs
index c619e6ce3df..876dc649001 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs
@@ -9,8 +9,6 @@ namespace Microsoft.Interop
public const string LibraryImportAttribute = "System.Runtime.InteropServices.LibraryImportAttribute";
public const string StringMarshalling = "System.Runtime.InteropServices.StringMarshalling";
- public const string GeneratedMarshallingAttribute = "System.Runtime.InteropServices.GeneratedMarshallingAttribute";
-
public const string NativeMarshallingAttribute = "System.Runtime.InteropServices.Marshalling.NativeMarshallingAttribute";
public const string MarshalUsingAttribute = "System.Runtime.InteropServices.Marshalling.MarshalUsingAttribute";
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
index bb10cf31c12..513b961c590 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
@@ -13,34 +13,72 @@ namespace Microsoft.Interop
{
public static class TypeSymbolExtensions
{
- public static bool HasOnlyBlittableFields(this ITypeSymbol type) => HasOnlyBlittableFields(type, ImmutableHashSet.Create<ITypeSymbol>(SymbolEqualityComparer.Default));
+ /// <summary>
+ /// Is the type blittable according to source generator invariants.
+ /// </summary>
+ /// <remarks>
+ /// Source generation attempts to reconcile the notion of blittability
+ /// with the C# notion of an "unmanaged" type. This can be accomplished through
+ /// the use of DisableRuntimeMarshallingAttribute.
+ /// </remarks>
+ /// <param name="type">The type to check.</param>
+ /// <returns>Returns true if considered blittable, otherwise false.</returns>
+ public static bool IsConsideredBlittable(this ITypeSymbol type)
+ {
+ unsafe
+ {
+ return IsBlittableWorker(type, ImmutableHashSet.Create<ITypeSymbol>(SymbolEqualityComparer.Default), &IsConsideredBlittableWorker);
+ }
- private static bool HasOnlyBlittableFields(this ITypeSymbol type, ImmutableHashSet<ITypeSymbol> seenTypes)
+ static bool IsConsideredBlittableWorker(ITypeSymbol t, ImmutableHashSet<ITypeSymbol> seenTypes)
+ {
+ return t.IsUnmanagedType;
+ }
+ }
+
+ /// <summary>
+ /// Is the type strictly blittable.
+ /// </summary>
+ /// <remarks>
+ /// Source generation uses a heavily restricted defintion for strictly blittable.
+ /// The definition is based on the built-in marshallers blittable definition but further
+ /// restricts the definition to require only uses primitive types (not including char or bool)
+ /// and do types defined in the source being compiled.
+ /// </remarks>
+ /// <param name="type">The type to check.</param>
+ /// <returns>Returns true if strictly blittable, otherwise false.</returns>
+ public static bool IsStrictlyBlittable(this ITypeSymbol type)
{
- if (seenTypes.Contains(type))
+ unsafe
{
- // A recursive struct type is illegal in C#, but source generators run before that is detected,
- // so we check here to avoid a stack overflow.
- return false;
+ return IsBlittableWorker(type, ImmutableHashSet.Create<ITypeSymbol>(SymbolEqualityComparer.Default), &IsStrictlyBlittableWorker);
}
- foreach (IFieldSymbol field in type.GetMembers().OfType<IFieldSymbol>())
+ static unsafe bool IsStrictlyBlittableWorker(ITypeSymbol t, ImmutableHashSet<ITypeSymbol> seenTypes)
{
- if (!field.IsStatic)
+ if (t.SpecialType is not SpecialType.None)
+ {
+ return t.SpecialType.IsAlwaysBlittable();
+ }
+ else if (t.IsValueType)
{
- if (!IsConsideredBlittable(field.Type, seenTypes.Add(type)))
+ // If the containing assembly for the type is backed by metadata (non-null),
+ // then the type is not internal and therefore coming from a reference assembly
+ // that we can not confirm is strictly blittable.
+ if (t.ContainingAssembly is not null
+ && t.ContainingAssembly.GetMetadata() is not null)
{
return false;
}
+
+ return t.HasOnlyBlittableFields(seenTypes, &IsStrictlyBlittableWorker);
}
- }
- return true;
+ return false;
+ }
}
- public static bool IsConsideredBlittable(this ITypeSymbol type) => IsConsideredBlittable(type, ImmutableHashSet.Create<ITypeSymbol>(SymbolEqualityComparer.Default));
-
- private static bool IsConsideredBlittable(this ITypeSymbol type, ImmutableHashSet<ITypeSymbol> seenTypes)
+ private static unsafe bool IsBlittableWorker(this ITypeSymbol type, ImmutableHashSet<ITypeSymbol> seenTypes, delegate*<ITypeSymbol, ImmutableHashSet<ITypeSymbol>, bool> isBlittable)
{
// Assume that type parameters that can be blittable are blittable.
// We'll re-evaluate blittability for generic fields of generic types at instantation time.
@@ -48,7 +86,7 @@ namespace Microsoft.Interop
{
return true;
}
- if (!type.IsUnmanagedType || type.IsAutoLayout())
+ if (type.IsAutoLayout() || !isBlittable(type, seenTypes))
{
return false;
}
@@ -59,21 +97,16 @@ namespace Microsoft.Interop
{
continue;
}
- else if (attr.AttributeClass.ToDisplayString() == "System.Runtime.InteropServices.GeneratedMarshallingAttribute")
- {
- // If we have generated struct marshalling,
- // then the generated marshalling will be non-blittable when one of the fields is not unmanaged.
- return type.HasOnlyBlittableFields(seenTypes);
- }
else if (attr.AttributeClass.ToDisplayString() == "System.Runtime.InteropServices.NativeMarshallingAttribute")
{
+ // Types marked with NativeMarshallingAttribute require marshalling by definition.
return false;
}
}
return true;
}
- public static bool IsAutoLayout(this ITypeSymbol type)
+ private static bool IsAutoLayout(this ITypeSymbol type)
{
foreach (AttributeData attr in type.GetAttributes())
{
@@ -85,6 +118,29 @@ namespace Microsoft.Interop
return type.IsReferenceType;
}
+ private static unsafe bool HasOnlyBlittableFields(this ITypeSymbol type, ImmutableHashSet<ITypeSymbol> seenTypes, delegate*<ITypeSymbol, ImmutableHashSet<ITypeSymbol>, bool> isBlittable)
+ {
+ if (seenTypes.Contains(type))
+ {
+ // A recursive struct type is illegal in C#, but source generators run before that is detected,
+ // so we check here to avoid a stack overflow.
+ return false;
+ }
+
+ foreach (IFieldSymbol field in type.GetMembers().OfType<IFieldSymbol>())
+ {
+ if (!field.IsStatic)
+ {
+ if (!IsBlittableWorker(field.Type, seenTypes.Add(type), isBlittable))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
public static TypeSyntax AsTypeSyntax(this ITypeSymbol type)
{
return SyntaxFactory.ParseTypeName(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
index b99404232e1..768cb0ecebf 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
@@ -336,14 +336,11 @@ partial class Test
";
public static readonly string DisableRuntimeMarshalling = "[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]";
- public static readonly string UseCustomTypeMarshaller =
-@$"using System.Runtime.InteropServices.Marshalling;
-{DisableRuntimeMarshalling}";
/// <summary>
/// Declaration with parameters with <see cref="StringMarshalling"/> set.
/// </summary>
- public static string BasicParametersAndModifiersWithStringMarshalling(string typename, StringMarshalling value, string preDeclaration = "") => @$"
+ public static string BasicParametersAndModifiersWithStringMarshalling(string typename, StringMarshalling value, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
{preDeclaration}
partial class Test
@@ -363,8 +360,9 @@ partial class Test
/// <summary>
/// Declaration with parameters with <see cref="StringMarshallingCustomType"/> set.
/// </summary>
- public static string BasicParametersAndModifiersWithStringMarshallingCustomType(string typeName, string stringMarshallingCustomTypeName, string preDeclaration = "") => @$"
+ public static string BasicParametersAndModifiersWithStringMarshallingCustomType(string typeName, string stringMarshallingCustomTypeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -383,7 +381,7 @@ partial class Test
public static string CustomStringMarshallingParametersAndModifiers<T>()
{
string typeName = typeof(T).ToString();
- return BasicParametersAndModifiersWithStringMarshallingCustomType(typeName, "Native", UseCustomTypeMarshaller) + @$"
+ return BasicParametersAndModifiersWithStringMarshallingCustomType(typeName, "Native", DisableRuntimeMarshalling) + $@"
[CustomTypeMarshaller(typeof({typeName}))]
struct Native
{{
@@ -396,8 +394,9 @@ struct Native
/// <summary>
/// Declaration with parameters.
/// </summary>
- public static string BasicParametersAndModifiers(string typeName, string preDeclaration = "") => @$"
+ public static string BasicParametersAndModifiers(string typeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -412,8 +411,9 @@ partial class Test
/// <summary>
/// Declaration with parameters.
/// </summary>
- public static string BasicParametersAndModifiersNoRef(string typeName, string preDeclaration = "") => @$"
+ public static string BasicParametersAndModifiersNoRef(string typeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -427,7 +427,7 @@ partial class Test
/// <summary>
/// Declaration with parameters and unsafe.
/// </summary>
- public static string BasicParametersAndModifiersUnsafe(string typeName, string preDeclaration = "") => @$"
+ public static string BasicParametersAndModifiersUnsafe(string typeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
{preDeclaration}
partial class Test
@@ -445,8 +445,9 @@ partial class Test
/// <summary>
/// Declaration with [In, Out] style attributes on a by-value parameter.
/// </summary>
- public static string ByValueParameterWithModifier(string typeName, string attributeName, string preDeclaration = "") => @$"
+ public static string ByValueParameterWithModifier(string typeName, string attributeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -460,7 +461,7 @@ partial class Test
/// <summary>
/// Declaration with by-value parameter with custom name.
/// </summary>
- public static string ByValueParameterWithName(string methodName, string paramName) => @$"
+ public static string ByValueParameterWithName(string methodName, string paramName) => $@"
using System.Runtime.InteropServices;
partial class Test
{{
@@ -472,7 +473,7 @@ partial class Test
/// <summary>
/// Declaration with parameters with MarshalAs.
/// </summary>
- public static string MarshalAsParametersAndModifiers(string typeName, UnmanagedType unmanagedType) => @$"
+ public static string MarshalAsParametersAndModifiers(string typeName, UnmanagedType unmanagedType) => $@"
using System.Runtime.InteropServices;
partial class Test
{{
@@ -489,7 +490,7 @@ partial class Test
/// <summary>
/// Declaration with parameters with MarshalAs.
/// </summary>
- public static string MarshalAsParametersAndModifiersUnsafe(string typeName, UnmanagedType unmanagedType) => @$"
+ public static string MarshalAsParametersAndModifiersUnsafe(string typeName, UnmanagedType unmanagedType) => $@"
using System.Runtime.InteropServices;
partial class Test
{{
@@ -508,7 +509,7 @@ partial class Test
/// <summary>
/// Declaration with enum parameters.
/// </summary>
- public static string EnumParameters => @$"
+ public static string EnumParameters => $@"
using System.Runtime.InteropServices;
using NS;
@@ -535,7 +536,7 @@ partial class Test
/// <summary>
/// Declaration with PreserveSig = false.
/// </summary>
- public static string SetLastErrorTrue(string typeName) => @$"
+ public static string SetLastErrorTrue(string typeName) => $@"
using System.Runtime.InteropServices;
partial class Test
{{
@@ -564,12 +565,13 @@ delegate int MyDelegate(int a);";
private void* vptr;
}}";
- public static string BlittableStructParametersAndModifiers = BasicParametersAndModifiers("MyStruct", DisableRuntimeMarshalling) + $@"
+ public static string BlittableStructParametersAndModifiers(string attr) => BasicParametersAndModifiers("MyStruct", attr) + $@"
{BlittableMyStruct()}
";
public static string MarshalAsArrayParametersAndModifiers(string elementType, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -618,8 +620,9 @@ partial class Test
/// <summary>
/// Declaration with parameters with MarshalAs.
/// </summary>
- public static string MarshalUsingParametersAndModifiers(string typeName, string nativeTypeName, string preDeclaration = "") => @$"
+ public static string MarshalUsingParametersAndModifiers(string typeName, string nativeTypeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -632,48 +635,31 @@ partial class Test
[MarshalUsing(typeof({nativeTypeName}))] out {typeName} pOut);
}}
";
-
- public static string BasicNonBlittableUserDefinedType = @"
-[NativeMarshalling(typeof(Native))]
+ public static string BasicNonBlittableUserDefinedType(bool defineNativeMarshalling = true) => $@"
+{(defineNativeMarshalling ? "[NativeMarshalling(typeof(Native))]" : string.Empty)}
struct S
-{
+{{
public bool b;
-}
+}}
[CustomTypeMarshaller(typeof(S))]
struct Native
-{
+{{
private int i;
public Native(S s)
- {
+ {{
i = s.b ? 1 : 0;
- }
+ }}
- public S ToManaged() => new S { b = i != 0 };
-}";
-
- public static string CustomStructMarshallingParametersAndModifiers = BasicParametersAndModifiers("S", UseCustomTypeMarshaller) + BasicNonBlittableUserDefinedType;
-
- public static string CustomStructMarshallingMarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Native", UseCustomTypeMarshaller) + @"
-struct S
-{
- public bool b;
-}
+ public S ToManaged() => new S {{ b = i != 0 }};
+}}
+";
-[CustomTypeMarshaller(typeof(S))]
-struct Native
-{
- private int i;
- public Native(S s)
- {
- i = s.b ? 1 : 0;
- }
+ public static string CustomStructMarshallingParametersAndModifiers = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + BasicNonBlittableUserDefinedType(defineNativeMarshalling: false);
- public S ToManaged() => new S { b = i != 0 };
-}
-";
+ public static string CustomStructMarshallingMarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Native", DisableRuntimeMarshalling) + BasicNonBlittableUserDefinedType(defineNativeMarshalling: true);
- public static string CustomStructMarshallingStackallocParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingStackallocParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
struct S
{
@@ -692,7 +678,7 @@ struct Native
public S ToManaged() => new S { b = i != 0 };
}
";
- public static string CustomStructMarshallingStackallocOnlyRefParameter = BasicParameterWithByRefModifier("ref", "S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingStackallocOnlyRefParameter = BasicParameterWithByRefModifier("ref", "S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
struct S
{
@@ -711,7 +697,7 @@ struct Native
public S ToManaged() => new S { b = i != 0 };
}
";
- public static string CustomStructMarshallingOptionalStackallocParametersAndModifiers = BasicParametersAndModifiers("S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingOptionalStackallocParametersAndModifiers = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
struct S
{
@@ -735,7 +721,7 @@ struct Native
}
";
- public static string CustomStructMarshallingStackallocValuePropertyParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingStackallocValuePropertyParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
struct S
{
@@ -755,7 +741,7 @@ struct Native
public void FromNativeValue(int value) => throw null;
}
";
- public static string CustomStructMarshallingValuePropertyParametersAndModifiers = BasicParametersAndModifiers("S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingValuePropertyParametersAndModifiers = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
struct S
{
@@ -775,7 +761,7 @@ struct Native
public void FromNativeValue(int value) => throw null;
}
";
- public static string CustomStructMarshallingPinnableParametersAndModifiers = BasicParametersAndModifiers("S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingPinnableParametersAndModifiers = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
class S
{
@@ -802,69 +788,69 @@ unsafe struct Native
}
";
- public static string CustomStructMarshallingNativeTypePinnable = @"
+ public static string CustomStructMarshallingNativeTypePinnable = $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
[NativeMarshalling(typeof(Native))]
class S
-{
+{{
public byte c;
-}
+}}
[CustomTypeMarshaller(typeof(S), Features = CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling, BufferSize = 1)]
unsafe ref struct Native
-{
+{{
private byte* ptr;
private Span<byte> stackBuffer;
public Native(S s) : this()
- {
+ {{
ptr = (byte*)Marshal.AllocCoTaskMem(sizeof(byte));
*ptr = s.c;
stackBuffer = new Span<byte>(ptr, 1);
- }
+ }}
public Native(S s, Span<byte> buffer) : this()
- {
+ {{
stackBuffer = buffer;
stackBuffer[0] = s.c;
- }
+ }}
public ref byte GetPinnableReference() => ref stackBuffer.GetPinnableReference();
public S ToManaged()
- {
- return new S { c = *ptr };
- }
+ {{
+ return new S {{ c = *ptr }};
+ }}
public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference());
public void FromNativeValue(byte* value) => ptr = value;
public void FreeNative()
- {
+ {{
if (ptr != null)
- {
+ {{
Marshal.FreeCoTaskMem((IntPtr)ptr);
- }
- }
-}
+ }}
+ }}
+}}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
S s,
in S sIn);
-}
+}}
";
- public static string CustomStructMarshallingByRefValueProperty = BasicParametersAndModifiers("S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingByRefValueProperty = BasicParametersAndModifiers("S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
class S
{
@@ -885,8 +871,9 @@ unsafe struct Native
}
";
- public static string BasicParameterWithByRefModifier(string byRefKind, string typeName, string preDeclaration = "") => @$"
+ public static string BasicParameterWithByRefModifier(string byRefKind, string typeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -895,8 +882,9 @@ partial class Test
{byRefKind} {typeName} p);
}}";
- public static string BasicParameterByValue(string typeName, string preDeclaration = "") => @$"
+ public static string BasicParameterByValue(string typeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -905,8 +893,9 @@ partial class Test
{typeName} p);
}}";
- public static string BasicReturnType(string typeName, string preDeclaration = "") => @$"
+ public static string BasicReturnType(string typeName, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
{preDeclaration}
partial class Test
{{
@@ -914,7 +903,7 @@ partial class Test
public static partial {typeName} Method();
}}";
- public static string BasicReturnAndParameterByValue(string returnType, string parameterType, string preDeclaration = "") => @$"
+ public static string BasicReturnAndParameterByValue(string returnType, string parameterType, string preDeclaration = "") => $@"
using System.Runtime.InteropServices;
{preDeclaration}
partial class Test
@@ -923,7 +912,7 @@ partial class Test
public static partial {returnType} Method({parameterType} p);
}}";
- public static string CustomStructMarshallingManagedToNativeOnlyOutParameter => BasicParameterWithByRefModifier("out", "S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingManagedToNativeOnlyOutParameter => BasicParameterWithByRefModifier("out", "S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
[StructLayout(LayoutKind.Sequential)]
struct S
@@ -942,7 +931,7 @@ struct Native
}
";
- public static string CustomStructMarshallingManagedToNativeOnlyReturnValue => BasicReturnType("S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingManagedToNativeOnlyReturnValue => BasicReturnType("S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
[StructLayout(LayoutKind.Sequential)]
struct S
@@ -961,7 +950,7 @@ struct Native
}
";
- public static string CustomStructMarshallingNativeToManagedOnlyInParameter => BasicParameterWithByRefModifier("in", "S", UseCustomTypeMarshaller) + @"
+ public static string CustomStructMarshallingNativeToManagedOnlyInParameter => BasicParameterWithByRefModifier("in", "S", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Native))]
struct S
{
@@ -977,7 +966,7 @@ struct Native
}
";
- public static string ArrayMarshallingWithCustomStructElementWithValueProperty => MarshalAsArrayParametersAndModifiers("IntStructWrapper", UseCustomTypeMarshaller) + @"
+ public static string ArrayMarshallingWithCustomStructElementWithValueProperty => MarshalAsArrayParametersAndModifiers("IntStructWrapper", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(IntStructWrapperNative))]
public struct IntStructWrapper
{
@@ -998,7 +987,7 @@ public struct IntStructWrapperNative
}
";
- public static string ArrayMarshallingWithCustomStructElement => MarshalAsArrayParametersAndModifiers("IntStructWrapper", UseCustomTypeMarshaller) + @"
+ public static string ArrayMarshallingWithCustomStructElement => MarshalAsArrayParametersAndModifiers("IntStructWrapper", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(IntStructWrapperNative))]
public struct IntStructWrapper
{
@@ -1030,7 +1019,7 @@ class MySafeHandle : SafeHandle
}}";
public static string PreprocessorIfAroundFullFunctionDefinition(string define) =>
- @$"
+ $@"
partial class Test
{{
#if {define}
@@ -1043,7 +1032,7 @@ partial class Test
}}";
public static string PreprocessorIfAroundFullFunctionDefinitionWithFollowingFunction(string define) =>
- @$"
+ $@"
using System.Runtime.InteropServices;
partial class Test
{{
@@ -1059,7 +1048,7 @@ partial class Test
}}";
public static string PreprocessorIfAfterAttributeAroundFunction(string define) =>
- @$"
+ $@"
using System.Runtime.InteropServices;
partial class Test
{{
@@ -1078,7 +1067,7 @@ partial class Test
}}";
public static string PreprocessorIfAfterAttributeAroundFunctionAdditionalFunctionAfter(string define) =>
- @$"
+ $@"
using System.Runtime.InteropServices;
partial class Test
{{
@@ -1127,7 +1116,7 @@ struct RecursiveStruct2
int i;
}";
- public static string CollectionByValue(string elementType) => BasicParameterByValue($"TestCollection<{elementType}>", UseCustomTypeMarshaller) + @"
+ public static string CollectionByValue(string elementType) => BasicParameterByValue($"TestCollection<{elementType}>", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Marshaller<>))]
class TestCollection<T> {}
@@ -1271,7 +1260,7 @@ partial class Test
);
}}";
- public static string GenericCollectionMarshallingArityMismatch => BasicParameterByValue("TestCollection<int>", UseCustomTypeMarshaller) + @"
+ public static string GenericCollectionMarshallingArityMismatch => BasicParameterByValue("TestCollection<int>", DisableRuntimeMarshalling) + @"
[NativeMarshalling(typeof(Marshaller<,>))]
class TestCollection<T> {}
@@ -1290,12 +1279,12 @@ ref struct Marshaller<T, U>
public TestCollection<T> ToManaged() => throw null;
}";
- public static string GenericCollectionWithCustomElementMarshalling => @"
+ public static string GenericCollectionWithCustomElementMarshalling => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
[return:MarshalUsing(ConstantElementCount=10)]
[return:MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)]
@@ -1307,123 +1296,123 @@ partial class Test
[MarshalUsing(CountElementName = ""pOutSize"")][MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] out TestCollection<int> pOut,
out int pOutSize
);
-}
+}}
struct IntWrapper
-{
- public IntWrapper(int i){}
+{{
+ public IntWrapper(int i){{}}
public int ToManaged() => throw null;
-}
+}}
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth => @"
+ public static string GenericCollectionWithCustomElementMarshallingDuplicateElementIndirectionDepth => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
[MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] [MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 1)] TestCollection<int> p);
-}
+}}
struct IntWrapper
-{
- public IntWrapper(int i){}
+{{
+ public IntWrapper(int i){{}}
public int ToManaged() => throw null;
-}
+}}
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth => @"
+ public static string GenericCollectionWithCustomElementMarshallingUnusedElementIndirectionDepth => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
[MarshalUsing(typeof(IntWrapper), ElementIndirectionDepth = 2)] TestCollection<int> p);
-}
+}}
struct IntWrapper
-{
- public IntWrapper(int i){}
+{{
+ public IntWrapper(int i){{}}
public int ToManaged() => throw null;
-}
+}}
" + CustomCollectionWithMarshaller(enableDefaultMarshalling: true);
- public static string MarshalAsAndMarshalUsingOnReturnValue => @"
+ public static string MarshalAsAndMarshalUsingOnReturnValue => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
[return:MarshalUsing(ConstantElementCount=10)]
[return:MarshalAs(UnmanagedType.LPArray, SizeConst=10)]
public static partial int[] Method();
-}
+}}
";
- public static string RecursiveCountElementNameOnReturnValue => @"
+ public static string RecursiveCountElementNameOnReturnValue => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
[return:MarshalUsing(CountElementName=MarshalUsingAttribute.ReturnsCountValue)]
public static partial int[] Method();
-}
+}}
";
- public static string RecursiveCountElementNameOnParameter => @"
+ public static string RecursiveCountElementNameOnParameter => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
[MarshalUsing(CountElementName=""arr"")] ref int[] arr
);
-}
+}}
";
- public static string MutuallyRecursiveCountElementNameOnParameter => @"
+ public static string MutuallyRecursiveCountElementNameOnParameter => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
[MarshalUsing(CountElementName=""arr2"")] ref int[] arr,
[MarshalUsing(CountElementName=""arr"")] ref int[] arr2
);
-}
+}}
";
- public static string MutuallyRecursiveSizeParamIndexOnParameter => @"
+ public static string MutuallyRecursiveSizeParamIndexOnParameter => $@"
using System.Runtime.InteropServices;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ref int[] arr,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ref int[] arr2
);
-}
+}}
";
- public static string CollectionsOfCollectionsStress => @"
+ public static string CollectionsOfCollectionsStress => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]
+{DisableRuntimeMarshalling}
partial class Test
-{
+{{
[LibraryImport(""DoesNotExist"")]
public static partial void Method(
[MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]
@@ -1494,7 +1483,7 @@ partial class Test
[MarshalUsing(CountElementName=""arr0"", ElementIndirectionDepth = 0)]ref int[] arr1,
ref int arr0
);
-}
+}}
";
public static string RefReturn(string typeName) => $@"
@@ -1535,5 +1524,28 @@ partial struct Basic
}
";
+ public static class ValidateDisableRuntimeMarshalling
+ {
+ public static string NonBlittableUserDefinedTypeWithNativeType = $@"
+public struct S
+{{
+ public string s;
+}}
+
+[CustomTypeMarshaller(typeof(S))]
+public struct Native
+{{
+ private System.IntPtr p;
+ public Native(S s)
+ {{
+ p = System.IntPtr.Zero;
+ }}
+
+ public S ToManaged() => new S {{ s = string.Empty }};
+}}
+";
+
+ public static string TypeUsage(string attr) => MarshalUsingParametersAndModifiers("S", "Native", attr);
+ }
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
index 3a0eb6ecbca..9d2591ede7f 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -170,5 +171,32 @@ namespace LibraryImportGenerator.UnitTests
int compilerErrors = newComp.GetDiagnostics().Count(d => d.Severity == DiagnosticSeverity.Error);
Assert.Equal(expectedCompilerErrors, compilerErrors);
}
+
+ [Fact]
+ public async Task ValidateDisableRuntimeMarshallingForBlittabilityCheckFromAssemblyReference()
+ {
+ string assemblySource = $@"
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+{CodeSnippets.ValidateDisableRuntimeMarshalling.NonBlittableUserDefinedTypeWithNativeType}
+";
+ Compilation assemblyComp = await TestUtils.CreateCompilation(assemblySource);
+ TestUtils.AssertPreSourceGeneratorCompilation(assemblyComp);
+
+ var ms = new MemoryStream();
+ Assert.True(assemblyComp.Emit(ms).Success);
+
+ string testSource = CodeSnippets.ValidateDisableRuntimeMarshalling.TypeUsage(string.Empty);
+
+ Compilation testComp = await TestUtils.CreateCompilation(testSource, refs: new[] { MetadataReference.CreateFromImage(ms.ToArray()) });
+ TestUtils.AssertPreSourceGeneratorCompilation(testComp);
+
+ var newComp = TestUtils.RunGenerators(testComp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator());
+
+ // The errors should indicate the DisableRuntimeMarshalling is required.
+ Assert.True(generatorDiags.All(d => d.Id == "SYSLIB1051"));
+
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
+ }
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
index 680785316b6..e62247a20e1 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
@@ -114,8 +114,8 @@ namespace LibraryImportGenerator.UnitTests
// [In, Out] attributes
// By value non-blittable array
- yield return new[] { CodeSnippets.ByValueParameterWithModifier("S[]", "Out", CodeSnippets.UseCustomTypeMarshaller + CodeSnippets.BasicNonBlittableUserDefinedType) };
- yield return new[] { CodeSnippets.ByValueParameterWithModifier("S[]", "In, Out", CodeSnippets.UseCustomTypeMarshaller + CodeSnippets.BasicNonBlittableUserDefinedType) };
+ yield return new[] { CodeSnippets.ByValueParameterWithModifier("S[]", "Out", CodeSnippets.DisableRuntimeMarshalling + CodeSnippets.BasicNonBlittableUserDefinedType()) };
+ yield return new[] { CodeSnippets.ByValueParameterWithModifier("S[]", "In, Out", CodeSnippets.DisableRuntimeMarshalling + CodeSnippets.BasicNonBlittableUserDefinedType()) };
// Enums
yield return new[] { CodeSnippets.EnumParameters };
@@ -149,7 +149,12 @@ namespace LibraryImportGenerator.UnitTests
yield return new[] { CodeSnippets.MarshalAsParametersAndModifiersUnsafe("delegate* unmanaged<int>", UnmanagedType.FunctionPtr) };
// Structs
- yield return new[] { CodeSnippets.BlittableStructParametersAndModifiers };
+ yield return new[] { CodeSnippets.BlittableStructParametersAndModifiers(string.Empty) };
+ yield return new[] { CodeSnippets.BlittableStructParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling) };
+ yield return new[] { CodeSnippets.ValidateDisableRuntimeMarshalling.TypeUsage(string.Empty)
+ + CodeSnippets.ValidateDisableRuntimeMarshalling.NonBlittableUserDefinedTypeWithNativeType };
+ yield return new[] { CodeSnippets.ValidateDisableRuntimeMarshalling.TypeUsage(CodeSnippets.DisableRuntimeMarshalling)
+ + CodeSnippets.ValidateDisableRuntimeMarshalling.NonBlittableUserDefinedTypeWithNativeType };
// SafeHandle
yield return new[] { CodeSnippets.BasicParametersAndModifiers("Microsoft.Win32.SafeHandles.SafeFileHandle") };
@@ -252,8 +257,7 @@ namespace LibraryImportGenerator.UnitTests
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator());
Assert.Empty(generatorDiags);
- var newCompDiags = newComp.GetDiagnostics();
- Assert.Empty(newCompDiags);
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
}
public static IEnumerable<object[]> CodeSnippetsToCompileWithPreprocessorSymbols()
@@ -278,8 +282,7 @@ namespace LibraryImportGenerator.UnitTests
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator());
Assert.Empty(generatorDiags);
- var newCompDiags = newComp.GetDiagnostics();
- Assert.Empty(newCompDiags);
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
}
public static IEnumerable<object[]> CodeSnippetsToValidateFallbackForwarder()
@@ -338,8 +341,7 @@ namespace LibraryImportGenerator.UnitTests
Assert.Empty(generatorDiags);
- var newCompDiags = newComp.GetDiagnostics();
- Assert.Empty(newCompDiags);
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
// Verify that the forwarder generates the method as a DllImport.
SyntaxTree generatedCode = newComp.SyntaxTrees.Last();
@@ -375,8 +377,7 @@ namespace LibraryImportGenerator.UnitTests
Assert.Empty(generatorDiags);
- var newCompDiags = newComp.GetDiagnostics();
- Assert.Empty(newCompDiags);
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
// Verify that the forwarder generates the method as a DllImport.
SyntaxTree generatedCode = newComp.SyntaxTrees.Last();
@@ -409,8 +410,7 @@ namespace LibraryImportGenerator.UnitTests
Assert.Empty(generatorDiags);
- var newCompDiags = newComp.GetDiagnostics();
- Assert.Empty(newCompDiags);
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
// Verify that the generator generates stubs with inner DllImports for all methods.
SyntaxTree generatedCode = newComp.SyntaxTrees.Last();
@@ -449,13 +449,7 @@ namespace LibraryImportGenerator.UnitTests
Assert.Empty(generatorDiags);
- var newCompDiags = newComp.GetDiagnostics();
-
- Assert.All(newCompDiags, diag =>
- {
- Assert.Equal("CS0117", diag.Id);
- Assert.StartsWith("'Marshal' does not contain a definition for ", diag.GetMessage());
- });
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp, "CS0117");
}
public static IEnumerable<object[]> CodeSnippetsToCompileMultipleSources()
@@ -475,8 +469,7 @@ namespace LibraryImportGenerator.UnitTests
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator());
Assert.Empty(generatorDiags);
- var newCompDiags = newComp.GetDiagnostics();
- Assert.Empty(newCompDiags);
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
}
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/TestUtils.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/TestUtils.cs
index 83f943478d6..1498bb587e9 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/TestUtils.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/TestUtils.cs
@@ -66,7 +66,7 @@ namespace LibraryImportGenerator.UnitTests
}.ToImmutableDictionary();
/// <summary>
- /// Assert the pre-srouce generator compilation has only
+ /// Assert the pre-source generator compilation has only
/// the expected failure diagnostics.
/// </summary>
/// <param name="comp"></param>
@@ -93,15 +93,41 @@ namespace LibraryImportGenerator.UnitTests
}
/// <summary>
+ /// Assert the post-source generator compilation has only
+ /// the expected failure diagnostics.
+ /// </summary>
+ /// <param name="comp"></param>
+ public static void AssertPostSourceGeneratorCompilation(Compilation comp, params string[] additionalAllowedDiagnostics)
+ {
+ var allowedDiagnostics = new HashSet<string>()
+ {
+ "CS8019", // Unnecessary using
+ };
+
+ foreach (string diagnostic in additionalAllowedDiagnostics)
+ {
+ allowedDiagnostics.Add(diagnostic);
+ }
+
+ var compDiags = comp.GetDiagnostics();
+ Assert.All(compDiags, diag =>
+ {
+ Assert.Subset(allowedDiagnostics, new HashSet<string> { diag.Id });
+ });
+ }
+
+ /// <summary>
/// Create a compilation given source
/// </summary>
/// <param name="source">Source to compile</param>
/// <param name="targetFramework">Target framework of the compilation</param>
/// <param name="outputKind">Output type</param>
+ /// <param name="refs">Addtional metadata references</param>
+ /// <param name="preprocessorSymbols">Prepocessor symbols</param>
/// <returns>The resulting compilation</returns>
- public static Task<Compilation> CreateCompilation(string source, TestTargetFramework targetFramework = TestTargetFramework.Net, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary, IEnumerable<string>? preprocessorSymbols = null)
+ public static Task<Compilation> CreateCompilation(string source, TestTargetFramework targetFramework = TestTargetFramework.Net, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary, IEnumerable<MetadataReference>? refs = null, IEnumerable<string>? preprocessorSymbols = null)
{
- return CreateCompilation(new[] { source }, targetFramework, outputKind, preprocessorSymbols);
+ return CreateCompilation(new[] { source }, targetFramework, outputKind, refs, preprocessorSymbols);
}
/// <summary>
@@ -110,14 +136,17 @@ namespace LibraryImportGenerator.UnitTests
/// <param name="sources">Sources to compile</param>
/// <param name="targetFramework">Target framework of the compilation</param>
/// <param name="outputKind">Output type</param>
+ /// <param name="refs">Addtional metadata references</param>
+ /// <param name="preprocessorSymbols">Prepocessor symbols</param>
/// <returns>The resulting compilation</returns>
- public static Task<Compilation> CreateCompilation(string[] sources, TestTargetFramework targetFramework = TestTargetFramework.Net, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary, IEnumerable<string>? preprocessorSymbols = null)
+ public static Task<Compilation> CreateCompilation(string[] sources, TestTargetFramework targetFramework = TestTargetFramework.Net, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary, IEnumerable<MetadataReference>? refs = null, IEnumerable<string>? preprocessorSymbols = null)
{
return CreateCompilation(
sources.Select(source =>
CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview, preprocessorSymbols: preprocessorSymbols))).ToArray(),
targetFramework,
- outputKind);
+ outputKind,
+ refs);
}
/// <summary>
@@ -126,8 +155,9 @@ namespace LibraryImportGenerator.UnitTests
/// <param name="sources">Sources to compile</param>
/// <param name="targetFramework">Target framework of the compilation</param>
/// <param name="outputKind">Output type</param>
+ /// <param name="refs">Addtional metadata references</param>
/// <returns>The resulting compilation</returns>
- public static async Task<Compilation> CreateCompilation(SyntaxTree[] sources, TestTargetFramework targetFramework = TestTargetFramework.Net, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
+ public static async Task<Compilation> CreateCompilation(SyntaxTree[] sources, TestTargetFramework targetFramework = TestTargetFramework.Net, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary, IEnumerable<MetadataReference>? refs = null)
{
var referenceAssemblies = await GetReferenceAssemblies(targetFramework);
@@ -137,6 +167,11 @@ namespace LibraryImportGenerator.UnitTests
referenceAssemblies = referenceAssemblies.Add(GetAncillaryReference());
}
+ if (refs is not null)
+ {
+ referenceAssemblies = referenceAssemblies.AddRange(refs);
+ }
+
return CSharpCompilation.Create("compilation",
sources,
referenceAssemblies,