[X] do not fail on generic BP (#7588)
authorStephane Delcroix <stephane@delcroix.org>
Thu, 19 Sep 2019 13:58:29 +0000 (15:58 +0200)
committerGitHub <noreply@github.com>
Thu, 19 Sep 2019 13:58:29 +0000 (15:58 +0200)
While looking for a potential TypeConverter attribute on the static getter of a
generic attached BP, resolve the generic return type.

- fixes #7559

Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs
Xamarin.Forms.Xaml.UnitTests/Issues/Gh7494.xaml.cs
Xamarin.Forms.Xaml.UnitTests/Issues/Gh7559.xaml [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/Issues/Gh7559.xaml.cs [new file with mode: 0644]

index 641232b..082e594 100644 (file)
@@ -34,10 +34,9 @@ namespace Xamarin.Forms.Build.Tasks
 
                public static TypeReference GetBindablePropertyTypeConverter(this FieldReference bpRef, ModuleDefinition module)
                {
-                       TypeReference propertyDeclaringType;
                        var owner = bpRef.DeclaringType;
                        var bpName = bpRef.Name.EndsWith("Property", StringComparison.Ordinal) ? bpRef.Name.Substring(0, bpRef.Name.Length - 8) : bpRef.Name;
-                       var property = owner.GetProperty(pd => pd.Name == bpName, out propertyDeclaringType);
+                       var property = owner.GetProperty(pd => pd.Name == bpName, out TypeReference propertyDeclaringType);
                        var propertyType = property?.PropertyType?.ResolveGenericParameters(propertyDeclaringType);
                        var staticGetter = owner.GetMethods(md => md.Name == $"Get{bpName}" &&
                                                                                                md.IsStatic &&
@@ -52,8 +51,8 @@ namespace Xamarin.Forms.Build.Tasks
                                attributes.AddRange(propertyType.ResolveCached().CustomAttributes);
                        if (staticGetter != null && staticGetter.HasCustomAttributes)
                                attributes.AddRange(staticGetter.CustomAttributes);
-                       if (staticGetter != null && staticGetter.ReturnType.ResolveCached().HasCustomAttributes)
-                               attributes.AddRange(staticGetter.ReturnType.ResolveCached().CustomAttributes);
+                       if (staticGetter != null && staticGetter.ReturnType.ResolveGenericParameters(bpRef.DeclaringType).ResolveCached().HasCustomAttributes)
+                               attributes.AddRange(staticGetter.ReturnType.ResolveGenericParameters(bpRef.DeclaringType).ResolveCached().CustomAttributes);
 
                        return attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))?.ConstructorArguments [0].Value as TypeReference;
                }
index 46ca4d5..1f07ba8 100644 (file)
@@ -10,10 +10,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
 {
        public partial class Gh7494 : ContentPage
        {
-               public Gh7494()
-               {
-                       InitializeComponent();
-               }
+               public Gh7494() => InitializeComponent();
                public Gh7494(bool useCompiledXaml)
                {
                        //this stub will be replaced at compile time
diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7559.xaml b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7559.xaml
new file mode 100644 (file)
index 0000000..e5b3ed9
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ContentPage
+        xmlns="http://xamarin.com/schemas/2014/forms"
+        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+        xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"
+        x:Class="Xamarin.Forms.Xaml.UnitTests.Gh7559"
+        local:Gh7559A.Icon="LetterA" >
+</ContentPage>
diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7559.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7559.xaml.cs
new file mode 100644 (file)
index 0000000..28b609a
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using Xamarin.Forms;
+using Xamarin.Forms.Core.UnitTests;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+       public partial class Gh7559 : ContentPage
+       {
+               public Gh7559() => InitializeComponent();
+               public Gh7559(bool useCompiledXaml)
+               {
+                       //this stub will be replaced at compile time
+               }
+
+               [TestFixture]
+               class Tests
+               {
+                       [SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
+                       [TearDown] public void TearDown() => Device.PlatformServices = null;
+
+                       [Test]
+                       public void GenericBPCompiles([Values(false, true)]bool useCompiledXaml)
+                       {
+                               if (useCompiledXaml)
+                                       MockCompiler.Compile(typeof(Gh7559));
+                               var layout = new Gh7559(useCompiledXaml);
+                               var value = Gh7559Generic<Gh7559Enum>.GetIcon(layout);
+                               Assert.That(value, Is.EqualTo(Gh7559Enum.LetterA));
+                       }
+               }
+       }
+
+       public abstract class Gh7559Generic<T>
+       {
+               public static readonly BindableProperty IconProperty = BindableProperty.Create("Icon", typeof(T), typeof(Gh7559Generic<T>), default(T));
+
+               public static T GetIcon(BindableObject bindable)
+               {
+                       return (T)bindable.GetValue(IconProperty);
+               }
+
+               public static void SetIcon(BindableObject bindable, T value)
+               {
+                       bindable.SetValue(IconProperty, value);
+               }
+       }
+
+       public enum Gh7559Enum
+       {
+               LetterX = 'X',
+               LetterA = 'A',
+       }
+
+       public class Gh7559A : Gh7559Generic<Gh7559Enum>
+       { }
+}