Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest staging changes #171

Merged
merged 20 commits into from
Mar 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f34cd5e
fixes multiple issues with array initialization / assignment (#153, #…
adrianoc Feb 24, 2022
d78c9ad
fixes wrong type being used in jagged array instantiations (#159)
adrianoc Mar 3, 2022
f86efaf
fixes wrong IL (stelem.ref) alyways being emited when assigning to el…
adrianoc Mar 3, 2022
419b765
add tests for ref properties (#155)
adrianoc Mar 3, 2022
7c5d3f6
adds support for readonly fields (#157)
adrianoc Mar 4, 2022
7432692
improves mapping snippet <--> cecilified code for a couple of syntax …
adrianoc Mar 4, 2022
a7421f0
code cleanup
adrianoc Mar 4, 2022
caecd1f
use async API
adrianoc Mar 7, 2022
314710d
removes some code duplication in default ctor generation
adrianoc Mar 7, 2022
8b8c5e2
cleans up field initialization a little bit
adrianoc Mar 8, 2022
11497dc
fixes initializer expression being ignored in property declarations (…
adrianoc Mar 8, 2022
1c73986
fixes events with add/remove accessors (#162)
adrianoc Mar 11, 2022
c3a2f59
updates packages
adrianoc Mar 11, 2022
24cd3b0
fixes initializing Span<PrimitiveTypeBiggerThanOneByte> with stackall…
adrianoc Mar 12, 2022
39fab99
renames generated variable name to better reflect intent
adrianoc Mar 12, 2022
959bd1f
fixes stack unbalance when for increment expression is not consumed (…
adrianoc Mar 14, 2022
c2be33b
fixes value being loaded to stack instead its address (#166)
adrianoc Mar 14, 2022
3289469
fixes invalid code generation when overloads takes generic instance t…
adrianoc Mar 16, 2022
97ed14c
fixes invalid method reference on calls to generic methods of generic…
adrianoc Mar 17, 2022
7e96879
fixes invalid IL for calls on forwarded methods taking type parameter…
adrianoc Mar 20, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions Cecilifier.Core.Tests/Cecilifier.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@
<LangVersion>10</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.0.3">
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0-preview-20211109-03" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0-1.final" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0-preview-20220131-20" />
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="ReportGenerator" Version="4.8.9" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Cecilifier.Core\Cecilifier.Core.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class StackAllocWithSpan
Dummy(s);
}

private void SpanOfIntWithConstantRank()
{
Span<int> s = stackalloc int[3];
DummyInt(s);
}

private void PassingAsParameterToStaticMethodSizeFromLocal(int n)
{
int length = 42 * n;
Expand All @@ -30,6 +36,7 @@ class StackAllocWithSpan
*/

private void Dummy(Span<byte> span) {}
private void DummyInt(Span<int> span) {}
private static void StaticDummy(Span<byte> span) {}
private int Size() => 42;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class C<T>
{
public void M(string name, C<int> ci) {}
public void M(string name, C<string> cs) {}

public void Call()
{
M("int", new C<int>());
M("string", new C<string>());
}
}

class Overloads
{
static void Main()
{
var c = new C<int>();
c.Call();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class RefProperties
{
private int field;
ref int Property
{
get => ref field;
}

public ref int UseRefProperty() => ref Property;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class ArraySmokeTests
{
int[] intArrayField = new int[1];

void M(int []intArrayParameter, char [][]charJaggedArrayParameter)
{
var intArrayLocal = new int[2];
System.Console.WriteLine(intArrayLocal[0]);
M(new [] { 3 }, new char [4][]);

charJaggedArrayParameter[42][24] = 'B';
}
}
12 changes: 12 additions & 0 deletions Cecilifier.Core.Tests/Tests/Integration/MethodTestCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,18 @@ public void TestRefLocals()
{
AssertResourceTest("Members/Methods/RefLocals");
}

[Test]
public void TestRefProperties()
{
AssertResourceTest("Members/Methods/RefProperties");
}

[Test]
public void TestOverloads()
{
AssertResourceTest("Members/Methods/Overloads");
}

private void AssertCecilifiedCodeContainsSnippet(string code, string expectedSnippet)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using NUnit.Framework;

namespace Cecilifier.Core.Tests.Integration.Types
{
[TestFixture]
internal class ArraySmokeTests : IntegrationResourceBasedTest
{
[Test]
public void Test()
{
AssertResourceTest(@"Types/ArraySmoke");
}
}
}
100 changes: 95 additions & 5 deletions Cecilifier.Core.Tests/Tests/Unit/ArrayTests.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,112 @@
using Mono.Cecil.Cil;
using NUnit.Framework;

namespace Cecilifier.Core.Tests.Tests.Unit;

[TestFixture]
public class ArrayTests : CecilifierUnitTestBase
{
[TestCase("string")]
[TestCase("C")]
public void TestAccessStringArray(string elementType)
[TestCase("string", Code.Ldelem_Ref)]
[TestCase("C", Code.Ldelem_Ref)]
[TestCase("S", Code.Ldelem_Any, ", st_S_\\d+")]
[TestCase("byte", Code.Ldelem_I1)]
[TestCase("char", Code.Ldelem_I2)]
[TestCase("short", Code.Ldelem_I2)]
[TestCase("int", Code.Ldelem_I4)]
[TestCase("long", Code.Ldelem_I8)]
[TestCase("float", Code.Ldelem_R4)]
[TestCase("double", Code.Ldelem_R8)]
[TestCase("System.DateTime", Code.Ldelem_Any, ", assembly.MainModule.TypeSystem.DateTime")]
public void TestAccessStringArray(string elementType, Code code, string operand="")
{
var result = RunCecilifier($@"class C {{ {elementType} M({elementType} []a) => a[2]; }}");
var result = RunCecilifier($@"struct S {{}} class C {{ {elementType} M({elementType} []a) => a[2]; }}");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();

Assert.That(
cecilifiedCode,
Does.Match(
@"(.+\.Emit\(OpCodes\.)Ldarg_1\);\s+" +
@"\1Ldc_I4, 2\);\s+" +
@"\1Ldelem_Ref\);"));
$@"\1{code}{operand}\);"));
}

[TestCase("string", Code.Stelem_Ref)]
[TestCase("C", Code.Stelem_Ref)]
[TestCase("byte", Code.Stelem_I1)]
[TestCase("char", Code.Stelem_I2)]
[TestCase("short", Code.Stelem_I2)]
[TestCase("int", Code.Stelem_I4)]
[TestCase("long", Code.Stelem_I8)]
[TestCase("float", Code.Stelem_R4)]
[TestCase("double", Code.Stelem_R8)]
[TestCase("System.DateTime", Code.Stelem_Any, ", assembly.MainModule.TypeSystem.DateTime")]
[TestCase("S", Code.Stelem_Any, @", st_S_\d+")]
public void TestArrayCreation(string elementType, Code code, string operand="")
{
var result = RunCecilifier($@"struct S {{}} class C {{ void M({elementType} value) {{ var data = new[] {{ value }}; }} }}");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();

Assert.That(
cecilifiedCode,
Does.Match(
@"(.+\.Emit\(OpCodes\.)Dup\);\s+" +
@"\1Ldc_I4, 0\);\s+" +
@"\1Ldarg_1.+\s+" +
$@"\1{code}{operand}\);\s+"));
}

[TestCase("System.String")]
[TestCase("C", @"cls_C_\d+")]
[TestCase("System.Byte")]
[TestCase("System.Char")]
[TestCase("System.Int16")]
[TestCase("System.Int32")]
[TestCase("System.Int64")]
[TestCase("System.Single")]
[TestCase("System.Double")]
[TestCase("System.DateTime")]
[TestCase("S", @"st_S_\d+")]
public void TestJaggedArrayCreation(string elementType, string operand=null)
{
var result = RunCecilifier($@"struct S {{}} class C {{ void M({elementType} value) {{ var data = new {elementType}[42][]; }} }}");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();

var operandTypeMatch = operand ?? $"assembly.MainModule.Type{elementType}";

Assert.That(cecilifiedCode, Does.Match($@"new VariableDefinition\({operandTypeMatch}.MakeArrayType\(\).MakeArrayType\(\)\);\s+"));

Assert.That(
cecilifiedCode,
Does.Match(
@"(.+\.Emit\(OpCodes\.)Ldc_I4, 42\);\s+" +
$@"\1Newarr, {operandTypeMatch}.MakeArrayType\(\)\);\s+"));
}

[TestCase("string", Code.Stelem_Ref)]
[TestCase("C", Code.Stelem_Ref)]
[TestCase("byte", Code.Stelem_I1)]
[TestCase("char", Code.Stelem_I2)]
[TestCase("short", Code.Stelem_I2)]
[TestCase("int", Code.Stelem_I4)]
[TestCase("long", Code.Stelem_I8)]
[TestCase("float", Code.Stelem_R4)]
[TestCase("double", Code.Stelem_R8)]
[TestCase("System.DateTime", Code.Stelem_Any, ", assembly.MainModule.TypeSystem.DateTime")]
[TestCase("S", Code.Stelem_Any, @", st_S_\d+")]
public void TestJaggedArrayAssignment(string elementType, Code code, string operand="")
{
var result = RunCecilifier($@"struct S {{}} class C {{ void M({elementType} [][]array, {elementType} value) {{ array[0][1] = value; }} }}");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();

Assert.That(
cecilifiedCode,
Does.Match(
@"//array\[0\]\[1\] = value;\s+" +
@"(.+Emit\(OpCodes\.)Ldarg_1\);\s+" +
@"\1Ldc_I4, 0.+\s+" +
@"\1Ldelem_Ref.+\s+" +
@"\1Ldc_I4, 1.+\s+" +
@"\1Ldarg_2.+\s+" +
$@"\1{code}{operand}.+;"));
}
}
78 changes: 78 additions & 0 deletions Cecilifier.Core.Tests/Tests/Unit/EventsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using NUnit.Framework;

namespace Cecilifier.Core.Tests.Tests.Unit;

[TestFixture]
public class EventsTests : CecilifierUnitTestBase
{
[Test]
public void EventDeclaration()
{
var code = @"using System;
class C
{
event Action E
{
add { Console.WriteLine(""add""); }
remove { Console.WriteLine(""remove""); }
}
}";

var result = RunCecilifier(code);

var cecilified = result.GeneratedCode.ReadToEnd();

Assert.That(cecilified, Does.Match(@"cls_C_0.Events.Add\(evt_E_\d+\);"));
Assert.That(cecilified, Does.Match(@"var m_add_\d+ = new MethodDefinition\(""add_E"", .+, assembly.MainModule.TypeSystem.Void\);"));
Assert.That(cecilified, Does.Match(@"m_add_\d+.Parameters.Add\(.*Action.*\);"));
Assert.That(cecilified, Does.Match(@"var il_add_\d+ = m_add_\d+.Body.GetILProcessor\(\);"));

Assert.That(cecilified, Does.Match(@"var m_remove_\d+ = new MethodDefinition\(""remove_E"", .+, assembly.MainModule.TypeSystem.Void\);"));
Assert.That(cecilified, Does.Match(@"m_remove_\d+.Parameters.Add\(.*Action.*\);"));
Assert.That(cecilified, Does.Match(@"var il_remove_\d+ = m_remove_\d+.Body.GetILProcessor\(\);"));

Assert.That(cecilified, Does.Match(@"cls_C_\d+.Methods.Add\(m_add_\d+\);"));
Assert.That(cecilified, Does.Match(@"cls_C_\d+.Methods.Add\(m_remove_\d+\);"));
}

[Test]
public void EventSubscription()
{
var code = @"using System;
class C
{
event Action E { add { Console.WriteLine(""add""); } remove { Console.WriteLine(""remove""); } }
void Sub(Action a)
{
E += a;
E -= a;
}
}";

var result = RunCecilifier(code);

var cecilified = result.GeneratedCode.ReadToEnd();

Assert.That(cecilified, Does.Match(@"Call, m_add_\d+"));
Assert.That(cecilified, Does.Match(@"Call, m_remove_\d+"));
}

[Test]
public void ForwardMethodReferenceTest()
{
var code = @"using System;
class C
{
event Action E;
void Sub() { E += M; }

void M() {}
}";

var result = RunCecilifier(code);

var cecilified = result.GeneratedCode.ReadToEnd();

Assert.That(cecilified, Does.Match(@"Call, m_add_\d+"));
}
}
21 changes: 12 additions & 9 deletions Cecilifier.Core.Tests/Tests/Unit/FieldsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ public void TestFieldAsMemberReferences(string code, params string[] instruction
Assert.That(cecilifiedCode, Does.Match(expectedSnippet));
}

// [Test]
// public void TestExternalInstanceFields()
// {
// const string code = "class ExternalInstanceFields { int Instance(System.ValueTuple<int> t) => t.Item1; }";
// var result = RunCecilifier(code);
// var cecilifiedCode = result.GeneratedCode.ReadToEnd();
//
// Assert.That(cecilifiedCode, Contains.Substring("XX FORCE IT TO FAIL XX;"));
// }
[Test]
public void TestReadOnlyField()
{
var result = RunCecilifier("class Foo { readonly int ro = 42; }");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();

Assert.That(
cecilifiedCode,
Does.Match(
@"var fld_ro_1 = new FieldDefinition\(""ro"", .+InitOnly.+Int32\);\s+" +
@"cls_foo_0.Fields.Add\(fld_ro_1\);"));
}
}
27 changes: 27 additions & 0 deletions Cecilifier.Core.Tests/Tests/Unit/ForStatementTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using NUnit.Framework;

namespace Cecilifier.Core.Tests.Tests.Unit;

[TestFixture]
public class ForStatementTests : CecilifierUnitTestBase
{
[TestCase ("parameter++", true)]
[TestCase("local++", true)]
[TestCase("field++", true)]
[TestCase("F()", true)]
[TestCase ("localDummy = parameter++", false)]
[TestCase("localDummy = local++", false)]
[TestCase("localDummy = field++", false)]
[TestCase("localDummy = F()", false)]
public void TestForIncrement_IsPopped_IfNotConsumed(string value, bool expectPop)
{
var result = RunCecilifier($@"class C {{ int F() => 0; int field; void M(int parameter) {{ int localDummy; int local = parameter; for(int x = 0; x < 1; {value}); }} }}");
var cecilifiedCode = result.GeneratedCode.ReadToEnd();

Assert.That(
cecilifiedCode,
expectPop
? Does.Contain("Pop")
: Does.Not.Contains("Pop"));
}
}
Loading