[linker] Preserve smart enum conversion methods when needed.
This commit is contained in:
Родитель
9041503149
Коммит
34f31b5b34
|
@ -1201,6 +1201,10 @@ Something unexpected occured when trying to mark `NSObject` subclasses from the
|
||||||
|
|
||||||
Something unexpected occured when trying to inline code from the application. The assembly causing the issue is named in the error message. In order to fix this issue the assembly will need to be provided in a [bug report](https://bugzilla.xamarin.com) along with a complete build log with verbosity enabled (i.e. `-v -v -v -v` in the **Additional mtouch arguments**).
|
Something unexpected occured when trying to inline code from the application. The assembly causing the issue is named in the error message. In order to fix this issue the assembly will need to be provided in a [bug report](https://bugzilla.xamarin.com) along with a complete build log with verbosity enabled (i.e. `-v -v -v -v` in the **Additional mtouch arguments**).
|
||||||
|
|
||||||
|
### <a name="MT2100"/>MT2100: Smart Enum Conversion Preserver failed processing `...`.
|
||||||
|
|
||||||
|
Something unexpected occured when trying to mark the conversion methods for smart enums from the application. The assembly causing the issue is named in the error message. In order to fix this issue the assembly will need to be provided in a [bug report](https://bugzilla.xamarin.com) along with a complete build log with verbosity enabled (i.e. `-v -v -v -v` in the **Additional mtouch arguments**).
|
||||||
|
|
||||||
<!-- MT21xx: more linker errors -->
|
<!-- MT21xx: more linker errors -->
|
||||||
|
|
||||||
<!--- 2100 used by mmp -->
|
<!--- 2100 used by mmp -->
|
||||||
|
|
|
@ -164,5 +164,60 @@ namespace LinkAll.Attributes {
|
||||||
var method = klass.GetMethod ("GetHandle", BindingFlags.Public | BindingFlags.Static);
|
var method = klass.GetMethod ("GetHandle", BindingFlags.Public | BindingFlags.Static);
|
||||||
Assert.NotNull (method, "GetHandle");
|
Assert.NotNull (method, "GetHandle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SmartEnumTest ()
|
||||||
|
{
|
||||||
|
var consumer = GetType ().Assembly.GetType ("LinkAll.Attributes.SmartConsumer");
|
||||||
|
Assert.NotNull (consumer, "SmartConsumer");
|
||||||
|
Assert.NotNull (consumer.GetMethod ("GetSmartEnumValue"), "GetSmartEnumValue");
|
||||||
|
Assert.NotNull (consumer.GetMethod ("SetSmartEnumValue"), "SetSmartEnumValue");
|
||||||
|
var smartEnum = GetType ().Assembly.GetType ("LinkAll.Attributes.SmartEnum");
|
||||||
|
Assert.NotNull (smartEnum, "SmartEnum");
|
||||||
|
var smartExtensions = GetType ().Assembly.GetType ("LinkAll.Attributes.SmartEnumExtensions");
|
||||||
|
Assert.NotNull (smartExtensions, "SmartEnumExtensions");
|
||||||
|
Assert.NotNull (smartExtensions.GetMethod ("GetConstant"), "GetConstant");
|
||||||
|
Assert.NotNull (smartExtensions.GetMethod ("GetValue"), "GetValue");
|
||||||
|
|
||||||
|
// Unused smart enums and their extensions should be linked away
|
||||||
|
Assert.IsNull (typeof (NSObject).Assembly.GetType ("AVFoundation.AVMediaTypes"), "AVMediaTypes");
|
||||||
|
Assert.IsNull (typeof (NSObject).Assembly.GetType ("AVFoundation.AVMediaTypesExtensions"), "AVMediaTypesExtensions");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Preserve (AllMembers = true)]
|
||||||
|
class SmartConsumer : NSObject
|
||||||
|
{
|
||||||
|
// The Smart Get/Set methods should not be linked away, and neither should the Smart enums + extensions
|
||||||
|
[Export ("getSmartEnumValue")]
|
||||||
|
[return: BindAs (typeof (SmartEnum), OriginalType = typeof (NSString))]
|
||||||
|
public SmartEnum GetSmartEnumValue ()
|
||||||
|
{
|
||||||
|
return SmartEnum.Smart;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export ("setSmartEnumValue:")]
|
||||||
|
public void SetSmartEnumValue ([BindAs (typeof (SmartEnum), OriginalType = typeof (NSString))] SmartEnum value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SmartEnum : int
|
||||||
|
{
|
||||||
|
Smart = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SmartEnumExtensions
|
||||||
|
{
|
||||||
|
public static NSString GetConstant (this SmartEnum self)
|
||||||
|
{
|
||||||
|
return (NSString) "Smart";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SmartEnum GetValue (NSString constant)
|
||||||
|
{
|
||||||
|
return SmartEnum.Smart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
// Copyright 2017 Xamarin Inc.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using Mono.Linker;
|
||||||
|
using Mono.Tuner;
|
||||||
|
using MonoTouch.Tuner;
|
||||||
|
|
||||||
|
namespace Xamarin.Linker.Steps
|
||||||
|
{
|
||||||
|
public class PreserveSmartEnumConversionsSubStep : ExceptionalSubStep
|
||||||
|
{
|
||||||
|
Dictionary<TypeDefinition, Tuple<MethodDefinition, MethodDefinition>> cache;
|
||||||
|
protected override string Name { get; } = "Smart Enum Conversion Preserver";
|
||||||
|
protected override int ErrorCode { get; } = 2100;
|
||||||
|
|
||||||
|
public override SubStepTargets Targets {
|
||||||
|
get {
|
||||||
|
return SubStepTargets.Method | SubStepTargets.Property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsActiveFor (AssemblyDefinition assembly)
|
||||||
|
{
|
||||||
|
// we need to process all assemblies, because the functions we want to
|
||||||
|
// preserve are not necessarily in the assembly we're processing.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preserve (Tuple<MethodDefinition, MethodDefinition> pair, MethodDefinition conditionA, MethodDefinition conditionB = null)
|
||||||
|
{
|
||||||
|
if (conditionA != null) {
|
||||||
|
context.Annotations.AddPreservedMethod (conditionA, pair.Item1);
|
||||||
|
context.Annotations.AddPreservedMethod (conditionA, pair.Item2);
|
||||||
|
}
|
||||||
|
if (conditionB != null) {
|
||||||
|
context.Annotations.AddPreservedMethod (conditionB, pair.Item1);
|
||||||
|
context.Annotations.AddPreservedMethod (conditionB, pair.Item2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessAttributeProvider (ICustomAttributeProvider provider, MethodDefinition conditionA, MethodDefinition conditionB = null)
|
||||||
|
{
|
||||||
|
if (provider?.HasCustomAttributes != true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var ca in provider.CustomAttributes) {
|
||||||
|
var tr = ca.Constructor.DeclaringType;
|
||||||
|
|
||||||
|
if (!tr.IsPlatformType ("ObjCRuntime", "BindAsAttribute"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ca.ConstructorArguments.Count != 1) {
|
||||||
|
Console.WriteLine ("WARNING");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var managedType = ca.ConstructorArguments [0].Value as TypeReference;
|
||||||
|
var managedEnumType = managedType?.GetElementType ().Resolve ();
|
||||||
|
if (managedEnumType == null) {
|
||||||
|
Console.WriteLine ("WARNING");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple<MethodDefinition, MethodDefinition> pair;
|
||||||
|
if (cache != null && cache.TryGetValue (managedEnumType, out pair)) {
|
||||||
|
Preserve (pair, conditionA, conditionB);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine (managedEnumType);
|
||||||
|
// Find the Extension type
|
||||||
|
TypeDefinition extensionType = null;
|
||||||
|
var extensionName = managedEnumType.Name + "Extensions";
|
||||||
|
foreach (var type in managedEnumType.Module.Types) {
|
||||||
|
if (type.Namespace != managedEnumType.Namespace)
|
||||||
|
continue;
|
||||||
|
if (type.Name != extensionName)
|
||||||
|
continue;
|
||||||
|
extensionType = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (extensionType == null) {
|
||||||
|
Console.WriteLine ("WARNING");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the GetConstant/GetValue methods
|
||||||
|
MethodDefinition getConstant = null;
|
||||||
|
MethodDefinition getValue = null;
|
||||||
|
|
||||||
|
foreach (var method in extensionType.Methods) {
|
||||||
|
if (!method.IsStatic)
|
||||||
|
continue;
|
||||||
|
if (!method.HasParameters || method.Parameters.Count != 1)
|
||||||
|
continue;
|
||||||
|
if (method.Name == "GetConstant") {
|
||||||
|
if (!method.ReturnType.IsPlatformType ("Foundation", "NSString"))
|
||||||
|
continue;
|
||||||
|
if (method.Parameters [0].ParameterType != managedEnumType)
|
||||||
|
continue;
|
||||||
|
getConstant = method;
|
||||||
|
} else if (method.Name == "GetValue") {
|
||||||
|
if (!method.Parameters [0].ParameterType.IsPlatformType ("Foundation", "NSString"))
|
||||||
|
continue;
|
||||||
|
if (method.ReturnType != managedEnumType)
|
||||||
|
continue;
|
||||||
|
getValue = method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getConstant == null || getValue == null) {
|
||||||
|
Console.WriteLine ("WARNING");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = new Tuple<MethodDefinition, MethodDefinition> (getConstant, getValue);
|
||||||
|
if (cache == null)
|
||||||
|
cache = new Dictionary<TypeDefinition, Tuple<MethodDefinition, MethodDefinition>> ();
|
||||||
|
cache.Add (managedEnumType, pair);
|
||||||
|
Preserve (pair, conditionA, conditionB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Process (MethodDefinition method)
|
||||||
|
{
|
||||||
|
ProcessAttributeProvider (method, method);
|
||||||
|
ProcessAttributeProvider (method.MethodReturnType, method);
|
||||||
|
if (method.HasParameters) {
|
||||||
|
foreach (var p in method.Parameters)
|
||||||
|
ProcessAttributeProvider (p, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Process (PropertyDefinition property)
|
||||||
|
{
|
||||||
|
ProcessAttributeProvider (property, property.GetMethod, property.SetMethod);
|
||||||
|
if (property.GetMethod != null)
|
||||||
|
Process (property.GetMethod);
|
||||||
|
if (property.SetMethod != null)
|
||||||
|
Process (property.SetMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,6 +94,7 @@ tuner_sources = \
|
||||||
../linker/MonoTouch.Tuner/Extensions.cs \
|
../linker/MonoTouch.Tuner/Extensions.cs \
|
||||||
../linker/MonoTouch.Tuner/ListExportedSymbols.cs \
|
../linker/MonoTouch.Tuner/ListExportedSymbols.cs \
|
||||||
../linker/MonoTouch.Tuner/ProcessExportedFields.cs \
|
../linker/MonoTouch.Tuner/ProcessExportedFields.cs \
|
||||||
|
../linker/MonoTouch.Tuner/PreserveSmartEnumConversionsSubStep.cs \
|
||||||
../../src/build/mac/Constants.cs
|
../../src/build/mac/Constants.cs
|
||||||
|
|
||||||
linker_resources = \
|
linker_resources = \
|
||||||
|
|
|
@ -265,6 +265,9 @@
|
||||||
<Compile Include="..\linker\MonoTouch.Tuner\ProcessExportedFields.cs">
|
<Compile Include="..\linker\MonoTouch.Tuner\ProcessExportedFields.cs">
|
||||||
<Link>MonoTouch.Tuner\ProcessExportedFields.cs</Link>
|
<Link>MonoTouch.Tuner\ProcessExportedFields.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\linker\MonoTouch.Tuner\PreserveSmartEnumConversionsSubStep.cs">
|
||||||
|
<Link>MonoTouch.Tuner\PreserveSmartEnumConversionsSubStep.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\..\src\build\mac\Constants.cs">
|
<Compile Include="..\..\src\build\mac\Constants.cs">
|
||||||
<Link>external\Constants.cs</Link>
|
<Link>external\Constants.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -71,6 +71,7 @@ LINKER_SOURCES = \
|
||||||
$(LINKER_DIR)/MonoTouch.Tuner/RemoveAttributes.cs \
|
$(LINKER_DIR)/MonoTouch.Tuner/RemoveAttributes.cs \
|
||||||
$(LINKER_DIR)/MonoTouch.Tuner/RemoveCode.cs \
|
$(LINKER_DIR)/MonoTouch.Tuner/RemoveCode.cs \
|
||||||
$(LINKER_DIR)/MonoTouch.Tuner/SealerSubStep.cs \
|
$(LINKER_DIR)/MonoTouch.Tuner/SealerSubStep.cs \
|
||||||
|
$(LINKER_DIR)/MonoTouch.Tuner/PreserveSmartEnumConversionsSubStep.cs \
|
||||||
$(TOP)/tools/linker/ApplyPreserveAttribute.cs \
|
$(TOP)/tools/linker/ApplyPreserveAttribute.cs \
|
||||||
$(TOP)/tools/linker/BaseProfile.cs \
|
$(TOP)/tools/linker/BaseProfile.cs \
|
||||||
$(TOP)/tools/linker/CoreHttpMessageHandler.cs \
|
$(TOP)/tools/linker/CoreHttpMessageHandler.cs \
|
||||||
|
|
|
@ -157,6 +157,7 @@ namespace MonoTouch.Tuner {
|
||||||
sub.Add (new PreserveSoapHttpClients ());
|
sub.Add (new PreserveSoapHttpClients ());
|
||||||
sub.Add (new CoreHttpMessageHandler (options));
|
sub.Add (new CoreHttpMessageHandler (options));
|
||||||
sub.Add (new InlinerSubStep ());
|
sub.Add (new InlinerSubStep ());
|
||||||
|
sub.Add (new PreserveSmartEnumConversionsSubStep ());
|
||||||
return sub;
|
return sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -335,6 +335,9 @@
|
||||||
<Compile Include="..\linker\MonoTouch.Tuner\InlinerSubStep.cs">
|
<Compile Include="..\linker\MonoTouch.Tuner\InlinerSubStep.cs">
|
||||||
<Link>MonoTouch.Tuner\InlinerSubStep.cs</Link>
|
<Link>MonoTouch.Tuner\InlinerSubStep.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\linker\MonoTouch.Tuner\PreserveSmartEnumConversionsSubStep.cs">
|
||||||
|
<Link>MonoTouch.Tuner\PreserveSmartEnumConversionsSubStep.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\common\BuildTasks.cs">
|
<Compile Include="..\common\BuildTasks.cs">
|
||||||
<Link>common\BuildTasks.cs</Link>
|
<Link>common\BuildTasks.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче