Xaml convert on add (#273)
* [Xaml] add test for conversion on Set and Add * [Xaml] Fix conversion on Add() * [XamlC] use op_implicit before Add()
This commit is contained in:
Родитель
ac44cf9dec
Коммит
89199205e4
|
@ -141,10 +141,10 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
}
|
||||
else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
|
||||
{
|
||||
// IL_000d: ldloc.2
|
||||
// IL_000e: callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Xamarin.Forms.Core]Xamarin.Forms.Layout`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::get_Children()
|
||||
// IL_0013: ldloc.0
|
||||
// IL_0014: callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::Add(!0)
|
||||
// IL_000d: ldloc.2
|
||||
// IL_000e: callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Xamarin.Forms.Core]Xamarin.Forms.Layout`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::get_Children()
|
||||
// IL_0013: ldloc.0
|
||||
// IL_0014: callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::Add(!0)
|
||||
|
||||
var parentList = (ListNode)parentNode;
|
||||
var parent = Context.Variables[((IElementNode)parentNode.Parent)];
|
||||
|
@ -314,16 +314,16 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
GetNameAndTypeRef(ref elementType, propertyName.NamespaceURI, ref localName, context, iXmlLineInfo);
|
||||
|
||||
//If the target is an event, connect
|
||||
// IL_0007: ldloc.0
|
||||
// IL_0008: ldarg.0
|
||||
//
|
||||
// IL_0009: ldftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
|
||||
// IL_0007: ldloc.0
|
||||
// IL_0008: ldarg.0
|
||||
//
|
||||
// IL_0009: ldftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
|
||||
//OR, if the handler is virtual
|
||||
// IL_000x: ldarg.0
|
||||
// IL_0009: ldvirtftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
|
||||
//
|
||||
// IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
|
||||
// IL_0014: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::add_Clicked(class [mscorlib]System.EventHandler)
|
||||
// IL_000x: ldarg.0
|
||||
// IL_0009: ldvirtftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
|
||||
//
|
||||
// IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
|
||||
// IL_0014: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::add_Clicked(class [mscorlib]System.EventHandler)
|
||||
|
||||
var eventinfo = elementType.GetEvent(ed => ed.Name == localName);
|
||||
if (eventinfo != null)
|
||||
|
@ -409,10 +409,10 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
}
|
||||
|
||||
//If it's a BP, SetValue ()
|
||||
// IL_0007: ldloc.0
|
||||
// IL_0008: ldsfld class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty [Xamarin.Forms.Core]Xamarin.Forms.Label::TextProperty
|
||||
// IL_000d: ldstr "foo"
|
||||
// IL_0012: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.BindableObject::SetValue(class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty, object)
|
||||
// IL_0007: ldloc.0
|
||||
// IL_0008: ldsfld class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty [Xamarin.Forms.Core]Xamarin.Forms.Label::TextProperty
|
||||
// IL_000d: ldstr "foo"
|
||||
// IL_0012: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.BindableObject::SetValue(class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty, object)
|
||||
if (bpRef != null)
|
||||
{
|
||||
//TODO: check if parent is a BP
|
||||
|
@ -454,9 +454,9 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
}
|
||||
|
||||
//If it's a property, set it
|
||||
// IL_0007: ldloc.0
|
||||
// IL_0008: ldstr "foo"
|
||||
// IL_000d: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Label::set_Text(string)
|
||||
// IL_0007: ldloc.0
|
||||
// IL_0008: ldstr "foo"
|
||||
// IL_000d: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Label::set_Text(string)
|
||||
PropertyDefinition property = elementType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
|
||||
MethodDefinition propertySetter;
|
||||
if (property != null && (propertySetter = property.SetMethod) != null && propertySetter.IsPublic)
|
||||
|
@ -483,28 +483,7 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
if (valueNode is IElementNode)
|
||||
{
|
||||
var vardef = context.Variables[(ElementNode)valueNode];
|
||||
var implicitOperators =
|
||||
vardef.VariableType.GetMethods(md => md.IsPublic && md.IsStatic && md.IsSpecialName && md.Name == "op_Implicit",
|
||||
module).ToList();
|
||||
MethodReference implicitOperator = null;
|
||||
if (implicitOperators.Any())
|
||||
{
|
||||
foreach (var op in implicitOperators)
|
||||
{
|
||||
var cast = op.Item1;
|
||||
var opDeclTypeRef = op.Item2;
|
||||
var castDef = module.Import(cast).ResolveGenericParameters(opDeclTypeRef, module);
|
||||
var returnType = castDef.ReturnType;
|
||||
if (returnType.IsGenericParameter)
|
||||
returnType = ((GenericInstanceType)opDeclTypeRef).GenericArguments[((GenericParameter)returnType).Position];
|
||||
if (returnType.FullName == propertyType.FullName &&
|
||||
cast.Parameters[0].ParameterType.Name == vardef.VariableType.Name)
|
||||
{
|
||||
implicitOperator = castDef;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
|
||||
|
||||
//TODO replace latest check by a runtime type check
|
||||
if (implicitOperator != null || vardef.VariableType.InheritsFromOrImplements(propertyType) ||
|
||||
|
@ -514,7 +493,7 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
context.IL.Emit(OpCodes.Ldloc, vardef);
|
||||
if (implicitOperator != null)
|
||||
{
|
||||
// IL_000f: call !0 class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<bool>::op_Implicit(class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<!0>)
|
||||
// IL_000f: call !0 class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<bool>::op_Implicit(class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<!0>)
|
||||
context.IL.Emit(OpCodes.Call, module.Import(implicitOperator));
|
||||
}
|
||||
else if (!vardef.VariableType.IsValueType && propertyType.IsValueType)
|
||||
|
@ -537,6 +516,7 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
var propertyGetterRef = module.Import(propertyGetter);
|
||||
propertyGetterRef = module.Import(propertyGetterRef.ResolveGenericParameters(declaringTypeReference, module));
|
||||
var propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
|
||||
var vardef = context.Variables [(ElementNode)valueNode];
|
||||
|
||||
//TODO check md.Parameters[0] type
|
||||
var adderTuple =
|
||||
|
@ -545,12 +525,16 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
{
|
||||
var adderRef = module.Import(adderTuple.Item1);
|
||||
adderRef = module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, module));
|
||||
var childType = GetParameterType(adderRef.Parameters [0]);
|
||||
var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(childType, module);
|
||||
|
||||
if (valueNode is IElementNode)
|
||||
{
|
||||
context.IL.Emit(OpCodes.Ldloc, parent);
|
||||
context.IL.Emit(OpCodes.Callvirt, propertyGetterRef);
|
||||
context.IL.Emit(OpCodes.Ldloc, context.Variables[(ElementNode)valueNode]);
|
||||
context.IL.Emit(OpCodes.Ldloc, vardef);
|
||||
if (implicitOperator != null)
|
||||
context.IL.Emit(OpCodes.Call, module.Import(implicitOperator));
|
||||
context.IL.Emit(OpCodes.Callvirt, adderRef);
|
||||
if (adderRef.ReturnType.FullName != "System.Void")
|
||||
context.IL.Emit(OpCodes.Pop);
|
||||
|
@ -567,6 +551,14 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
context.IL.Append(br);
|
||||
}
|
||||
|
||||
public static TypeReference GetParameterType(ParameterDefinition param)
|
||||
{
|
||||
if (!param.ParameterType.IsGenericParameter)
|
||||
return param.ParameterType;
|
||||
var type = (param.Method as MethodReference).DeclaringType as GenericInstanceType;
|
||||
return type.GenericArguments [0];
|
||||
}
|
||||
|
||||
static bool GetNameAndTypeRef(ref TypeReference elementType, string namespaceURI, ref string localname,
|
||||
ILContext context, IXmlLineInfo lineInfo)
|
||||
{
|
||||
|
|
|
@ -200,6 +200,27 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
yield return tuple;
|
||||
}
|
||||
|
||||
public static MethodReference GetImplicitOperatorTo(this TypeReference fromType, TypeReference toType, ModuleDefinition module)
|
||||
{
|
||||
var implicitOperators = fromType.GetMethods(md => md.IsPublic && md.IsStatic && md.IsSpecialName && md.Name == "op_Implicit",
|
||||
module).ToList();
|
||||
if (implicitOperators.Any()) {
|
||||
foreach (var op in implicitOperators) {
|
||||
var cast = op.Item1;
|
||||
var opDeclTypeRef = op.Item2;
|
||||
var castDef = module.Import(cast).ResolveGenericParameters(opDeclTypeRef, module);
|
||||
var returnType = castDef.ReturnType;
|
||||
if (returnType.IsGenericParameter)
|
||||
returnType = ((GenericInstanceType)opDeclTypeRef).GenericArguments [((GenericParameter)returnType).Position];
|
||||
if (returnType.FullName == toType.FullName &&
|
||||
cast.Parameters [0].ParameterType.Name == fromType.Name) {
|
||||
return castDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TypeReference ResolveGenericParameters(this TypeReference self, TypeReference declaringTypeReference)
|
||||
{
|
||||
var genericself = self as GenericInstanceType;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<ContentPage
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Forms.Xaml.UnitTests.ImplicitConversions">
|
||||
x:Class="Xamarin.Forms.Xaml.UnitTests.BuiltInConversions">
|
||||
<StackLayout>
|
||||
<DatePicker x:Name="datetime0" Date="2015-01-16"/>
|
||||
<DatePicker x:Name="datetime1">
|
|
@ -1,15 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Xamarin.Forms;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Xamarin.Forms.Xaml.UnitTests
|
||||
{
|
||||
public partial class ImplicitConversions : ContentPage
|
||||
public partial class BuiltInConversions : ContentPage
|
||||
{
|
||||
public ImplicitConversions ()
|
||||
public BuiltInConversions ()
|
||||
{
|
||||
InitializeComponent ();
|
||||
}
|
||||
|
@ -20,7 +17,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
|
|||
[Test]
|
||||
public void Datetime ()
|
||||
{
|
||||
var layout = new ImplicitConversions ();
|
||||
var layout = new BuiltInConversions ();
|
||||
|
||||
Assert.AreEqual (new DateTime (2015, 01, 16), layout.datetime0.Date);
|
||||
Assert.AreEqual (new DateTime (2015, 01, 16), layout.datetime1.Date);
|
||||
|
@ -29,7 +26,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
|
|||
[Test]
|
||||
public void String ()
|
||||
{
|
||||
var layout = new ImplicitConversions ();
|
||||
var layout = new BuiltInConversions ();
|
||||
|
||||
Assert.AreEqual ("foobar", layout.label0.Text);
|
||||
Assert.AreEqual ("foobar", layout.label1.Text);
|
|
@ -2,7 +2,7 @@
|
|||
<ContentPage
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Forms.Xaml.UnitTests.Compiled.FindByName"
|
||||
x:Class="Xamarin.Forms.Xaml.UnitTests.FindByName"
|
||||
x:Name="root">
|
||||
<StackLayout>
|
||||
<Label Text="Foo" x:Name="label0"/>
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Xamarin.Forms.Xaml.UnitTests.Compiled
|
||||
namespace Xamarin.Forms.Xaml.UnitTests
|
||||
{
|
||||
public partial class FindByName : ContentPage
|
||||
{
|
|
@ -2,7 +2,8 @@
|
|||
<ContentPage
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Forms.Xaml.UnitTests.Compiled.SetValue">
|
||||
xmlns:local="clr-namespace:Xamarin.Forms.Xaml.UnitTests"
|
||||
x:Class="Xamarin.Forms.Xaml.UnitTests.SetValue">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<Color x:Key="purple">Purple</Color>
|
||||
|
@ -67,5 +68,11 @@
|
|||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
<Label x:Name="label14" AbsoluteLayout.LayoutFlags="PositionProportional,WidthProportional" />
|
||||
<ContentView x:Name="content0">
|
||||
<local:ConvertibleToView/>
|
||||
</ContentView>
|
||||
<StackLayout x:Name="stack4">
|
||||
<local:ConvertibleToView/>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ContentPage>
|
|
@ -1,13 +1,18 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Xamarin.Forms;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Xamarin.Forms.Xaml.UnitTests.Compiled
|
||||
namespace Xamarin.Forms.Xaml.UnitTests
|
||||
{
|
||||
public class ConvertibleToView
|
||||
{
|
||||
public static implicit operator View(ConvertibleToView source)
|
||||
{
|
||||
return new Button();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class SetValue : ContentPage
|
||||
{
|
||||
public SetValue ()
|
||||
|
@ -186,6 +191,22 @@ namespace Xamarin.Forms.Xaml.UnitTests.Compiled
|
|||
var page = new SetValue (useCompiledXaml);
|
||||
Assert.AreEqual (AbsoluteLayoutFlags.PositionProportional | AbsoluteLayoutFlags.WidthProportional, AbsoluteLayout.GetLayoutFlags (page.label14));
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void ConversionsAreAppliedOnSet(bool useCompiledXaml)
|
||||
{
|
||||
var page = new SetValue(useCompiledXaml);
|
||||
Assert.That(page.content0.Content, Is.TypeOf<Button>());
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void ConversionsAreAppliedOnAdd(bool useCompiledXaml)
|
||||
{
|
||||
var page = new SetValue(useCompiledXaml);
|
||||
Assert.That(page.stack4.Children[0], Is.TypeOf<Button>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -121,9 +121,6 @@
|
|||
<Compile Include="Issues\Issue2016.xaml.cs">
|
||||
<DependentUpon>Issue2016.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Compiled\FindByName.xaml.cs">
|
||||
<DependentUpon>FindByName.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Validation\SetterOnNonBP.xaml.cs">
|
||||
<DependentUpon>SetterOnNonBP.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -143,8 +140,8 @@
|
|||
<Compile Include="Issues\Issue2152.xaml.cs">
|
||||
<DependentUpon>Issue2152.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ImplicitConversions.xaml.cs">
|
||||
<DependentUpon>ImplicitConversions.xaml</DependentUpon>
|
||||
<Compile Include="BuiltInConversions.xaml.cs">
|
||||
<DependentUpon>BuiltInConversions.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Issues\Issue2450.xaml.cs">
|
||||
<DependentUpon>Issue2450.xaml</DependentUpon>
|
||||
|
@ -170,9 +167,6 @@
|
|||
<Compile Include="Issues\Issue2742.xaml.cs">
|
||||
<DependentUpon>Issue2742.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Compiled\SetValue.xaml.cs">
|
||||
<DependentUpon>SetValue.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="X2009Primitives.xaml.cs">
|
||||
<DependentUpon>X2009Primitives.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -353,6 +347,12 @@
|
|||
<Compile Include="Issues\Unreported004.xaml.cs">
|
||||
<DependentUpon>Unreported004.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FindByName.xaml.cs">
|
||||
<DependentUpon>FindByName.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="SetValue.xaml.cs">
|
||||
<DependentUpon>SetValue.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
|
||||
|
@ -422,7 +422,7 @@
|
|||
<EmbeddedResource Include="Issues\Issue2152.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="ImplicitConversions.xaml">
|
||||
<EmbeddedResource Include="BuiltInConversions.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Issues\Issue2450.xaml">
|
||||
|
@ -449,12 +449,6 @@
|
|||
<EmbeddedResource Include="Issues\Issue2742.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Compiled\FindByName.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Compiled\SetValue.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="X2009Primitives.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
|
@ -629,6 +623,12 @@
|
|||
<EmbeddedResource Include="Issues\Unreported004.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="FindByName.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="SetValue.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
|
|
|
@ -417,7 +417,7 @@ namespace Xamarin.Forms.Xaml
|
|||
null)
|
||||
{
|
||||
addMethod.Invoke(collection,
|
||||
new[] { value.ConvertTo(propertyInfo.PropertyType, (Func<TypeConverter>)null, serviceProvider) });
|
||||
new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче