[Xaml[C]] support op_implicit declared on Target (#585)
authorStephane Delcroix <stephane@delcroix.org>
Wed, 7 Dec 2016 10:35:32 +0000 (11:35 +0100)
committerGitHub <noreply@github.com>
Wed, 7 Dec 2016 10:35:32 +0000 (11:35 +0100)
Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
Xamarin.Forms.Xaml.UnitTests/SetValue.xaml
Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs
Xamarin.Forms.Xaml/TypeConversionExtensions.cs

index 86ef268..0c9b9e6 100644 (file)
@@ -109,6 +109,9 @@ namespace Xamarin.Forms.Build.Tasks
                                nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1;
                                nullableCtor = nullableCtor.ResolveGenericParameters(nullableTypeRef, module);
                        }
+
+                       var implicitOperator = module.TypeSystem.String.GetImplicitOperatorTo(targetTypeRef, module);
+
                        //Obvious Built-in conversions
                        if (targetTypeRef.Resolve().BaseType != null && targetTypeRef.Resolve().BaseType.FullName == "System.Enum")
                                yield return PushParsedEnum(targetTypeRef, str, node);
@@ -203,10 +206,13 @@ namespace Xamarin.Forms.Build.Tasks
                                                context.Body.Method.Module.Import(typeof(decimal))
                                                        .Resolve()
                                                        .Methods.FirstOrDefault(
-                                                               md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters [0].ParameterType.FullName == "System.Int32");
+                                                               md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == "System.Int32");
                                        var decimalctor = context.Body.Method.Module.Import(decimalctorinfo);
                                        yield return Instruction.Create(OpCodes.Newobj, decimalctor);
                                }
+                       } else if (implicitOperator != null) {
+                               yield return Instruction.Create(OpCodes.Ldstr, node.Value as string);
+                               yield return Instruction.Create(OpCodes.Call, module.Import(implicitOperator));
                        } else
                                yield return Instruction.Create(OpCodes.Ldnull);
 
index 5ebc4f4..cf5fe1d 100644 (file)
                                <local:SV_Foo Value="Bar"/>
                        </local:MockViewWithValues.BPBar>
                </local:MockViewWithValues>
-               <!--<local:MockViewWithValues x:Name="implicit1" BPFoo="Foo" />-->
+               <local:MockViewWithValues x:Name="implicit1" BPFoo="Foo" />
                <local:MockViewWithValues x:Name="implicit2">
                        <local:MockViewWithValues.Bar>
                                <local:SV_Foo Value="Bar"/>
                        </local:MockViewWithValues.Bar>
                </local:MockViewWithValues>
-               <!--<local:MockViewWithValues x:Name="implicit3" Foo="Foo" />-->
+               <local:MockViewWithValues x:Name="implicit3" Foo="Foo" />
        </StackLayout>
 </ContentPage>
index d8c7d2c..6e3cdc1 100644 (file)
@@ -311,13 +311,13 @@ namespace Xamarin.Forms.Xaml.UnitTests
                                Assert.AreEqual("Bar", page.implicit0.GetValue(MockViewWithValues.BPBarProperty));
                        }
 
-                       //[TestCase(false)]
-                       //[TestCase(true)]
-                       //public void SetValueWithImplicitOperatorOnTarget(bool useCompiledXaml)
-                       //{
-                       //      var page = new SetValue(useCompiledXaml);
-                       //      Assert.AreEqual("Foo", ((SV_Foo)page.implicit1.GetValue(MockViewWithValues.BPFooProperty)).Value);
-                       //}
+                       [TestCase(false)]
+                       [TestCase(true)]
+                       public void SetValueWithImplicitOperatorOnTarget(bool useCompiledXaml)
+                       {
+                               var page = new SetValue(useCompiledXaml);
+                               Assert.AreEqual("Foo", ((SV_Foo)page.implicit1.GetValue(MockViewWithValues.BPFooProperty)).Value);
+                       }
 
                        [TestCase(false)]
                        [TestCase(true)]
@@ -327,13 +327,13 @@ namespace Xamarin.Forms.Xaml.UnitTests
                                Assert.AreEqual("Bar", page.implicit2.Bar);
                        }
 
-                       //[TestCase(false)]
-                       //[TestCase(true)]
-                       //public void SetWithImplicitOperatorOnTarget(bool useCompiledXaml)
-                       //{
-                       //      var page = new SetValue(useCompiledXaml);
-                       //      Assert.AreEqual("Foo", page.implicit3.Foo.Value);
-                       //}
+                       [TestCase(false)]
+                       [TestCase(true)]
+                       public void SetWithImplicitOperatorOnTarget(bool useCompiledXaml)
+                       {
+                               var page = new SetValue(useCompiledXaml);
+                               Assert.AreEqual("Foo", page.implicit3.Foo.Value);
+                       }
                }
        }
 }
index a29b3af..15a66f5 100644 (file)
@@ -170,11 +170,34 @@ namespace Xamarin.Forms.Xaml
                        }
 
                        //if there's an implicit conversion, convert
-                       if (value != null)
-                       {
-                               var cast = value.GetType().GetRuntimeMethod("op_Implicit", new[] { value.GetType() });
-                               if (cast != null && cast.ReturnType == toType) {
-                                       value = cast.Invoke(null, new [] { value });
+                       if (value != null) {
+                               MethodInfo opImplicit = null;
+                               foreach (var mi in value.GetType().GetRuntimeMethods()) {
+                                       if (!mi.IsSpecialName) continue;
+                                       if (mi.Name != "op_Implicit") continue;
+                                       if (!mi.IsPublic) continue;
+                                       if (mi.ReturnType != toType) continue;
+                                       var parameters = mi.GetParameters();
+                                       if (parameters.Length != 1) continue;
+                                       if (parameters[0].ParameterType != value.GetType()) continue;
+                                       opImplicit = mi;
+                                       break;
+                               }
+                               if (opImplicit == null) {
+                                       foreach (var mi in toType.GetRuntimeMethods()) {
+                                               if (!mi.IsSpecialName) continue;
+                                               if (mi.Name != "op_Implicit") continue;
+                                               if (!mi.IsPublic) continue;
+                                               if (mi.ReturnType != toType) continue;
+                                               var parameters = mi.GetParameters();
+                                               if (parameters.Length != 1) continue;
+                                               if (parameters[0].ParameterType != value.GetType()) continue;
+                                               opImplicit = mi;
+                                               break;
+                                       }
+                               }
+                               if (opImplicit != null) {
+                                       value = opImplicit.Invoke(null, new[] { value });
                                        return value;
                                }
                        }