/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs
1 615 строк
61 KB
AlekseyTs
Support `field` keyword in EE. (#80515)
04 окт 2025, 19:23
Не верифицирован
04 окт 2025, 19:23
b02727d
Код
Авторство
О чём код?
// 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.Immutable; using System.Text; using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Debugger.Evaluation; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests { public class CompileExpressionsTests : ExpressionCompilerTestBase { [Fact] public void NoRequests() { var source = @"class C { static void F() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions(ImmutableArray<string>.Empty, out var methodTokens, out var errorMessages); Assert.Null(assembly); Assert.True(methodTokens.IsEmpty); Assert.True(errorMessages.IsEmpty); }); } [Fact] public void SingleRequest() { var source = @"class C { static void F() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("1"), out var methodTokens, out var errorMessages); Assert.NotNull(assembly); Assert.True(errorMessages.IsEmpty); Assert.Equal(1, methodTokens.Length); assembly.VerifyIL(methodTokens[0], "<>x0.<>m0", @"{ // Code size 2 (0x2) .maxstack 8 IL_0000: ldc.i4.1 IL_0001: ret }"); }); } [Fact] public void MultipleRequests() { var source = @"class C { static void F(object x) { object y; } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("x", "x ?? y"), out var methodTokens, out var errorMessages); Assert.NotNull(assembly); Assert.True(errorMessages.IsEmpty); Assert.Equal(2, methodTokens.Length); assembly.VerifyIL(methodTokens[0], "<>x0.<>m0", @"Locals: object { // Code size 2 (0x2) .maxstack 1 IL_0000: ldarg.0 IL_0001: ret }"); assembly.VerifyIL(methodTokens[1], "<>x1.<>m0", @"Locals: object { // Code size 7 (0x7) .maxstack 2 IL_0000: ldarg.0 IL_0001: dup IL_0002: brtrue.s IL_0006 IL_0004: pop IL_0005: ldloc.0 IL_0006: ret }"); }); } [Fact] public void ParseErrors() { var source = @"class C { static void F(object x) { object y; } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("x", "x ??", "?? z", "x ?? z"), out var methodTokens, out var errorMessages); Assert.Null(assembly); AssertEx.Equal(new[] { $"(1,5): error CS1733: { CSharpResources.ERR_ExpressionExpected }", $"(1,1): error CS1525: { string.Format(CSharpResources.ERR_InvalidExprTerm, "??") }", }, errorMessages); Assert.True(methodTokens.IsEmpty); }); } [Fact] public void BindingErrors() { var source = @"class C { static void F(object x) { object y; } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create( "x", "z", // (1,1): error CS0103: The name 'z' does not exist in the current context "x ?? y", "x ?? z", // (1,6): error CS0103: The name 'z' does not exist in the current context "0l"), // (1,2): warning CS0078: The 'l' suffix is easily confused with the digit '1' -- use 'L' for clarity out var methodTokens, out var errorMessages); Assert.Null(assembly); AssertEx.Equal(new[] { $"(1,1): error CS0103: { string.Format(CSharpResources.ERR_NameNotInContext,"z") }", $"(1,6): error CS0103: { string.Format(CSharpResources.ERR_NameNotInContext,"z") }", }, errorMessages); Assert.True(methodTokens.IsEmpty); }); } [Fact] public void EmitErrors() { var longName = new string('P', 1100); var source = @"class C { static void F() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create($"new {{ {longName} = 1 }}"), out var methodTokens, out var errorMessages); Assert.Null(assembly); AssertEx.Equal(new[] { $"error CS7013: { string.Format(CSharpResources.ERR_MetadataNameTooLong, $"<{longName}>i__Field") }", $"error CS7013: { string.Format(CSharpResources.ERR_MetadataNameTooLong, $"<{longName}>j__TPar") }", $"error CS7013: { string.Format(CSharpResources.ERR_MetadataNameTooLong, $"<{longName}>i__Field") }", $"error CS7013: { string.Format(CSharpResources.ERR_MetadataNameTooLong, $"get_{longName}") }", $"error CS7013: { string.Format(CSharpResources.ERR_MetadataNameTooLong, $"{longName}") }", $"error CS7013: { string.Format(CSharpResources.ERR_MetadataNameTooLong, $"{longName}") }", }, errorMessages); Assert.True(methodTokens.IsEmpty); }); } [Fact] public void Assignment() { var source = @"class C { object F; void M() { object o; } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.M"); var assembly = context.CompileExpressions( ImmutableArray.Create("o = F"), out var methodTokens, out var errorMessages); Assert.NotNull(assembly); Assert.True(errorMessages.IsEmpty); Assert.Equal(1, methodTokens.Length); assembly.VerifyIL(methodTokens[0], "<>x0.<>m0", @"Locals: object { // Code size 9 (0x9) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldfld 0x0A000006 IL_0006: dup IL_0007: stloc.0 IL_0008: ret }"); }); } [Fact] public void VoidExpression() { var source = @"class C { static void F() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("F()"), out var methodTokens, out var errorMessages); Assert.NotNull(assembly); Assert.True(errorMessages.IsEmpty); Assert.Equal(1, methodTokens.Length); assembly.VerifyIL(methodTokens[0], "<>x0.<>m0", @"{ // Code size 6 (0x6) .maxstack 8 IL_0000: call 0x0A000006 IL_0005: ret }"); }); } [Fact] public void Declaration() { var source = @"class C { static void F() { } static void G(out object o) { o = null; } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("G(out var o)"), out var methodTokens, out var errorMessages); Assert.Null(assembly); AssertEx.Equal( new[] { $"(1,11): error CS8185: {CSharpResources.ERR_DeclarationExpressionNotPermitted}" }, errorMessages); Assert.True(methodTokens.IsEmpty); }); } [Fact] public void PseudoVariables() { var source = @"class C { static void F() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("$exception", "$1 ?? $unknown"), out var methodTokens, out var errorMessages); Assert.Null(assembly); AssertEx.Equal(new[] { $"(1,1): error CS0103: { string.Format(CSharpResources.ERR_NameNotInContext, "$exception") }", $"(1,1): error CS0103: { string.Format(CSharpResources.ERR_NameNotInContext, "$1") }", $"(1,7): error CS0103: { string.Format(CSharpResources.ERR_NameNotInContext, "$unknown") }", }, errorMessages); Assert.True(methodTokens.IsEmpty); }); } [Fact] public void GenericAndDynamic() { var source = @"class C<T> { static void F<U>(dynamic d) { d.F(); } }"; var comp = CreateCompilation(source, new[] { CSharpRef }, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("default(T)", "default(U)", "d.F()"), out var methodTokens, out var errorMessages); Assert.NotNull(assembly); Assert.True(errorMessages.IsEmpty); Assert.Equal(3, methodTokens.Length); assembly.VerifyIL(methodTokens[0], "<>x0.<>m0", @"Locals: !0 { // Code size 10 (0xa) .maxstack 1 IL_0000: ldloca.s V_0 IL_0002: initobj 0x1B000001 IL_0008: ldloc.0 IL_0009: ret }"); assembly.VerifyIL(methodTokens[1], "<>x1.<>m0", @"Locals: !!0 { // Code size 10 (0xa) .maxstack 1 IL_0000: ldloca.s V_0 IL_0002: initobj 0x1B000002 IL_0008: ldloc.0 IL_0009: ret }"); assembly.VerifyIL(methodTokens[2], "<>x2.<>m0", @"{ // Code size 77 (0x4d) .maxstack 9 IL_0000: ldsfld 0x0A000008 IL_0005: brtrue.s IL_0037 IL_0007: ldc.i4.0 IL_0008: ldstr 0x70000001 IL_000d: ldnull IL_000e: ldtoken 0x1B000004 IL_0013: call 0x0A000009 IL_0018: ldc.i4.1 IL_0019: newarr 0x01000011 IL_001e: dup IL_001f: ldc.i4.0 IL_0020: ldc.i4.0 IL_0021: ldnull IL_0022: call 0x0A00000A IL_0027: stelem.ref IL_0028: call 0x0A00000B IL_002d: call 0x0A00000C IL_0032: stsfld 0x0A000008 IL_0037: ldsfld 0x0A000008 IL_003c: ldfld 0x0A00000D IL_0041: ldsfld 0x0A000008 IL_0046: ldarg.0 IL_0047: callvirt 0x0A00000E IL_004c: ret }"); }); } [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=482753")] public void LocalsInAsync() { var source = @"using System; using System.Threading.Tasks; class C { static Task<object> E(object o, Func<object, bool> p) { throw new NotImplementedException(); } object F() { throw new NotImplementedException(); } Task G(object o) { throw new NotImplementedException(); } async Task M(object x) { var z = await E(F(), y => x == y); #line 999 await G(z); } }"; // Test with CompileExpression rather than CompileExpressions // so field references in IL are named. // Debug build. var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, references: new[] { Net40.References.SystemCore }); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.<M>d__3.MoveNext()", atLineNumber: 999); string error; var testData = new CompilationTestData(); var result = context.CompileExpression("z ?? x", out error, testData); Assert.NotNull(result.Assembly); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL( @"{ // Code size 22 (0x16) .maxstack 2 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter<object> V_1, C.<M>d__3 V_2, System.Runtime.CompilerServices.TaskAwaiter V_3, System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""object C.<M>d__3.<z>5__2"" IL_0006: dup IL_0007: brtrue.s IL_0015 IL_0009: pop IL_000a: ldarg.0 IL_000b: ldfld ""C.<>c__DisplayClass3_0 C.<M>d__3.<>8__1"" IL_0010: ldfld ""object C.<>c__DisplayClass3_0.x"" IL_0015: ret }"); }); // Release build. comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDll, references: new[] { SystemCoreRef }); { // Note from MoveNext() below that local CS$<>8__locals0 should not be // used in the compiled expression to access the display class since that // local is only set the first time through MoveNext() (see loc.2 below). var testData = new CompilationTestData(); comp.EmitToArray(testData: testData); testData.GetMethodData("C.<M>d__3.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()").VerifyIL( @"{ // Code size 293 (0x125) .maxstack 3 .locals init (int V_0, C V_1, C.<>c__DisplayClass3_0 V_2, //CS$<>8__locals0 object V_3, //z System.Runtime.CompilerServices.TaskAwaiter<object> V_4, System.Runtime.CompilerServices.TaskAwaiter V_5, System.Exception V_6) IL_0000: ldarg.0 IL_0001: ldfld ""int C.<M>d__3.<>1__state"" IL_0006: stloc.0 IL_0007: ldarg.0 IL_0008: ldfld ""C C.<M>d__3.<>4__this"" IL_000d: stloc.1 .try { IL_000e: ldloc.0 IL_000f: brfalse.s IL_0075 IL_0011: ldloc.0 IL_0012: ldc.i4.1 IL_0013: beq IL_00d2 IL_0018: newobj ""C.<>c__DisplayClass3_0..ctor()"" IL_001d: stloc.2 IL_001e: ldloc.2 IL_001f: ldarg.0 IL_0020: ldfld ""object C.<M>d__3.x"" IL_0025: stfld ""object C.<>c__DisplayClass3_0.x"" IL_002a: ldloc.1 IL_002b: call ""object C.F()"" IL_0030: ldloc.2 IL_0031: ldftn ""bool C.<>c__DisplayClass3_0.<M>b__0(object)"" IL_0037: newobj ""System.Func<object, bool>..ctor(object, System.IntPtr)"" IL_003c: call ""System.Threading.Tasks.Task<object> C.E(object, System.Func<object, bool>)"" IL_0041: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<object> System.Threading.Tasks.Task<object>.GetAwaiter()"" IL_0046: stloc.s V_4 IL_0048: ldloca.s V_4 IL_004a: call ""bool System.Runtime.CompilerServices.TaskAwaiter<object>.IsCompleted.get"" IL_004f: brtrue.s IL_0092 IL_0051: ldarg.0 IL_0052: ldc.i4.0 IL_0053: dup IL_0054: stloc.0 IL_0055: stfld ""int C.<M>d__3.<>1__state"" IL_005a: ldarg.0 IL_005b: ldloc.s V_4 IL_005d: stfld ""System.Runtime.CompilerServices.TaskAwaiter<object> C.<M>d__3.<>u__1"" IL_0062: ldarg.0 IL_0063: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<M>d__3.<>t__builder"" IL_0068: ldloca.s V_4 IL_006a: ldarg.0 IL_006b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<object>, C.<M>d__3>(ref System.Runtime.CompilerServices.TaskAwaiter<object>, ref C.<M>d__3)"" IL_0070: leave IL_0124 IL_0075: ldarg.0 IL_0076: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<object> C.<M>d__3.<>u__1"" IL_007b: stloc.s V_4 IL_007d: ldarg.0 IL_007e: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<object> C.<M>d__3.<>u__1"" IL_0083: initobj ""System.Runtime.CompilerServices.TaskAwaiter<object>"" IL_0089: ldarg.0 IL_008a: ldc.i4.m1 IL_008b: dup IL_008c: stloc.0 IL_008d: stfld ""int C.<M>d__3.<>1__state"" IL_0092: ldloca.s V_4 IL_0094: call ""object System.Runtime.CompilerServices.TaskAwaiter<object>.GetResult()"" IL_0099: stloc.3 IL_009a: ldloc.1 IL_009b: ldloc.3 IL_009c: call ""System.Threading.Tasks.Task C.G(object)"" IL_00a1: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" IL_00a6: stloc.s V_5 IL_00a8: ldloca.s V_5 IL_00aa: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" IL_00af: brtrue.s IL_00ef IL_00b1: ldarg.0 IL_00b2: ldc.i4.1 IL_00b3: dup IL_00b4: stloc.0 IL_00b5: stfld ""int C.<M>d__3.<>1__state"" IL_00ba: ldarg.0 IL_00bb: ldloc.s V_5 IL_00bd: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.<M>d__3.<>u__2"" IL_00c2: ldarg.0 IL_00c3: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<M>d__3.<>t__builder"" IL_00c8: ldloca.s V_5 IL_00ca: ldarg.0 IL_00cb: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter, C.<M>d__3>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.<M>d__3)"" IL_00d0: leave.s IL_0124 IL_00d2: ldarg.0 IL_00d3: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.<M>d__3.<>u__2"" IL_00d8: stloc.s V_5 IL_00da: ldarg.0 IL_00db: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.<M>d__3.<>u__2"" IL_00e0: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" IL_00e6: ldarg.0 IL_00e7: ldc.i4.m1 IL_00e8: dup IL_00e9: stloc.0 IL_00ea: stfld ""int C.<M>d__3.<>1__state"" IL_00ef: ldloca.s V_5 IL_00f1: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" IL_00f6: leave.s IL_0111 } catch System.Exception { IL_00f8: stloc.s V_6 IL_00fa: ldarg.0 IL_00fb: ldc.i4.s -2 IL_00fd: stfld ""int C.<M>d__3.<>1__state"" IL_0102: ldarg.0 IL_0103: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<M>d__3.<>t__builder"" IL_0108: ldloc.s V_6 IL_010a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_010f: leave.s IL_0124 } IL_0111: ldarg.0 IL_0112: ldc.i4.s -2 IL_0114: stfld ""int C.<M>d__3.<>1__state"" IL_0119: ldarg.0 IL_011a: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<M>d__3.<>t__builder"" IL_011f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" IL_0124: ret }"); } WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.<M>d__3.MoveNext()", atLineNumber: 999); string error; var testData = new CompilationTestData(); var result = context.CompileExpression("z ?? x", out error, testData); Assert.NotNull(result.Assembly); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL( @"{ // Code size 12 (0xc) .maxstack 2 .locals init (int V_0, C V_1, C.<>c__DisplayClass3_0 V_2, //CS$<>8__locals0 object V_3, //z System.Runtime.CompilerServices.TaskAwaiter<object> V_4, System.Runtime.CompilerServices.TaskAwaiter V_5, System.Exception V_6) IL_0000: ldloc.3 IL_0001: dup IL_0002: brtrue.s IL_000b IL_0004: pop IL_0005: ldarg.0 IL_0006: ldfld ""object C.<M>d__3.x"" IL_000b: ret }"); }); } [Fact] public void FileLocalType_01() { var source = @"file class C { public static int X = 42; } class Program { public static void F() { } }"; var comp = CreateCompilation(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular11, path: "path/to/MyFile.cs", Encoding.Default), options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "Program.F"); var testData = new CompilationTestData(); var result = context.CompileExpression( "C.X", out var error, testData); if (runtime.DebugFormat == DebugInformationFormat.Pdb) { Assert.Null(result); Assert.Equal("error CS0103: The name 'C' does not exist in the current context", error); } else { Assert.NotNull(result.Assembly); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 6 (0x6) .maxstack 1 IL_0000: ldsfld "int C.X" IL_0005: ret } """); } }); } [Fact] public void FileLocalType_02() { var source1 = @"file class C { public static int X = 42; } class Program { public static void F() { } }"; var source2 = @"file class C { public static int X = 43; } "; var comp = CreateCompilation( new[] { SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.Regular11, path: "path/to/Source1.cs", Encoding.Default), SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.Regular11, path: "path/to/Source2.cs", Encoding.Default) }, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "Program.F"); var testData = new CompilationTestData(); var result = context.CompileExpression( "C.X", out var error, testData); if (runtime.DebugFormat == DebugInformationFormat.Pdb) { Assert.Null(result); Assert.Equal("error CS0103: The name 'C' does not exist in the current context", error); } else { Assert.Null(error); Assert.NotNull(result.Assembly); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 6 (0x6) .maxstack 1 IL_0000: ldsfld "int C.X" IL_0005: ret } """); } }); } [Fact] public void FileLocalType_03() { var source1 = @"file class Outer { public class Inner { public static int X = 42; } } class Program { public static void F() { } }"; var source2 = @"file class Outer { public class Inner { public static int X = 43; } } "; var comp = CreateCompilation( new[] { SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.Regular11, path: "path/to/Source1.cs", Encoding.Default), SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.Regular11, path: "path/to/Source2.cs", Encoding.Default) }, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "Program.F"); var testData = new CompilationTestData(); var result = context.CompileExpression( "Outer.Inner.X", out var error, testData); if (runtime.DebugFormat == DebugInformationFormat.Pdb) { Assert.Null(result); Assert.Equal("error CS0103: The name 'Outer' does not exist in the current context", error); } else { Assert.Null(error); Assert.NotNull(result.Assembly); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 6 (0x6) .maxstack 1 IL_0000: ldsfld "int Outer.Inner.X" IL_0005: ret } """); } }); } [Fact] public void FileLocalType_04() { var source1 = @"class Program { public static void F() { } }"; var source2 = @"file class C { public static int X = 43; } "; var comp = CreateCompilation( new[] { SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.Regular11, path: "path/to/Source1.cs", Encoding.Default), SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.Regular11, path: "path/to/Source2.cs", Encoding.Default) }, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "Program.F"); var assembly = context.CompileExpressions( ImmutableArray.Create("C.X"), out var methodTokens, out var errorMessages); Assert.Equal(new[] { "(1,1): error CS0103: The name 'C' does not exist in the current context" }, errorMessages); Assert.Null(assembly); Assert.Empty(methodTokens); }); } [Fact] public void FileLocalType_05() { var source = @"file class C { } class Program { static void Main() { } }"; var comp = CreateCompilation(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular11, path: "path/to/MyFile.cs", Encoding.Default), options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "Program.Main"); var testData = new CompilationTestData(); var result = context.CompileExpression( "new C()", out var error, testData); if (runtime.DebugFormat == DebugInformationFormat.Pdb) { Assert.Null(result); Assert.Equal("error CS0246: The type or namespace name 'C' could not be found (are you missing a using directive or an assembly reference?)", error); } else { Assert.NotNull(result.Assembly); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "C..ctor()" IL_0005: ret } """); } }); } [Fact] public void FileLocalType_06() { var source = @"file class C { int F = 1; void M() { } }"; var comp = CreateCompilation(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular11, path: "path/to/MyFile.cs", Encoding.Default), options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.M"); var testData = new CompilationTestData(); var result = context.CompileExpression( "F", out var error, testData); if (runtime.DebugFormat == DebugInformationFormat.Pdb) { Assert.Null(result); Assert.Equal("error CS0103: The name 'F' does not exist in the current context", error); } else { Assert.NotNull(result.Assembly); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: ldfld "int C.F" IL_0006: ret } """); } }); } [WorkItem("https://github.com/dotnet/roslyn/issues/66109")] [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64098")] public void FileLocalType_07() { var sourceA = """ file class A { public int F1() => 1; public int F2() => 2; } class Program { static void M1() { A x = new A(); } static void M2() { #line 100 "B.cs" A y = new A(); #line 200 "C.cs" A z = new A(); } } """; var sourceB = """ class B { } """; var sourceC = """ class C { } """; var comp = CreateCompilation( new[] { SyntaxFactory.ParseSyntaxTree(sourceA, path: "path/to/A.cs", encoding: Encoding.Default), SyntaxFactory.ParseSyntaxTree(sourceB, path: "path/to/B.cs", encoding: Encoding.Default), SyntaxFactory.ParseSyntaxTree(sourceC, path: "path/to/C.cs", encoding: Encoding.Default), }, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "Program.M1"); var testData = new CompilationTestData(); ResultProperties resultProperties; string error; ImmutableArray<AssemblyIdentity> missingAssemblyIdentities; var result = context.CompileExpression( "x.F1() + (new A()).F2()", DkmEvaluationFlags.TreatAsExpression, NoAliases, DebuggerDiagnosticFormatter.Instance, out resultProperties, out error, out missingAssemblyIdentities, EnsureEnglishUICulture.PreferredOrNull, testData); if (runtime.DebugFormat == DebugInformationFormat.Pdb) { Assert.Null(result); Assert.Equal("error CS1061: 'A' does not contain a definition for 'F1' and no accessible extension method 'F1' accepting a first argument of type 'A' could be found (are you missing a using directive or an assembly reference?)", error); } else { Assert.NotNull(result.Assembly); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 18 (0x12) .maxstack 2 .locals init (A V_0) //x IL_0000: ldloc.0 IL_0001: callvirt "int A.F1()" IL_0006: newobj "A..ctor()" IL_000b: call "int A.F2()" IL_0010: add IL_0011: ret } """); } // https://github.com/dotnet/roslyn/issues/64098: EE doesn't handle methods that span multiple documents correctly context = CreateMethodContext(runtime, "Program.M2"); testData = new CompilationTestData(); result = context.CompileExpression( "y.F1() + (new A()).F2()", DkmEvaluationFlags.TreatAsExpression, NoAliases, DebuggerDiagnosticFormatter.Instance, out resultProperties, out error, out missingAssemblyIdentities, EnsureEnglishUICulture.PreferredOrNull, testData); Assert.Null(result); Assert.Equal("error CS1061: 'A' does not contain a definition for 'F1' and no accessible extension method 'F1' accepting a first argument of type 'A' could be found (are you missing a using directive or an assembly reference?)", error); }); } [Fact] public void IllFormedFilePath_01() { var source = @"class C { public static int X = 42; } class Program { public static void F() { } }"; var comp = CreateCompilation(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular11, path: "path/to/\uD800.cs", Encoding.Default), options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "Program.F"); var testData = new CompilationTestData(); var result = context.CompileExpression( "C.X", out var error, testData); Assert.NotNull(result.Assembly); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 6 (0x6) .maxstack 1 IL_0000: ldsfld "int C.X" IL_0005: ret } """); }); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66109")] public void SequencePointsMultipleDocuments_01() { var sourceA = @"partial class Program { private int x = 1; private void F() { } }"; var sourceB = @"partial class Program { private int y = 2; public Program() { F(); int z = x + y; } }"; var comp = CreateCompilation( new[] { SyntaxFactory.ParseSyntaxTree(sourceA, path: "A.cs", encoding: Encoding.Default), SyntaxFactory.ParseSyntaxTree(sourceB, path: "B.cs", encoding: Encoding.Default) }, options: TestOptions.DebugDll); comp.VerifyPdb(""" <symbols> <files> <file id="1" name="A.cs" language="C#" checksumAlgorithm="SHA1" checksum="09-65-32-19-5F-F8-8A-58-BF-BC-0C-D3-68-2C-2C-7B-15-33-18-E4" /> <file id="2" name="B.cs" language="C#" checksumAlgorithm="SHA1" checksum="62-4B-E2-91-A3-E9-43-48-4F-A0-E6-E8-22-74-EB-90-24-C3-05-A5" /> </files> <methods> <method containingType="Program" name="F"> <customDebugInfo> <using> <namespace usingCount="0" /> </using> </customDebugInfo> <sequencePoints> <entry offset="0x0" startLine="5" startColumn="5" endLine="5" endColumn="6" document="1" /> <entry offset="0x1" startLine="6" startColumn="5" endLine="6" endColumn="6" document="1" /> </sequencePoints> </method> <method containingType="Program" name=".ctor"> <customDebugInfo> <forward declaringType="Program" methodName="F" /> <encLocalSlotMap> <slot kind="0" offset="29" /> </encLocalSlotMap> </customDebugInfo> <sequencePoints> <entry offset="0x0" startLine="3" startColumn="5" endLine="3" endColumn="23" document="1" /> <entry offset="0x7" startLine="3" startColumn="5" endLine="3" endColumn="23" document="2" /> <entry offset="0xe" startLine="4" startColumn="5" endLine="4" endColumn="21" document="2" /> <entry offset="0x15" startLine="5" startColumn="5" endLine="5" endColumn="6" document="2" /> <entry offset="0x16" startLine="6" startColumn="9" endLine="6" endColumn="13" document="2" /> <entry offset="0x1d" startLine="7" startColumn="9" endLine="7" endColumn="23" document="2" /> <entry offset="0x2b" startLine="8" startColumn="5" endLine="8" endColumn="6" document="2" /> </sequencePoints> <scope startOffset="0x0" endOffset="0x2c"> <scope startOffset="0x15" endOffset="0x2c"> <local name="z" il_index="0" il_start="0x15" il_end="0x2c" attributes="0" /> </scope> </scope> </method> </methods> </symbols> """, format: Microsoft.CodeAnalysis.Emit.DebugInformationFormat.Pdb); comp.VerifyPdb(""" <symbols> <files> <file id="1" name="A.cs" language="C#" checksumAlgorithm="SHA1" checksum="09-65-32-19-5F-F8-8A-58-BF-BC-0C-D3-68-2C-2C-7B-15-33-18-E4" /> <file id="2" name="B.cs" language="C#" checksumAlgorithm="SHA1" checksum="62-4B-E2-91-A3-E9-43-48-4F-A0-E6-E8-22-74-EB-90-24-C3-05-A5" /> </files> <methods> <method containingType="Program" name="F"> <sequencePoints> <entry offset="0x0" startLine="5" startColumn="5" endLine="5" endColumn="6" document="1" /> <entry offset="0x1" startLine="6" startColumn="5" endLine="6" endColumn="6" document="1" /> </sequencePoints> </method> <method containingType="Program" name=".ctor"> <customDebugInfo> <encLocalSlotMap> <slot kind="0" offset="29" /> </encLocalSlotMap> </customDebugInfo> <sequencePoints> <entry offset="0x0" startLine="3" startColumn="5" endLine="3" endColumn="23" document="1" /> <entry offset="0x7" startLine="3" startColumn="5" endLine="3" endColumn="23" document="2" /> <entry offset="0xe" startLine="4" startColumn="5" endLine="4" endColumn="21" document="2" /> <entry offset="0x15" startLine="5" startColumn="5" endLine="5" endColumn="6" document="2" /> <entry offset="0x16" startLine="6" startColumn="9" endLine="6" endColumn="13" document="2" /> <entry offset="0x1d" startLine="7" startColumn="9" endLine="7" endColumn="23" document="2" /> <entry offset="0x2b" startLine="8" startColumn="5" endLine="8" endColumn="6" document="2" /> </sequencePoints> <scope startOffset="0x0" endOffset="0x2c"> <scope startOffset="0x15" endOffset="0x2c"> <local name="z" il_index="0" il_start="0x15" il_end="0x2c" attributes="0" /> </scope> </scope> </method> </methods> </symbols> """, format: Microsoft.CodeAnalysis.Emit.DebugInformationFormat.PortablePdb); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { GetContextState(runtime, "Program..ctor", out var blocks, out var moduleVersionId, out var symReader, out var methodToken, out var localSignatureToken); var appDomain = new AppDomain(); uint ilOffset = ExpressionCompilerTestHelpers.GetOffset(methodToken, symReader); var context = CreateMethodContext( appDomain, blocks, symReader, moduleVersionId, methodToken: methodToken, methodVersion: 1, ilOffset: 0x15, // offset matches startOffset of "z" scope localSignatureToken: localSignatureToken, kind: MakeAssemblyReferencesKind.AllAssemblies); var testData = new CompilationTestData(); var result = context.CompileExpression( "z", out var error, testData); Assert.Null(error); Assert.NotNull(result.Assembly); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 2 (0x2) .maxstack 1 .locals init (int V_0) //z IL_0000: ldloc.0 IL_0001: ret } """); testData = new CompilationTestData(); var locals = ArrayBuilder<LocalAndMethod>.GetInstance(); string typeName; var assembly = context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData); Assert.Equal(2, locals.Count); VerifyLocal(testData, typeName, locals[0], "<>m0", "this", expectedILOpt: """ { // Code size 2 (0x2) .maxstack 1 .locals init (int V_0) //z IL_0000: ldarg.0 IL_0001: ret } """); VerifyLocal(testData, typeName, locals[1], "<>m1", "z", expectedILOpt: """ { // Code size 2 (0x2) .maxstack 1 .locals init (int V_0) //z IL_0000: ldloc.0 IL_0001: ret } """); locals.Free(); }); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66109")] public void SequencePointsMultipleDocuments_02() { var sourceA = """ class A { static void Main() { int x = 1; #line 100 "B.cs" int y = 2; #line 200 "C.cs" int z = 3; } } """; var sourceB = """ class B { } """; var sourceC = """ class C { } """; var comp = CreateCompilation( new[] { SyntaxFactory.ParseSyntaxTree(sourceA, path: "A.cs", encoding: Encoding.Default), SyntaxFactory.ParseSyntaxTree(sourceB, path: "B.cs", encoding: Encoding.Default), SyntaxFactory.ParseSyntaxTree(sourceC, path: "C.cs", encoding: Encoding.Default), }, options: TestOptions.DebugDll); comp.VerifyPdb(""" <symbols> <files> <file id="1" name="A.cs" language="C#" checksumAlgorithm="SHA1" checksum="8E-FF-02-A2-A9-6A-80-AA-31-CC-19-BE-FA-C4-84-88-5B-C8-09-08" /> <file id="2" name="B.cs" language="C#" checksumAlgorithm="SHA1" checksum="29-99-77-37-69-95-33-C4-02-3B-65-8D-5F-61-43-CF-F0-04-61-C2" /> <file id="3" name="C.cs" language="C#" checksumAlgorithm="SHA1" checksum="A2-ED-D2-5C-84-2F-E1-0E-AB-C5-11-C8-51-E6-76-03-C8-5A-6D-06" /> </files> <methods> <method containingType="A" name="Main"> <customDebugInfo> <using> <namespace usingCount="0" /> </using> <encLocalSlotMap> <slot kind="0" offset="15" /> <slot kind="0" offset="53" /> <slot kind="0" offset="91" /> </encLocalSlotMap> </customDebugInfo> <sequencePoints> <entry offset="0x0" startLine="4" startColumn="5" endLine="4" endColumn="6" document="1" /> <entry offset="0x1" startLine="5" startColumn="9" endLine="5" endColumn="19" document="1" /> <entry offset="0x3" startLine="100" startColumn="9" endLine="100" endColumn="19" document="2" /> <entry offset="0x5" startLine="200" startColumn="9" endLine="200" endColumn="19" document="3" /> <entry offset="0x7" startLine="201" startColumn="5" endLine="201" endColumn="6" document="3" /> </sequencePoints> <scope startOffset="0x0" endOffset="0x8"> <local name="x" il_index="0" il_start="0x0" il_end="0x8" attributes="0" /> <local name="y" il_index="1" il_start="0x0" il_end="0x8" attributes="0" /> <local name="z" il_index="2" il_start="0x0" il_end="0x8" attributes="0" /> </scope> </method> </methods> </symbols> """, format: Microsoft.CodeAnalysis.Emit.DebugInformationFormat.Pdb); comp.VerifyPdb(""" <symbols> <files> <file id="1" name="A.cs" language="C#" checksumAlgorithm="SHA1" checksum="8E-FF-02-A2-A9-6A-80-AA-31-CC-19-BE-FA-C4-84-88-5B-C8-09-08" /> <file id="2" name="B.cs" language="C#" checksumAlgorithm="SHA1" checksum="29-99-77-37-69-95-33-C4-02-3B-65-8D-5F-61-43-CF-F0-04-61-C2" /> <file id="3" name="C.cs" language="C#" checksumAlgorithm="SHA1" checksum="A2-ED-D2-5C-84-2F-E1-0E-AB-C5-11-C8-51-E6-76-03-C8-5A-6D-06" /> </files> <methods> <method containingType="A" name="Main"> <customDebugInfo> <using> <namespace usingCount="0" /> </using> <encLocalSlotMap> <slot kind="0" offset="15" /> <slot kind="0" offset="53" /> <slot kind="0" offset="91" /> </encLocalSlotMap> </customDebugInfo> <sequencePoints> <entry offset="0x0" startLine="4" startColumn="5" endLine="4" endColumn="6" document="1" /> <entry offset="0x1" startLine="5" startColumn="9" endLine="5" endColumn="19" document="1" /> <entry offset="0x3" startLine="100" startColumn="9" endLine="100" endColumn="19" document="2" /> <entry offset="0x5" startLine="200" startColumn="9" endLine="200" endColumn="19" document="3" /> <entry offset="0x7" startLine="201" startColumn="5" endLine="201" endColumn="6" document="3" /> </sequencePoints> <scope startOffset="0x0" endOffset="0x8"> <local name="x" il_index="0" il_start="0x0" il_end="0x8" attributes="0" /> <local name="y" il_index="1" il_start="0x0" il_end="0x8" attributes="0" /> <local name="z" il_index="2" il_start="0x0" il_end="0x8" attributes="0" /> </scope> </method> </methods> </symbols> """, format: Microsoft.CodeAnalysis.Emit.DebugInformationFormat.PortablePdb); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "A.Main"); var testData = new CompilationTestData(); var result = context.CompileExpression( "x + y + z", out var error, testData); Assert.Null(error); Assert.NotNull(result.Assembly); testData.GetMethodData("<>x.<>m0").VerifyIL(""" { // Code size 6 (0x6) .maxstack 2 .locals init (int V_0, //x int V_1, //y int V_2) //z IL_0000: ldloc.0 IL_0001: ldloc.1 IL_0002: add IL_0003: ldloc.2 IL_0004: add IL_0005: ret } """); testData = new CompilationTestData(); var locals = ArrayBuilder<LocalAndMethod>.GetInstance(); string typeName; var assembly = context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData); Assert.Equal(3, locals.Count); VerifyLocal(testData, typeName, locals[0], "<>m0", "x", expectedILOpt: """ { // Code size 2 (0x2) .maxstack 1 .locals init (int V_0, //x int V_1, //y int V_2) //z IL_0000: ldloc.0 IL_0001: ret } """); VerifyLocal(testData, typeName, locals[1], "<>m1", "y", expectedILOpt: """ { // Code size 2 (0x2) .maxstack 1 .locals init (int V_0, //x int V_1, //y int V_2) //z IL_0000: ldloc.1 IL_0001: ret } """); VerifyLocal(testData, typeName, locals[2], "<>m2", "z", expectedILOpt: """ { // Code size 2 (0x2) .maxstack 1 .locals init (int V_0, //x int V_1, //y int V_2) //z IL_0000: ldloc.2 IL_0001: ret } """); locals.Free(); }); } [Fact] public void FieldKeyword_01() { var source = @" class C { public int P1 { get { return field; } set { field = value; } } public int P2 { get { #line 100 return field; #line 200 } set { field = value; } } public int P3 { get { return field; } set { field = value; } } } "; var comp = CreateCompilation(source, options: TestOptions.DebugDll); WithRuntimeInstance( comp, references: null, includeLocalSignatures: true, includeIntrinsicAssembly: false, validator: runtime => { var context = CreateMethodContext(runtime, "C.get_P2", atLineNumber: 100); var assembly = context.CompileExpressions( ImmutableArray.Create("field"), out var methodTokens, out var errorMessages); Assert.NotNull(assembly); Assert.True(errorMessages.IsEmpty); Assert.Equal(1, methodTokens.Length); assembly.VerifyIL(methodTokens[0], "<>x0.<>m0", @" Locals: int32 { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: ldfld 0x0A000006 IL_0006: ret } "); }); } } }