From cd43402f024cd10d4d8a217ef051888e0b758a88 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 22 Feb 2019 09:56:42 +0900 Subject: [PATCH] [XamlC] Identify generic instance types correctly when importing ctor (#5309) The old implementation fails to identify generic instance types for typed binding getter, whose type is: System.Func`2> This fixes the issue by taking generic arguments into account. --- .../ModuleDefinitionExtensions.cs | 11 +++- .../XamlC/ModuleDefinitionExtensionsTests.cs | 62 ++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 Xamarin.Forms.Xaml.UnitTests/XamlC/ModuleDefinitionExtensionsTests.cs diff --git a/Xamarin.Forms.Build.Tasks/ModuleDefinitionExtensions.cs b/Xamarin.Forms.Build.Tasks/ModuleDefinitionExtensions.cs index 29693e8..b8e08ad 100644 --- a/Xamarin.Forms.Build.Tasks/ModuleDefinitionExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/ModuleDefinitionExtensions.cs @@ -47,7 +47,7 @@ namespace Xamarin.Forms.Build.Tasks public static MethodReference ImportCtorReference(this ModuleDefinition module, TypeReference type, TypeReference[] parameterTypes) { - var ctorKey = $"{type}.ctor({(parameterTypes == null ? "" : string.Join(",", parameterTypes.Select(tr => (tr.Scope.Name, tr.Namespace, tr.Name))))})"; + var ctorKey = $"{type}.ctor({(parameterTypes == null ? "" : string.Join(",", parameterTypes.Select(SerializeTypeReference)))})"; if (MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef)) return ctorRef; ctorRef = module.ImportCtorReference(type, classArguments: null, predicate: md => { @@ -88,7 +88,7 @@ namespace Xamarin.Forms.Build.Tasks public static MethodReference ImportCtorReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, int paramCount, TypeReference[] classArguments) { - var ctorKey = $"{type}<{(string.Join(",", classArguments.Select(tr => (tr.Scope.Name, tr.Namespace, tr.Name))))}>.ctor({(string.Join(",", Enumerable.Repeat("_", paramCount)))})"; + var ctorKey = $"{type}<{string.Join(",", classArguments.Select(SerializeTypeReference))}>.ctor({(string.Join(",", Enumerable.Repeat("_", paramCount)))})"; if (!MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef)) MethodRefCache.Add((module, ctorKey), ctorRef = module.ImportCtorReference(module.GetTypeDefinition(type), classArguments, predicate: md => md.Parameters.Count == paramCount)); return ctorRef; @@ -303,5 +303,12 @@ namespace Xamarin.Forms.Build.Tasks foreach (var property in typedef.BaseType.ResolveCached().Properties(true)) yield return property; } + + static string SerializeTypeReference(TypeReference tr) + { + var serialized = $"{tr.Scope.Name},{tr.Namespace},{tr.Name}"; + var gitr = tr as GenericInstanceType; + return gitr == null ? serialized : $"{serialized}<{string.Join(",", gitr.GenericArguments.Select(SerializeTypeReference))}>"; + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/XamlC/ModuleDefinitionExtensionsTests.cs b/Xamarin.Forms.Xaml.UnitTests/XamlC/ModuleDefinitionExtensionsTests.cs new file mode 100644 index 0000000..5fb3719 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/XamlC/ModuleDefinitionExtensionsTests.cs @@ -0,0 +1,62 @@ +using System; +using NUnit.Framework; +using Mono.Cecil; +using Xamarin.Forms.Build.Tasks; + +namespace Xamarin.Forms.XamlcUnitTests +{ + [TestFixture] + public class ModuleDefinitionExtensionsTests + { + class WithGenericInstanceCtorParameter + { + public WithGenericInstanceCtorParameter(Tuple argument) + { + } + + public WithGenericInstanceCtorParameter(Tuple argument) + { + } + } + + ModuleDefinition module; + + [SetUp] + public void SetUp() + { + var resolver = new XamlCAssemblyResolver(); + resolver.AddAssembly(Uri.UnescapeDataString((new UriBuilder(typeof(ModuleDefinitionExtensionsTests).Assembly.CodeBase)).Path)); + resolver.AddAssembly(Uri.UnescapeDataString((new UriBuilder(typeof(byte).Assembly.CodeBase)).Path)); + + module = ModuleDefinition.CreateModule("foo", new ModuleParameters { + AssemblyResolver = resolver, + Kind = ModuleKind.Dll + }); + } + + [Test] + public void TestImportCtorReferenceWithGenericInstanceCtorParameter() + { + var type = module.ImportReference(typeof(WithGenericInstanceCtorParameter)); + var byteTuple = module.ImportReference(typeof(Tuple)); + var byteTupleCtor = module.ImportCtorReference(type, new[] { byteTuple }); + var int16Tuple = module.ImportReference(typeof(Tuple)); + var int16TupleCtor = module.ImportCtorReference(type, new[] { int16Tuple }); + + Assert.AreEqual("System.Tuple`1", byteTupleCtor.Parameters[0].ParameterType.FullName); + Assert.AreEqual("System.Tuple`1", int16TupleCtor.Parameters[0].ParameterType.FullName); + } + + [Test] + public void TestImportCtorReferenceWithGenericInstanceTypeParameter() + { + var byteTuple = module.ImportReference(typeof(Tuple)); + var byteTupleCtor = module.ImportCtorReference(("mscorlib", "System", "Tuple`1"), 1, new[] { byteTuple }); + var in16Tuple = module.ImportReference(typeof(Tuple)); + var int16TupleCtor = module.ImportCtorReference(("mscorlib", "System", "Tuple`1"), 1, new[] { in16Tuple }); + + Assert.AreEqual("System.Tuple`1", ((GenericInstanceType)byteTupleCtor.DeclaringType).GenericArguments[0].FullName); + Assert.AreEqual("System.Tuple`1", ((GenericInstanceType)int16TupleCtor.DeclaringType).GenericArguments[0].FullName); + } + } +} -- 2.7.4