File: Microsoft.NetCore.Analyzers\InteropServices\DisableRuntimeMarshallingTests.cs
Web Access
Project: ..\..\..\src\Microsoft.CodeAnalysis.NetAnalyzers\tests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests.csproj (Microsoft.CodeAnalysis.NetAnalyzers.UnitTests)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.NetCore.Analyzers.InteropServices.DisableRuntimeMarshallingAnalyzer,
    Microsoft.NetCore.Analyzers.InteropServices.CSharpDisableRuntimeMarshallingFixer>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.NetCore.Analyzers.InteropServices.DisableRuntimeMarshallingAnalyzer,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
namespace Microsoft.CodeAnalysis.NetAnalyzers.UnitTests.Microsoft.NetCore.Analyzers.InteropServices
{
    public class DisableRuntimeMarshallingTests
    {
        [Fact]
        public async Task CS_PInvokeWithSetLastError_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"", SetLastError = true)]
    public static extern void {|CA1420:Method|}();
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_Local_PInvokeWithSetLastError_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static void Outer()
    {
        [DllImport(""NativeLibrary"", SetLastError = true)]
        static extern void {|CA1420:Method|}();
    }
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithSetLastError_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"", SetLastError:=True)>
    Public Shared Sub {|CA1420:Method|}()
    End Sub
End Class
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithLCIDConversion_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    [LCIDConversion(0)]
    public static extern void {|CA1420:Method|}();
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithLCIDConversion_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    <LCIDConversion(0)>
    Public Shared Sub {|CA1420:Method|}()
    End Sub
End Class
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithClassParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void Method(string {|CA1420:param|});
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithClassParameter_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Sub Method({|CA1420:s|} As string)
    End Sub
End Class
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithClassReturnValue_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern string {|CA1420:Method|}();
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithClassReturnValue_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Function {|CA1420:Method|}() As string
    End Function
End Class
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokePropertyWithClassReturnValue_EmitsDiagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static extern string P { [DllImport(""abc"")] {|CA1420:get|}; }
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeOperatorWithClassType_EmitsDiagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""abc"")]
    public static extern int operator +(C {|CA1420:a|}, C {|CA1420:b|});
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeEvent_EmitsDiagnostic()
        {
            string source = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [method: DllImport(""abc"")]
    public extern static event Action {|CA1420:G|};
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithManagedValueTypeReturnValue_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern ValueType {|CA1420:Method|}();
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithRecursiveManagedValueTypeReturnValue_DoesNotEmitDiagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern ValueType Method();
}
 
struct ValueType
{
    ValueType {|CS0523:v|};
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithMutuallyRecursiveManagedValueTypeReturnValue_DoesNotEmitDiagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern ValueType Method();
}
 
struct ValueType
{
    ValueType2 {|CS0523:v|};
}
struct ValueType2
{
    ValueType {|CS0523:v|};
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithManagedValueTypeReturnValue_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Function {|CA1420:Method|}() As ValueType
    End Function
End Class
 
Public Structure ValueType
    Public s As String
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void Method(ValueType {|CA1420:param|});
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Sub Method({|CA1420:param|} As ValueType)
    End Sub
End Class
 
Public Structure ValueType
    Public s As String
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithByRefManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void Method(ref ValueType {|CA1420:{|CA1420:param|}|});
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithByRefManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Sub Method(ByRef {|CA1420:{|CA1420:param|}|} As ValueType)
    End Sub
End Class
 
Public Structure ValueType
    Public s As String
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithByRefUnmanagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void Method(ref ValueType {|CA1420:param|});
}
 
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithByRefUnmanagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Sub Method(ByRef {|CA1420:param|} As ValueType)
    End Sub
End Class
 
Public Structure ValueType
    Public s As Char
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithUnmnagedValueTypeReturnValue_Does_Not_Emit_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern ValueType Method();
}
 
