summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephane Delcroix <stephane@delcroix.org>2016-09-21 13:28:59 +0200
committerJason Smith <jason.smith@xamarin.com>2016-09-22 23:57:19 -0700
commitb0749259099b120a19e5f47add9626fd51e6cf5f (patch)
tree403975f875eb32dabc2f02509938073150cfa13c
parenteb79ff842e701ca4d2c9e1c9d02f654fd2c0f058 (diff)
downloadxamarin-forms-b0749259099b120a19e5f47add9626fd51e6cf5f.tar.gz
xamarin-forms-b0749259099b120a19e5f47add9626fd51e6cf5f.tar.bz2
xamarin-forms-b0749259099b120a19e5f47add9626fd51e6cf5f.zip
[XamlC] supports enum and consts in x:Static
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs44
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/StaticExtensionTests.cs72
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/XStatic.xaml8
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/XStatic.xaml.cs56
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml8
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml.cs55
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj7
-rw-r--r--Xamarin.Forms.Xaml/MarkupExtensions/StaticExtension.cs6
8 files changed, 168 insertions, 88 deletions
diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs
index 82654969..14797c53 100644
--- a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs
+++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs
@@ -32,16 +32,52 @@ namespace Xamarin.Forms.Build.Tasks
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);
+ throw new XamlParseException($"x:Static: unable to find a public static field, static property, const or enum value named {membername} in {typename}", node as IXmlLineInfo);
+ var fieldDef = fieldRef?.Resolve();
if (fieldRef != null) {
memberRef = fieldRef.FieldType;
- return new [] { Instruction.Create(OpCodes.Ldsfld, fieldRef) };
+ if (!fieldDef.HasConstant)
+ return new [] { Instruction.Create(OpCodes.Ldsfld, fieldRef) };
+
+ //Constants can be numbers, Boolean values, strings, or a null reference. (https://msdn.microsoft.com/en-us/library/e6w8fe1b.aspx)
+ if (memberRef == module.TypeSystem.Boolean)
+ return new [] { Instruction.Create(((bool)fieldDef.Constant) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0) };
+ if (memberRef == module.TypeSystem.String)
+ return new [] { Instruction.Create(OpCodes.Ldstr, (string)fieldDef.Constant) };
+ if (fieldDef.Constant == null)
+ return new [] { Instruction.Create(OpCodes.Ldnull) };
+ if (memberRef == module.TypeSystem.Char)
+ return new [] { Instruction.Create(OpCodes.Ldc_I4, (char)fieldDef.Constant) };
+ if (memberRef == module.TypeSystem.Single)
+ return new [] { Instruction.Create(OpCodes.Ldc_R4, (float)fieldDef.Constant) };
+ if (memberRef == module.TypeSystem.Double)
+ return new [] { Instruction.Create(OpCodes.Ldc_R8, (double)fieldDef.Constant) };
+ if (memberRef == module.TypeSystem.Byte || memberRef == module.TypeSystem.Int16 || memberRef == module.TypeSystem.Int32)
+ return new [] { Instruction.Create(OpCodes.Ldc_I4, (int)fieldDef.Constant) };
+ if (memberRef == module.TypeSystem.SByte || memberRef == module.TypeSystem.UInt16 || memberRef == module.TypeSystem.UInt32)
+ return new [] { Instruction.Create(OpCodes.Ldc_I4, (uint)fieldDef.Constant) };
+ if (memberRef == module.TypeSystem.Int64)
+ return new [] { Instruction.Create(OpCodes.Ldc_I8, (long)fieldDef.Constant) };
+ if (memberRef == module.TypeSystem.UInt64)
+ return new [] { Instruction.Create(OpCodes.Ldc_I8, (ulong)fieldDef.Constant) };
+
+ //enum values
+ if (memberRef.Resolve().IsEnum) {
+ if (fieldDef.Constant is long)
+ return new [] { Instruction.Create(OpCodes.Ldc_I8, (long)fieldDef.Constant) };
+ if (fieldDef.Constant is ulong)
+ return new [] { Instruction.Create(OpCodes.Ldc_I8, (ulong)fieldDef.Constant) };
+ if (fieldDef.Constant is uint)
+ return new [] { Instruction.Create(OpCodes.Ldc_I4, (uint)fieldDef.Constant) };
+ //everything else will cast just fine to an int
+ return new [] { Instruction.Create(OpCodes.Ldc_I4, (int)fieldDef.Constant) };
+ }
}
memberRef = propertyDef.PropertyType;
var getterDef = propertyDef.GetMethod;
- return new [] { Instruction.Create(OpCodes.Call, getterDef)};
+ return new [] { Instruction.Create(OpCodes.Call, getterDef) };
}
@@ -49,7 +85,7 @@ namespace Xamarin.Forms.Build.Tasks
{
var split = xmlType.Split(':');
if (split.Length > 2)
- throw new Xaml.XamlParseException(string.Format("Type \"{0}\" is invalid", xmlType), node as IXmlLineInfo);
+ throw new XamlParseException($"Type \"{xmlType}\" is invalid", node as IXmlLineInfo);
string prefix, name;
if (split.Length == 2) {
diff --git a/Xamarin.Forms.Xaml.UnitTests/StaticExtensionTests.cs b/Xamarin.Forms.Xaml.UnitTests/StaticExtensionTests.cs
deleted file mode 100644
index 86e02fe7..00000000
--- a/Xamarin.Forms.Xaml.UnitTests/StaticExtensionTests.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System;
-using NUnit.Framework;
-using System.Xml;
-
-using Xamarin.Forms.Core.UnitTests;
-using System.Reflection;
-
-namespace Xamarin.Forms.Xaml.UnitTests
-{
- [TestFixture]
- public class StaticExtensionTests : BaseTestFixture
- {
- IXamlTypeResolver typeResolver;
-
- [SetUp]
- public override void Setup ()
- {
- base.Setup ();
- var nsManager = new XmlNamespaceManager (new NameTable ());
- nsManager.AddNamespace ("local", "clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests");
- nsManager.AddNamespace ("x", "http://schemas.microsoft.com/winfx/2006/xaml");
-
- typeResolver = new Internals.XamlTypeResolver (nsManager, XamlParser.GetElementType, Assembly.GetCallingAssembly ());
- }
-
- [Test]
- public void TestxStatic ()
- {
- //{x:Static Member=prefix:typeName.staticMemberName}
- //{x:Static prefix:typeName.staticMemberName}
-
- //The code entity that is referenced must be one of the following:
- // - A constant
- // - A static property
- // - A field
- // - An enumeration value
- // All other cases should throw
-
- var serviceProvider = new Internals.XamlServiceProvider (null, null) {
- IXamlTypeResolver = typeResolver,
- };
-
- //Static property
- var markupString = @"{x:Static Member=""local:MockxStatic.MockStaticProperty""}";
- Assert.AreEqual ("Property", (new MarkupExtensionParser ()).ParseExpression (ref markupString, serviceProvider));
-
- //constant
- markupString = @"{x:Static Member=""local:MockxStatic.MockConstant""}";
- Assert.AreEqual ("Constant", (new MarkupExtensionParser ()).ParseExpression (ref markupString, serviceProvider));
-
- //field
- markupString = @"{x:Static Member=""local:MockxStatic.MockField""}";
- Assert.AreEqual ("Field", (new MarkupExtensionParser ()).ParseExpression (ref markupString, serviceProvider));
-
- //enum
- markupString = @"{x:Static Member=""local:MockEnum.Second""}";
- Assert.AreEqual (MockEnum.Second, (new MarkupExtensionParser ()).ParseExpression (ref markupString, serviceProvider));
-
- //throw on InstanceProperty
- markupString = @"{x:Static Member=""local:MockxStatic.InstanceProperty""}";
- Assert.Throws<XamlParseException> (()=> (new MarkupExtensionParser ()).ParseExpression (ref markupString, serviceProvider));
-
- //quotes are optional
- markupString = @"{x:Static Member=local:MockxStatic.MockStaticProperty}";
- Assert.AreEqual ("Property", (new MarkupExtensionParser ()).ParseExpression (ref markupString, serviceProvider));
-
- //Member is optional
- markupString = @"{x:Static local:MockxStatic.MockStaticProperty}";
- Assert.AreEqual ("Property", (new MarkupExtensionParser ()).ParseExpression (ref markupString, serviceProvider));
- }
- }
-} \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml b/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml
index 7c2910cd..32d2945e 100644
--- a/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml
+++ b/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Xamarin.Forms.Xaml.UnitTests"
@@ -10,5 +10,11 @@
Text="{x:Static local:MockxStatic.MockStaticProperty}" />
<Label x:Name="color"
TextColor="{x:Static local:MockxStatic.BackgroundColor}" />
+ <Label x:Name="constant"
+ Text="{x:Static local:MockxStatic.MockConstant}"/>
+ <Label x:Name="field"
+ Text="{x:Static local:MockxStatic.MockField}"/>
+ <ScrollView x:Name="enuM"
+ Orientation="{x:Static ScrollOrientation.Both}"/>
</StackLayout>
</ContentPage> \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml.cs
index ff1f0199..d8a466e9 100644
--- a/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml.cs
+++ b/Xamarin.Forms.Xaml.UnitTests/XStatic.xaml.cs
@@ -1,9 +1,5 @@
-using System;
-using System.Collections.Generic;
-
-using Xamarin.Forms;
-
-using NUnit.Framework;
+using NUnit.Framework;
+using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
@@ -16,7 +12,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
public static readonly Color BackgroundColor = Color.Fuchsia;
}
- public enum MockEnum
+ public enum MockEnum : long
{
First,
Second,
@@ -37,6 +33,28 @@ namespace Xamarin.Forms.Xaml.UnitTests
[TestFixture]
public class Tests
{
+ //{x:Static Member=prefix:typeName.staticMemberName}
+ //{x:Static prefix:typeName.staticMemberName}
+
+ //The code entity that is referenced must be one of the following:
+ // - A constant
+ // - A static property
+ // - A field
+ // - An enumeration value
+ // All other cases should throw
+
+ [SetUp]
+ public void Setup()
+ {
+ Device.PlatformServices = new MockPlatformServices();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ }
+
[TestCase (false)]
[TestCase (true)]
public void StaticProperty (bool useCompiledXaml)
@@ -60,6 +78,30 @@ namespace Xamarin.Forms.Xaml.UnitTests
var layout = new XStatic (useCompiledXaml);
Assert.AreEqual (Color.Fuchsia, layout.color.TextColor);
}
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void Constant(bool useCompiledXaml)
+ {
+ var layout = new XStatic(useCompiledXaml);
+ Assert.AreEqual("Constant", layout.constant.Text);
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void Field(bool useCompiledXaml)
+ {
+ var layout = new XStatic(useCompiledXaml);
+ Assert.AreEqual("Field", layout.field.Text);
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void Enum(bool useCompiledXaml)
+ {
+ var layout = new XStatic(useCompiledXaml);
+ Assert.AreEqual(ScrollOrientation.Both, layout.enuM.Orientation);
+ }
}
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml b/Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml
new file mode 100644
index 00000000..58d3cb10
--- /dev/null
+++ b/Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+ xmlns:local="clr-namespace:Xamarin.Forms.Xaml.UnitTests"
+ x:Class="Xamarin.Forms.Xaml.UnitTests.XStaticException">
+ <Label x:Name="shouldThrow"
+ Text="{x:Static Member=local:MockxStatic.InstanceProperty}" />
+</ContentPage> \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml.cs
new file mode 100644
index 00000000..261de06a
--- /dev/null
+++ b/Xamarin.Forms.Xaml.UnitTests/XStaticException.xaml.cs
@@ -0,0 +1,55 @@
+using NUnit.Framework;
+using Xamarin.Forms.Core.UnitTests;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+ [XamlCompilation(XamlCompilationOptions.Skip)]
+ public partial class XStaticException : ContentPage
+ {
+ public XStaticException()
+ {
+ InitializeComponent();
+ }
+
+ public XStaticException(bool useCompiledXaml)
+ {
+ //this stub will be replaced at compile time
+ }
+
+ [TestFixture]
+ public class Tests
+ {
+ //{x:Static Member=prefix:typeName.staticMemberName}
+ //{x:Static prefix:typeName.staticMemberName}
+
+ //The code entity that is referenced must be one of the following:
+ // - A constant
+ // - A static property
+ // - A field
+ // - An enumeration value
+ // All other cases should throw
+
+ [SetUp]
+ public void Setup()
+ {
+ Device.PlatformServices = new MockPlatformServices();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void ThrowOnInstanceProperty(bool useCompiledXaml)
+ {
+ if (!useCompiledXaml)
+ Assert.Throws(new XamlParseExceptionConstraint(7, 6), () => new XStaticException(useCompiledXaml));
+ else
+ Assert.Throws(new XamlParseExceptionConstraint(7, 6), () => MockCompiler.Compile(typeof(XStaticException)));
+ }
+ }
+ }
+} \ 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 16f54e88..b2f5e0ac 100644
--- a/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj
+++ b/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj
@@ -96,7 +96,6 @@
<Compile Include="MarkupExtensionTests.cs" />
<Compile Include="NameScopeTests.cs" />
<Compile Include="OnPlatformTests.cs" />
- <Compile Include="StaticExtensionTests.cs" />
<Compile Include="NullExtensionTests.cs" />
<Compile Include="TypeExtensionTests.cs" />
<Compile Include="FactoryMethodTests.cs" />
@@ -366,6 +365,9 @@
<DependentUpon>NativeViewsAndBindings.xaml</DependentUpon>
</Compile>
<Compile Include="MockCompiler.cs" />
+ <Compile Include="XStaticException.xaml.cs">
+ <DependentUpon>XStaticException.xaml</DependentUpon>
+ </Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
@@ -648,6 +650,9 @@
<EmbeddedResource Include="NativeViewsAndBindings.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
+ <EmbeddedResource Include="XStaticException.xaml">
+ <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+ </EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
diff --git a/Xamarin.Forms.Xaml/MarkupExtensions/StaticExtension.cs b/Xamarin.Forms.Xaml/MarkupExtensions/StaticExtension.cs
index 7585eb6e..8de0ebf4 100644
--- a/Xamarin.Forms.Xaml/MarkupExtensions/StaticExtension.cs
+++ b/Xamarin.Forms.Xaml/MarkupExtensions/StaticExtension.cs
@@ -5,7 +5,7 @@ using System.Xml;
namespace Xamarin.Forms.Xaml
{
- [ContentProperty("Member")]
+ [ContentProperty(nameof(Member))]
public class StaticExtension : IMarkupExtension
{
public string Member { get; set; }
@@ -16,7 +16,7 @@ namespace Xamarin.Forms.Xaml
IXmlLineInfo lineInfo;
if (serviceProvider == null)
- throw new ArgumentNullException("serviceProvider");
+ throw new ArgumentNullException(nameof(serviceProvider));
var typeResolver = serviceProvider.GetService(typeof (IXamlTypeResolver)) as IXamlTypeResolver;
if (typeResolver == null)
throw new ArgumentException("No IXamlTypeResolver in IServiceProvider");
@@ -44,7 +44,7 @@ namespace Xamarin.Forms.Xaml
lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
- throw new XamlParseException(String.Format("No static member found for {0}", Member), lineInfo);
+ throw new XamlParseException($"No static member found for {Member}", lineInfo);
}
}
} \ No newline at end of file