From 3878335d60c7c2c916ae93eb0d091c813bd58694 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Thu, 26 Jul 2018 11:22:51 +0200 Subject: [PATCH] [XamlC] Resolve generic base type on GetProperty (#3394) GetMethod, GetField, ... were already correctly resolving generic base types. GetProperty or GetEvent were not, causing NRE later on. - fixes #3260 --- .../SetPropertiesVisitor.cs | 4 +- .../TypeReferenceExtensions.cs | 7 +-- .../ContentPropertyAttribute.cs | 4 +- .../Issues/Gh3260.xaml | 11 ++++ .../Issues/Gh3260.xaml.cs | 62 +++++++++++++++++++ .../Xamarin.Forms.Xaml.UnitTests.csproj | 7 +++ 6 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml create mode 100644 Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml.cs diff --git a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs index d1db1373a..18ba9151f 100644 --- a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs +++ b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs @@ -799,7 +799,6 @@ namespace Xamarin.Forms.Build.Tasks var localName = propertyName.LocalName; bool attached; var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo); - TypeReference _; //If it's a BP, GetValue () if (CanGetValue(parent, bpRef, attached, lineInfo, context, out _)) @@ -1181,8 +1180,7 @@ namespace Xamarin.Forms.Build.Tasks static IEnumerable Get(VariableDefinition parent, string localName, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType) { var module = context.Body.Method.Module; - TypeReference declaringTypeReference; - var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference); + var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out var declaringTypeReference); var propertyGetter = property.GetMethod; module.ImportReference(parent.VariableType.ResolveCached()); diff --git a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs index 43f2c4e4e..933b23674 100644 --- a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs @@ -70,7 +70,7 @@ namespace Xamarin.Forms.Build.Tasks return properties.Single(); if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object") return null; - return typeDef.BaseType.GetProperty(predicate, out declaringTypeRef); + return typeDef.BaseType.ResolveGenericParameters(typeRef).GetProperty(predicate, out declaringTypeRef); } public static EventDefinition GetEvent(this TypeReference typeRef, Func predicate, @@ -85,7 +85,7 @@ namespace Xamarin.Forms.Build.Tasks } if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object") return null; - return typeDef.BaseType.GetEvent(predicate, out declaringTypeRef); + return typeDef.BaseType.ResolveGenericParameters(typeRef).GetEvent(predicate, out declaringTypeRef); } //this resolves generic eventargs (https://bugzilla.xamarin.com/show_bug.cgi?id=57574) @@ -120,8 +120,7 @@ namespace Xamarin.Forms.Build.Tasks return bp.Single(); if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object") return null; - var basetype = typeDef.BaseType.ResolveGenericParameters(typeRef); - return basetype.GetField(predicate, out declaringTypeRef); + return typeDef.BaseType.ResolveGenericParameters(typeRef).GetField(predicate, out declaringTypeRef); } public static bool ImplementsInterface(this TypeReference typeRef, TypeReference @interface) diff --git a/Xamarin.Forms.Core/ContentPropertyAttribute.cs b/Xamarin.Forms.Core/ContentPropertyAttribute.cs index 7aa607449..654a9ec98 100644 --- a/Xamarin.Forms.Core/ContentPropertyAttribute.cs +++ b/Xamarin.Forms.Core/ContentPropertyAttribute.cs @@ -11,7 +11,7 @@ using System; namespace Xamarin.Forms { - [AttributeUsage(AttributeTargets.Class)] + [AttributeUsage(AttributeTargets.Class, Inherited = true)] public sealed class ContentPropertyAttribute : Attribute { internal static string[] ContentPropertyTypes = { "Xamarin.Forms.ContentPropertyAttribute", "System.Windows.Markup.ContentPropertyAttribute" }; @@ -21,6 +21,6 @@ namespace Xamarin.Forms Name = name; } - public string Name { get; private set; } + public string Name { get; } } } \ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml new file mode 100644 index 000000000..9d486310e --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml.cs new file mode 100644 index 000000000..9fa7882e2 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3260.xaml.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Xamarin.Forms; +using Xamarin.Forms.Core.UnitTests; + +namespace Xamarin.Forms.Xaml.UnitTests +{ + public abstract class Gh3260MyGLayout : Layout where T : View + { + protected override void LayoutChildren(double x, double y, double width, double height) + { + throw new NotImplementedException(); + } + } + + public class Gh3260MyLayout : Gh3260MyGLayout + { + protected override void LayoutChildren(double x, double y, double width, double height) + { + throw new NotImplementedException(); + } + } + + public partial class Gh3260 : ContentPage + { + public Gh3260() + { + InitializeComponent(); + } + + public Gh3260(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; + } + + [TestCase(false), TestCase(true)] + public void AssignContentWithNoContentAttributeDoesNotThrow(bool useCompiledXaml) + { + var layout = new Gh3260(useCompiledXaml); + Assert.That(layout.mylayout.Children.Count, Is.EqualTo(1)); + Assert.That(layout.mylayout.Children[0], Is.EqualTo(layout.label)); + } + } + } +} diff --git a/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj b/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj index 768d741e9..681fb1714 100644 --- a/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj +++ b/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj @@ -628,6 +628,9 @@ Gh3082.xaml + + Gh3260.xaml + @@ -1138,6 +1141,10 @@ Designer MSBuild:UpdateDesignTimeXaml + + MSBuild:UpdateDesignTimeXaml + Designer +