struct ValueType
{
    char s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithUnmnagedValueTypeReturnValue_Does_Not_Emit_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Function Method() As ValueType
    End Function
End Class
 
Public Structure ValueType
    Public s As Char
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithUnmanagedValueTypeParameter_Does_Not_Emit_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void Method(ValueType param);
}
 
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithUnmanagedValueTypeParameter_Does_Not_Emit_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Sub Method(param As ValueType)
    End Sub
End Class
 
Public Structure ValueType
    Public s As Char
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithUnmanagedValueTypeParameter_WithAutoLayout_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void Method(ValueType {|CA1420:param|});
}
 
[StructLayout(LayoutKind.Auto)]
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithUnmanagedValueTypeParameter_WithAutoLayout_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Sub Method({|CA1420:param|} As ValueType)
    End Sub
End Class
 
<StructLayout(LayoutKind.Auto)>
Public Structure ValueType
    Public s As Char
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_PInvokeWithUnmanagedValueTypeParameter_WithAutoLayoutField_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void Method(ValueType {|CA1420:param|});
}
 
struct ValueType
{
    ValueType2 v;
}
 
[StructLayout(LayoutKind.Auto)]
struct ValueType2
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_PInvokeWithUnmanagedValueTypeParameter_WithAutoLayoutField_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class C
    <DllImport(""NativeLibrary"")>
    Public Shared Sub Method({|CA1420:param|} As ValueType)
    End Sub
End Class
 
Public Structure ValueType
    Public s As ValueType2
End Structure
 
<StructLayout(LayoutKind.Auto)>
Public Structure ValueType2
    Public s As char
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task Declare_Declaration_Emits_Diagnostic()
        {
            string source = @"
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Public Class D
    Declare Sub {|CA1420:Method|} Lib ""NativeLibrary""
End Class
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task PInvokeWithVarargs_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"")]
    public static extern void {|CA1420:Method|}(__arglist);
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task PInvokeWithPreserveSigFalse_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [DllImport(""NativeLibrary"", PreserveSig = false)]
    public static extern int {|CA1420:Method|}(int p);
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_DelegateWithClassParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate void DelegateType(string {|CA1420:param|});
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_DelegateWithClassParameter_Emits_Diagnostic()
        {
            string source = @"
Imports System
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
 
<UnmanagedFunctionPointer(CallingConvention.Winapi)>
Public Delegate Sub DelegateType({|CA1420:param|} As String)
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task CS_DelegateWithClassReturnValue_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate string {|CA1420:DelegateType|}();
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        [WorkItem(5995, "https://github.com/dotnet/roslyn-analyzers/issues/5995")]
        public async Task CS_DelegateWithClassReturnValue_NoUnmanagedFunctionPointer_MarshalAPIUsage_Emits_Diagnostic()
        {
            string delegateDefinition = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
public delegate string DelegateType();
";
 
            string source = @"
using System;
using System.Runtime.InteropServices;
 
class C
{
    public static void M(DelegateType d, IntPtr i)
    {
        _ = Marshal.GetFunctionPointerForDelegate((Delegate){|CA1420:d|});
        _ = Marshal.GetFunctionPointerForDelegate({|CA1420:d|});
        _ = Marshal.GetDelegateForFunctionPointer(i, {|CA1420:typeof(DelegateType)|});
        _ = {|CA1420:Marshal.GetDelegateForFunctionPointer<DelegateType>(i)|};
    }
}
";
            await VerifyCSAnalyzerWithAdditionalSourceAsync(source, delegateDefinition);
            await VerifyCSAnalyzerWithAdditionalAssemblyAsync(source, delegateDefinition);
        }
 
        [Fact]
        [WorkItem(5995, "https://github.com/dotnet/roslyn-analyzers/issues/5995")]
        public async Task CS_DelegateWithClassReturnValue_NoUnmanagedFunctionPointer_PInvokeUsage_Emits_Diagnostic()
        {
            string delegateDefinition = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
public delegate string DelegateType();
";
 
            string source = @"
using System;
using System.Runtime.InteropServices;
 
class C
{
    [DllImport(""Native"")]
    public static extern void PInvoke(DelegateType {|CA1420:d|});
    [DllImport(""Native"")]
    public static extern DelegateType {|CA1420:PInvoke|}();
    [DllImport(""Native"")]
    public static extern void PInvokeArray(DelegateType[] {|CA1420:d|});
    [DllImport(""Native"")]
    public static extern DelegateType[] {|CA1420:PInvokeArray|}();
}
";
            await VerifyCSAnalyzerWithAdditionalAssemblyAsync(source, delegateDefinition);
        }
 
        [Fact]
        [WorkItem(6094, "https://github.com/dotnet/roslyn-analyzers/issues/6094")]
        public async Task CS_DelegateWith_NonBlittableParameter_PInvokeUsage_NoDisableRuntimeMarshalling_DoesNotEmit_Diagnostic()
        {
            string source = @"
using System;
using System.Runtime.InteropServices;
 
internal delegate void DelegateType(string[] str);
 
class C
{
    [DllImport(""Native"")]
    public static extern void PInvoke(DelegateType d);
    [DllImport(""Native"")]
    public static extern DelegateType PInvoke();
    [DllImport(""Native"")]
    public static extern void PInvokeArray(DelegateType[] d);
    [DllImport(""Native"")]
    public static extern DelegateType[] PInvokeArray();
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        [WorkItem(6094, "https://github.com/dotnet/roslyn-analyzers/issues/5995")]
        public async Task CS_DelegateWithClassReturnValue_NoUnmanagedFunctionPointer_MarshalAPIUsage_NoDisableRuntimeMarshalling_DoesNotEmit_Diagnostic()
        {
            string source = @"
using System;
using System.Runtime.InteropServices;
 
public delegate string DelegateType();
 
class C
{
    public static void M(DelegateType d, IntPtr i)
    {
        _ = Marshal.GetFunctionPointerForDelegate((Delegate)d);
        _ = Marshal.GetFunctionPointerForDelegate(d);
        _ = Marshal.GetDelegateForFunctionPointer(i, typeof(DelegateType));
        _ = Marshal.GetDelegateForFunctionPointer<DelegateType>(i);
    }
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task VB_DelegateWithClassReturnValue_Emits_Diagnostic()
        {
            string source = @"
Imports System
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
 
<UnmanagedFunctionPointer(CallingConvention.Winapi)>
Public Delegate Function {|CA1420:DelegateType|}() As String
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithManagedValueTypeReturnValue_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate ValueType {|CA1420:DelegateType|}();
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate void DelegateType(ValueType {|CA1420:param|});
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithByRefManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate void DelegateType(ref ValueType {|CA1420:{|CA1420:param|}|});
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithByRefUnmanagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate void DelegateType(ref ValueType {|CA1420:param|});
}
 
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithUnmnagedValueTypeReturnValue_Does_Not_Emit_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate ValueType DelegateType();
}
 
struct ValueType
{
    char s;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithUnmanagedValueTypeParameter_Does_Not_Emit_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate void DelegateType(ValueType param);
}
 
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithUnmanagedValueTypeParameter_WithAutoLayout_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate void DelegateType(ValueType {|CA1420:param|});
}
 
[StructLayout(LayoutKind.Auto)]
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task DelegateWithUnmanagedValueTypeParameter_WithAutoLayoutField_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    public delegate void DelegateType(ValueType {|CA1420:param|});
}
 
struct ValueType
{
    ValueType2 v;
}
 
[StructLayout(LayoutKind.Auto)]
struct ValueType2
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task FunctionPointerWithClassParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<string, void> cb)
    {
        {|CA1420:cb("""")|};
    }
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithClassReturnValue_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<string> cb)
    {
        _ = {|CA1420:cb()|};
    }
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithManagedValueTypeReturnValue_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ValueType> cb)
    {
        _ = {|CA1420:cb()|};
    }
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ValueType, void> cb)
    {
        {|CA1420:cb(default)|};
    }
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithByRefManagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ref ValueType, void> cb)
    {
        ValueType vt = default;
        {|CA1420:{|CA1420:cb(ref vt)|}|};
    }
}
 
struct ValueType
{
    string s;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithByRefUnmanagedValueTypeParameter_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ref ValueType, void> cb)
    {
        ValueType vt = default;
        {|CA1420:cb(ref vt)|};
    }
}
 
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithUnmnagedValueTypeReturnValue_Does_Not_Emit_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ValueType> cb)
    {
        _ = cb();
    }
}
 
struct ValueType
{
    char s;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithUnmanagedValueTypeParameter_Does_Not_Emit_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ValueType, void> cb)
    {
        cb(default);
    }
}
 
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithUnmanagedValueTypeParameter_WithAutoLayout_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ValueType, void> cb)
    {
        {|CA1420:cb(default)|};
    }
}
 
[StructLayout(LayoutKind.Auto)]
struct ValueType
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task FunctionPointerWithUnmanagedValueTypeParameter_WithAutoLayoutField_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate* unmanaged<ValueType, void> cb)
    {
        {|CA1420:cb(default)|};
    }
}
 
struct ValueType
{
    ValueType2 v;
}
 
[StructLayout(LayoutKind.Auto)]
struct ValueType2
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task ManagedFunctionPointerWithUnmanagedValueTypeParameter_WithAutoLayoutField_Does_Not_Emit_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public static unsafe void Test(delegate*<ValueType, void> cb)
    {
        cb(default);
    }
}
 
struct ValueType
{
    ValueType2 v;
}
 
[StructLayout(LayoutKind.Auto)]
struct ValueType2
{
    char c;
}
";
            await VerifyCSAnalyzerAsync(source, allowUnsafeBlocks: true);
        }
 
        [Fact]
        public async Task MarshalOffsetOf_Emits_Diagnostic()
        {
            string source = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public void Test()
    {
        IntPtr offset = {|CA1421:Marshal.OffsetOf(typeof(ValueType), ""field"")|};
        IntPtr offsetGeneric = {|CA1421:Marshal.OffsetOf<ValueType>(""field"")|};
    }
}
 
struct ValueType
{
    int field;
}
";
            await VerifyCSAnalyzerAsync(source);
        }
 
        [Fact]
        public async Task MarshalSizeOf_Emits_Diagnostic()
        {
            string source = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public void Test<T, U>(System.Type type)
        where U : unmanaged
    {
        object obj = default(ValueType);
        int instanceSize = {|CA1421:Marshal.SizeOf(obj)|};
        int size = {|CA1421:Marshal.SizeOf(typeof(ValueType))|};
        int sizeGeneric = {|CA1421:Marshal.SizeOf<ValueType>()|};
        int sizePassedInType = {|CA1421:Marshal.SizeOf(type)|};
        int sizePassedInGeneric = {|CA1421:Marshal.SizeOf<T>()|};
        int sizePassedInGenericUnmanaged = {|CA1421:Marshal.SizeOf<U>()|};
    }
}
 
struct ValueType
{
    int field;
}
";
            string codeFix = @"
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public unsafe void Test<T, U>(System.Type type)
        where U : unmanaged
    {
        object obj = default(ValueType);
        int instanceSize = {|CA1421:Marshal.SizeOf(obj)|};
        int size = sizeof(ValueType);
        int sizeGeneric = sizeof(ValueType);
        int sizePassedInType = {|CA1421:Marshal.SizeOf(type)|};
        int sizePassedInGeneric = {|CA1421:Marshal.SizeOf<T>()|};
        int sizePassedInGenericUnmanaged = sizeof(U);
    }
}
 
struct ValueType
{
    int field;
}
";
            await VerifyCSCodeFixAsync(source, codeFix, allowUnsafeBlocks: true);
 
            // The code fix is not applicable when unsafe blocks are not allowed.
            await VerifyCSCodeFixAsync(source, source, allowUnsafeBlocks: false);
        }
 
        [Fact]
        public async Task MarshalStructureToPtr_Emits_Diagnostic()
        {
            string source = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public void Test(IntPtr ptr)
    {
        {|CA1421:Marshal.StructureToPtr((object)default(ValueType), ptr, false)|};
        {|CA1421:Marshal.StructureToPtr((object)default(ValueType), ptr, true)|};
        {|CA1421:Marshal.StructureToPtr(default(ValueType), ptr, false)|};
        {|CA1421:Marshal.StructureToPtr(default(ValueType), ptr, true)|};
        {|CA1421:Marshal.StructureToPtr(default(ManagedValueType), ptr, false)|};
        {|CA1421:Marshal.StructureToPtr(default(ManagedValueType), ptr, true)|};
    }
}
 
struct ValueType
{
    int field;
}
struct ManagedValueType
{
    string field;
}
";
            string codeFix = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public unsafe void Test(IntPtr ptr)
    {
        {|CA1421:Marshal.StructureToPtr((object)default(ValueType), ptr, false)|};
        {|CA1421:Marshal.StructureToPtr((object)default(ValueType), ptr, true)|};
        *(ValueType*)ptr = default(ValueType);
        *(ValueType*)ptr = default(ValueType);
        {|CA1421:Marshal.StructureToPtr(default(ManagedValueType), ptr, false)|};
        {|CA1421:Marshal.StructureToPtr(default(ManagedValueType), ptr, true)|};
    }
}
 
struct ValueType
{
    int field;
}
struct ManagedValueType
{
    string field;
}
";
            await VerifyCSCodeFixAsync(source, codeFix, allowUnsafeBlocks: true);
 
            // The code fix is not applicable when unsafe blocks are not allowed.
            await VerifyCSCodeFixAsync(source, source, allowUnsafeBlocks: false);
        }
 
        [Fact]
        public async Task MarshalPtrToStructure_Emits_Diagnostic()
        {
            string source = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public void Test(IntPtr ptr, Type t)
    {
        {|CA1421:Marshal.PtrToStructure(ptr, (object)default(ValueType))|};
        {|CA1421:Marshal.PtrToStructure(ptr, new ClassType())|};
        _ = {|CA1421:Marshal.PtrToStructure(ptr, typeof(ManagedValueType))|};
        _ = {|CA1421:Marshal.PtrToStructure(ptr, typeof(ValueType))|};
        _ = {|CA1421:Marshal.PtrToStructure(ptr, typeof(ValueType?))|};
        _ = {|CA1421:Marshal.PtrToStructure(ptr + 1, typeof(ValueType?))|};
        _ = {|CA1421:Marshal.PtrToStructure(ptr, t)|};
        _ = {|CA1421:Marshal.PtrToStructure<ValueType>(ptr)|};
        _ = {|CA1421:Marshal.PtrToStructure<ValueType?>(ptr)|};
        {|CA1421:Marshal.PtrToStructure<ValueType>(ptr, default(ValueType))|};
        {|CA1421:Marshal.PtrToStructure<ClassType>(ptr, new ClassType())|};
    }
}
 
struct ValueType
{
    int field;
}
struct ManagedValueType
{
    string field;
}
class ClassType
{
    int field;
}
";
            string codeFix = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:DisableRuntimeMarshalling]
 
class C
{
    public unsafe void Test(IntPtr ptr, Type t)
    {
        {|CA1421:Marshal.PtrToStructure(ptr, (object)default(ValueType))|};
        {|CA1421:Marshal.PtrToStructure(ptr, new ClassType())|};
        _ = {|CA1421:Marshal.PtrToStructure(ptr, typeof(ManagedValueType))|};
        _ = (object)(*(ValueType*)ptr);
        _ = (ValueType*)ptr is not null and var ptr1 ? *ptr1 : (object)null;
        _ = (ValueType*)(ptr + 1) is not null and var ptr2 ? *ptr2 : (object)null;
        _ = {|CA1421:Marshal.PtrToStructure(ptr, t)|};
        _ = (*(ValueType*)ptr);
        _ = (ValueType*)ptr is not null and var ptr3 ? *ptr3 : (ValueType?)null;
        {|CA1421:Marshal.PtrToStructure<ValueType>(ptr, default(ValueType))|};
        {|CA1421:Marshal.PtrToStructure<ClassType>(ptr, new ClassType())|};
    }
}
 
struct ValueType
{
    int field;
}
struct ManagedValueType
{
    string field;
}
class ClassType
{
    int field;
}
";
            await VerifyCSCodeFixAsync(source, codeFix, allowUnsafeBlocks: true);
 
            // The code fix is not applicable when unsafe blocks are not allowed.
            await VerifyCSCodeFixAsync(source, source, allowUnsafeBlocks: false);
        }
 
        [Fact]
        public async Task VB_Marshal_APIs_Emits_Diagnostic()
        {
            string source = @"
Imports System
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly:DisableRuntimeMarshalling>
Class C
    Public Shared Sub Test()
        Dim size As Int32
        Dim ptr As IntPtr
        Dim bar As S
        
        size = {|CA1421:Marshal.SizeOf(GetType(S))|}
        size = {|CA1421:Marshal.SizeOf(Of S)()|}
        bar = {|CA1421:Marshal.PtrToStructure(Of S)(ptr)|}
        {|CA1421:Marshal.StructureToPtr(bar, ptr, False)|}
        size = {|CA1421:Marshal.OffsetOf(GetType(S), NameOf(bar.Baz))|}
        size = {|CA1421:Marshal.OffsetOf(Of S)(NameOf(bar.Baz))|}
    End Sub
End Class
 
Structure S
    Public Baz As Int32
End Structure
";
            await VerifyVBAnalyzerAsync(source);
        }
 
        private static async Task VerifyCSAnalyzerWithAdditionalSourceAsync(string source, string additionalSourceFile)
        {
            var test = new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp9,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70,
                TestCode = source,
                MarkupOptions = MarkupOptions.UseFirstDescriptor
            };
 
            test.TestState.Sources.Add(additionalSourceFile);
 
            await test.RunAsync();
        }
 
        private static async Task VerifyCSAnalyzerWithAdditionalAssemblyAsync(string source, string additionalReferencedAssemblySource)
        {
            var test = new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp9,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70,
                TestCode = source,
                MarkupOptions = MarkupOptions.UseFirstDescriptor
            };
 
            const string AdditionalAssemblyName = "AdditionalAssembly";
 
            var additionalProject = new ProjectState(AdditionalAssemblyName, LanguageNames.CSharp, "Additional_", ".cs");
 
            additionalProject.Sources.Add(additionalReferencedAssemblySource);
 
            test.TestState.AdditionalProjects.Add(AdditionalAssemblyName, additionalProject);
            test.TestState.AdditionalProjectReferences.Add(AdditionalAssemblyName);
 
            await test.RunAsync();
        }
 
        private static Task VerifyCSAnalyzerAsync(string source, bool allowUnsafeBlocks = false)
        {
            return VerifyCSCodeFixAsync(source, source, allowUnsafeBlocks);
        }
 
        private static async Task VerifyCSCodeFixAsync(string source, string codeFix, bool allowUnsafeBlocks = false)
        {
            var test = new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp9,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70,
                TestCode = source,
                FixedCode = codeFix,
                SolutionTransforms =
                {
                    (solution, projectId) => solution.WithProjectCompilationOptions(projectId, (solution.GetProject(projectId).CompilationOptions as CSharpCompilationOptions)?.WithAllowUnsafe(allowUnsafeBlocks))
                },
                // Because we can't always fix all cases of our diagnostic,
                // the test infrastructure can run up to 2 iterations of our fix-all code fix.
                // The first run fixes all the fixable diagnostics.
                // Since there are still some (unfixable) diagnostics, the test infrastructure decides to run the fix-all provider again.
                // The second run doesn't do anything, since the remaining diagnostics are unfixable.
                // Setting NumberOfFixAllIterations to -2 specifies that the fix-all provider can be run up to 2 times as part of a test run.
                NumberOfFixAllIterations = -2
            };
 
            // Verify that there are some instances of the diagnostic that we can't fix.
            test.FixedState.MarkupHandling = MarkupMode.Allow;
            test.MarkupOptions = MarkupOptions.UseFirstDescriptor;
 
            await test.RunAsync();
        }
 
        private static async Task VerifyVBAnalyzerAsync(string source)
        {
            var test = new VerifyVB.Test
            {
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70,
                TestCode = source,
                FixedCode = source
            };
            test.MarkupOptions = MarkupOptions.UseFirstDescriptor;
 
            await test.RunAsync();
        }
    }
}