File: Emit\EmitErrorTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit.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.IO;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.UnitTests.Emit;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Emit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    /// <summary>
    /// this place is dedicated to emit/codegen related error tests
    /// </summary>
    public class EmitErrorTests : EmitMetadataTestBase
    {
        #region "Mixed Error Tests"
 
        [WorkItem(543039, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543039")]
        [Fact]
        public void BadConstantInOtherAssemblyUsedByField()
        {
            string source1 = @"
public class A
{
    public const int x = x;
}
";
            var compilation1 = CreateCompilation(source1);
            compilation1.VerifyDiagnostics(
                // (4,22): error CS0110: The evaluation of the constant value for 'A.x' involves a circular definition
                Diagnostic(CSharp.ErrorCode.ERR_CircConstValue, "x").WithArguments("A.x"));
 
            string source2 = @"
public class B
{
    public const int y = A.x;
 
    public static void Main()
    {
        System.Console.WriteLine(""Hello"");
    }
}
";
            VerifyEmitDiagnostics(source2, compilation1);
        }
 
        [WorkItem(543039, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543039")]
        [Fact]
        public void BadConstantInOtherAssemblyUsedByLocal()
        {
            string source1 = @"
public class A
{
    public const int x = x;
}
";
            var compilation1 = CreateCompilation(source1);
            compilation1.VerifyDiagnostics(
                // (4,22): error CS0110: The evaluation of the constant value for 'A.x' involves a circular definition
                Diagnostic(CSharp.ErrorCode.ERR_CircConstValue, "x").WithArguments("A.x"));
 
            string source2 = @"
public class B
{
    public static void Main()
    {
        const int y = A.x;
        System.Console.WriteLine(""Hello"");
    }
}
";
            VerifyEmitDiagnostics(source2, compilation1,
                // (6,19): warning CS0219: The variable 'y' is assigned but its value is never used
                Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "y").WithArguments("y"));
        }
 
        [WorkItem(543039, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543039")]
        [Fact]
        public void BadDefaultArgumentInOtherAssembly()
        {
            string source1 = @"
public class A
{
    public const int x = x;
 
    public static int Goo(int y = x) { return y; }
}
";
            var compilation1 = CreateCompilation(source1);
            compilation1.VerifyDiagnostics(
                // (4,22): error CS0110: The evaluation of the constant value for 'A.x' involves a circular definition
                Diagnostic(CSharp.ErrorCode.ERR_CircConstValue, "x").WithArguments("A.x"));
 
            string source2 = @"
public class B
{
    public static void Main()
    {
        System.Console.WriteLine(A.Goo());
    }
}
";
            // ILVerify null ref
            // Tracked by https://github.com/dotnet/roslyn/issues/58652
            var compilation2 = CompileAndVerify(
                source2,
                new[] { new CSharpCompilationReference(compilation1) },
                verify: Verification.Fails);
        }
 
        [WorkItem(543039, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543039")]
        [Fact]
        public void BadDefaultArgumentInOtherAssembly_Decimal()
        {
            string source1 = @"
public class A
{
    public const decimal x = x;
 
    public static decimal Goo(decimal y = x) { return y; }
}
";
            var compilation1 = CreateCompilation(source1);
            compilation1.VerifyDiagnostics(
                // (4,22): error CS0110: The evaluation of the constant value for 'A.x' involves a circular definition
                Diagnostic(ErrorCode.ERR_CircConstValue, "x").WithArguments("A.x"));
 
            string source2 = @"
public class B
{
    public static void Main()
    {
        System.Console.WriteLine(A.Goo());
    }
}
";
            // ILVerify null ref
            // Tracked by https://github.com/dotnet/roslyn/issues/58652
            var compilation2 = CompileAndVerify(
                source2,
                new[] { new CSharpCompilationReference(compilation1) },
                verify: Verification.Fails);
        }
 
        [WorkItem(543039, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543039")]
        [Fact]
        public void BadDefaultArgumentInOtherAssembly_UserDefinedType()
        {
            string source1 = @"
public struct S 
{
    public override string ToString() { return ""S::ToString""; }
}
 
public class A
{
    public static S Goo(S p = 42) { return p; }
}
";
            var compilation1 = CreateCompilation(source1);
            compilation1.VerifyDiagnostics(
                // (9,27): error CS1750: A value of type 'int' cannot be used as a default parameter because there are no standard conversions to type 'S'
                //     public static S Goo(S p = 42) { return p; }
                Diagnostic(ErrorCode.ERR_NoConversionForDefaultParam, "p").WithArguments("int", "S").WithLocation(9, 27));
 
            string source2 = @"
public class B
{
    public static void Main()
    {
        System.Console.WriteLine(A.Goo());
    }
}
";
 
            // ILVerify null ref
            // Tracked by https://github.com/dotnet/roslyn/issues/58652
            var compilation2 = CompileAndVerify(
                source2,
                new[] { new CSharpCompilationReference(compilation1) },
                verify: Verification.Fails);
            compilation2.VerifyIL("B.Main()", @"
{
  // Code size       25 (0x19)
  .maxstack  1
  .locals init (S V_0)
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""S""
  IL_0008:  ldloc.0
  IL_0009:  call       ""S A.Goo(S)""
  IL_000e:  box        ""S""
  IL_0013:  call       ""void System.Console.WriteLine(object)""
  IL_0018:  ret
}");
        }
 
        [WorkItem(543039, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543039")]
        [Fact]
        public void BadReturnTypeInOtherAssembly()
        {
            string source1 = @"
public class A
{
    public static Missing Goo() { return null; }
}
";
            var compilation1 = CreateCompilation(source1);
            compilation1.VerifyDiagnostics(
                // (4,19): error CS0246: The type or namespace name 'Missing' could not be found (are you missing a using directive or an assembly reference?)
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Missing").WithArguments("Missing"));
 
            string source2 = @"
public class B
{
    public static void Main()
    {
        var f = A.Goo();
        System.Console.WriteLine(f);
    }
}
";
            VerifyEmitDiagnostics(source2, compilation1);
        }
 
        private static void VerifyEmitDiagnostics(string source2, CSharpCompilation compilation1, params DiagnosticDescription[] expectedDiagnostics)
        {
            var compilation2 = CreateCompilation(source2, new MetadataReference[] { new CSharpCompilationReference(compilation1) });
            compilation2.VerifyDiagnostics(expectedDiagnostics);
 
            using (var executableStream = new MemoryStream())
            {
                var result = compilation2.Emit(executableStream);
                Assert.False(result.Success);
 
                result.Diagnostics.Verify(expectedDiagnostics.Concat(new[]
                {
                    // error CS7038: Failed to emit module 'Test': Unable to determine specific cause of the failure.
                    Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments(compilation2.AssemblyName, "Unable to determine specific cause of the failure.")
                }).ToArray());
            }
 
            using (var executableStream = new MemoryStream())
            {
                var result = compilation2.Emit(executableStream, options: new EmitOptions(metadataOnly: true));
                Assert.True(result.Success);
                result.Diagnostics.Verify();
            }
        }
 
        [Fact, WorkItem(530211, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530211")]
        public void ModuleNameMismatch()
        {
            var moduleSource = "class Test {}";
            var netModule = CreateCompilation(moduleSource, options: TestOptions.ReleaseModule, assemblyName: "ModuleNameMismatch");
 
            var moduleMetadata = ModuleMetadata.CreateFromImage(netModule.EmitToArray());
 
            var source = @"class Module1 { }";
 
            var compilationOK = CreateCompilation(source, new MetadataReference[] { moduleMetadata.GetReference(filePath: @"R:\A\B\ModuleNameMismatch.netmodule") });
 
            CompileAndVerify(compilationOK);
 
            var compilationError = CreateCompilation(source, new MetadataReference[] { moduleMetadata.GetReference(filePath: @"R:\A\B\ModuleNameMismatch.mod") });
 
            compilationError.VerifyDiagnostics(
                // error CS7086: Module name 'ModuleNameMismatch.netmodule' stored in 'ModuleNameMismatch.mod' must match its filename.
                Diagnostic(ErrorCode.ERR_NetModuleNameMismatch).WithArguments("ModuleNameMismatch.netmodule", "ModuleNameMismatch.mod"));
        }
 
        [ConditionalFact(typeof(NoIOperationValidation))]
        public void CS0204_ERR_TooManyLocals()
        {
            var builder = new System.Text.StringBuilder();
            builder.Append(@"
public class A
{
    public static int Main ()
        {
");
            for (int i = 0; i < 65536; i++)
            {
                builder.AppendLine(string.Format("    int i{0} = {0};", i));
            }
 
            builder.Append(@"
        return 1;
        }
}
");
 
            //Compiling this with optimizations enabled causes the stack scheduler to eliminate a bunch of these locals.
            //It could eliminate 'em all, but doesn't.
            var warnOpts = new System.Collections.Generic.Dictionary<string, ReportDiagnostic>();
            warnOpts.Add(MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_UnreferencedVarAssg), ReportDiagnostic.Suppress);
            var compilation1 = CreateCompilation(builder.ToString(), null, TestOptions.DebugDll.WithSpecificDiagnosticOptions(warnOpts));
            compilation1.VerifyEmitDiagnostics(
                // (4,23): error CS0204: Only 65534 locals, including those generated by the compiler, are allowed
                //     public static int Main ()
                Diagnostic(ErrorCode.ERR_TooManyLocals, "Main"));
        }
 
        [Fact, WorkItem(8287, "https://github.com/dotnet/roslyn/issues/8287")]
        public void ToManyUserStrings()
        {
            var builder = new System.Text.StringBuilder();
            builder.Append(@"
public class A
{
    public static void Main ()
        {
");
            for (int i = 0; i < 11; i++)
            {
                builder.Append("System.Console.WriteLine(\"");
                builder.Append((char)('A' + i), 1000000);
                builder.Append("\");");
                builder.AppendLine();
            }
 
            builder.Append(@"
        }
}
");
 
            var compilation = CreateCompilation(builder.ToString());
 
            compilation.VerifyEmitDiagnostics(
    // error CS8103: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals.
    Diagnostic(ErrorCode.ERR_TooManyUserStrings).WithLocation(1, 1)
                );
        }
 
        #endregion
    }
}