diff --git a/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs b/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs index 70df0509..2ee60fb0 100644 --- a/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs @@ -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; diff --git a/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs b/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs index d673e4d2..e2e19b0e 100644 --- a/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs +++ b/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Mono.Cecil; +using System.Linq; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables { @@ -12,12 +13,18 @@ namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables 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 @@ -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 } } diff --git a/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj b/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj index 601594f3..04374fb8 100644 --- a/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj +++ b/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj @@ -32,6 +32,7 @@ + diff --git a/MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs b/MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs new file mode 100644 index 00000000..dd34d0d5 --- /dev/null +++ b/MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs @@ -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; + } + } + } +} diff --git a/MetadataProcessor.Tests/TestObjectHelper.cs b/MetadataProcessor.Tests/TestObjectHelper.cs index 863e875d..d4366e9b 100644 --- a/MetadataProcessor.Tests/TestObjectHelper.cs +++ b/MetadataProcessor.Tests/TestObjectHelper.cs @@ -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, @@ -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); + } } }