summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs12
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs88
-rw-r--r--Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs293
-rw-r--r--Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs5
-rw-r--r--Xamarin.Forms.Build.Tasks/MethodDefinitionExtensions.cs4
-rw-r--r--Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj5
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml14
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs30
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/Validation/StaticExtensionException.xaml.cs2
-rw-r--r--Xamarin.Forms.Xaml/CreateValuesVisitor.cs6
-rw-r--r--Xamarin.Forms.Xaml/ExpandMarkupsVisitor.cs10
-rw-r--r--Xamarin.Forms.Xaml/XamlParser.cs3
12 files changed, 313 insertions, 159 deletions
diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs
new file mode 100644
index 00000000..b18d9561
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs
@@ -0,0 +1,12 @@
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using System.Collections.Generic;
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Build.Tasks
+{
+ interface ICompiledMarkupExtension
+ {
+ IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, 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
new file mode 100644
index 00000000..82654969
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Xamarin.Forms.Xaml;
+using System.Xml;
+
+using static System.String;
+
+namespace Xamarin.Forms.Build.Tasks
+{
+ class StaticExtension : ICompiledMarkupExtension
+ {
+ public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, out TypeReference memberRef)
+ {
+ INode ntype;
+ if (!node.Properties.TryGetValue(new XmlName("", "Member"), out ntype))
+ ntype = node.CollectionItems [0];
+ var member = ((ValueNode)ntype).Value as string;
+
+ if (IsNullOrEmpty(member) || !member.Contains(".")) {
+ var lineInfo = node as IXmlLineInfo;
+ throw new XamlParseException("Syntax for x:Static is [Member=][prefix:]typeName.staticMemberName", lineInfo);
+ }
+
+ var dotIdx = member.LastIndexOf('.');
+ var typename = member.Substring(0, dotIdx);
+ var membername = member.Substring(dotIdx + 1);
+
+ var typeRef = GetTypeReference(typename, module, node);
+ var fieldRef = GetFieldReference(typeRef, membername, module);
+ var propertyDef = GetPropertyDefinition(typeRef, membername, module);
+
+ if (fieldRef == null && propertyDef == null)
+ throw new XamlParseException(Format("x:Static: unable to find a public static field or property named {0} in {1}", membername, typename), node as IXmlLineInfo);
+
+ if (fieldRef != null) {
+ memberRef = fieldRef.FieldType;
+ return new [] { Instruction.Create(OpCodes.Ldsfld, fieldRef) };
+ }
+
+ memberRef = propertyDef.PropertyType;
+ var getterDef = propertyDef.GetMethod;
+ return new [] { Instruction.Create(OpCodes.Call, getterDef)};
+ }
+
+
+ public static TypeReference GetTypeReference(string xmlType, ModuleDefinition module, IElementNode node)
+ {
+ var split = xmlType.Split(':');
+ if (split.Length > 2)
+ throw new Xaml.XamlParseException(string.Format("Type \"{0}\" is invalid", xmlType), node as IXmlLineInfo);
+
+ string prefix, name;
+ if (split.Length == 2) {
+ prefix = split [0];
+ name = split [1];
+ } else {
+ prefix = "";
+ name = split [0];
+ }
+ var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? "";
+ return XmlTypeExtensions.GetTypeReference(new XmlType(namespaceuri, name, null), module, node as IXmlLineInfo);
+ }
+
+ public static FieldReference GetFieldReference(TypeReference typeRef, string fieldName, ModuleDefinition module)
+ {
+ TypeReference declaringTypeReference;
+ FieldReference fRef = typeRef.GetField(fd => fd.Name == fieldName &&
+ fd.IsStatic &&
+ fd.IsPublic, out declaringTypeReference);
+ if (fRef != null) {
+ fRef = module.Import(fRef.ResolveGenericParameters(declaringTypeReference));
+ fRef.FieldType = module.Import(fRef.FieldType);
+ }
+ return fRef;
+ }
+
+ public static PropertyDefinition GetPropertyDefinition(TypeReference typeRef, string propertyName, ModuleDefinition module)
+ {
+ TypeReference declaringTypeReference;
+ PropertyDefinition pDef = typeRef.GetProperty(pd => pd.Name == propertyName &&
+ pd.GetMethod.IsPublic &&
+ pd.GetMethod.IsStatic, out declaringTypeReference);
+ return pDef;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
index 5f9adafd..e6453575 100644
--- a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
+++ b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
@@ -5,6 +5,7 @@ using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Xamarin.Forms.Xaml;
+using System.Xml;
namespace Xamarin.Forms.Build.Tasks
{
@@ -67,165 +68,161 @@ namespace Xamarin.Forms.Build.Tasks
var typeref = node.XmlType.GetTypeReference(Module, node);
TypeDefinition typedef = typeref.Resolve();
- if (IsXaml2009LanguagePrimitive(node))
- {
+ if (IsXaml2009LanguagePrimitive(node)) {
var vardef = new VariableDefinition(typeref);
- Context.Variables[node] = vardef;
+ Context.Variables [node] = vardef;
Context.Body.Variables.Add(vardef);
Context.IL.Append(PushValueFromLanguagePrimitive(typedef, node));
Context.IL.Emit(OpCodes.Stloc, vardef);
+ return;
}
- else
- {
- MethodDefinition factoryCtorInfo = null;
- MethodDefinition factoryMethodInfo = null;
- MethodDefinition parameterizedCtorInfo = null;
- MethodDefinition ctorInfo = null;
- if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod))
- {
- factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
- !md.IsStatic &&
- md.HasParameters &&
- md.MatchXArguments(node, Module));
- if (factoryCtorInfo == null)
- {
- throw new XamlParseException(
- string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
- }
- ctorInfo = factoryCtorInfo;
- if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
- Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
- }
- else if (node.Properties.ContainsKey(XmlName.xFactoryMethod))
- {
- var factoryMethod = (string)(node.Properties[XmlName.xFactoryMethod] as ValueNode).Value;
- factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
- md.Name == factoryMethod &&
- md.IsStatic &&
- md.MatchXArguments(node, Module));
- if (factoryMethodInfo == null)
- {
- throw new XamlParseException(
- String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
- }
- Context.IL.Append(PushCtorXArguments(factoryMethodInfo, node));
- }
- if (ctorInfo == null && factoryMethodInfo == null)
- {
- parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
- !md.IsStatic &&
- md.HasParameters &&
- md.Parameters.All(
- pd =>
- pd.CustomAttributes.Any(
- ca =>
- ca.AttributeType.FullName ==
- "Xamarin.Forms.ParameterAttribute")));
- }
- if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node))
- {
- ctorInfo = parameterizedCtorInfo;
- // IL_0000: ldstr "foo"
- Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
- }
- ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
+ if (typeref.FullName == "Xamarin.Forms.Xaml.StaticExtension") {
+ var markupProvider = new StaticExtension();
- var ctorinforef = ctorInfo?.ResolveGenericParameters(typeref, Module);
- var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(typeref, Module);
- var implicitOperatorref = typedef.Methods.FirstOrDefault(md =>
- md.IsPublic &&
- md.IsStatic &&
- md.IsSpecialName &&
- md.Name == "op_Implicit" && md.Parameters[0].ParameterType.FullName == "System.String");
+ var il = markupProvider.ProvideValue(node, Module, out typeref);
- if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType)
- {
- VariableDefinition vardef = new VariableDefinition(typeref);
- Context.Variables[node] = vardef;
- Context.Body.Variables.Add(vardef);
+ var vardef = new VariableDefinition(typeref);
+ Context.Variables [node] = vardef;
+ Context.Body.Variables.Add(vardef);
- ValueNode vnode = null;
- if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
- vardef.VariableType.IsValueType)
- {
- //<Color>Purple</Color>
- Context.IL.Append(vnode.PushConvertedValue(Context, typeref, new ICustomAttributeProvider[] { typedef },
- node.PushServiceProvider(Context), false, true));
- Context.IL.Emit(OpCodes.Stloc, vardef);
- }
- else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
- implicitOperatorref != null)
- {
- //<FileImageSource>path.png</FileImageSource>
- var implicitOperator = Module.Import(implicitOperatorref);
- Context.IL.Emit(OpCodes.Ldstr, ((ValueNode)(node.CollectionItems.First())).Value as string);
- Context.IL.Emit(OpCodes.Call, implicitOperator);
- Context.IL.Emit(OpCodes.Stloc, vardef);
- }
- else if (factorymethodinforef != null)
- {
- var factory = Module.Import(factorymethodinforef);
- Context.IL.Emit(OpCodes.Call, factory);
- Context.IL.Emit(OpCodes.Stloc, vardef);
- }
- else if (!typedef.IsValueType)
- {
- var ctor = Module.Import(ctorinforef);
- // IL_0001: newobj instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::'.ctor'()
- // IL_0006: stloc.0
- Context.IL.Emit(OpCodes.Newobj, ctor);
- Context.IL.Emit(OpCodes.Stloc, vardef);
- }
- else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
- !node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, Module))
- {
- // IL_0008: ldloca.s 1
- // IL_000a: ldc.i4.1
- // IL_000b: call instance void valuetype Test/Foo::'.ctor'(bool)
-
- var ctor = Module.Import(ctorinforef);
- Context.IL.Emit(OpCodes.Ldloca, vardef);
- Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
- Context.IL.Emit(OpCodes.Call, ctor);
- }
- else
- {
- // IL_0000: ldloca.s 0
- // IL_0002: initobj Test/Foo
- Context.IL.Emit(OpCodes.Ldloca, vardef);
- Context.IL.Emit(OpCodes.Initobj, Module.Import(typedef));
- }
+ Context.IL.Append(il);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
- if (typeref.FullName == "Xamarin.Forms.Xaml.TypeExtension")
- {
- 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);
-
- //As we're stripping the TypeExtension bare, keep the type if we need it later (hint: we do need it)
- INode ntype;
- if (!node.Properties.TryGetValue(new XmlName("", "TypeName"), out ntype))
- ntype = node.CollectionItems[0];
-
- var type = ((ValueNode)ntype).Value as string;
- var namespaceuri = type.Contains(":") ? node.NamespaceResolver.LookupNamespace(type.Split(':')[0].Trim()) : "";
- type = type.Contains(":") ? type.Split(':')[1].Trim() : type;
- Context.TypeExtensions[node] = new XmlType(namespaceuri, type, null).GetTypeReference(Module, node);
-
- node.Properties.Clear();
- node.CollectionItems.Clear();
-
- var vardefref = new VariableDefinitionReference(vardef);
- Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
- if (vardef != vardefref.VariableDefinition)
- {
- Context.Variables[node] = vardefref.VariableDefinition;
- Context.Body.Variables.Add(vardefref.VariableDefinition);
- }
+ //clean the node as it has been fully exhausted
+ node.Properties.Clear();
+ node.CollectionItems.Clear();
+ return;
+ }
+
+ MethodDefinition factoryCtorInfo = null;
+ MethodDefinition factoryMethodInfo = null;
+ MethodDefinition parameterizedCtorInfo = null;
+ MethodDefinition ctorInfo = null;
+
+ if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod)) {
+ factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
+ !md.IsStatic &&
+ md.HasParameters &&
+ md.MatchXArguments(node, Module, Context));
+ if (factoryCtorInfo == null) {
+ throw new XamlParseException(
+ string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
+ }
+ ctorInfo = factoryCtorInfo;
+ if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
+ Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
+ } else if (node.Properties.ContainsKey(XmlName.xFactoryMethod)) {
+ var factoryMethod = (string)(node.Properties [XmlName.xFactoryMethod] as ValueNode).Value;
+ factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
+ md.Name == factoryMethod &&
+ md.IsStatic &&
+ md.MatchXArguments(node, Module, Context));
+ if (factoryMethodInfo == null) {
+ throw new XamlParseException(
+ String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
+ }
+ Context.IL.Append(PushCtorXArguments(factoryMethodInfo, node));
+ }
+ if (ctorInfo == null && factoryMethodInfo == null) {
+ parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
+ !md.IsStatic &&
+ md.HasParameters &&
+ md.Parameters.All(
+ pd =>
+ pd.CustomAttributes.Any(
+ ca =>
+ ca.AttributeType.FullName ==
+ "Xamarin.Forms.ParameterAttribute")));
+ }
+ if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node)) {
+ ctorInfo = parameterizedCtorInfo;
+ // IL_0000: ldstr "foo"
+ Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
+ }
+ ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
+
+ var ctorinforef = ctorInfo?.ResolveGenericParameters(typeref, Module);
+ var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(typeref, Module);
+ var implicitOperatorref = typedef.Methods.FirstOrDefault(md =>
+ md.IsPublic &&
+ md.IsStatic &&
+ md.IsSpecialName &&
+ md.Name == "op_Implicit" && md.Parameters [0].ParameterType.FullName == "System.String");
+
+ if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType) {
+ VariableDefinition vardef = new VariableDefinition(typeref);
+ Context.Variables [node] = vardef;
+ Context.Body.Variables.Add(vardef);
+
+ ValueNode vnode = null;
+ if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
+ vardef.VariableType.IsValueType) {
+ //<Color>Purple</Color>
+ Context.IL.Append(vnode.PushConvertedValue(Context, typeref, new ICustomAttributeProvider [] { typedef },
+ node.PushServiceProvider(Context), false, true));
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ } else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
+ implicitOperatorref != null) {
+ //<FileImageSource>path.png</FileImageSource>
+ var implicitOperator = Module.Import(implicitOperatorref);
+ Context.IL.Emit(OpCodes.Ldstr, ((ValueNode)(node.CollectionItems.First())).Value as string);
+ Context.IL.Emit(OpCodes.Call, implicitOperator);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ } else if (factorymethodinforef != null) {
+ var factory = Module.Import(factorymethodinforef);
+ Context.IL.Emit(OpCodes.Call, factory);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ } else if (!typedef.IsValueType) {
+ var ctor = Module.Import(ctorinforef);
+// IL_0001: newobj instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::'.ctor'()
+// IL_0006: stloc.0
+ Context.IL.Emit(OpCodes.Newobj, ctor);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ } else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
+ !node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, Module, Context)) {
+// IL_0008: ldloca.s 1
+// IL_000a: ldc.i4.1
+// IL_000b: call instance void valuetype Test/Foo::'.ctor'(bool)
+
+ var ctor = Module.Import(ctorinforef);
+ Context.IL.Emit(OpCodes.Ldloca, vardef);
+ Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
+ Context.IL.Emit(OpCodes.Call, ctor);
+ } else {
+// IL_0000: ldloca.s 0
+// IL_0002: initobj Test/Foo
+ Context.IL.Emit(OpCodes.Ldloca, vardef);
+ 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())
+ cnode.Accept(visitor, node);
+ foreach (var cnode in node.CollectionItems)
+ cnode.Accept(visitor, node);
+
+ //As we're stripping the TypeExtension bare, keep the type if we need it later (hint: we do need it)
+ INode ntype;
+ if (!node.Properties.TryGetValue(new XmlName("", "TypeName"), out ntype))
+ ntype = node.CollectionItems [0];
+
+ var type = ((ValueNode)ntype).Value as string;
+ var namespaceuri = type.Contains(":") ? node.NamespaceResolver.LookupNamespace(type.Split(':') [0].Trim()) : "";
+ type = type.Contains(":") ? type.Split(':') [1].Trim() : type;
+ Context.TypeExtensions [node] = new XmlType(namespaceuri, type, null).GetTypeReference(Module, node);
+
+ node.Properties.Clear();
+ node.CollectionItems.Clear();
+
+ var vardefref = new VariableDefinitionReference(vardef);
+ Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
+ if (vardef != vardefref.VariableDefinition) {
+ Context.Variables [node] = vardefref.VariableDefinition;
+ Context.Body.Variables.Add(vardefref.VariableDefinition);
}
}
}
diff --git a/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs b/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs
index bbdaa6c8..feafe214 100644
--- a/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs
+++ b/Xamarin.Forms.Build.Tasks/ExpandMarkupsVisitor.cs
@@ -12,7 +12,6 @@ namespace Xamarin.Forms.Build.Tasks
{
XmlName.xKey,
XmlName.xTypeArguments,
- XmlName.xArguments,
XmlName.xFactoryMethod,
XmlName.xName
};
@@ -175,8 +174,8 @@ namespace Xamarin.Forms.Build.Tasks
throw new NotSupportedException();
node = xmlLineInfo == null
- ? new ElementNode(type, null, nsResolver)
- : new ElementNode(type, null, nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
+ ? new ElementNode(type, "", nsResolver)
+ : new ElementNode(type, "", nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
if (remaining.StartsWith("}", StringComparison.Ordinal))
{
diff --git a/Xamarin.Forms.Build.Tasks/MethodDefinitionExtensions.cs b/Xamarin.Forms.Build.Tasks/MethodDefinitionExtensions.cs
index 41d7cb20..8c3dba22 100644
--- a/Xamarin.Forms.Build.Tasks/MethodDefinitionExtensions.cs
+++ b/Xamarin.Forms.Build.Tasks/MethodDefinitionExtensions.cs
@@ -6,7 +6,7 @@ namespace Xamarin.Forms.Build.Tasks
{
static class MethodDefinitionExtensions
{
- public static bool MatchXArguments(this MethodDefinition methodDefinition, ElementNode enode, ModuleDefinition module)
+ public static bool MatchXArguments(this MethodDefinition methodDefinition, ElementNode enode, ModuleDefinition module, ILContext context)
{
if (!enode.Properties.ContainsKey(XmlName.xArguments))
return !methodDefinition.HasParameters;
@@ -28,7 +28,7 @@ namespace Xamarin.Forms.Build.Tasks
for (var i = 0; i < methodDefinition.Parameters.Count; i++)
{
var paramType = methodDefinition.Parameters[i].ParameterType;
- var argType = ((IElementNode)arguments[i]).XmlType.GetTypeReference(module, null);
+ var argType = context.Variables [arguments [i] as IElementNode].VariableType;
if (!argType.InheritsFromOrImplements(paramType))
return false;
}
diff --git a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
index 1bdd8bf1..0b26e277 100644
--- a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
+++ b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
@@ -88,6 +88,8 @@
<Compile Include="XamlCAssemblyResolver.cs" />
<Compile Include="FixedCreateCSharpManifestResourceName.cs" />
<Compile Include="MethodDefinitionExtensions.cs" />
+ <Compile Include="CompiledMarkupExtensions\StaticExtension.cs" />
+ <Compile Include="CompiledMarkupExtensions\ICompiledMarkupExtension.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
@@ -113,6 +115,9 @@
<Name>ICSharpCode.Decompiler</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Folder Include="CompiledMarkupExtensions\" />
+ </ItemGroup>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml
index a90a0378..5225c7d9 100644
--- a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml
+++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml
@@ -54,5 +54,19 @@
</local:MockFactory>
</local:MockView.Content>
</local:MockView>
+ <local:MockView x:Name="v6">
+ <local:MockView.Content>
+ <local:MockFactory>
+ <x:Arguments>
+ <StaticExtension Member="local:MockxStatic.MockStaticProperty"/>
+ </x:Arguments>
+ </local:MockFactory>
+ </local:MockView.Content>
+ </local:MockView>
+ <local:MockView x:Name="v7">
+ <local:MockView.Content>
+ <local:MockFactory x:Arguments="{x:Static local:MockxStatic.MockStaticProperty}"/>
+ </local:MockView.Content>
+ </local:MockView>
</StackLayout>
</ContentPage> \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs
index 42f359b7..9fa4e924 100644
--- a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs
+++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs
@@ -1,5 +1,6 @@
using Xamarin.Forms;
using NUnit.Framework;
+using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
@@ -16,11 +17,16 @@ namespace Xamarin.Forms.Xaml.UnitTests
Content = "default ctor";
}
- public MockFactory (string arg0, string arg1)
+ public MockFactory(string arg0, string arg1)
{
Content = "alternate ctor " + arg0 + arg1;
}
+ public MockFactory(string arg0)
+ {
+ Content = "alternate ctor " + arg0;
+ }
+
public MockFactory (int arg)
{
Content = "int ctor " + arg.ToString ();
@@ -63,6 +69,12 @@ namespace Xamarin.Forms.Xaml.UnitTests
[TestFixture]
public class Tests
{
+ [SetUp]
+ public void SetUp()
+ {
+ Device.PlatformServices = new MockPlatformServices();
+ }
+
[TestCase (false)]
[TestCase (true)]
public void TestDefaultCtor (bool useCompiledXaml)
@@ -110,6 +122,22 @@ namespace Xamarin.Forms.Xaml.UnitTests
var layout = new FactoryMethods (useCompiledXaml);
Assert.AreEqual ("factory 42foo", layout.v5.Content.Content);
}
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestCtorWithxStatic(bool useCompiledXaml)
+ {
+ var layout = new FactoryMethods(useCompiledXaml);
+ Assert.AreEqual("alternate ctor Property", layout.v6.Content.Content);
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestCtorWithxStaticAttribute(bool useCompiledXaml)
+ {
+ var layout = new FactoryMethods(useCompiledXaml);
+ Assert.AreEqual("alternate ctor Property", layout.v7.Content.Content);
+ }
}
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/Validation/StaticExtensionException.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/Validation/StaticExtensionException.xaml.cs
index d7476b74..cb8b22b4 100644
--- a/Xamarin.Forms.Xaml.UnitTests/Validation/StaticExtensionException.xaml.cs
+++ b/Xamarin.Forms.Xaml.UnitTests/Validation/StaticExtensionException.xaml.cs
@@ -7,6 +7,7 @@ using NUnit.Framework;
namespace Xamarin.Forms.Xaml.UnitTests
{
+ [XamlCompilation(XamlCompilationOptions.Skip)]
public partial class StaticExtensionException : ContentPage
{
public StaticExtensionException ()
@@ -23,7 +24,6 @@ namespace Xamarin.Forms.Xaml.UnitTests
public class Issue2115
{
[TestCase (false)]
- [TestCase (true)]
public void xStaticThrowsMeaningfullException (bool useCompiledXaml)
{
Assert.Throws (new XamlParseExceptionConstraint (6, 34), () => new StaticExtensionException (useCompiledXaml));
diff --git a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs
index e52ae594..014d82c2 100644
--- a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs
+++ b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs
@@ -124,8 +124,8 @@ namespace Xamarin.Forms.Xaml
Values[node] = value;
- var typeExtension = value as TypeExtension;
- if (typeExtension != null)
+ var markup = value as IMarkupExtension;
+ if (markup != null && (value is TypeExtension || value is StaticExtension))
{
var serviceProvider = new XamlServiceProvider(node, Context);
@@ -135,7 +135,7 @@ namespace Xamarin.Forms.Xaml
foreach (var cnode in node.CollectionItems)
cnode.Accept(visitor, node);
- value = typeExtension.ProvideValue(serviceProvider);
+ value = markup.ProvideValue(serviceProvider);
node.Properties.Clear();
node.CollectionItems.Clear();
diff --git a/Xamarin.Forms.Xaml/ExpandMarkupsVisitor.cs b/Xamarin.Forms.Xaml/ExpandMarkupsVisitor.cs
index 0d5e9ee6..36e8fc17 100644
--- a/Xamarin.Forms.Xaml/ExpandMarkupsVisitor.cs
+++ b/Xamarin.Forms.Xaml/ExpandMarkupsVisitor.cs
@@ -12,6 +12,14 @@ namespace Xamarin.Forms.Xaml
Context = context;
}
+ public static readonly IList<XmlName> Skips = new List<XmlName>
+ {
+ XmlName.xKey,
+ XmlName.xTypeArguments,
+ XmlName.xFactoryMethod,
+ XmlName.xName
+ };
+
Dictionary<INode, object> Values
{
get { return Context.Values; }
@@ -44,7 +52,7 @@ namespace Xamarin.Forms.Xaml
XmlName propertyName;
if (!ApplyPropertiesVisitor.TryGetPropertyName(markupnode, parentNode, out propertyName))
return;
- if (ApplyPropertiesVisitor.Skips.Contains(propertyName))
+ if (Skips.Contains(propertyName))
return;
if (parentElement.SkipProperties.Contains(propertyName))
return;
diff --git a/Xamarin.Forms.Xaml/XamlParser.cs b/Xamarin.Forms.Xaml/XamlParser.cs
index 730c1624..7dd79d77 100644
--- a/Xamarin.Forms.Xaml/XamlParser.cs
+++ b/Xamarin.Forms.Xaml/XamlParser.cs
@@ -223,6 +223,9 @@ namespace Xamarin.Forms.Xaml
case "x:FactoryMethod":
propertyName = XmlName.xFactoryMethod;
break;
+ case "x:Arguments":
+ propertyName = XmlName.xArguments;
+ break;
default:
Debug.WriteLine("Unhandled {0}", reader.Name);
continue;