|
// 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.Text;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
public class CodeGenFieldInitTests : CSharpTestBase
{
[Fact]
public void TestInstanceFieldInitializersPartialClass()
{
var source = @"
class C
{
static void Main()
{
Partial p;
System.Console.WriteLine(""Start Partial()"");
p = new Partial();
System.Console.WriteLine(""p.a = {0}"", p.a);
System.Console.WriteLine(""p.b = {0}"", p.b);
System.Console.WriteLine(""p.c = {0}"", p.c);
System.Console.WriteLine(""End Partial()"");
System.Console.WriteLine(""Start Partial(int)"");
p = new Partial(3);
System.Console.WriteLine(""p.a = {0}"", p.a);
System.Console.WriteLine(""p.b = {0}"", p.b);
System.Console.WriteLine(""p.c = {0}"", p.c);
System.Console.WriteLine(""End Partial(int)"");
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
partial class Partial
{
public int a = C.Init(1, ""Partial.a"");
public Partial()
{
}
}
partial class Partial
{
public int c, b = C.Init(2, ""Partial.b"");
public Partial(int garbage)
{
this.c = C.Init(3, ""Partial.c"");
}
}
";
CompileAndVerify(source, expectedOutput: @"
Start Partial()
Partial.a
Partial.b
p.a = 1
p.b = 2
p.c = 0
End Partial()
Start Partial(int)
Partial.a
Partial.b
Partial.c
p.a = 1
p.b = 2
p.c = 3
End Partial(int)
");
}
[Fact]
public void TestInstanceFieldInitializersInheritance()
{
var source = @"
class C
{
static void Main()
{
Derived2 d = new Derived2();
System.Console.WriteLine(""d.a = {0}"", d.a);
System.Console.WriteLine(""d.b = {0}"", d.b);
System.Console.WriteLine(""d.c = {0}"", d.c);
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
class Base
{
public int a = C.Init(1, ""Base.a"");
public Base()
{
System.Console.WriteLine(""Base()"");
}
}
class Derived : Base
{
public int b = C.Init(2, ""Derived.b"");
public Derived()
{
System.Console.WriteLine(""Derived()"");
}
}
class Derived2 : Derived
{
public int c = C.Init(3, ""Derived2.c"");
public Derived2()
{
System.Console.WriteLine(""Derived2()"");
}
}
";
CompileAndVerify(source, expectedOutput: @"
Derived2.c
Derived.b
Base.a
Base()
Derived()
Derived2()
d.a = 1
d.b = 2
d.c = 3
");
}
[Fact]
public void TestStaticFieldInitializersPartialClass()
{
var source = @"
class C
{
static void Main()
{
System.Console.WriteLine(""Partial.a = {0}"", Partial.a);
System.Console.WriteLine(""Partial.b = {0}"", Partial.b);
System.Console.WriteLine(""Partial.c = {0}"", Partial.c);
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
partial class Partial
{
public static int a = C.Init(1, ""Partial.a"");
}
partial class Partial
{
public static int c, b = C.Init(2, ""Partial.b"");
static Partial()
{
c = C.Init(3, ""Partial.c"");
}
}
";
CompileAndVerify(source, expectedOutput: @"
Partial.a
Partial.b
Partial.c
Partial.a = 1
Partial.b = 2
Partial.c = 3
");
}
[Fact]
public void TestStaticFieldInitializersInheritance1()
{
var source = @"
class C
{
static void Main()
{
Base b = new Base();
System.Console.WriteLine(""Base.a = {0}"", Base.a);
System.Console.WriteLine(""Derived.b = {0}"", Derived.b);
System.Console.WriteLine(""Derived2.c = {0}"", Derived2.c);
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
class Base
{
public static int a = C.Init(1, ""Base.a"");
static Base() { System.Console.WriteLine(""Base()""); }
}
class Derived : Base
{
public static int b = C.Init(2, ""Derived.b"");
static Derived() { System.Console.WriteLine(""Derived()""); }
}
class Derived2 : Derived
{
public static int c = C.Init(3, ""Derived2.c"");
static Derived2() { System.Console.WriteLine(""Derived2()""); }
}
";
CompileAndVerify(source, expectedOutput: @"
Base.a
Base()
Base.a = 1
Derived.b
Derived()
Derived.b = 2
Derived2.c
Derived2()
Derived2.c = 3
");
}
[Fact]
public void TestStaticFieldInitializersInheritance2()
{
var source = @"
class C
{
static void Main()
{
Base b = new Derived();
System.Console.WriteLine(""Base.a = {0}"", Base.a);
System.Console.WriteLine(""Derived.b = {0}"", Derived.b);
System.Console.WriteLine(""Derived2.c = {0}"", Derived2.c);
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
class Base
{
public static int a = C.Init(1, ""Base.a"");
static Base() { System.Console.WriteLine(""Base()""); }
}
class Derived : Base
{
public static int b = C.Init(2, ""Derived.b"");
static Derived() { System.Console.WriteLine(""Derived()""); }
}
class Derived2 : Derived
{
public static int c = C.Init(3, ""Derived2.c"");
static Derived2() { System.Console.WriteLine(""Derived2()""); }
}
";
CompileAndVerify(source, expectedOutput: @"
Derived.b
Derived()
Base.a
Base()
Base.a = 1
Derived.b = 2
Derived2.c
Derived2()
Derived2.c = 3
");
}
[Fact]
public void TestStaticFieldInitializersInheritance3()
{
var source = @"
class C
{
static void Main()
{
Base b = new Derived2();
System.Console.WriteLine(""Base.a = {0}"", Base.a);
System.Console.WriteLine(""Derived.b = {0}"", Derived.b);
System.Console.WriteLine(""Derived2.c = {0}"", Derived2.c);
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
class Base
{
public static int a = C.Init(1, ""Base.a"");
static Base() { System.Console.WriteLine(""Base()""); }
}
class Derived : Base
{
public static int b = C.Init(2, ""Derived.b"");
static Derived() { System.Console.WriteLine(""Derived()""); }
}
class Derived2 : Derived
{
public static int c = C.Init(3, ""Derived2.c"");
static Derived2() { System.Console.WriteLine(""Derived2()""); }
}
";
CompileAndVerify(source, expectedOutput: @"
Derived2.c
Derived2()
Derived.b
Derived()
Base.a
Base()
Base.a = 1
Derived.b = 2
Derived2.c = 3
");
}
[Fact]
public void TestFieldInitializersMixed()
{
var source = @"
class C
{
static void Main()
{
Derived d = new Derived();
System.Console.WriteLine(""Base.a = {0}"", Base.a);
System.Console.WriteLine(""Derived.b = {0}"", Derived.b);
System.Console.WriteLine(""d.x = {0}"", d.x);
System.Console.WriteLine(""d.y = {0}"", d.y);
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
class Base
{
public static int a = C.Init(1, ""Base.a"");
public int x = C.Init(3, ""Base.x"");
static Base()
{
System.Console.WriteLine(""static Base()"");
}
public Base()
{
System.Console.WriteLine(""Base()"");
}
}
class Derived : Base
{
public static int b = C.Init(2, ""Derived.b"");
public int y = C.Init(4, ""Derived.y"");
static Derived()
{
System.Console.WriteLine(""static Derived()"");
}
public Derived()
{
System.Console.WriteLine(""Derived()"");
}
}
";
CompileAndVerify(source, expectedOutput: @"
Derived.b
static Derived()
Derived.y
Base.a
static Base()
Base.x
Base()
Derived()
Base.a = 1
Derived.b = 2
d.x = 3
d.y = 4
");
}
[Fact]
public void TestFieldInitializersInOptimizedMode1()
{
var source = @"
class C
{
public string str1 = null;
public string str2 = ""a"";
public string str3 = (string)(null);
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
CompileAndVerify(compilation).VerifyIL("C..ctor", @"
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldstr ""a""
IL_0006: stfld ""string C.str2""
IL_000b: ldarg.0
IL_000c: call ""object..ctor()""
IL_0011: ret
}
");
}
[Fact]
public void TestFieldInitializersInOptimizedMode2()
{
var source = @"
class C
{
public int f1 = 0;
public short f2 = (short)0;
public bool f3 = false;
public char f4 = '\0';
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
CompileAndVerify(compilation).VerifyIL("C..ctor", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""object..ctor()""
IL_0006: ret
}
");
}
[Fact]
public void TestFieldInitializersInOptimizedMode3()
{
var source = @"
class C<T>
{
public T f1 = default(T);
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
CompileAndVerify(compilation).VerifyIL("C<T>..ctor", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""object..ctor()""
IL_0006: ret
}
");
}
[Fact]
public void TestFieldInitializersInOptimizedMode4()
{
var source = @"
class C
{
public static string str1 = null;
public static string str2 = ""a"";
public static string str3 = (string)(null);
public static int f1 = 0;
public static short f2 = (short)0;
public static bool f3 = false;
public static char f4 = '\0';
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
CompileAndVerify(compilation).VerifyIL("C..cctor", @"
{
// Code size 47 (0x2f)
.maxstack 1
IL_0000: ldnull
IL_0001: stsfld ""string C.str1""
IL_0006: ldstr ""a""
IL_000b: stsfld ""string C.str2""
IL_0010: ldnull
IL_0011: stsfld ""string C.str3""
IL_0016: ldc.i4.0
IL_0017: stsfld ""int C.f1""
IL_001c: ldc.i4.0
IL_001d: stsfld ""short C.f2""
IL_0022: ldc.i4.0
IL_0023: stsfld ""bool C.f3""
IL_0028: ldc.i4.0
IL_0029: stsfld ""char C.f4""
IL_002e: ret
}
");
}
[Fact]
public void TestFieldInitializersInOptimizedMode5()
{
var source = @"
using System;
enum E1 : byte
{
a,
b
}
class C<T> where T:Exception
{
public static string str1 = null;
public static T tt = default(T);
public static Exception tt1 = (T)null;
public static Exception tt2 = null as T;
public static T tt3 = (T)(Exception)(object)default(T);
public static E1 ee = 0;
public static E1 ee1 = (E1)(int)(E1)0;
public static E1 ee2 = (E1)(int)E1.a;
public static object str3 = (object)(string)(null);
public static int f1 = 0;
public static short f2 = (short)0;
public static bool f3 = false;
public static char f4 = '\0';
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
CompileAndVerify(
source,
symbolValidator: validator,
options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All));
void validator(ModuleSymbol module)
{
// note: we could make the synthesized constructor smarter and realize that
// nothing needs to be emitted for these initializers.
// but it doesn't serve any realistic scenarios at this time.
var type = module.ContainingAssembly.GetTypeByMetadataName("C`1");
Assert.NotNull(type.GetMember(".cctor"));
}
}
[WorkItem(530445, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530445")]
[Fact]
public void TestFieldInitializersInOptimizedMode6()
{
var source = @"
class C
{
private bool a = false;
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
CompileAndVerify(compilation).VerifyIL("C..ctor", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""object..ctor()""
IL_0006: ret
}
");
}
[Fact]
public void TestFieldInitializersConstructorInitializers()
{
var source = @"
class C
{
static void Main()
{
A a = new A();
System.Console.WriteLine(""a.a = {0}"", a.a);
}
public static int Init(int value, string message)
{
System.Console.WriteLine(message);
return value;
}
}
class A
{
public int a = C.Init(1, ""A.a"");
public A()
: this(1)
{
System.Console.WriteLine(""A()"");
}
public A(int garbage)
{
System.Console.WriteLine(""A(int)"");
}
}
";
CompileAndVerify(source, expectedOutput: @"
A.a
A(int)
A()
a.a = 1
");
}
[Fact]
public void Ordering()
{
var trees = new List<SyntaxTree>();
var expectedOutput = new StringBuilder();
for (int i = 0; i < 20; i++)
{
trees.Add(SyntaxFactory.ParseSyntaxTree("System.Console.WriteLine(" + i + ");", options: TestOptions.Script));
expectedOutput.AppendLine(i.ToString());
}
var compilation = CreateCompilationWithMscorlib461(trees, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: expectedOutput.ToString());
}
[Fact]
public void FieldInitializerWithBadConstantValueSameModule()
{
var source =
@"class A
{
public int F = B.F1;
}
class B
{
public const int F1 = F2;
public static int F2 = 0;
}";
CreateCompilation(source).VerifyDiagnostics(
// (7,27): error CS0133: The expression being assigned to 'B.F1' must be constant
Diagnostic(ErrorCode.ERR_NotConstantExpression, "F2").WithArguments("B.F1").WithLocation(7, 27));
}
[Fact]
public void FieldInitializerWithBadConstantValueDifferentModule()
{
var source1 =
@"public class B
{
public const int F1 = F2;
public static int F2 = 0;
}";
var compilation1 = CreateCompilation(source1, assemblyName: "1110a705-cc34-430b-9450-ca37031aa828");
compilation1.VerifyDiagnostics(
// (3,27): error CS0133: The expression being assigned to 'B.F1' must be constant
Diagnostic(ErrorCode.ERR_NotConstantExpression, "F2").WithArguments("B.F1").WithLocation(3, 27));
var source2 =
@"class A
{
public object F = M(B.F1);
private static object M(int i) { return null; }
}";
CreateCompilation(source2, new[] { new CSharpCompilationReference(compilation1) }, assemblyName: "2110a705-cc34-430b-9450-ca37031aa828")
.Emit(new System.IO.MemoryStream()).Diagnostics
.Verify(
// error CS7038: Failed to emit module '2110a705-cc34-430b-9450-ca37031aa828': Unable to determine specific cause of the failure.
Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments("2110a705-cc34-430b-9450-ca37031aa828", "Unable to determine specific cause of the failure."));
}
}
}
|