* [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:
Stephane Delcroix 2016-08-02 22:24:50 +02:00 коммит произвёл Jason Smith
Родитель ac44cf9dec
Коммит 89199205e4
10 изменённых файлов: 113 добавлений и 75 удалений

Просмотреть файл

@ -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;
}
}