File: Attributes\AttributeTests_MarshalAs.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit3\Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public class AttributeTests_MarshalAs : WellKnownAttributesTestBase
    {
        #region Helpers
 
        private void VerifyFieldMetadataDecoding(CompilationVerifier verifier, Dictionary<string, byte[]> blobs)
        {
            int count = 0;
            using (var assembly = AssemblyMetadata.CreateFromImage(verifier.EmittedAssemblyData))
            {
                var compilation = CreateEmptyCompilation(new SyntaxTree[0], new[] { assembly.GetReference() },
                    options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All));
 
                foreach (NamedTypeSymbol type in compilation.GlobalNamespace.GetMembers().Where(s => s.Kind == SymbolKind.NamedType))
                {
                    var fields = type.GetMembers().Where(s => s.Kind == SymbolKind.Field);
                    foreach (FieldSymbol field in fields)
                    {
                        Assert.Null(field.MarshallingInformation);
                        var blob = blobs[field.Name];
                        if (blob != null && blob[0] <= 0x50)
                        {
                            Assert.Equal((UnmanagedType)blob[0], field.MarshallingType);
                        }
                        else
                        {
                            Assert.Equal((UnmanagedType)0, field.MarshallingType);
                        }
 
                        count++;
                    }
                }
            }
 
            Assert.True(count > 0, "Expected at least one parameter");
        }
 
        private void VerifyParameterMetadataDecoding(CompilationVerifier verifier, Dictionary<string, byte[]> blobs)
        {
            int count = 0;
            using (var assembly = AssemblyMetadata.CreateFromImage(verifier.EmittedAssemblyData))
            {
                var compilation = CreateEmptyCompilation(
                    new SyntaxTree[0],
                    new[] { assembly.GetReference() },
                    options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All));
 
                foreach (NamedTypeSymbol type in compilation.GlobalNamespace.GetMembers().Where(s => s.Kind == SymbolKind.NamedType))
                {
                    var methods = type.GetMembers().Where(s => s.Kind == SymbolKind.Method);
                    foreach (MethodSymbol method in methods)
                    {
                        foreach (ParameterSymbol parameter in method.Parameters)
                        {
                            Assert.Null(parameter.MarshallingInformation);
                            var blob = blobs[method.Name + ":" + parameter.Name];
                            if (blob != null && blob[0] <= 0x50)
                            {
                                Assert.Equal((UnmanagedType)blob[0], parameter.MarshallingType);
                            }
                            else
                            {
                                Assert.Equal((UnmanagedType)0, parameter.MarshallingType);
                            }
 
                            count++;
                        }
                    }
                }
            }
 
            Assert.True(count > 0, "Expected at least one parameter");
        }
 
        #endregion
 
        #region Fields
 
        /// <summary>
        /// type only, others ignored, field type ignored
        /// </summary>
        [Fact]
        public void SimpleTypes()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs((short)0)]
    public X ZeroShort;
 
    [MarshalAs((UnmanagedType)0)]
    public X Zero;
 
    [MarshalAs((UnmanagedType)0x1FFFFFFF)]
    public X MaxValue;
 
    [MarshalAs((UnmanagedType)(0x123456))]
    public X _0x123456;
 
    [MarshalAs((UnmanagedType)(0x1000))]
    public X _0x1000;
 
    [MarshalAs(UnmanagedType.AnsiBStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X AnsiBStr;
 
    [MarshalAs(UnmanagedType.AsAny, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public double AsAny;
 
    [MarshalAs(UnmanagedType.Bool, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X Bool;
 
    [MarshalAs(UnmanagedType.BStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X BStr;
 
    [MarshalAs(UnmanagedType.Currency, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int Currency;
 
    [MarshalAs(UnmanagedType.Error, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int Error;
 
    [MarshalAs(UnmanagedType.FunctionPtr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int FunctionPtr;
 
    [MarshalAs(UnmanagedType.I1, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int I1;
 
    [MarshalAs(UnmanagedType.I2, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int I2;
 
    [MarshalAs(UnmanagedType.I4, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int I4;
 
    [MarshalAs(UnmanagedType.I8, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int I8;
 
    [MarshalAs(UnmanagedType.LPStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int LPStr;
 
    [MarshalAs(UnmanagedType.LPStruct, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int LPStruct;
 
    [MarshalAs(UnmanagedType.LPTStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int LPTStr;
 
    [MarshalAs(UnmanagedType.LPWStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int LPWStr;
 
    [MarshalAs(UnmanagedType.R4, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int R4;
 
    [MarshalAs(UnmanagedType.R8, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int R8;
 
    [MarshalAs(UnmanagedType.Struct, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int Struct;
 
    [MarshalAs(UnmanagedType.SysInt, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public decimal SysInt;
 
    [MarshalAs(UnmanagedType.SysUInt, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int[] SysUInt;
 
    [MarshalAs(UnmanagedType.TBStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public object[] TBStr;
 
    [MarshalAs(UnmanagedType.U1, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int U1;
 
    [MarshalAs(UnmanagedType.U2, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public double U2;
 
    [MarshalAs(UnmanagedType.U4, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public bool U4;
 
    [MarshalAs(UnmanagedType.U8, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public string U8;
 
    [MarshalAs(UnmanagedType.VariantBool, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int VariantBool;   
}";
            var blobs = new Dictionary<string, byte[]>
            {
                { "ZeroShort",    new byte[] { 0x00 } },
                { "Zero",         new byte[] { 0x00 } },
                { "MaxValue",     new byte[] { 0xdf, 0xff, 0xff, 0xff } },
                { "_0x1000",      new byte[] { 0x90, 0x00 } },
                { "_0x123456",    new byte[] { 0xC0, 0x12, 0x34, 0x56 } },
                { "AnsiBStr",     new byte[] { 0x23 } },
                { "AsAny",        new byte[] { 0x28 } },
                { "Bool",         new byte[] { 0x02 } },
                { "BStr",         new byte[] { 0x13 } },
                { "Currency",     new byte[] { 0x0f } },
                { "Error",        new byte[] { 0x2d } },
                { "FunctionPtr",  new byte[] { 0x26 } },
                { "I1",           new byte[] { 0x03 } },
                { "I2",           new byte[] { 0x05 } },
                { "I4",           new byte[] { 0x07 } },
                { "I8",           new byte[] { 0x09 } },
                { "LPStr",        new byte[] { 0x14 } },
                { "LPStruct",     new byte[] { 0x2b } },
                { "LPTStr",       new byte[] { 0x16 } },
                { "LPWStr",       new byte[] { 0x15 } },
                { "R4",           new byte[] { 0x0b } },
                { "R8",           new byte[] { 0x0c } },
                { "Struct",       new byte[] { 0x1b } },
                { "SysInt",       new byte[] { 0x1f } },
                { "SysUInt",      new byte[] { 0x20 } },
                { "TBStr",        new byte[] { 0x24 } },
                { "U1",           new byte[] { 0x04 } },
                { "U2",           new byte[] { 0x06 } },
                { "U4",           new byte[] { 0x08 } },
                { "U8",           new byte[] { 0x0a } },
                { "VariantBool",  new byte[] { 0x25 } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void SimpleTypes_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System.Runtime.InteropServices;
 
class X
{
    [MarshalAs((UnmanagedType)(-1))]
    X MinValue_1;
 
    [MarshalAs((UnmanagedType)0x20000000)]
    X MaxValue_1;
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (6,16): error CS0591: Invalid value for argument to 'MarshalAs' attribute
                Diagnostic(ErrorCode.ERR_InvalidAttributeArgument, "(UnmanagedType)(-1)").WithArguments("MarshalAs"),
                // (9,16): error CS0591: Invalid value for argument to 'MarshalAs' attribute
                Diagnostic(ErrorCode.ERR_InvalidAttributeArgument, "(UnmanagedType)0x20000000").WithArguments("MarshalAs"));
        }
 
        /// <summary>
        /// (type, IidParamIndex), others ignored, field type ignored
        /// </summary>
        [Fact]
        public void ComInterfaces()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.IDispatch, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public byte IDispatch;
 
    [MarshalAs(UnmanagedType.Interface, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X Interface;
 
    [MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 2, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X[] IUnknown;
 
    [MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0x1FFFFFFF, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int MaxValue;
 
    [MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0x123456, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int _123456;
 
    [MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0x1000, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X _0x1000;
 
    [MarshalAs(UnmanagedType.IDispatch)]
    public int Default;
}
";
            var blobs = new Dictionary<string, byte[]>
            {
                { "IDispatch", new byte[] { 0x1a, 0x00 } },
                { "Interface", new byte[] { 0x1c, 0x01 } },
                { "IUnknown",  new byte[] { 0x19, 0x02 } },
                { "MaxValue",  new byte[] { 0x19, 0xdf, 0xff, 0xff, 0xff } },
                { "_123456",   new byte[] { 0x19, 0xc0, 0x12, 0x34, 0x56 } },
                { "_0x1000",   new byte[] { 0x19, 0x90, 0x00 } },
                { "Default",   new byte[] { 0x1a } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        [WorkItem(22512, "https://github.com/dotnet/roslyn/issues/22512")]
        public void ComInterfacesInProperties()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
public class X
{
    [field: MarshalAs(UnmanagedType.IDispatch, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public byte IDispatch { get; set; }
 
    [field: MarshalAs(UnmanagedType.Interface, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X Interface { get; set; }
 
    [field: MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 2, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X[] IUnknown { get; set; }
 
    [field: MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0x1FFFFFFF, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int MaxValue { get; set; }
 
    [field: MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0x123456, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int _123456 { get; set; }
 
    [field: MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0x1000, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public X _0x1000 { get; set; }
 
    [field: MarshalAs(UnmanagedType.IDispatch)]
    public int Default { get; set; }
}
";
            var blobs = new Dictionary<string, byte[]>
            {
                { "<IDispatch>k__BackingField", new byte[] { 0x1a, 0x00 } },
                { "<Interface>k__BackingField", new byte[] { 0x1c, 0x01 } },
                { "<IUnknown>k__BackingField",  new byte[] { 0x19, 0x02 } },
                { "<MaxValue>k__BackingField",  new byte[] { 0x19, 0xdf, 0xff, 0xff, 0xff } },
                { "<_123456>k__BackingField",   new byte[] { 0x19, 0xc0, 0x12, 0x34, 0x56 } },
                { "<_0x1000>k__BackingField",   new byte[] { 0x19, 0x90, 0x00 } },
                { "<Default>k__BackingField",   new byte[] { 0x1a } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void ComInterfaces_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System.Runtime.InteropServices;
 
class X
{
    [MarshalAs(UnmanagedType.IDispatch, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType=VarEnum.VT_BSTR, SafeArrayUserDefinedSubType=null, SizeConst=-1, SizeParamIndex=-1)]
    int IDispatch_MinValue_1;
 
    [MarshalAs(UnmanagedType.Interface, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType=VarEnum.VT_BSTR, SafeArrayUserDefinedSubType=null, SizeConst=-1, SizeParamIndex=-1)]
    int Interface_MinValue_1;
 
    [MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType=VarEnum.VT_BSTR, SafeArrayUserDefinedSubType=null, SizeConst=-1, SizeParamIndex=-1)]
    int IUnknown_MinValue_1;
 
    [MarshalAs(UnmanagedType.IUnknown, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = 0x20000000, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArraySubType=VarEnum.VT_BSTR, SafeArrayUserDefinedSubType=null, SizeConst=-1, SizeParamIndex=-1)]
    int IUnknown_MaxValue_1;
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (8,81): error CS0599: Invalid value for argument to 'MarshalAs' attribute
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "IidParameterIndex = -1").WithArguments("IidParameterIndex"),
                // (11,81): error CS0599: Invalid value for argument to 'MarshalAs' attribute
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "IidParameterIndex = -1").WithArguments("IidParameterIndex"),
                // (14,80): error CS0599: Invalid value for argument to 'MarshalAs' attribute
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "IidParameterIndex = -1").WithArguments("IidParameterIndex"),
                // (17,80): error CS0599: Invalid value for argument to 'MarshalAs' attribute
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "IidParameterIndex = 0x20000000").WithArguments("IidParameterIndex"));
        }
 
        /// <summary>
        /// (ArraySubType, SizeConst, SizeParamIndex), SafeArraySubType not allowed, others ignored
        /// </summary>
        [Fact]
        public void NativeTypeArray()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.LPArray)]
    public int LPArray0;
 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
         SafeArrayUserDefinedSubType = null)]
    public int LPArray1;
 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = 0, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
         SafeArrayUserDefinedSubType = null)]
    public int LPArray2;
 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = 0x1fffffff, SizeParamIndex = short.MaxValue, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
         SafeArrayUserDefinedSubType = null)]
    public int LPArray3;
 
    // NATIVE_TYPE_MAX = 0x50
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)0x50)]
    public int LPArray4;
 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)0x1fffffff)]
    public int LPArray5;
 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)0)]
    public int LPArray6;
}
";
            var blobs = new Dictionary<string, byte[]>
            {
                { "LPArray0", new byte[] { 0x2a, 0x50 } },
                { "LPArray1", new byte[] { 0x2a, 0x17 } },
                { "LPArray2", new byte[] { 0x2a, 0x17, 0x00, 0x00, 0x00 } },
                { "LPArray3", new byte[] { 0x2a, 0x17, 0xc0, 0x00, 0x7f, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x01 } },
                { "LPArray4", new byte[] { 0x2a, 0x50 } },
                { "LPArray5", new byte[] { 0x2a, 0xdf, 0xff, 0xff, 0xff } },
                { "LPArray6", new byte[] { 0x2a, 0x00 } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void NativeTypeArray_ElementTypes()
        {
            StringBuilder source = new StringBuilder(@"
using System;
using System.Runtime.InteropServices;
 
class X
{
");
            var expectedBlobs = new Dictionary<string, byte[]>();
 
            for (int i = 0; i < sbyte.MaxValue; i++)
            {
                // CustomMarshaler is not allowed
                if (i != (int)UnmanagedType.CustomMarshaler)
                {
                    string fldName = string.Format("_{0:X}", i);
                    source.AppendLine(string.Format("[MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)0x{0:X})]int {1};", i, fldName));
                    expectedBlobs.Add(fldName, new byte[] { 0x2a, (byte)i });
                }
            }
 
            source.AppendLine("}");
 
            CompileAndVerifyFieldMarshal(source.ToString(), expectedBlobs);
        }
 
        [Fact]
        public void NativeTypeArray_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System.Runtime.InteropServices;
 
class X
{
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int LPArray_e0;
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = -1)]                                                                                             int LPArray_e1;
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = 0, SizeParamIndex = -1)]                                                                         int LPArray_e2;
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = int.MaxValue, SizeParamIndex = short.MaxValue)]                                                  int LPArray_e3;
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U8, SizeConst = int.MaxValue/4 + 1, SizeParamIndex = short.MaxValue)]                                                   int LPArray_e4;
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.CustomMarshaler)]                                                                                                       int LPArray_e5;
    [MarshalAs(UnmanagedType.LPArray, SafeArraySubType=VarEnum.VT_I1)]                                                                                                                     int LPArray_e6;
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)0x20000000)]                                                                                                           int LPArray_e7;
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)(-1))]                                                                                                                 int LPArray_e8;
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (8,79): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int LPArray_e0;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArraySubType = VarEnum.VT_BSTR"),
                // (8,151): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int LPArray_e0;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = -1").WithArguments("SizeConst"),
                // (8,167): error CS0599: Invalid value for named attribute argument 'SizeParamIndex'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int LPArray_e0;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeParamIndex = -1").WithArguments("SizeParamIndex"),
                // (9,79): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = -1)]                                                                                             int LPArray_e1;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = -1").WithArguments("SizeConst"),
                // (10,94): error CS0599: Invalid value for named attribute argument 'SizeParamIndex'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = 0, SizeParamIndex = -1)]                                                                         int LPArray_e2;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeParamIndex = -1").WithArguments("SizeParamIndex"),
                // (11,79): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = int.MaxValue, SizeParamIndex = short.MaxValue)]                                                  int LPArray_e3;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = int.MaxValue").WithArguments("SizeConst"),
                // (12,72): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U8, SizeConst = int.MaxValue/4 + 1, SizeParamIndex = short.MaxValue)]                                                   int LPArray_e4;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = int.MaxValue/4 + 1").WithArguments("SizeConst"),
                // (13,39): error CS0599: Invalid value for named attribute argument 'ArraySubType'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.CustomMarshaler)]                                                                                                       int LPArray_e5;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "ArraySubType = UnmanagedType.CustomMarshaler").WithArguments("ArraySubType"),
                // (14,39): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.LPArray, SafeArraySubType=VarEnum.VT_I1)]                                                                                                                     int LPArray_e6;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArraySubType=VarEnum.VT_I1"),
                // (15,39): error CS0599: Invalid value for named attribute argument 'ArraySubType'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)0x20000000)]                                                                                                           int LPArray_e7;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "ArraySubType = (UnmanagedType)0x20000000").WithArguments("ArraySubType"),
                // (16,39): error CS0599: Invalid value for named attribute argument 'ArraySubType'
                //     [MarshalAs(UnmanagedType.LPArray, ArraySubType = (UnmanagedType)(-1))]                                                                                                                 int LPArray_e8;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "ArraySubType = (UnmanagedType)(-1)").WithArguments("ArraySubType"));
        }
 
        /// <summary>
        /// (ArraySubType, SizeConst), (SizeParamIndex, SafeArraySubType) not allowed, others ignored
        /// </summary>
        [Fact]
        public void NativeTypeFixedArray()
        {
            var source = @"
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.ByValArray)]
    public int ByValArray0;
 
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
         SafeArrayUserDefinedSubType = null)]
    public int ByValArray1;
 
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = 0, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
         SafeArrayUserDefinedSubType = null)]
    public int ByValArray2;
 
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = (int.MaxValue - 3) / 4, IidParameterIndex = -1,
        MarshalCookie = null, MarshalType = null, MarshalTypeRef = null, SafeArrayUserDefinedSubType = null)]
    public int ByValArray3;
 
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.AsAny)]
    public int ByValArray4;
 
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.CustomMarshaler)]
    public int ByValArray5;
}
";
            var blobs = new Dictionary<string, byte[]>
            {
                { "ByValArray0", new byte[] { 0x1e, 0x01 } },
                { "ByValArray1", new byte[] { 0x1e, 0x01, 0x17 } },
                { "ByValArray2", new byte[] { 0x1e, 0x00, 0x17 } },
                { "ByValArray3", new byte[] { 0x1e, 0xdf, 0xff, 0xff, 0xff, 0x17} },
                { "ByValArray4", new byte[] { 0x1e, 0x01, 0x28 } },
                { "ByValArray5", new byte[] { 0x1e, 0x01, 0x2c } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            verifier.VerifyDiagnostics(
                // (6,6): warning CS9125: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValArray)]
                Diagnostic(ErrorCode.WRN_ByValArraySizeConstRequired, "MarshalAs(UnmanagedType.ByValArray)").WithLocation(6, 6),
                // (9,6): warning CS9125: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
                Diagnostic(ErrorCode.WRN_ByValArraySizeConstRequired, @"MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
         SafeArrayUserDefinedSubType = null)").WithLocation(9, 6),
                // (21,6): warning CS9125: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.AsAny)]
                Diagnostic(ErrorCode.WRN_ByValArraySizeConstRequired, "MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.AsAny)").WithLocation(21, 6),
                // (24,6): warning CS9125: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.CustomMarshaler)]
                Diagnostic(ErrorCode.WRN_ByValArraySizeConstRequired, "MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.CustomMarshaler)").WithLocation(24, 6));
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void NativeTypeFixedArray_ElementTypes()
        {
            StringBuilder source = new StringBuilder(@"
using System;
using System.Runtime.InteropServices;
 
class X
{
");
            var expectedBlobs = new Dictionary<string, byte[]>();
 
            for (int i = 0; i < sbyte.MaxValue; i++)
            {
                string fldName = string.Format("_{0:X}", i);
                source.AppendLine(string.Format("[MarshalAs(UnmanagedType.ByValArray, ArraySubType = (UnmanagedType)0x{0:X})]int {1};", i, fldName));
                expectedBlobs.Add(fldName, new byte[] { 0x1e, 0x01, (byte)i });
            }
 
            source.AppendLine("}");
 
            CompileAndVerifyFieldMarshal(source.ToString(), expectedBlobs);
        }
 
        [Fact]
        public void NativeTypeFixedArray_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int ByValArray_e1;
    [MarshalAs(UnmanagedType.ByValArray, SizeParamIndex = short.MaxValue)]                                                                                                                    int ByValArray_e2;
    [MarshalAs(UnmanagedType.ByValArray, SafeArraySubType = VarEnum.VT_I2)]                                                                                                                   int ByValArray_e3;
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = 0x20000000)]                                                                                     int ByValArray_e4;
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (8,82): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int ByValArray_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArraySubType = VarEnum.VT_BSTR"),
                // (8,154):error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int ByValArray_e1;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = -1").WithArguments("SizeConst"),
                // (8,170): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]int ByValArray_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeParamIndex = -1"),
                // (9,6): warning CS9124: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValArray, SizeParamIndex = short.MaxValue)]                                                                                                                    int ByValArray_e2;
                Diagnostic(ErrorCode.WRN_ByValArraySizeConstRequired, "MarshalAs(UnmanagedType.ByValArray, SizeParamIndex = short.MaxValue)"),
                // (9,42): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValArray, SizeParamIndex = short.MaxValue)]                                                                                                                    int ByValArray_e2;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeParamIndex = short.MaxValue"),
                // (10,6): warning CS9124: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValArray, SafeArraySubType = VarEnum.VT_I2)]                                                                                                                   int ByValArray_e3;
                Diagnostic(ErrorCode.WRN_ByValArraySizeConstRequired, "MarshalAs(UnmanagedType.ByValArray, SafeArraySubType = VarEnum.VT_I2)"),
                // (10,42): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValArray, SafeArraySubType = VarEnum.VT_I2)]                                                                                                                   int ByValArray_e3;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArraySubType = VarEnum.VT_I2"),
                // (11,82): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.ByValTStr, SizeConst = 0x20000000)]                                                                                     int ByValArray_e4;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = 0x20000000").WithArguments("SizeConst"));
        }
 
        [Fact]
        [WorkItem(68988, "https://github.com/dotnet/roslyn/issues/68988")]
        public void NativeTypeFixedArray_SizeConstWarning_RespectsWarningLevel()
        {
            var source = @"
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.ByValArray)]
    public int ByValArray0;
}
";
            CreateCompilation(
                source,
                options: TestOptions.ReleaseDll.WithWarningLevel(7))
                .VerifyDiagnostics();
 
            CreateCompilation(
                source,
                options: TestOptions.ReleaseDll.WithWarningLevel(8))
                .VerifyDiagnostics(
                // (6,6): warning CS9125: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValArray)]
                Diagnostic(ErrorCode.WRN_ByValArraySizeConstRequired, "MarshalAs(UnmanagedType.ByValArray)").WithLocation(6, 6));
        }
 
        /// <summary>
        /// (SafeArraySubType, SafeArrayUserDefinedSubType), (ArraySubType, SizeConst, SizeParamIndex) not allowed,
        /// (SafeArraySubType, SafeArrayUserDefinedSubType) not allowed together unless VT_DISPATCH, VT_UNKNOWN, VT_RECORD; others ignored.
        /// </summary>
        [Fact]
        public void NativeTypeSafeArray()
        {
            var source = @"
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.SafeArray)]
    public int SafeArray0;
 
    [MarshalAs(UnmanagedType.SafeArray, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR)]
    public int SafeArray1;
 
    [MarshalAs(UnmanagedType.SafeArray, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArrayUserDefinedSubType = typeof(X))]
    public int SafeArray2;
 
    [MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = null)]
    public int SafeArray3;
 
    [MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = typeof(void))]
    public int SafeArray4;
 
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_EMPTY)]
    public int SafeArray8;
 
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD, SafeArrayUserDefinedSubType = typeof(int*[][]))]
    public int SafeArray9;
 
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD, SafeArrayUserDefinedSubType = typeof(Nullable<>))]
    public int SafeArray10;
}
";
            var arrayAqn = Encoding.ASCII.GetBytes("System.Int32*[][], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
            var openGenericAqn = Encoding.ASCII.GetBytes("System.Nullable`1, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
 
            var blobs = new Dictionary<string, byte[]>
            {
                { "SafeArray0", new byte[] { 0x1d } },
                { "SafeArray1", new byte[] { 0x1d, 0x08 } },
                { "SafeArray2", new byte[] { 0x1d } },
                { "SafeArray3", new byte[] { 0x1d } },
                { "SafeArray4", new byte[] { 0x1d } },
                { "SafeArray8", new byte[] { 0x1d, 0x00 } },
                { "SafeArray9", new byte[] { 0x1d, 0x24, (byte)arrayAqn.Length }.Append(arrayAqn) },
                { "SafeArray10", new byte[] { 0x1d, 0x24, (byte)openGenericAqn.Length }.Append(openGenericAqn) },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void NativeTypeSafeArray_CCIOnly()
        {
            var source = @"
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
 
public class C<T> 
{
    public class D<S>
    {
        public class E { }
    }
}
 
public class X
{
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD, SafeArrayUserDefinedSubType = typeof(C<int>.D<bool>.E))]
    public int SafeArray11;
}
";
            var nestedAqn = Encoding.ASCII.GetBytes("C`1+D`1+E[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]");
 
            var blobs = new Dictionary<string, byte[]>
            {
                { "SafeArray11", new byte[] { 0x1d, 0x24, 0x80, 0xc4 }.Append(nestedAqn) },
            };
 
            // RefEmit has slightly different encoding of the type name
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void NativeTypeSafeArray_RefEmitDiffers()
        {
            var source = @"
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_DISPATCH, SafeArrayUserDefinedSubType = typeof(List<X>[][]))]
    int SafeArray5;
 
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN, SafeArrayUserDefinedSubType = typeof(X))]
    int SafeArray6;
 
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD, SafeArrayUserDefinedSubType = typeof(X))]
    int SafeArray7;
}
";
            var e = Encoding.ASCII;
 
            var cciBlobs = new Dictionary<string, byte[]>
            {
                { "SafeArray5", new byte[] { 0x1d, 0x09, 0x75 }.Append(e.GetBytes("System.Collections.Generic.List`1[X][][], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")) },
                { "SafeArray6", new byte[] { 0x1d, 0x0d, 0x01, 0x58 } },
                { "SafeArray7", new byte[] { 0x1d, 0x24, 0x01, 0x58 } },
            };
 
            CompileAndVerifyFieldMarshal(source, cciBlobs);
        }
 
        [Fact]
        public void NativeTypeSafeArray_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.SafeArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int SafeArray_e1;
    [MarshalAs(UnmanagedType.SafeArray, ArraySubType = UnmanagedType.ByValTStr)]                                                                                                                int SafeArray_e2;
    [MarshalAs(UnmanagedType.SafeArray, SizeConst = 1)]                                                                                                                                         int SafeArray_e3;
    [MarshalAs(UnmanagedType.SafeArray, SizeParamIndex = 1)]                                                                                                                                    int SafeArray_e4;
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null)]                                                                                int SafeArray_e5;
    [MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = null, SafeArraySubType = VarEnum.VT_BLOB)]                                                                                int SafeArray_e6;
    [MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = typeof(int), SafeArraySubType = 0)]                                                                                       int SafeArray_e7;
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (8,41): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int SafeArray_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "ArraySubType = UnmanagedType.ByValTStr"),
                // (8,153): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int SafeArray_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeConst = -1"),
                // (8,169): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int SafeArray_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeParamIndex = -1"),
                // (8,117): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int SafeArray_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArrayUserDefinedSubType = null"),
                // (9,41): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, ArraySubType = UnmanagedType.ByValTStr)]                                                                                                                int SafeArray_e2;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "ArraySubType = UnmanagedType.ByValTStr"),
                // (10,41): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, SizeConst = 1)]                                                                                                                                         int SafeArray_e3;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeConst = 1"),
                // (11,41): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, SizeParamIndex = 1)]                                                                                                                                    int SafeArray_e4;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeParamIndex = 1"),
                // (12,77): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null)]                                                                                int SafeArray_e5;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArrayUserDefinedSubType = null"),
                // (13,41): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = null, SafeArraySubType = VarEnum.VT_BLOB)]                                                                                int SafeArray_e6;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArrayUserDefinedSubType = null"),
                // (14,41): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = typeof(int), SafeArraySubType = 0)]                                                                                       int SafeArray_e7;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SafeArrayUserDefinedSubType = typeof(int)"));
        }
 
        /// <summary>
        /// (SizeConst - required), (SizeParamIndex, ArraySubType) not allowed
        /// </summary>
        [Fact]
        public void NativeTypeFixedSysString()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
    public int ByValTStr1;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x1fffffff, SafeArrayUserDefinedSubType = typeof(int), IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null)]
    public int ByValTStr2;
}
";
            var blobs = new Dictionary<string, byte[]>
            {
                { "ByValTStr1", new byte[] { 0x17, 0x01 } },
                { "ByValTStr2", new byte[] { 0x17, 0xdf, 0xff, 0xff, 0xff } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void NativeTypeFixedSysString_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.ByValTStr, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int ByValTStr_e1;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = -1)]                                                                                                                                        int ByValTStr_e2;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Int32.MaxValue / 4 + 1)]                                                                                                                    int ByValTStr_e3;
    [MarshalAs(UnmanagedType.ByValTStr)]                                                                                                                                                        int ByValTStr_e4;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1, SizeParamIndex=1)]                                                                                                                       int ByValTStr_e5;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1, ArraySubType = UnmanagedType.ByValTStr)]                                                                                                 int ByValTStr_e6;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1, SafeArraySubType = VarEnum.VT_BSTR)]                                                                                                     int ByValTStr_e7;
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (9,41): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValTStr, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int ByValTStr_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "ArraySubType = UnmanagedType.ByValTStr"),
                // (9,153): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.ByValTStr, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int ByValTStr_e1;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = -1").WithArguments("SizeConst"),
                // (9,169): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValTStr, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int ByValTStr_e1;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeParamIndex = -1"),
                // (9,6): error CS7046: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValTStr, ArraySubType = UnmanagedType.ByValTStr, SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]   int ByValTStr_e1;
                Diagnostic(ErrorCode.ERR_AttributeParameterRequired1, "MarshalAs").WithArguments("SizeConst"),
                // (10,41): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = -1)]                                                                                                                                        int ByValTStr_e2;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = -1").WithArguments("SizeConst"),
                // (10,6): error CS7046: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = -1)]                                                                                                                                        int ByValTStr_e2;
                Diagnostic(ErrorCode.ERR_AttributeParameterRequired1, "MarshalAs").WithArguments("SizeConst"),
                // (11,41): error CS0599: Invalid value for named attribute argument 'SizeConst'
                //     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Int32.MaxValue / 4 + 1)]                                                                                                                    int ByValTStr_e3;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "SizeConst = Int32.MaxValue / 4 + 1").WithArguments("SizeConst"),
                // (12,6): error CS7046: Attribute parameter 'SizeConst' must be specified.
                //     [MarshalAs(UnmanagedType.ByValTStr)]                                                                                                                                                        int ByValTStr_e4;
                Diagnostic(ErrorCode.ERR_AttributeParameterRequired1, "MarshalAs").WithArguments("SizeConst"),
                // (13,56): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1, SizeParamIndex=1)]                                                                                                                       int ByValTStr_e5;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "SizeParamIndex=1"),
                // (14,56): error CS7045: Parameter not valid for the specified unmanaged type.
                //     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1, ArraySubType = UnmanagedType.ByValTStr)]                                                                                                 int ByValTStr_e6;
                Diagnostic(ErrorCode.ERR_ParameterNotValidForType, "ArraySubType = UnmanagedType.ByValTStr"));
        }
 
        /// <summary>
        /// Custom (MarshalType, MarshalTypeRef, MarshalCookie) one of {MarshalType, MarshalTypeRef} required, others ignored
        /// </summary>
        [Fact]
        public void CustomMarshal()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = null)]
    public int CustomMarshaler1;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = null)]
    public int CustomMarshaler2;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""foo"", MarshalTypeRef = typeof(int))]
    public int CustomMarshaler3;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""\u1234f\0oozzz"")]
    public int CustomMarshaler4;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""f\0oozzz"")]
    public int CustomMarshaler5;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"")]
    public int CustomMarshaler6;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
        SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    public int CustomMarshaler7;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(int))]
    public int CustomMarshaler8;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(int), MarshalType = ""foo"", MarshalCookie = ""hello\0world(\u1234)"")]
    public int CustomMarshaler9;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = null, MarshalTypeRef = typeof(int))]
    public int CustomMarshaler10;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""foo"", MarshalTypeRef = null)]
    public int CustomMarshaler11;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = null, MarshalTypeRef = null)]
    public int CustomMarshaler12;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""aaa\0bbb"", MarshalCookie = ""ccc\0ddd"" )]
    public int CustomMarshaler13;
 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""\uD869\uDED6"", MarshalCookie = ""\uD869\uDED6"" )]
    public int CustomMarshaler14;
}
";
            var blobs = new Dictionary<string, byte[]>
            {
                { "CustomMarshaler1",  new byte[] { 0x2c, 0x00, 0x00, 0x00, 0x00 } },
                { "CustomMarshaler2",  new byte[] { 0x2c, 0x00, 0x00, 0x00, 0x00 } },
                { "CustomMarshaler3",  new byte[] { 0x2c, 0x00, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x00 } },
                { "CustomMarshaler4",  new byte[] { 0x2c, 0x00, 0x00, 0x0a, 0xe1, 0x88, 0xb4, 0x66, 0x00, 0x6f, 0x6f, 0x7a, 0x7a, 0x7a, 0x00 } },
                { "CustomMarshaler5",  new byte[] { 0x2c, 0x00, 0x00, 0x07, 0x66, 0x00, 0x6f, 0x6f, 0x7a, 0x7a, 0x7a, 0x00 } },
                { "CustomMarshaler6",  new byte[] { 0x2c, 0x00, 0x00, 0x60 }.Append(Encoding.UTF8.GetBytes("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\0")) },
                { "CustomMarshaler7",  new byte[] { 0x2c, 0x00, 0x00, 0x00, 0x00 } },
                { "CustomMarshaler8",  new byte[] { 0x2c, 0x00, 0x00, 0x59 }.Append(Encoding.UTF8.GetBytes("System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\0")) },
                { "CustomMarshaler9",  new byte[] { 0x2c, 0x00, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x28, 0xe1, 0x88, 0xb4, 0x29 } },
                { "CustomMarshaler10", new byte[] { 0x2c, 0x00, 0x00, 0x00, 0x00 } },
                { "CustomMarshaler11", new byte[] { 0x2c, 0x00, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x00 } },
                { "CustomMarshaler12", new byte[] { 0x2c, 0x00, 0x00, 0x00, 0x00 } },
                { "CustomMarshaler13", new byte[] { 0x2c, 0x00, 0x00, 0x07, 0x61, 0x61, 0x61, 0x00, 0x62, 0x62, 0x62, 0x07, 0x63, 0x63, 0x63, 0x00, 0x64, 0x64, 0x64 } },
                { "CustomMarshaler14", new byte[] { 0x2c, 0x00, 0x00, 0x04, 0xf0, 0xaa, 0x9b, 0x96, 0x04, 0xf0, 0xaa, 0x9b, 0x96 } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs);
            VerifyFieldMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void CustomMarshal_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System.Runtime.InteropServices;
 
public class X
{
    [MarshalAs(UnmanagedType.CustomMarshaler)]int CustomMarshaler_e0;
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""a\udc00b"", MarshalCookie = ""b"" )]int CustomMarshaler_e1;
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""x"", MarshalCookie = ""y\udc00"" )]int CustomMarshaler_e2;
}
";
            // Dev10 encodes incomplete surrogates, we don't.
 
            CreateCompilation(source).VerifyDiagnostics(
                // (8,6): error CS7047: Attribute parameter 'MarshalType' or 'MarshalTypeRef' must be specified.
                //     [MarshalAs(UnmanagedType.CustomMarshaler)]int CustomMarshaler_e0;
                Diagnostic(ErrorCode.ERR_AttributeParameterRequired2, "MarshalAs").WithArguments("MarshalType", "MarshalTypeRef"),
                // (9,47): error CS0599: Invalid value for named attribute argument 'MarshalType'
                //     [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "a\udc00b", MarshalCookie = "b" )]int CustomMarshaler_e1;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, @"MarshalType = ""a\udc00b""").WithArguments("MarshalType"),
                // (10,66): error CS0599: Invalid value for named attribute argument 'MarshalCookie'
                //     [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "x", MarshalCookie = "y\udc00" )]int CustomMarshaler_e2;
                Diagnostic(ErrorCode.ERR_InvalidNamedArgument, @"MarshalCookie = ""y\udc00""").WithArguments("MarshalCookie"));
        }
 
        [Fact]
        public void EventAndEnumMembers()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
