Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/linker
diff options
context:
space:
mode:
authorVladislav Rishe <vlados.v10.0@gmail.com>2017-07-28 12:12:47 +0300
committerMarek Safar <marek.safar@gmail.com>2017-08-02 22:30:55 +0300
commitc39f545b10306e5e0420501a0777f7288bbbbf24 (patch)
tree749f2a1d16c1647f2b98d235f5f9c01c8b6673d1 /linker
parent39b70e7550e38188a6f411d7ec46fc9ac5528cd8 (diff)
Provide 'event' and 'property' elements support with Link XML step.
Diffstat (limited to 'linker')
-rw-r--r--linker/Mono.Linker.Steps/ResolveFromXmlStep.cs202
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs5
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs23
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.xml8
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs16
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml5
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj4
-rw-r--r--linker/Tests/TestCasesRunner/AssemblyChecker.cs54
-rw-r--r--linker/Tests/TestCasesRunner/PeVerifier.cs34
9 files changed, 316 insertions, 35 deletions
diff --git a/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs b/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs
index a74548730..1f4cc89c6 100644
--- a/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs
+++ b/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs
@@ -29,7 +29,7 @@
//
using System;
-using SR = System.Reflection;
+using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.XPath;
@@ -51,8 +51,12 @@ namespace Mono.Linker.Steps {
static readonly string _fullname = "fullname";
static readonly string _required = "required";
static readonly string _preserve = "preserve";
+ static readonly string _accessors = "accessors";
static readonly string _ns = string.Empty;
+ static readonly string[] _accessorsAll = new string[] { "all" };
+ static readonly char[] _accessorsSep = new char[] { ';' };
+
XPathDocument _document;
string _xmlDocumentLocation;
@@ -161,7 +165,7 @@ namespace Mono.Linker.Steps {
static Regex CreateRegexFromPattern (string pattern)
{
- return new Regex (pattern.Replace(".", @"\.").Replace("*", "(.*)"));
+ return new Regex (pattern.Replace (".", @"\.").Replace ("*", "(.*)"));
}
void MatchType (TypeDefinition type, Regex regex, XPathNavigator nav)
@@ -204,7 +208,7 @@ namespace Mono.Linker.Steps {
if (assembly.MainModule.HasExportedTypes) {
foreach (var exported in assembly.MainModule.ExportedTypes) {
- MatchExportedType(exported, assembly.MainModule, regex, nav);
+ MatchExportedType (exported, assembly.MainModule, regex, nav);
}
}
}
@@ -234,6 +238,8 @@ namespace Mono.Linker.Steps {
if (nav.HasChildren) {
MarkSelectedFields (nav, type);
MarkSelectedMethods (nav, type);
+ MarkSelectedEvents (nav, type);
+ MarkSelectedProperties (nav, type);
}
}
@@ -255,6 +261,24 @@ namespace Mono.Linker.Steps {
ProcessMethods (type, methods);
}
+ void MarkSelectedEvents (XPathNavigator nav, TypeDefinition type)
+ {
+ XPathNodeIterator events = nav.SelectChildren ("event", _ns);
+ if (events.Count == 0)
+ return;
+
+ ProcessEvents (type, events);
+ }
+
+ void MarkSelectedProperties (XPathNavigator nav, TypeDefinition type)
+ {
+ XPathNodeIterator properties = nav.SelectChildren ("property", _ns);
+ if (properties.Count == 0)
+ return;
+
+ ProcessProperties (type, properties);
+ }
+
static TypePreserve GetTypePreserve (XPathNavigator nav)
{
string attribute = GetAttribute (nav, _preserve);
@@ -324,7 +348,7 @@ namespace Mono.Linker.Steps {
void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
{
- while (iterator.MoveNext()) {
+ while (iterator.MoveNext ()) {
string value = GetSignature (iterator.Current);
if (!String.IsNullOrEmpty (value))
ProcessMethodSignature (type, value);
@@ -344,12 +368,25 @@ namespace Mono.Linker.Steps {
void MarkMethod (TypeDefinition type, MethodDefinition method, string signature)
{
if (method != null) {
- Annotations.Mark (method);
- Annotations.SetAction (method, MethodAction.Parse);
+ MarkMethod (method);
} else
AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
}
+ void MarkMethod (MethodDefinition method)
+ {
+ Annotations.Mark (method);
+ Annotations.SetAction (method, MethodAction.Parse);
+ }
+
+ void MarkMethodIfNotNull (MethodDefinition method)
+ {
+ if (method == null)
+ return;
+
+ MarkMethod (method);
+ }
+
void ProcessMethodName (TypeDefinition type, string name)
{
if (!type.HasMethods)
@@ -389,6 +426,141 @@ namespace Mono.Linker.Steps {
return sb.ToString ();
}
+ void ProcessEvents (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ()) {
+ string value = GetSignature (iterator.Current);
+ if (!String.IsNullOrEmpty (value))
+ ProcessEventSignature (type, value);
+
+ value = GetAttribute (iterator.Current, "name");
+ if (!String.IsNullOrEmpty (value))
+ ProcessEventName (type, value);
+ }
+ }
+
+ void ProcessEventSignature (TypeDefinition type, string signature)
+ {
+ EventDefinition @event = GetEvent (type, signature);
+ MarkEvent (type, @event, signature);
+ }
+
+ void MarkEvent (TypeDefinition type, EventDefinition @event, string signature)
+ {
+ if (@event != null) {
+ Annotations.Mark (@event);
+
+ MarkMethod (@event.AddMethod);
+ MarkMethod (@event.RemoveMethod);
+ MarkMethodIfNotNull (@event.InvokeMethod);
+ } else
+ AddUnresolveMarker (string.Format ("T: {0}; E: {1}", type, signature));
+ }
+
+ void ProcessEventName (TypeDefinition type, string name)
+ {
+ if (!type.HasEvents)
+ return;
+
+ foreach (EventDefinition @event in type.Events)
+ if (@event.Name == name)
+ MarkEvent (type, @event, name);
+ }
+
+ static EventDefinition GetEvent (TypeDefinition type, string signature)
+ {
+ if (!type.HasEvents)
+ return null;
+
+ foreach (EventDefinition @event in type.Events)
+ if (signature == GetEventSignature (@event))
+ return @event;
+
+ return null;
+ }
+
+ static string GetEventSignature (EventDefinition @event)
+ {
+ return @event.EventType.FullName + " " + @event.Name;
+ }
+
+ void ProcessProperties (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ()) {
+ string value = GetSignature (iterator.Current);
+ if (!String.IsNullOrEmpty (value))
+ ProcessPropertySignature (type, value, GetAccessors (iterator.Current));
+
+ value = GetAttribute (iterator.Current, "name");
+ if (!String.IsNullOrEmpty (value))
+ ProcessPropertyName (type, value, _accessorsAll);
+ }
+ }
+
+ void ProcessPropertySignature (TypeDefinition type, string signature, string[] accessors)
+ {
+ PropertyDefinition property = GetProperty (type, signature);
+ MarkProperty (type, property, signature, accessors);
+ }
+
+ void MarkProperty (TypeDefinition type, PropertyDefinition property, string signature, string[] accessors)
+ {
+ if (property != null) {
+ Annotations.Mark (property);
+
+ MarkPropertyAccessors (type, property, accessors);
+ } else
+ AddUnresolveMarker (string.Format ("T: {0}; P: {1}", type, signature));
+ }
+
+ void MarkPropertyAccessors (TypeDefinition type, PropertyDefinition property, string[] accessors)
+ {
+ if (Array.IndexOf (accessors, "all") >= 0) {
+ MarkMethodIfNotNull (property.GetMethod);
+ MarkMethodIfNotNull (property.SetMethod);
+
+ return;
+ }
+ if (property.GetMethod != null
+ && Array.IndexOf (accessors, "get") >= 0)
+ MarkMethod (property.GetMethod);
+ else if (property.GetMethod == null)
+ AddUnresolveMarker (string.Format ("T: {0}' M: {1} get_{2}", type, property.PropertyType, property.Name));
+
+ if (property.SetMethod != null
+ && Array.IndexOf (accessors, "set") >= 0)
+ MarkMethod (property.SetMethod);
+ else if (property.SetMethod == null)
+ AddUnresolveMarker (string.Format ("T: {0}' M: System.Void set_{2} ({1})", type, property.PropertyType, property.Name));
+ }
+
+ void ProcessPropertyName (TypeDefinition type, string name, string[] accessors)
+ {
+ if (!type.HasProperties)
+ return;
+
+ foreach (PropertyDefinition property in type.Properties)
+ if (property.Name == name)
+ MarkProperty (type, property, name, accessors);
+ }
+
+ static PropertyDefinition GetProperty (TypeDefinition type, string signature)
+ {
+ if (!type.HasProperties)
+ return null;
+
+ foreach (PropertyDefinition property in type.Properties)
+ if (signature == GetPropertySignature (property))
+ return property;
+
+ return null;
+ }
+
+ static string GetPropertySignature (PropertyDefinition property)
+ {
+ return property.PropertyType.FullName + " " + property.Name;
+ }
+
static AssemblyDefinition GetAssembly (LinkContext context, string assemblyName)
{
AssemblyNameReference reference = AssemblyNameReference.Parse (assemblyName);
@@ -433,6 +605,24 @@ namespace Mono.Linker.Steps {
return GetAttribute (nav, _fullname);
}
+ static string[] GetAccessors (XPathNavigator nav)
+ {
+ string accessorsValue = GetAttribute (nav, _accessors);
+
+ if (accessorsValue != null) {
+ string[] accessors = accessorsValue.Split (
+ _accessorsSep, StringSplitOptions.RemoveEmptyEntries);
+
+ if (accessors.Length > 0) {
+ for (int i = 0; i < accessors.Length; ++i)
+ accessors[i] = accessors[i].ToLower ();
+
+ return accessors;
+ }
+ }
+ return _accessorsAll;
+ }
+
static string GetAttribute (XPathNavigator nav, string attribute)
{
return nav.GetAttribute (attribute, _ns);
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&lt;System.EventArgs&gt; Preserved" />
+ <event signature="System.EventHandler`1&lt;System.EventArgs&gt; 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;
}
}
}