diff options
author | Mike Voorhees <michaelv@unity3d.com> | 2017-05-10 00:20:26 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2017-05-11 22:21:05 +0300 |
commit | 7fadbac85790cde18d7daed6ab38fd8b205b127f (patch) | |
tree | 12a1a6799777b63c697bdb1b7da057691a1ada4c /linker/Tests | |
parent | 98d8cffc84cdc3101267587f158b17467cb21ee5 (diff) |
Implement Kept & Removed Member in assembly
Diffstat (limited to 'linker/Tests')
6 files changed, 155 insertions, 2 deletions
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberInAssemblyAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberInAssemblyAttribute.cs new file mode 100644 index 000000000..31dd5131d --- /dev/null +++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberInAssemblyAttribute.cs @@ -0,0 +1,18 @@ +using System; + + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions { + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class KeptMemberInAssemblyAttribute : BaseExpectedLinkedBehaviorAttribute { + public readonly string AssemblyFileName; + public readonly Type Type; + public readonly string [] MemberNames; + + public KeptMemberInAssemblyAttribute (string assemblyFileName, Type type, params string [] memberNames) + { + AssemblyFileName = assemblyFileName; + Type = type; + MemberNames = memberNames; + } + } +} diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedMemberInAssemblyAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedMemberInAssemblyAttribute.cs new file mode 100644 index 000000000..3bcd63b9d --- /dev/null +++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedMemberInAssemblyAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions { + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class RemovedMemberInAssemblyAttribute : BaseExpectedLinkedBehaviorAttribute { + public readonly string AssemblyFileName; + public readonly Type Type; + public readonly string [] MemberNames; + + public RemovedMemberInAssemblyAttribute (string assemblyFileName, Type type, params string [] memberNames) + { + AssemblyFileName = assemblyFileName; + Type = type; + MemberNames = memberNames; + } + } +} diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj index a9ba2d50b..d330e6c40 100644 --- a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj +++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj @@ -43,8 +43,10 @@ <Compile Include="Assertions\BaseExpectedLinkedBehaviorAttribute.cs" /> <Compile Include="Assertions\KeptBackingFieldAttribute.cs" /> <Compile Include="Assertions\KeptMemberAttribute.cs" /> + <Compile Include="Assertions\KeptMemberInAssemblyAttribute.cs" /> <Compile Include="Assertions\KeptTypeInAssemblyAttribute.cs" /> <Compile Include="Assertions\RemovedAssemblyAttribute.cs" /> + <Compile Include="Assertions\RemovedMemberInAssemblyAttribute.cs" /> <Compile Include="Assertions\RemovedTypeInAssemblyAttribute.cs" /> <Compile Include="Metadata\BaseMetadataAttribute.cs" /> <Compile Include="Metadata\CoreLinkAttribute.cs" /> diff --git a/linker/Tests/Mono.Linker.Tests.Cases/CoreLink/LinkingOfCoreLibrariesRemovesUnusedMethods.cs b/linker/Tests/Mono.Linker.Tests.Cases/CoreLink/LinkingOfCoreLibrariesRemovesUnusedMethods.cs new file mode 100644 index 000000000..78b460939 --- /dev/null +++ b/linker/Tests/Mono.Linker.Tests.Cases/CoreLink/LinkingOfCoreLibrariesRemovesUnusedMethods.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections; +using System.IO; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.CoreLink +{ + [CoreLink ("link")] + + [KeptAssembly ("mscorlib.dll")] + [KeptMemberInAssembly ("mscorlib.dll", typeof (Stack), ".ctor(System.Int32)", "Pop()", "Push(System.Object)")] + // We can't check everything that should be removed, but we should be able to check a few niche things that + // we known should be removed which will at least verify that the core library was processed + [RemovedMemberInAssembly ("mscorlib.dll", typeof (Stack), ".ctor(System.Collections.ICollection)")] + class LinkingOfCoreLibrariesRemovesUnusedMethods { + public static void Main() + { + Stack stack = new Stack (2); + stack.Push (1); + var val = stack.Pop (); + } + } +} diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj b/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj index 49463ed70..74325a8ac 100644 --- a/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj +++ b/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj @@ -56,6 +56,7 @@ <Compile Include="Basic\UnusedPropertyGetsRemoved.cs" /> <Compile Include="Basic\UnusedPropertySetterRemoved.cs" /> <Compile Include="Basic\UsedPropertyIsKept.cs" /> + <Compile Include="CoreLink\LinkingOfCoreLibrariesRemovesUnusedMethods.cs" /> <Compile Include="CoreLink\LinkingOfCoreLibrariesRemovesUnusedTypes.cs" /> <Compile Include="Advanced\DeadCodeElimination1.cs" /> <Compile Include="Advanced\FieldThatOnlyGetsSetIsRemoved.cs" /> diff --git a/linker/Tests/TestCasesRunner/ResultChecker.cs b/linker/Tests/TestCasesRunner/ResultChecker.cs index 259a53588..8ced27196 100644 --- a/linker/Tests/TestCasesRunner/ResultChecker.cs +++ b/linker/Tests/TestCasesRunner/ResultChecker.cs @@ -61,14 +61,102 @@ namespace Mono.Linker.Tests.TestCasesRunner { } else if (checkAttrInAssembly.AttributeType.Name == nameof (KeptTypeInAssemblyAttribute)) { if (linkedType == null) Assert.Fail ($"Type `{expectedTypeName}' should have been kept"); + } else if (checkAttrInAssembly.AttributeType.Name == nameof (RemovedMemberInAssemblyAttribute)) { + if (linkedType == null) + continue; + + VerifyRemovedMemberInAssembly (checkAttrInAssembly, linkedType); + } else if (checkAttrInAssembly.AttributeType.Name == nameof (KeptMemberInAssemblyAttribute)) { + if (linkedType == null) + Assert.Fail ($"Type `{expectedTypeName}' should have been kept"); + + VerifyKeptMemberInAssembly (checkAttrInAssembly, linkedType); } else { - throw new NotImplementedException ($"Type {original}, has an unknown other assembly attribute of type {checkAttrInAssembly.AttributeType}"); + throw new NotImplementedException ($"Type {expectedTypeName}, has an unknown other assembly attribute of type {checkAttrInAssembly.AttributeType}"); } } } } } + static void VerifyRemovedMemberInAssembly (CustomAttribute inAssemblyAttribute, TypeDefinition linkedType) + { + var originalType = ((TypeReference) inAssemblyAttribute.ConstructorArguments [1].Value).Resolve (); + foreach (var memberNameAttr in (CustomAttributeArgument[]) inAssemblyAttribute.ConstructorArguments [2].Value) { + string memberName = (string) memberNameAttr.Value; + + // We will find the matching type from the original assembly first that way we can confirm + // that the name defined in the attribute corresponds to a member that actually existed + var originalFieldMember = originalType.Fields.FirstOrDefault (m => m.Name == memberName); + if (originalFieldMember != null) { + var linkedField = linkedType.Fields.FirstOrDefault (m => m.Name == memberName); + if (linkedField != null) + Assert.Fail ($"Field `{memberName}` on Type `{originalType}` should have been removed"); + + continue; + } + + var originalPropertyMember = originalType.Properties.FirstOrDefault (m => m.Name == memberName); + if (originalPropertyMember != null) { + var linkedProperty = linkedType.Properties.FirstOrDefault (m => m.Name == memberName); + if (linkedProperty != null) + Assert.Fail ($"Property `{memberName}` on Type `{originalType}` should have been removed"); + + continue; + } + + var originalMethodMember = originalType.Methods.FirstOrDefault (m => m.GetSignature () == memberName); + if (originalMethodMember != null) { + var linkedMethod = linkedType.Methods.FirstOrDefault (m => m.GetSignature () == memberName); + if (linkedMethod != null) + Assert.Fail ($"Method `{memberName}` on Type `{originalType}` should have been removed"); + + continue; + } + + Assert.Fail ($"Invalid test assertion. No member named `{memberName}` exists on the original type `{originalType}`"); + } + } + + static void VerifyKeptMemberInAssembly (CustomAttribute inAssemblyAttribute, TypeDefinition linkedType) + { + var originalType = ((TypeReference) inAssemblyAttribute.ConstructorArguments [1].Value).Resolve (); + foreach (var memberNameAttr in (CustomAttributeArgument[]) inAssemblyAttribute.ConstructorArguments [2].Value) { + string memberName = (string) memberNameAttr.Value; + + // We will find the matching type from the original assembly first that way we can confirm + // that the name defined in the attribute corresponds to a member that actually existed + var originalFieldMember = originalType.Fields.FirstOrDefault (m => m.Name == memberName); + if (originalFieldMember != null) { + var linkedField = linkedType.Fields.FirstOrDefault (m => m.Name == memberName); + if (linkedField == null) + Assert.Fail ($"Field `{memberName}` on Type `{originalType}` should have been kept"); + + continue; + } + + var originalPropertyMember = originalType.Properties.FirstOrDefault (m => m.Name == memberName); + if (originalPropertyMember != null) { + var linkedProperty = linkedType.Properties.FirstOrDefault (m => m.Name == memberName); + if (linkedProperty == null) + Assert.Fail ($"Property `{memberName}` on Type `{originalType}` should have been kept"); + + continue; + } + + var originalMethodMember = originalType.Methods.FirstOrDefault (m => m.GetSignature () == memberName); + if (originalMethodMember != null) { + var linkedMethod = linkedType.Methods.FirstOrDefault (m => m.GetSignature () == memberName); + if (linkedMethod == null) + Assert.Fail ($"Method `{memberName}` on Type `{originalType}` should have been kept"); + + continue; + } + + Assert.Fail ($"Invalid test assertion. No member named `{memberName}` exists on the original type `{originalType}`"); + } + } + static Dictionary<string, List<CustomAttribute>> BuildOtherAssemblyCheckTable (AssemblyDefinition original) { var checks = new Dictionary<string, List<CustomAttribute>> (); @@ -89,7 +177,10 @@ namespace Mono.Linker.Tests.TestCasesRunner { static bool IsTypeInOtherAssemblyAssertion (CustomAttribute attr) { - return attr.AttributeType.Name == nameof (RemovedTypeInAssemblyAttribute) || attr.AttributeType.Name == nameof (KeptTypeInAssemblyAttribute); + return attr.AttributeType.Name == nameof (RemovedTypeInAssemblyAttribute) + || attr.AttributeType.Name == nameof (KeptTypeInAssemblyAttribute) + || attr.AttributeType.Name == nameof (RemovedMemberInAssemblyAttribute) + || attr.AttributeType.Name == nameof (KeptMemberInAssemblyAttribute); } struct AssemblyContainer : IDisposable |