class C
{
    [field: MarshalAs(UnmanagedType.Bool)]
    event Action e;
}
 
enum E
{
    [MarshalAs(UnmanagedType.Bool)]
    X = 1
}
 
";
 
            CompileAndVerifyFieldMarshal(source, (name, _omitted1) => (name == "e" || name == "X") ? new byte[] { 0x02 } : null);
        }
 
        #endregion
 
        #region Parameters and Return Values
 
        [Fact]
        public void Parameters()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
class X
{
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static X foo(
 
        [MarshalAs(UnmanagedType.IDispatch)]
        ref int IDispatch,
 
        [MarshalAs(UnmanagedType.LPArray)]
        out int LPArray0,
 
        [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_EMPTY)]
        int SafeArray8,
    
        [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""aaa\0bbb"", MarshalCookie = ""ccc\0ddd"" )]
        int CustomMarshaler13
    )
    {
        throw null;
    }
}
";
            var blobs = new Dictionary<string, byte[]>()
            {
                { "foo:",                  new byte[] { 0x14 } }, // return value
                { "foo:IDispatch",         new byte[] { 0x1a } },
                { "foo:LPArray0",          new byte[] { 0x2a, 0x50 } },
                { "foo:SafeArray8",        new byte[] { 0x1d, 0x00 } },
                { "foo:CustomMarshaler13", new byte[] { 0x2c, 0x00, 0x00, 0x07, 0x61, 0x61, 0x61, 0x00, 0x62, 0x62, 0x62, 0x07, 0x63, 0x63, 0x63, 0x00, 0x64, 0x64, 0x64 } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs, isField: false);
            VerifyParameterMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void Parameters_LocalFunction()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
class X
{
    void M()
    {
        [return: MarshalAs(UnmanagedType.LPStr)]
        static X local(
 
            [MarshalAs(UnmanagedType.IDispatch)]
            ref int IDispatch,
 
            [MarshalAs(UnmanagedType.LPArray)]
            out int LPArray0,
 
            [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_EMPTY)]
            int SafeArray8,
 
            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""aaa\0bbb"", MarshalCookie = ""ccc\0ddd"" )]
            int CustomMarshaler13
        )
        {
            throw null;
        }
    }
}
";
            var blobs = new Dictionary<string, byte[]>()
            {
                { "<M>g__local|0_0:",                  new byte[] { 0x14 } }, // return value
                { "<M>g__local|0_0:IDispatch",         new byte[] { 0x1a } },
                { "<M>g__local|0_0:LPArray0",          new byte[] { 0x2a, 0x50 } },
                { "<M>g__local|0_0:SafeArray8",        new byte[] { 0x1d, 0x00 } },
                { "<M>g__local|0_0:CustomMarshaler13", new byte[] { 0x2c, 0x00, 0x00, 0x07, 0x61, 0x61, 0x61, 0x00, 0x62, 0x62, 0x62, 0x07, 0x63, 0x63, 0x63, 0x00, 0x64, 0x64, 0x64 } },
            };
 
            var verifier = CompileAndVerifyFieldMarshal(source, blobs, isField: false);
            VerifyParameterMetadataDecoding(verifier, blobs);
        }
 
        [Fact]
        public void MarshalAs_AllParameterTargets_PartialMethods()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
