From: Stephane Delcroix Date: Wed, 7 Dec 2016 09:57:43 +0000 (+0100) Subject: [XamlC] Type ref tests, and fixes (#569) X-Git-Tag: 2.3.3.175~31 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8181e6d4cbe8aac6eb29c5140262d8bc51dba7b7;p=platform%2Fupstream%2Fxamarin-forms.git [XamlC] Type ref tests, and fixes (#569) * [XamlC] Add tests for TypeRefExts, fix and enhancements * [XamlC] more fixes, more tests * Fix failing test --- diff --git a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs index 613b0cc..9e1cc16 100644 --- a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs @@ -6,6 +6,33 @@ using Mono.Cecil.Rocks; namespace Xamarin.Forms.Build.Tasks { + class TypeRefComparer : IEqualityComparer + { + static string GetAssembly(TypeReference typeRef) + { + var md = typeRef.Scope as ModuleDefinition; + if (md != null) + return md.Assembly.FullName; + var anr = typeRef.Scope as AssemblyNameReference; + if (anr != null) + return anr.FullName; + throw new ArgumentOutOfRangeException(nameof(typeRef)); + } + + public bool Equals(TypeReference x, TypeReference y) + { + return GetAssembly(x) == GetAssembly(y) && x.FullName == y.FullName; + } + + public int GetHashCode(TypeReference obj) + { + return $"{GetAssembly(obj)}//{obj.FullName}".GetHashCode(); + } + + static TypeRefComparer s_default; + public static TypeRefComparer Default => s_default ?? (s_default = new TypeRefComparer()); + } + static class TypeReferenceExtensions { public static PropertyDefinition GetProperty(this TypeReference typeRef, Func predicate, @@ -79,54 +106,56 @@ namespace Xamarin.Forms.Build.Tasks return false; } + static readonly string[] arrayInterfaces = { + "System.ICloneable", + "System.Collections.IEnumerable", + "System.Collections.IList", + "System.Collections.ICollection", + "System.Collections.IStructuralComparable", + "System.Collections.IStructuralEquatable", + }; + + static readonly string[] arrayGenericInterfaces = { + "System.Collections.Generic.IEnumerable`1", + "System.Collections.Generic.IList`1", + "System.Collections.Generic.ICollection`1", + "System.Collections.Generic.IReadOnlyCollection`1", + "System.Collections.Generic.IReadOnlyList`1", + }; + public static bool InheritsFromOrImplements(this TypeReference typeRef, TypeReference baseClass) { - if (typeRef.FullName == baseClass.FullName) + if (TypeRefComparer.Default.Equals(typeRef, baseClass)) return true; - var arrayInterfaces = new[] - { - "System.Collections.IEnumerable", - "System.Collections.IList", - "System.Collections.Collection" - }; - - var arrayGenericInterfaces = new[] - { - "System.Collections.IEnumerable`1", - "System.Collections.Generic.IList`1", - "System.Collections.Generic.IReadOnlyCollection", - "System.Collections.Generic.IReadOnlyList", - "System.Collections.Generic.Collection" - }; - - if (typeRef.IsArray && baseClass.IsArray) { - typeRef = typeRef.Resolve(); - baseClass = baseClass.Resolve(); - } + if (typeRef.IsValueType) + return false; - if (typeRef.IsArray) - { + if (typeRef.IsArray) { + var array = (ArrayType)typeRef; var arrayType = typeRef.Resolve(); if (arrayInterfaces.Contains(baseClass.FullName)) return true; - if (arrayGenericInterfaces.Contains(baseClass.Resolve().FullName) && - baseClass.IsGenericInstance && - (baseClass as GenericInstanceType).GenericArguments[0].FullName == arrayType.FullName) + if (array.IsVector && //generic interfaces are not implemented on multidimensional arrays + arrayGenericInterfaces.Contains(baseClass.Resolve().FullName) && + baseClass.IsGenericInstance && + TypeRefComparer.Default.Equals((baseClass as GenericInstanceType).GenericArguments[0], arrayType)) return true; - return false; + return baseClass.FullName == "System.Object"; } + if (typeRef.FullName == "System.Object") + return false; var typeDef = typeRef.Resolve(); - if (typeDef.FullName == baseClass.FullName) + if (TypeRefComparer.Default.Equals(typeDef, baseClass.Resolve())) return true; - if (typeDef.Interfaces.Any(ir => ir.FullName == baseClass.FullName)) + if (typeDef.Interfaces.Any(ir => TypeRefComparer.Default.Equals(ir, baseClass))) return true; - if (typeDef.FullName == "System.Object") - return false; if (typeDef.BaseType == null) return false; - return typeDef.BaseType.InheritsFromOrImplements(baseClass); + + typeRef = typeDef.BaseType.ResolveGenericParameters(typeRef); + return typeRef.InheritsFromOrImplements(baseClass); } public static CustomAttribute GetCustomAttribute(this TypeReference typeRef, TypeReference attribute) @@ -248,4 +277,4 @@ namespace Xamarin.Forms.Build.Tasks return self.GetElementType().MakeGenericInstanceType(args.ToArray()); } } -} \ No newline at end of file +} diff --git a/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj b/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj index 4977edb..4f56c57 100644 --- a/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj +++ b/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj @@ -396,6 +396,7 @@ FactoryMethodMissingMethod.xaml + diff --git a/Xamarin.Forms.Xaml.UnitTests/XamlC/TypeReferenceExtensionsTests.cs b/Xamarin.Forms.Xaml.UnitTests/XamlC/TypeReferenceExtensionsTests.cs new file mode 100644 index 0000000..3b6f293 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/XamlC/TypeReferenceExtensionsTests.cs @@ -0,0 +1,112 @@ +using System; +using NUnit.Framework; +using Mono.Cecil; +using Xamarin.Forms.Build.Tasks; +using System.Collections.Generic; + +namespace Xamarin.Forms +{ + public class Effect + { + } +} +namespace Xamarin.Forms.Xaml.XamlcUnitTests +{ + [TestFixture] + public class TypeReferenceExtensionsTests + { + class Foo + { + } + + class Foo : Foo + { + } + + class Bar : Foo + { + } + + ModuleDefinition module; + + [SetUp] + public void SetUp() + { + var resolver = new XamlCAssemblyResolver(); + resolver.AddAssembly(Uri.UnescapeDataString((new UriBuilder(typeof(TypeReferenceExtensionsTests).Assembly.CodeBase)).Path)); + resolver.AddAssembly(Uri.UnescapeDataString((new UriBuilder(typeof(BindableObject).Assembly.CodeBase)).Path)); + resolver.AddAssembly(Uri.UnescapeDataString((new UriBuilder(typeof(object).Assembly.CodeBase)).Path)); + resolver.AddAssembly(Uri.UnescapeDataString((new UriBuilder(typeof(IList<>).Assembly.CodeBase)).Path)); + resolver.AddAssembly(Uri.UnescapeDataString((new UriBuilder(typeof(Queue<>).Assembly.CodeBase)).Path)); + + module = ModuleDefinition.CreateModule("foo", new ModuleParameters { + AssemblyResolver = resolver, + Kind = ModuleKind.NetModule + }); + } + + [TestCase(typeof(bool), typeof(BindableObject), ExpectedResult = false)] + [TestCase(typeof(Dictionary), typeof(BindableObject), ExpectedResult = false)] + [TestCase(typeof(List), typeof(BindableObject), ExpectedResult = false)] + [TestCase(typeof(List