Skip to content

Method flags now processes finalizer #169

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

Merged
merged 1 commit into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,13 @@ public static uint GetFlags(MethodDefinition method)
flag |= (method.IsStatic ? MD_StaticConstructor : MD_Constructor);
}

if(method.Name == "Finalize"
&& method.ReturnType.FullName == "System.Void"
&& method.Parameters.Count == 0)
{
flag |= MD_Finalizer;
}

if (method.IsSynchronized)
{
flag |= MD_Synchronized;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Mono.Cecil;
using System.Linq;

namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables
{
[TestClass]
public class nanoMethodDefinitionTableTests
{
private TypeDefinition _testDelegatesClassTypeDefinition;
private TypeDefinition _destructorTestClassTypeDefinition;
private TypeDefinition _destructorAnotherTestClassTypeDefinition;
private TypeDefinition _destructorAnotherBaseClassTypeDefinition;

[TestInitialize]
public void Setup()
{
var nanoTablesContext = TestObjectHelper.GetTestNFAppNanoTablesContext();
_testDelegatesClassTypeDefinition = TestObjectHelper.GetTestNFAppTestingDelegatesTypeDefinition(nanoTablesContext.AssemblyDefinition);
_destructorTestClassTypeDefinition = TestObjectHelper.GetTestNFAppDestructorsTestClassTypeDefinition(nanoTablesContext.AssemblyDefinition);
_destructorAnotherTestClassTypeDefinition = TestObjectHelper.GetTestNFAppDestructorsTestAnotherClassTypeDefinition(nanoTablesContext.AssemblyDefinition);
_destructorAnotherBaseClassTypeDefinition = TestObjectHelper.GetTestNFAppDestructorsTestAnotherClassBaseTypeDefinition(nanoTablesContext.AssemblyDefinition);
}

#region delegate method flags
Expand Down Expand Up @@ -75,5 +82,45 @@ public void TestDelegateEndInvokeMethodReturnsDelegateEndInvokeFlag()
}

#endregion

#region finalizer method flags

[DataRow("DestructorsTestClass")]
[DataRow("DestructorsTestAnotherClass")]
[DataRow("DestructorsTestAnotherClassBase")]
[TestMethod]
public void TestFinalizerMethodReturnsFinalizerFlag(string className)
{
// Arrange
MethodDefinition methodDefinition = null;

if (className == "DestructorsTestClass")
{
methodDefinition = _destructorTestClassTypeDefinition.Methods.First(m => m.Name == "Finalize");
}
else if (className == "DestructorsTestAnotherClass")
{
methodDefinition = _destructorAnotherTestClassTypeDefinition.Methods.First(m => m.Name == "Finalize");
}
else if (className == "DestructorsTestAnotherClassBase")
{
methodDefinition = _destructorAnotherBaseClassTypeDefinition.Methods.First(m => m.Name == "Finalize");
}
else
{
Assert.Fail("Invalid class name.");
}

Assert.IsNotNull(methodDefinition, "Finalizer method not found.");

// Act
uint flags = nanoMethodDefinitionTable.GetFlags(methodDefinition);

// Assert
const uint expectedFlag = 0x00004000; // MD_Finalizer
Assert.IsTrue((flags & expectedFlag) == expectedFlag, "Expected flag not set for Finalizer method.");
}

#endregion
}
}
1 change: 1 addition & 0 deletions MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<Compile Include="OneClassOverAll.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestingDestructors.cs" />
<Compile Include="TestingDelegates.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
133 changes: 133 additions & 0 deletions MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

using System;