public partial class X
{
    partial void F([MarshalAs(UnmanagedType.BStr)] int pf);
    partial void F(int pf) { }
 
    partial void G(int pg);
    partial void G([MarshalAs(UnmanagedType.BStr)] int pg) {}
    
    partial void H([MarshalAs(UnmanagedType.BStr)] int ph) {}
    partial void H(int ph);
 
    partial void I(int pi) { }
    partial void I([MarshalAs(UnmanagedType.BStr)] int pi);
}
";
            var blobs = new Dictionary<string, byte[]>()
            {
                {"F:pf", new byte[] {0x13}},
                {"G:pg", new byte[] {0x13}},
                {"H:ph", new byte[] {0x13}},
                {"I:pi", new byte[] {0x13}},
            };
 
            CompileAndVerifyFieldMarshal(source, blobs, isField: false);
        }
 
        [WorkItem(544508, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544508")]
        [Fact]
        public void Parameters_Property_Accessors()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
public interface I
{
    string P
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
}";
            CompileAndVerifyFieldMarshal(source, new Dictionary<string, byte[]>()
                {
                    { "get_P:", new byte[] { 0x13 } }, // return value for get accessor
                    { "set_P:" + ParameterSymbol.ValueParameterName, new byte[] { 0x13 } }, // value parameter for set accessor
                },
                isField: false);
        }
 
        [WorkItem(544508, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544508")]
        [Fact]
        public void Parameters_Event_Accessors()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
class C
{
    event Action<string> E
    {
        [param: MarshalAs(UnmanagedType.BStr)]
        add { }
        [param: MarshalAs(UnmanagedType.BStr)]
        remove { }
    }
}";
            CompileAndVerifyFieldMarshal(source, new Dictionary<string, byte[]>()
                {
                    { "add_E:" + ParameterSymbol.ValueParameterName, new byte[] { 0x13 } },
                    { "remove_E:" + ParameterSymbol.ValueParameterName, new byte[] { 0x13 } },
                },
                isField: false);
        }
 
        [Fact]
        public void Parameters_Indexer_Getter()
        {
            var source = @"
using System.Runtime.InteropServices;
public class C
{
    public int this[[MarshalAs(UnmanagedType.BStr)]int a, [MarshalAs(UnmanagedType.BStr)]int b]
    {
        get { return 0; }
    }
}
";
            CompileAndVerifyFieldMarshal(source, new Dictionary<string, byte[]>()
                {
                    { "get_Item:a", new byte[] { 0x13 } },
                    { "get_Item:b", new byte[] { 0x13 } },
                },
                isField: false);
        }
 
        [Fact]
        public void Parameters_Indexer_Setter()
        {
            var source = @"
using System.Runtime.InteropServices;
public class C
{
    public int this[[MarshalAs(UnmanagedType.BStr)]int a, [MarshalAs(UnmanagedType.BStr)]int b]
    {
        [param: MarshalAs(UnmanagedType.BStr)]
        set { }
    }
}
";
            CompileAndVerifyFieldMarshal(source, new Dictionary<string, byte[]>()
                {
                    { "set_Item:" + ParameterSymbol.ValueParameterName, new byte[] { 0x13 } },
                    { "set_Item:a", new byte[] { 0x13 } },
                    { "set_Item:b", new byte[] { 0x13 } },
                },
                isField: false);
        }
 
        [WorkItem(544509, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544509")]
        [Fact]
        public void Parameters_DelegateType()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
class C
{
    [return: MarshalAs(UnmanagedType.BStr)]
    public delegate string Delegate(
        [In, MarshalAs(UnmanagedType.BStr)]string p1,
        [param: In, Out, MarshalAs(UnmanagedType.BStr)]ref string p2,
        [Out, MarshalAs(UnmanagedType.BStr)]out string p3);
}";
            var marshalAsBstr = new byte[] { 0x13 };
 
            CompileAndVerifyFieldMarshal(source, new Dictionary<string, byte[]>()
                {
                    { ".ctor:object", null },
                    { ".ctor:method", null },
                    { "Invoke:",  marshalAsBstr}, // return value
                    { "Invoke:p1", marshalAsBstr },
                    { "Invoke:p2", marshalAsBstr },
                    { "Invoke:p3", marshalAsBstr },
                    { "BeginInvoke:p1", marshalAsBstr },
                    { "BeginInvoke:p2", marshalAsBstr },
                    { "BeginInvoke:p3", marshalAsBstr },
                    { "BeginInvoke:object", null },
                    { "BeginInvoke:callback", null },
                    { "EndInvoke:", marshalAsBstr },
                    { "EndInvoke:p1", marshalAsBstr },
                    { "EndInvoke:p2", marshalAsBstr },
                    { "EndInvoke:p3", marshalAsBstr },
                    { "EndInvoke:result", null },
                },
                isField: false);
        }
 
        [Fact]
        public void Parameters_Errors()
        {
            var source = @"
#pragma warning disable 169
 
using System.Runtime.InteropServices;
 
class X
{
    public static void f1(
        [MarshalAs(UnmanagedType.ByValArray)]
        int ByValArray,
 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
        int ByValTStr
    ) 
    {
    }
 
    [return: MarshalAs(UnmanagedType.ByValArray)]
    public static int f2() { return 0; }
 
    [return: MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
    public static int f3() { return 0; }
 
    [MarshalAs(UnmanagedType.VBByRefStr)]
    public int field;
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (7,20): error CS7055: Unmanaged type 'ByValArray' is only valid for fields.
                Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValArray").WithArguments("ByValArray"),
                // (10,20): error CS7055: Unmanaged type 'ByValTStr' is only valid for fields.
                Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValTStr").WithArguments("ByValTStr"),
                // (16,24): error CS7055: Unmanaged type 'ByValArray' is only valid for fields.
                Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValArray").WithArguments("ByValArray"),
                // (19,24): error CS7055: Unmanaged type 'ByValTStr' is only valid for fields.
                Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValTStr").WithArguments("ByValTStr"),
                // (22,16): error CS7054: Unmanaged type 'VBByRefStr' not valid for fields.
                Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeNotValidForFields, "UnmanagedType.VBByRefStr").WithArguments("VBByRefStr"),
 
                // TODO (tomat): remove
 
                // (23,16): warning CS0649: Field 'X.field' is never assigned to, and will always have its default value 0
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("X.field", "0"));
        }
 
        [Fact]
        public void Parameters_Errors_LocalFunction()
        {
            var source = @"
#pragma warning disable 8321 // Unreferenced local function
 
using System.Runtime.InteropServices;
 
class X
{
    void M()
    {
        static void f1(
            [MarshalAs(UnmanagedType.ByValArray)]
            int ByValArray,
 
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
            int ByValTStr
        )
        {
        }
 
        [return: MarshalAs(UnmanagedType.ByValArray)]
        static int f2() { return 0; }
 
        [return: MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
        static int f3() { return 0; }
    }
}
";
            CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
                    // (11,24): error CS7055: Unmanaged type 'ByValArray' is only valid for fields.
                    //             [MarshalAs(UnmanagedType.ByValArray)]
                    Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValArray").WithArguments("ByValArray").WithLocation(11, 24),
                    // (14,24): error CS7055: Unmanaged type 'ByValTStr' is only valid for fields.
                    //             [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
                    Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValTStr").WithArguments("ByValTStr").WithLocation(14, 24),
                    // (20,28): error CS7055: Unmanaged type 'ByValArray' is only valid for fields.
                    //         [return: MarshalAs(UnmanagedType.ByValArray)]
                    Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValArray").WithArguments("ByValArray").WithLocation(20, 28),
                    // (23,28): error CS7055: Unmanaged type 'ByValTStr' is only valid for fields.
                    //         [return: MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
                    Diagnostic(ErrorCode.ERR_MarshalUnmanagedTypeOnlyValidForFields, "UnmanagedType.ByValTStr").WithArguments("ByValTStr").WithLocation(23, 28));
        }
 
        /// <summary>
        ///  type only, only on parameters
        /// </summary>
        [Fact]
        public void NativeTypeByValStr()
        {
            var source = @"
using System;
using System.Runtime.InteropServices;
 
class X
{
    [return: MarshalAs(UnmanagedType.VBByRefStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
            SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
    static void f(
        [MarshalAs(UnmanagedType.VBByRefStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
            SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
        ref int VBByRefStr_e1,
 
        [MarshalAs(UnmanagedType.VBByRefStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
            SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
        char[] VBByRefStr_e2,
 
        [MarshalAs(UnmanagedType.VBByRefStr, ArraySubType = UnmanagedType.ByValTStr, IidParameterIndex = -1, MarshalCookie = null, MarshalType = null, MarshalTypeRef = null,
            SafeArraySubType = VarEnum.VT_BSTR, SafeArrayUserDefinedSubType = null, SizeConst = -1, SizeParamIndex = -1)]
        int VBByRefStr_e3)
    { }
}
";
            CompileAndVerifyFieldMarshal(source, new Dictionary<string, byte[]>
            {
                { "f:",              new byte[] { 0x22 } },  // return value
                { "f:VBByRefStr_e1", new byte[] { 0x22 } },
                { "f:VBByRefStr_e2", new byte[] { 0x22 } },
                { "f:VBByRefStr_e3", new byte[] { 0x22 } },
            },
            isField: false);
        }
 
        [Fact, WorkItem(545374, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545374")]
        public void ImportOptionalMarshalAsParameter()
        {
            string text1 = @"
using System.Runtime.InteropServices;
 
public class P2<T>
{
    public int Foo([Optional][MarshalAs(UnmanagedType.IDispatch)] T i)
    {
        if (i == null) 
            return 0;
        return 1;
    }
}
";
            string text2 = @"
class C
{
    public static void Main()
    {
        P2<object> p2 = new P2<object>();
        System.Console.WriteLine(p2.Foo());
    }
}
";
            var comp1 = CreateCompilation(text1, assemblyName: "OptionalMarshalAsLibrary");
            var comp2 = CreateCompilation(text2,
                options: TestOptions.ReleaseExe,
                references: new[] { comp1.EmitToImageReference() },  // it has to be real assembly, Comp2comp reference OK
                assemblyName: "APP");
 
            CompileAndVerify(comp2, expectedOutput: @"0").VerifyIL("C.Main", @"
{
  // Code size       17 (0x11)
  .maxstack  2
  IL_0000:  newobj     ""P2<object>..ctor()""
  IL_0005:  ldnull
  IL_0006:  callvirt   ""int P2<object>.Foo(object)""
  IL_000b:  call       ""void System.Console.WriteLine(int)""
  IL_0010:  ret
}
");
        }
 
        #endregion
    }
}