[XamlC] correctly resolve override of virtual event handlers (#247)
authorStephane Delcroix <stephane@delcroix.org>
Mon, 18 Jul 2016 23:30:08 +0000 (01:30 +0200)
committerJason Smith <jason.smith@xamarin.com>
Mon, 18 Jul 2016 23:30:08 +0000 (16:30 -0700)
Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
Xamarin.Forms.Xaml.UnitTests/EventsConnection.xaml
Xamarin.Forms.Xaml.UnitTests/EventsConnection.xaml.cs

index 71f19f5..16eddb4 100644 (file)
@@ -316,7 +316,12 @@ namespace Xamarin.Forms.Build.Tasks
                        //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)
+                       //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)
 
@@ -345,7 +350,14 @@ namespace Xamarin.Forms.Build.Tasks
                                                string.Format("EventHandler \"{0}\" not found in type \"{1}\"", value, context.Body.Method.DeclaringType.FullName),
                                                iXmlLineInfo);
                                }
-                               context.IL.Emit(OpCodes.Ldftn, handler);
+                               if (handler.IsVirtual)
+                               {
+                                       context.IL.Emit(OpCodes.Ldarg_0);
+                                       context.IL.Emit(OpCodes.Ldvirtftn, handler);
+                               }
+                               else
+                                       context.IL.Emit(OpCodes.Ldftn, handler);
+
                                //FIXME: eventually get the right ctor instead fo the First() one, just in case another one could exists (not even sure it's possible).
                                var ctor = module.Import(eventinfo.EventType.Resolve().GetConstructors().First());
                                ctor = ctor.ResolveGenericParameters(eventinfo.EventType, module);
index f903208..7e48e1b 100644 (file)
@@ -12,5 +12,7 @@
                                                                Clicked="HandleClickedOnBase" />
                <local:ElementWithEvent x:Name="elementwithAsyncprivateHandler"
                                                                Clicked="HandleClickedPrivateAsync" />
+               <local:ElementWithEvent x:Name="elementWithVirtualHandler"
+                                                               Clicked="HandleVirtualClicked" />
        </StackLayout>
 </local:BaseForEvents>
\ No newline at end of file
index 5727693..3552fa2 100644 (file)
@@ -71,6 +71,12 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        asyncPrivateClicked++;
                }
 
+               int baseForVirtualClicked;
+               protected virtual void HandleVirtualClicked(object sender, EventArgs e)
+               {
+                       baseForVirtualClicked++;
+               }
+
                [TestFixture]
                public class Tests
                {
@@ -113,6 +119,37 @@ namespace Xamarin.Forms.Xaml.UnitTests
                                layout.elementwithAsyncprivateHandler.SendClicked ();
                                Assert.AreEqual (1, layout.asyncPrivateClicked);
                        }
+
+                       [TestCase(false)]
+                       [TestCase(true)]
+                       public void TestVirtualHandler(bool useCompiledXaml)
+                       {
+                               var layout = new SubForEvents(useCompiledXaml);
+                               Assert.AreEqual(0, layout.baseForVirtualClicked);
+                               Assert.AreEqual(0, layout.overrideClicked);
+                               layout.elementWithVirtualHandler.SendClicked();
+                               Assert.AreEqual(0, layout.baseForVirtualClicked);
+                               Assert.AreEqual(1, layout.overrideClicked);
+                       }
+               }
+       }
+
+       public class SubForEvents : EventsConnection
+       {
+               public SubForEvents(bool useCompiledXaml) : base(useCompiledXaml)
+               {
+               }
+
+               public int overrideClicked;
+               protected override void HandleVirtualClicked(object sender, EventArgs e)
+               {
+                       overrideClicked++;
+               }
+
+#pragma warning disable 1998 // considered for removal
+               async void HandleClickedPrivateAsync(object sender, EventArgs e)
+#pragma warning restore 1998
+               {
                }
        }
 }
\ No newline at end of file