From 6d05762d54a56309e49e6d8b70dca272e78e3e19 Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Thu, 24 Dec 2020 12:43:30 +0100 Subject: Fixes removal of unused assembly references for linked assemblies (#1683) --- .../Metadata/SetupCompileAfterAttribute.cs | 2 +- .../Mono.Linker.Tests.Cases.csproj | 3 + .../AssemblyReferenceIsRemovedWhenUnused.cs | 22 ++++ .../AssemblyReferenceIsRemovedWhenUnusedLib.cs | 17 +++ ...emblyReferenceIsRemovedWhenUnused_RefLibrary.cs | 9 ++ .../TypeForwardedIsUpdatedForMissingTypeFwd.cs | 1 + .../TypeForwardedIsUpdatedForMissingTypeLib.cs | 6 + .../TypeForwardedIsUpdatedForMissingTypeLib2.cs | 6 + .../TypeForwardersRewriteForwarders.cs | 4 + .../Dependencies/TypeForwardersRewriteLib.cs | 24 ++++ .../TypeForwardedIsUpdatedForMissingType.cs | 33 ++++++ .../TypeForwarding/TypeForwardersRewrite.cs | 130 +++++++++++++++++++++ .../UsedForwarderIsRemovedWhenLink.cs | 1 + test/Mono.Linker.Tests/Mono.Linker.Tests.csproj | 2 +- .../TestCasesRunner/TestCaseCompiler.cs | 11 +- .../TestCasesRunner/TestRunner.cs | 1 + 16 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 test/Mono.Linker.Tests.Cases/References/AssemblyReferenceIsRemovedWhenUnused.cs create mode 100644 test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnusedLib.cs create mode 100644 test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnused_RefLibrary.cs create mode 100644 test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeFwd.cs create mode 100644 test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib.cs create mode 100644 test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib2.cs create mode 100644 test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteForwarders.cs create mode 100644 test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteLib.cs create mode 100644 test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardedIsUpdatedForMissingType.cs create mode 100644 test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardersRewrite.cs (limited to 'test') diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs index 199d9b495..54bcd6ca0 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs @@ -8,7 +8,7 @@ namespace Mono.Linker.Tests.Cases.Expectations.Metadata [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] public class SetupCompileAfterAttribute : BaseMetadataAttribute { - public SetupCompileAfterAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null) + public SetupCompileAfterAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false) { if (sourceFiles == null) throw new ArgumentNullException (nameof (sourceFiles)); diff --git a/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj b/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj index b3069ab7c..d3522b05e 100644 --- a/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj +++ b/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj @@ -26,6 +26,9 @@ + + + diff --git a/test/Mono.Linker.Tests.Cases/References/AssemblyReferenceIsRemovedWhenUnused.cs b/test/Mono.Linker.Tests.Cases/References/AssemblyReferenceIsRemovedWhenUnused.cs new file mode 100644 index 000000000..56581f512 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/References/AssemblyReferenceIsRemovedWhenUnused.cs @@ -0,0 +1,22 @@ +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.References.Dependencies; + +namespace Mono.Linker.Tests.Cases.References +{ + [SetupCompileBefore ("library1.dll", new[] { "Dependencies/AssemblyReferenceIsRemovedWhenUnusedLib.cs" })] + + [RemovedAssembly ("library1.dll")] + [RemovedAssemblyReference ("test", "library1")] + class AssemblyReferenceIsRemovedWhenUnused + { + public static void Main () + { + } + + static void Unused () + { + new AssemblyReferenceIsRemovedWhenUnusedLib ().UsedMethod (); + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnusedLib.cs b/test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnusedLib.cs new file mode 100644 index 000000000..72df62f7c --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnusedLib.cs @@ -0,0 +1,17 @@ +using System; + +namespace Mono.Linker.Tests.Cases.References.Dependencies +{ + public class AssemblyReferenceIsRemovedWhenUnusedLib + { + public void UsedMethod () + { + Console.WriteLine ("Used"); + } + + public void UnusedMethod () + { + Console.WriteLine ("NotUsed"); + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnused_RefLibrary.cs b/test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnused_RefLibrary.cs new file mode 100644 index 000000000..249145ea4 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/References/Dependencies/AssemblyReferenceIsRemovedWhenUnused_RefLibrary.cs @@ -0,0 +1,9 @@ +namespace Mono.Linker.Tests.Cases.References.Dependencies +{ + public class AssemblyReferenceIsRemovedWhenUnused + { + public static void UsedMethodLib () + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeFwd.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeFwd.cs new file mode 100644 index 000000000..7145725e4 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeFwd.cs @@ -0,0 +1 @@ +[assembly: System.Runtime.CompilerServices.TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.TypeForwarding.C1))] diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib.cs new file mode 100644 index 000000000..ec8389b0d --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib.cs @@ -0,0 +1,6 @@ +namespace Mono.Linker.Tests.Cases.TypeForwarding +{ + public class C1 + { + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib2.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib2.cs new file mode 100644 index 000000000..58dc0d77b --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardedIsUpdatedForMissingTypeLib2.cs @@ -0,0 +1,6 @@ +namespace Mono.Linker.Tests.Cases.TypeForwarding +{ + public class C2 + { + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteForwarders.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteForwarders.cs new file mode 100644 index 000000000..cb79a2f0d --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteForwarders.cs @@ -0,0 +1,4 @@ +[assembly: System.Runtime.CompilerServices.TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.TypeForwarding.C))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.TypeForwarding.G<>))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.TypeForwarding.I))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.TypeForwarding.S))] \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteLib.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteLib.cs new file mode 100644 index 000000000..6c5c01fff --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/Dependencies/TypeForwardersRewriteLib.cs @@ -0,0 +1,24 @@ +namespace Mono.Linker.Tests.Cases.TypeForwarding +{ + public class C + { + + } + + public class G + { + public class N + { + } + } + + public struct S + { + + } + + public interface I + { + public void Test (C c); + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardedIsUpdatedForMissingType.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardedIsUpdatedForMissingType.cs new file mode 100644 index 000000000..a5e019cb0 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardedIsUpdatedForMissingType.cs @@ -0,0 +1,33 @@ +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.TypeForwarding +{ + [SkipUnresolved (true)] + [KeepTypeForwarderOnlyAssemblies ("false")] + [SetupCompileBefore ("Lib.dll", new[] { "Dependencies/TypeForwardedIsUpdatedForMissingTypeLib.cs" })] + [SetupCompileBefore ("AnotherLibrary.dll", new[] { "Dependencies/TypeForwardedIsUpdatedForMissingTypeLib2.cs" })] + + [SetupCompileAfter ("AnotherLibrary.dll", new[] { "Dependencies/TypeForwardedIsUpdatedForMissingTypeLib2.cs" })] + [SetupCompileAfter ("Implementation.dll", new[] { "Dependencies/TypeForwardedIsUpdatedForMissingTypeLib.cs" }, removeFromLinkerInput: true)] + [SetupCompileAfter ("Lib.dll", new[] { "Dependencies/TypeForwardedIsUpdatedForMissingTypeFwd.cs" }, references: new[] { "Implementation.dll" })] + + public class TypeForwardedIsUpdatedForMissingType + { + public static void Main () + { + Test (null); + } + + // It's important that the assembly reference to AnotherLibrary is added before Lib + public void DependencyWhichIsRemovedFromAssemblyList (C2 c) + { + } + + [Kept] + static void Test (C1 c) + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardersRewrite.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardersRewrite.cs new file mode 100644 index 000000000..754d2c282 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/TypeForwardersRewrite.cs @@ -0,0 +1,130 @@ +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.TypeForwarding +{ + // Actions: + // link - This assembly, Forwarder.dll and Implementation.dll + [KeepTypeForwarderOnlyAssemblies ("false")] + + [SetupLinkerArgument ("--skip-unresolved", "true")] + + [SetupCompileArgument ("/unsafe")] + [SetupCompileBefore ("Forwarder.dll", new[] { "Dependencies/TypeForwardersRewriteLib.cs" })] + + [SetupCompileAfter ("Implementation.dll", new[] { "Dependencies/TypeForwardersRewriteLib.cs" })] + [SetupCompileAfter ("Forwarder.dll", new[] { "Dependencies/TypeForwardersRewriteForwarders.cs" }, references: new[] { "Implementation.dll" })] + + [RemovedAssembly ("Forwarder.dll")] + [RemovedAssemblyReference ("test", "Forwarder")] + unsafe class TypeForwardersRewrite + { + static void Main () + { +#if NETCOREAPP + Test (null); +#endif + Test2 (null); + Test3 (ref c); + Test4 (null, null); + Test5 (null); + Test6 (null); + c = null; + g = null; + e += null; + I tc = new TC (); + tc.Test (null); + I ti = new TS (); + ti.Test (null); + var gc = new GC (); + } + + [Kept] + static C c; + [Kept] + static G g; + + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + static event D e; + + [Kept] + [KeptBaseType (typeof (MulticastDelegate))] + [KeptMember (".ctor(System.Object,System.IntPtr)")] + [KeptMember ("Invoke()")] + delegate C D (); + +#if NETCOREAPP + [Kept] + static void Test (delegate* arg) + { + } +#endif + + [Kept] + static C Test2 (C c) + { + C lv = null; + return lv; + } + + [Kept] + static C[] Test3 (ref C c) where T : C + { + return null; + } + + [Kept] + static G Test4 (G[] a, object b) + { + Console.WriteLine (typeof (C)); + Console.WriteLine (typeof (G<>)); + Console.WriteLine (typeof (G<>.N)); + C c = (C) b; + Console.WriteLine (c); + return null; + } + + [Kept] + static G.N Test5 (G.N arg) + { + return null; + } + + [Kept] + static void Test6 (G.N arg) + { + } + + [Kept] + [KeptBaseType (typeof (C))] + [KeptMember (".ctor()")] + [KeptInterface (typeof (I))] + class TC : C, I + { + [Kept] + void I.Test (C c) + { + } + } + + [Kept] + [KeptInterface (typeof (I))] + struct TS : I + { + [Kept] + public void Test (C c) + { + } + } + + [Kept] + [KeptMember (".ctor()")] + class GC where T : I + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedForwarderIsRemovedWhenLink.cs b/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedForwarderIsRemovedWhenLink.cs index deef0e497..23b8ddc1e 100644 --- a/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedForwarderIsRemovedWhenLink.cs +++ b/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedForwarderIsRemovedWhenLink.cs @@ -18,6 +18,7 @@ namespace Mono.Linker.Tests.Cases.TypeForwarding [SetupCompileAfter ("Forwarder.dll", new[] { "Dependencies/ForwarderLibrary.cs" }, references: new[] { "Implementation.dll" })] [RemovedAssembly ("Forwarder.dll")] + [RemovedAssemblyReference ("test", "Forwarder")] [KeptMemberInAssembly ("Implementation.dll", typeof (ImplementationLibrary), "GetSomeValue()")] [KeptMemberInAssembly ("Library.dll", typeof (LibraryUsingForwarder), "GetValueFromOtherAssembly()")] class UsedForwarderIsRemovedWhenLink diff --git a/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj b/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj index 56c70481a..c9136c801 100644 --- a/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj +++ b/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj @@ -31,7 +31,7 @@ - +