namespace TestNFApp
{
public class TestingDestructors
{
public TestingDestructors()
{
Console.WriteLine("Test Destructors class 3");

if (DestructorsTestClass.TestMethod())
{
Console.WriteLine("Test Destructors class 3 passed!");
}
else
{
Console.WriteLine("Test Destructors class 3 failed!");
}

Console.WriteLine("Test Destructors class 4");
if (DestructorsTestAnotherClass.TestMethod())
{
Console.WriteLine("Test Destructors class 4 passed!");
}
else
{
Console.WriteLine("Test Destructors class 4 failed!");
}

Console.WriteLine("Test destructors completed!");
}
}

public class DestructorsTestClass
{
static int intI = 1;

~DestructorsTestClass()
{
// Calling Destructor for Test Class 3
intI = 2;

Console.WriteLine("Calling Destructor for Test Class 3");
}

public static bool TestMethod()
{
DestructorsTestClass mc = new DestructorsTestClass();
mc = null;

// should be calling GC
// nanoFramework.Runtime.Native.GC.Run(true);

int sleepTime = 5000;
int slept = 0;

while (intI != 2 && slept < sleepTime)
{
System.Threading.Thread.Sleep(10);
slept += 10;
}

// Thread has slept for
Console.WriteLine($"Thread has slept for {slept}");

if (intI == 2)
{
return true;
}
else
{
return false;
}
}
}

public class DestructorsTestAnotherClassBase
{
public static int intI = 2;

~DestructorsTestAnotherClassBase()
{
intI = intI * 2;

Console.WriteLine("Calling Destructor for Test Class 4 Base");
}
}

public class DestructorsTestAnotherClass : DestructorsTestAnotherClassBase
{
~DestructorsTestAnotherClass()
{
intI = intI + 2;

Console.WriteLine("Calling Destructor for Test Class 4");
}

public static bool TestMethod()
{
DestructorsTestAnotherClass mc = new DestructorsTestAnotherClass();

mc = null;

// should be calling GC
// nanoFramework.Runtime.Native.GC.Run(true);

int sleepTime = 5000;
int slept = 0;

while (intI != 8 && slept < sleepTime)
{
System.Threading.Thread.Sleep(10);
slept += 10;
}

Console.WriteLine($"Thread has slept for {slept}");

if (intI == 8)
{
return true;
}
else
{
return false;
}
}
}
}
47 changes: 47 additions & 0 deletions MetadataProcessor.Tests/TestObjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,46 @@ internal static TypeDefinition GetTestNFAppTestingDelegatesTypeDefinition(Assemb
return ret;
}

internal static TypeDefinition GetTestNFAppTestingDestructorsTypeDefinition(AssemblyDefinition assemblyDefinition)
{
TypeDefinition ret = null;

var module = assemblyDefinition.Modules[0];
ret = module.Types.First(i => i.FullName == "TestNFApp.TestingDestructors");

return ret;
}

internal static TypeDefinition GetTestNFAppDestructorsTestClassTypeDefinition(AssemblyDefinition assemblyDefinition)
{
TypeDefinition ret = null;

var module = assemblyDefinition.Modules[0];
ret = module.Types.First(i => i.FullName == "TestNFApp.DestructorsTestClass");

return ret;
}

internal static TypeDefinition GetTestNFAppDestructorsTestAnotherClassBaseTypeDefinition(AssemblyDefinition assemblyDefinition)
{
TypeDefinition ret = null;

var module = assemblyDefinition.Modules[0];
ret = module.Types.First(i => i.FullName == "TestNFApp.DestructorsTestAnotherClassBase");

return ret;
}

internal static TypeDefinition GetTestNFAppDestructorsTestAnotherClassTypeDefinition(AssemblyDefinition assemblyDefinition)
{
TypeDefinition ret = null;

var module = assemblyDefinition.Modules[0];
ret = module.Types.First(i => i.FullName == "TestNFApp.DestructorsTestAnotherClass");

return ret;
}

internal static MethodDefinition GetMethodDefinition(
TypeDefinition typeDefinition,
string delegateName,
Expand All @@ -393,5 +433,12 @@ internal static MethodDefinition GetMethodDefinition(
var delegateType = typeDefinition.NestedTypes.First(nt => nt.Name == delegateName);
return delegateType.Methods.First(m => m.Name == methodName);
}

internal static MethodDefinition GetMethodDefinition(
TypeDefinition typeDefinition,
string methodName)
{
return typeDefinition.Methods.First(m => m.Name == methodName);
}
}
}