diff options
author | Vladislav Rishe <vlados.v10.0@gmail.com> | 2017-07-28 12:12:47 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2017-08-02 22:30:55 +0300 |
commit | c39f545b10306e5e0420501a0777f7288bbbbf24 (patch) | |
tree | 749f2a1d16c1647f2b98d235f5f9c01c8b6673d1 /linker/Tests | |
parent | 39b70e7550e38188a6f411d7ec46fc9ac5528cd8 (diff) |
Provide 'event' and 'property' elements support with Link XML step.
Diffstat (limited to 'linker/Tests')
8 files changed, 120 insertions, 29 deletions
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs index a4160490a..b21ce0628 100644 --- a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs +++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs @@ -1,8 +1,7 @@ using System; -namespace Mono.Linker.Tests.Cases.Expectations.Assertions -{ - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] +namespace Mono.Linker.Tests.Cases.Expectations.Assertions { + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Event, AllowMultiple = false, Inherited = false)] public sealed class KeptBackingFieldAttribute : KeptAttribute { } } diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs new file mode 100644 index 000000000..c17eedfb6 --- /dev/null +++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs @@ -0,0 +1,23 @@ +using System; + +using Mono.Linker.Tests.Cases.Expectations.Assertions; + +namespace Mono.Linker.Tests.Cases.LinkXml { + class UnusedEventPreservedByLinkXmlIsKept { + public static void Main () + { + } + + [Kept] + class Unused { + [Kept] + [KeptBackingField] + public event EventHandler<EventArgs> Preserved; + + [Kept] + public event EventHandler<EventArgs> Preserved1 { [Kept] add { } [Kept] remove { } } + + public event EventHandler<EventArgs> NotPreserved; + } + } +}
\ No newline at end of file diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.xml new file mode 100644 index 000000000..6674d9784 --- /dev/null +++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.xml @@ -0,0 +1,8 @@ +<linker> + <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> + <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedEventPreservedByLinkXmlIsKept/Unused"> + <event signature="System.EventHandler`1<System.EventArgs> Preserved" /> + <event signature="System.EventHandler`1<System.EventArgs> Preserved1" /> + </type> + </assembly> +</linker>
\ No newline at end of file diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs index 65084580f..1dbd59a8a 100644 --- a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs +++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs @@ -20,6 +20,22 @@ namespace Mono.Linker.Tests.Cases.LinkXml { [KeptBackingField] public int PreservedProperty3 { get; [Kept] set; } + [Kept] + [KeptBackingField] + public int PreservedProperty4 { [Kept] get; [Kept] set; } + + [Kept] + [KeptBackingField] + public int PreservedProperty5 { [Kept] get; [Kept] set; } + + [Kept] + [KeptBackingField] + public int PreservedProperty6 { [Kept] get; set; } + + [Kept] + [KeptBackingField] + public int PreservedProperty7 { get; [Kept] set; } + public int NotPreservedProperty { get; set; } } } diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml index 1e182255d..de3fe0c7e 100644 --- a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml +++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml @@ -5,6 +5,11 @@ <method signature="System.Void set_PreservedProperty1(System.Int32)" /> <method signature="System.Int32 get_PreservedProperty2()" /> <method signature="System.Void set_PreservedProperty3(System.Int32)" /> + + <property signature="System.Int32 PreservedProperty4" /> + <property signature="System.Int32 PreservedProperty5" accessors="all" /> + <property signature="System.Int32 PreservedProperty6" accessors="get" /> + <property signature="System.Int32 PreservedProperty7" accessors="set" /> </type> </assembly> </linker>
\ No newline at end of file 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 a74c019af..be75f1d64 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 @@ -58,6 +58,7 @@ <Compile Include="Basic\UsedPropertyIsKept.cs" /> <Compile Include="Basic\UsedStructIsKept.cs" /> <Compile Include="LinkXml\UnusedAssemblyWithNoDefinedPreserveHasAllTypesPreserved.cs" /> + <Compile Include="LinkXml\UnusedEventPreservedByLinkXmlIsKept.cs" /> <Compile Include="LinkXml\UnusedTypeWithNoDefinedPreserveHasAllMembersPreserved.cs" /> <Compile Include="VirtualMethods\ClassUsedFromConcreteTypeHasInterfaceMethodRemoved.cs" /> <Compile Include="VirtualMethods\ClassUsedFromInterfaceHasInterfaceMethodKept.cs" /> @@ -133,6 +134,7 @@ <ItemGroup> <Content Include="LinkXml\TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.xml" /> <Content Include="LinkXml\UnusedAssemblyWithNoDefinedPreserveHasAllTypesPreserved.xml" /> + <Content Include="LinkXml\UnusedEventPreservedByLinkXmlIsKept.xml" /> <Content Include="LinkXml\UnusedFieldPreservedByLinkXmlIsKept.xml" /> <Content Include="LinkXml\UnusedMethodPreservedByLinkXmlIsKept.xml" /> <Content Include="LinkXml\UnusedNestedTypePreservedByLinkXmlIsKept.xml" /> @@ -160,4 +162,4 @@ <Target Name="AfterBuild"> </Target> --> -</Project> +</Project>
\ No newline at end of file diff --git a/linker/Tests/TestCasesRunner/AssemblyChecker.cs b/linker/Tests/TestCasesRunner/AssemblyChecker.cs index 3d28c7ddf..7a5132b95 100644 --- a/linker/Tests/TestCasesRunner/AssemblyChecker.cs +++ b/linker/Tests/TestCasesRunner/AssemblyChecker.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,6 +13,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { HashSet<string> linkedMembers; HashSet<string> verifiedBackingFields = new HashSet<string> (); + HashSet<string> verifiedEventMethods = new HashSet<string>(); public AssemblyChecker (AssemblyDefinition original, AssemblyDefinition linked) { @@ -96,6 +97,11 @@ namespace Mono.Linker.Tests.TestCasesRunner { VerifyProperty (p, linked?.Properties.FirstOrDefault (l => p.Name == l.Name), linked); linkedMembers.Remove (p.FullName); } + // Need to check events before fields so that the KeptBackingFieldAttribute is handled correctly + foreach (var e in original.Events) { + VerifyEvent (e, linked?.Events.FirstOrDefault (l => e.Name == l.Name), linked); + linkedMembers.Remove (e.FullName); + } foreach (var f in original.Fields) { if (verifiedBackingFields.Contains (f.FullName)) @@ -105,14 +111,11 @@ namespace Mono.Linker.Tests.TestCasesRunner { } foreach (var m in original.Methods) { + if (verifiedEventMethods.Contains (m.FullName)) + continue; VerifyMethod (m, linked?.Methods.FirstOrDefault (l => m.GetSignature () == l.GetSignature ())); linkedMembers.Remove (m.FullName); } - - foreach (var e in original.Events) { - VerifyEvent (e, linked?.Events.FirstOrDefault (l => e.Name == l.Name)); - linkedMembers.Remove (e.FullName); - } } void VerifyBaseType (TypeDefinition src, TypeDefinition linked) @@ -184,7 +187,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { void VerifyProperty (PropertyDefinition src, PropertyDefinition linked, TypeDefinition linkedType) { - VerifyBackingField (src, linkedType); + VerifyMemberBackingField (src, linkedType); bool expectedKept = ShouldBeKept (src); @@ -204,8 +207,10 @@ namespace Mono.Linker.Tests.TestCasesRunner { VerifyCustomAttributes (src, linked); } - void VerifyEvent (EventDefinition src, EventDefinition linked) + void VerifyEvent (EventDefinition src, EventDefinition linked, TypeDefinition linkedType) { + VerifyMemberBackingField (src, linkedType); + bool expectedKept = ShouldBeKept (src); if (!expectedKept) { @@ -213,6 +218,22 @@ namespace Mono.Linker.Tests.TestCasesRunner { Assert.Fail ($"Event `{src}' should have been removed"); return; + } else { + var keptBackingFieldAttribute = src.CustomAttributes + .FirstOrDefault (attr => attr.AttributeType.Name == nameof (KeptBackingFieldAttribute)); + + // If we have KeepBackingFieldAttribute set, + // then we expect having 'add' and 'remove' accessors marked as 'kept' implicitly. + if (keptBackingFieldAttribute != null) + { + VerifyMethodInternal (src.AddMethod, linked.AddMethod, true); + verifiedEventMethods.Add (src.AddMethod.FullName); + linkedMembers.Remove (src.AddMethod.FullName); + + VerifyMethodInternal (src.RemoveMethod, linked.RemoveMethod, true); + verifiedEventMethods.Add (src.RemoveMethod.FullName); + linkedMembers.Remove (src.RemoveMethod.FullName); + } } if (linked == null) @@ -228,6 +249,12 @@ namespace Mono.Linker.Tests.TestCasesRunner { var srcSignature = src.GetSignature (); bool expectedKept = ShouldBeKept (src, srcSignature) || (linked != null && linked.DeclaringType.Module.EntryPoint == linked); + VerifyMethodInternal (src, linked, expectedKept); + } + + + void VerifyMethodInternal (MethodDefinition src, MethodDefinition linked, bool expectedKept) + { if (!expectedKept) { if (linked != null) Assert.Fail ($"Method `{src.FullName}' should have been removed"); @@ -244,13 +271,14 @@ namespace Mono.Linker.Tests.TestCasesRunner { VerifyCustomAttributes (src, linked); } - void VerifyBackingField (PropertyDefinition src, TypeDefinition linkedType) + void VerifyMemberBackingField (IMemberDefinition src, TypeDefinition linkedType) { var keptBackingFieldAttribute = src.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (KeptBackingFieldAttribute)); if (keptBackingFieldAttribute == null) return; - var backingFieldName = $"<{src.Name}>k__BackingField"; + var backingFieldName = src.MetadataToken.TokenType == TokenType.Property + ? $"<{src.Name}>k__BackingField" : src.Name; var srcField = src.DeclaringType.Fields.FirstOrDefault (f => f.Name == backingFieldName); if (srcField == null) { @@ -263,7 +291,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { } if (srcField == null) - Assert.Fail ($"Property `{src}', could not locate the expected backing field {backingFieldName}"); + Assert.Fail ($"{src.MetadataToken.TokenType} `{src}', could not locate the expected backing field {backingFieldName}"); VerifyFieldKept (srcField, linkedType?.Fields.FirstOrDefault (l => srcField.Name == l.Name)); verifiedBackingFields.Add (srcField.FullName); @@ -317,8 +345,8 @@ namespace Mono.Linker.Tests.TestCasesRunner { static IEnumerable<T> GetCustomAttributeCtorValues<T> (ICustomAttributeProvider provider, string attributeName) where T : class { return provider.CustomAttributes. - Where (w => w.AttributeType.Name == attributeName && w.Constructor.Parameters.Count == 1). - Select (l => l.ConstructorArguments [0].Value as T); + Where (w => w.AttributeType.Name == attributeName && w.Constructor.Parameters.Count == 1). + Select (l => l.ConstructorArguments [0].Value as T); } } } diff --git a/linker/Tests/TestCasesRunner/PeVerifier.cs b/linker/Tests/TestCasesRunner/PeVerifier.cs index 388fa1e5d..0d87b63f5 100644 --- a/linker/Tests/TestCasesRunner/PeVerifier.cs +++ b/linker/Tests/TestCasesRunner/PeVerifier.cs @@ -9,8 +9,7 @@ using Mono.Linker.Tests.Extensions; using NUnit.Framework; namespace Mono.Linker.Tests.TestCasesRunner { - public class PeVerifier - { + public class PeVerifier { private readonly string _peExecutable; public PeVerifier () @@ -66,11 +65,11 @@ namespace Mono.Linker.Tests.TestCasesRunner { skipCheckEntirely = true; } else - throw new ArgumentException($"Unhandled platform and toolchain values of {Environment.OSVersion.Platform} and {skipToolchain}"); + throw new ArgumentException ($"Unhandled platform and toolchain values of {Environment.OSVersion.Platform} and {skipToolchain}"); } else if (ctorArg.Type.Name == nameof (String)) { assembliesToSkip.Add ((string)ctorArg.Value); } else { - throw new ArgumentException($"Unhandled constructor argument type of {ctorArg.Type} on {nameof (SkipPeVerifyAttribute)}"); + throw new ArgumentException ($"Unhandled constructor argument type of {ctorArg.Type} on {nameof (SkipPeVerifyAttribute)}"); } } } @@ -101,28 +100,39 @@ namespace Mono.Linker.Tests.TestCasesRunner { if (Environment.OSVersion.Platform != PlatformID.Win32NT) throw new InvalidOperationException ("This method should only be called on windows"); - var key = Registry.LocalMachine.OpenSubKey (@"SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows"); + NPath result; + if (TryFindPeExecutableFromRegustrySubfolder ("NETFXSDK", out result)) + return result; + if (TryFindPeExecutableFromRegustrySubfolder ("Windows", out result)) + return result; + + throw new InvalidOperationException ("Could not locate a peverify.exe executable"); + } + + private static bool TryFindPeExecutableFromRegustrySubfolder (string subfolder, out NPath peVerifyPath) + { + var keyPath = $"SOFTWARE\\Wow6432Node\\Microsoft\\Microsoft SDKs\\{subfolder}"; + var key = Registry.LocalMachine.OpenSubKey (keyPath); + foreach (var sdkKeyName in key.GetSubKeyNames ().OrderBy (name => new Version (name.TrimStart ('v').TrimEnd ('A'))).Reverse ()) { - var sdkKey = Registry.LocalMachine.OpenSubKey ($"SOFTWARE\\Wow6432Node\\Microsoft\\Microsoft SDKs\\Windows\\{sdkKeyName}"); + var sdkKey = Registry.LocalMachine.OpenSubKey ($"{keyPath}\\{sdkKeyName}"); var sdkDir = (string)sdkKey.GetValue ("InstallationFolder"); if (string.IsNullOrEmpty (sdkDir)) continue; var binDir = sdkDir.ToNPath ().Combine ("bin"); - if (!binDir.Exists ()) continue; foreach (var netSdkDirs in binDir.Directories ().OrderBy (dir => dir.FileName)) { - var peVerifyPath = netSdkDirs.Combine ("PEVerify.exe"); - + peVerifyPath = netSdkDirs.Combine ("PEVerify.exe"); if (peVerifyPath.FileExists ()) - return peVerifyPath; + return true; } } - - throw new InvalidOperationException ("Could not locate a peverify.exe executable"); + peVerifyPath = null; + return false; } } } |