-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathLocalFunctionTests.cs
100 lines (82 loc) · 4.44 KB
/
LocalFunctionTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using Cecilifier.Core.Tests.Tests.Unit.Framework;
using NUnit.Framework;
namespace Cecilifier.Core.Tests.Tests.Unit;
[TestFixture]
public class LocalFunctionTests : CecilifierUnitTestBase
{
[Test]
public void InTopLevel_Statements([Values("static", "")] string staticOrInstance)
{
var result = RunCecilifier($"{staticOrInstance} int LocalFoo() => 42; System.Console.WriteLine(LocalFoo());");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();
Assert.That(
cecilifiedCode,
Contains.Substring("var m_localFoo_6 = new MethodDefinition(\"<<Main>$>g__LocalFoo|0_0\", MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig, assembly.MainModule.TypeSystem.Int32);"),
cecilifiedCode);
// asserts that il_topLevelMain_3 is the variable holding the ILProcessor for the top level statement body.
Assert.That(cecilifiedCode, Contains.Substring("var il_topLevelMain_3 = m_topLevelStatements_1.Body.GetILProcessor();"), cecilifiedCode);
Assert.That(
cecilifiedCode,
Does.Not.Match(@"il_topLevelMain_3.Emit\(OpCodes.Ldarg_0\);"),
"Looks like local function is being handled as instance method, instead of a static one.");
}
[Test]
public void InTopLevel_Statements_ForwardReferenced([Values("static", "")] string staticOrInstance)
{
var result = RunCecilifier($"System.Console.WriteLine(LocalFoo()); {staticOrInstance} int LocalFoo() => 42;");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();
Assert.That(
cecilifiedCode,
Contains.Substring("var m_localFoo_6 = new MethodDefinition(\"<<Main>$>g__LocalFoo|0_0\", MethodAttributes.Private, assembly.MainModule.TypeSystem.Int32);"));
// asserts that il_topLevelMain_3 is the variable holding the ILProcessor for the top level statement body.
Assert.That(cecilifiedCode, Contains.Substring("var il_topLevelMain_3 = m_topLevelStatements_1.Body.GetILProcessor();"));
Assert.That(
cecilifiedCode,
Does.Not.Match(@"il_topLevelMain_3.Emit\(OpCodes.Ldarg_0\);"),
"Looks like local function is being handled as instance method, instead of a static one.");
}
[Test]
public void InTopLevel_Class([Values("static", "")] string staticOrInstance)
{
var result = RunCecilifier($"class Bar {{ void Normal() {{ {staticOrInstance} int LocalFoo() => 42; System.Console.WriteLine(LocalFoo()); }} }}");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();
Assert.That(
cecilifiedCode,
Does.Match("var m_localFoo_3 = new MethodDefinition\\(\"<Normal>g__LocalFoo|0_0\", MethodAttributes.Assembly \\| MethodAttributes.Static \\| MethodAttributes.HideBySig, .*\\);"));
Assert.That(
cecilifiedCode,
Does.Not.Match(@"l_normal_2.Emit\(OpCodes.Ldarg_0\);"),
"Looks like local function is being handled as instance method, instead of a static one.");
Assert.That(
cecilifiedCode,
Does.Match(@"//System.Console.WriteLine\(LocalFoo\(\)\);\s+il_normal_2.Emit\(OpCodes.Call, m_localFoo_3\);"));
}
[TestCase("""
M(10);
void M<T>(T t) => System.Console.WriteLine(t);
""", Description = "Issue=#268", TestName = "Top level")]
[TestCase("""
class Foo
{
void Call()
{
M(10);
void M<T>(T t) => System.Console.WriteLine(t);
}
}
""", Description = "Issue=#268", TestName = "Forward reference in method")]
public void GenericLocalFunctions_DoesNotReferencesTypeParameters_ThroughReflection(string snippetToTest)
{
var result = RunCecilifier(snippetToTest);
var cecilifiedCode = result.GeneratedCode.ReadToEnd();
Assert.That(cecilifiedCode, Does.Not.Contain("typeof(T)"));
Assert.Multiple(() =>
{
Assert.That(cecilifiedCode, Does.Match("""
\s+var (p_t_\d+) = new ParameterDefinition\("t", ParameterAttributes.None, gp_T_\d+\);
\s+m_M_\d+.Parameters.Add\(\1\);
"""));
Assert.That(cecilifiedCode, Does.Match(@"il_M_\d+.Emit\(OpCodes.Box, gp_T_\d+\);"));
});
}
}