diff options
author | Stephane Delcroix <stephane@delcroix.org> | 2016-12-04 22:08:11 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-04 22:08:11 +0100 |
commit | 39f2deb5e04886374e720013782c751a4bb7675d (patch) | |
tree | 64f2df7230760c26533730e73821a6dc5c7607da /Xamarin.Forms.Build.Tasks | |
parent | fb76107f4f3294a9d32c6983bc742ce8dff60cd8 (diff) | |
download | xamarin-forms-39f2deb5e04886374e720013782c751a4bb7675d.tar.gz xamarin-forms-39f2deb5e04886374e720013782c751a4bb7675d.tar.bz2 xamarin-forms-39f2deb5e04886374e720013782c751a4bb7675d.zip |
[Xaml] support arrays as x:Arguments (#545)
* [Xaml] port some FactoryMethod tests to XamlC
* [Xaml] support array parameters in factory ctors
* [XamlC] support arrays as x:Arguments
* fix build
Diffstat (limited to 'Xamarin.Forms.Build.Tasks')
6 files changed, 77 insertions, 17 deletions
diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ArrayExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ArrayExtension.cs new file mode 100644 index 00000000..06261147 --- /dev/null +++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ArrayExtension.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Xamarin.Forms.Xaml; + +namespace Xamarin.Forms.Build.Tasks +{ + class ArrayExtension : ICompiledMarkupExtension + { + public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference memberRef) + { + var typeNode = node.Properties[new XmlName("", "Type")] as IElementNode; + var typeTypeRef = context.TypeExtensions[typeNode]; + var n = node.CollectionItems.Count; + + var instructions = new List<Instruction>(); + instructions.Add(Instruction.Create(OpCodes.Ldc_I4, n)); + instructions.Add(Instruction.Create(OpCodes.Newarr, typeTypeRef)); + + memberRef = typeTypeRef.MakeArrayType(); + for (var i = 0; i < n; i++) { + instructions.Add(Instruction.Create(OpCodes.Dup)); + instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i)); + instructions.Add(Instruction.Create(OpCodes.Ldloc, context.Variables[node.CollectionItems[i] as IElementNode])); + instructions.Add(Instruction.Create(OpCodes.Stelem_Ref)); + } + return instructions; + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs index b18d9561..285a536b 100644 --- a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs +++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs @@ -7,6 +7,6 @@ namespace Xamarin.Forms.Build.Tasks { interface ICompiledMarkupExtension { - IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, out TypeReference typeRef); + IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference typeRef); } }
\ No newline at end of file diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs index 14797c53..014fb827 100644 --- a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs +++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; using Xamarin.Forms.Xaml; @@ -11,11 +10,11 @@ namespace Xamarin.Forms.Build.Tasks { class StaticExtension : ICompiledMarkupExtension { - public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, out TypeReference memberRef) + public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference memberRef) { INode ntype; if (!node.Properties.TryGetValue(new XmlName("", "Member"), out ntype)) - ntype = node.CollectionItems [0]; + ntype = node.CollectionItems[0]; var member = ((ValueNode)ntype).Value as string; if (IsNullOrEmpty(member) || !member.Contains(".")) { diff --git a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs index 4e1372c5..ac530216 100644 --- a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs +++ b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs @@ -64,7 +64,7 @@ namespace Xamarin.Forms.Build.Tasks if (typeref.FullName == "Xamarin.Forms.Xaml.StaticExtension") { var markupProvider = new StaticExtension(); - var il = markupProvider.ProvideValue(node, Module, out typeref); + var il = markupProvider.ProvideValue(node, Module, Context, out typeref); var vardef = new VariableDefinition(typeref); Context.Variables [node] = vardef; @@ -180,7 +180,6 @@ namespace Xamarin.Forms.Build.Tasks Context.IL.Emit(OpCodes.Initobj, Module.Import(typedef)); } - //if/when we land the compiled converters, those 2 blocks could be greatly simplified if (typeref.FullName == "Xamarin.Forms.Xaml.TypeExtension") { var visitor = new SetPropertiesVisitor(Context); foreach (var cnode in node.Properties.Values.ToList()) @@ -212,6 +211,30 @@ namespace Xamarin.Forms.Build.Tasks Context.Body.Variables.Add(vardefref.VariableDefinition); } } + + if (typeref.FullName == "Xamarin.Forms.Xaml.ArrayExtension") + { + var visitor = new SetPropertiesVisitor(Context); + foreach (var cnode in node.Properties.Values.ToList()) + cnode.Accept(visitor, node); + foreach (var cnode in node.CollectionItems) + cnode.Accept(visitor, node); + + var markupProvider = new ArrayExtension(); + + var il = markupProvider.ProvideValue(node, Module, Context, out typeref); + + vardef = new VariableDefinition(typeref); + Context.Variables[node] = vardef; + Context.Body.Variables.Add(vardef); + + Context.IL.Append(il); + Context.IL.Emit(OpCodes.Stloc, vardef); + + //clean the node as it has been fully exhausted + node.Properties.Remove(new XmlName("","Type")); + node.CollectionItems.Clear(); + } } } @@ -316,8 +339,10 @@ namespace Xamarin.Forms.Build.Tasks static bool IsXaml2009LanguagePrimitive(IElementNode node) { - if (node.NamespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml") - return true; + if (node.NamespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml") { + var n = node.XmlType.Name.Split(':') [1]; + return n != "Array"; + } if (node.NamespaceURI != "clr-namespace:System;assembly=mscorlib") return false; var name = node.XmlType.Name.Split(':')[1]; diff --git a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs index d0ccbc59..613b0cc0 100644 --- a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs @@ -65,12 +65,9 @@ namespace Xamarin.Forms.Build.Tasks genericArguments = null; var typeDef = typeRef.Resolve(); TypeReference iface; - if ( - (iface = - typeDef.Interfaces.FirstOrDefault( - tr => - tr.FullName.StartsWith(@interface) && tr.IsGenericInstance && (tr as GenericInstanceType).HasGenericArguments)) != - null) + if ((iface = typeDef.Interfaces.FirstOrDefault(tr => + tr.FullName.StartsWith(@interface, StringComparison.Ordinal) && + tr.IsGenericInstance && (tr as GenericInstanceType).HasGenericArguments)) != null) { interfaceReference = iface as GenericInstanceType; genericArguments = (iface as GenericInstanceType).GenericArguments; @@ -89,20 +86,25 @@ namespace Xamarin.Forms.Build.Tasks var arrayInterfaces = new[] { - "System.IEnumerable", + "System.Collections.IEnumerable", "System.Collections.IList", "System.Collections.Collection" }; var arrayGenericInterfaces = new[] { - "System.IEnumerable`1", + "System.Collections.IEnumerable`1", "System.Collections.Generic.IList`1", "System.Collections.Generic.IReadOnlyCollection<T>", "System.Collections.Generic.IReadOnlyList<T>", "System.Collections.Generic.Collection<T>" }; + if (typeRef.IsArray && baseClass.IsArray) { + typeRef = typeRef.Resolve(); + baseClass = baseClass.Resolve(); + } + if (typeRef.IsArray) { var arrayType = typeRef.Resolve(); @@ -112,7 +114,9 @@ namespace Xamarin.Forms.Build.Tasks baseClass.IsGenericInstance && (baseClass as GenericInstanceType).GenericArguments[0].FullName == arrayType.FullName) return true; + return false; } + var typeDef = typeRef.Resolve(); if (typeDef.FullName == baseClass.FullName) return true; diff --git a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj index 515319ef..46d4f23b 100644 --- a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj +++ b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj @@ -100,6 +100,7 @@ <Compile Include="CompiledConverters\RectangleTypeConverter.cs" /> <Compile Include="Logger.cs" /> <Compile Include="XamlTask.cs" /> + <Compile Include="CompiledMarkupExtensions\ArrayExtension.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Target Name="AfterBuild"> |