summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephane Delcroix <stephane@delcroix.org>2016-12-01 22:26:05 +0100
committerStephane Delcroix <stephane@delcroix.org>2016-12-01 23:29:38 +0100
commit68027394ba02895e466ff41f5395e8df3666e278 (patch)
tree1174f6212deeb0b5a4a49884fff1f4b052376d0c
parent6217c08c127b2b8846d61c5221e088161035bbee (diff)
downloadxamarin-forms-68027394ba02895e466ff41f5395e8df3666e278.tar.gz
xamarin-forms-68027394ba02895e466ff41f5395e8df3666e278.tar.bz2
xamarin-forms-68027394ba02895e466ff41f5395e8df3666e278.zip
[Xaml] support non-int enums (#575)
-rw-r--r--Xamarin.Forms.Build.Tasks/NodeILExtensions.cs84
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/SetValue.xaml3
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs41
3 files changed, 113 insertions, 15 deletions
diff --git a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
index a7fed895..ebd4b2c7 100644
--- a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
+++ b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
@@ -111,7 +111,7 @@ namespace Xamarin.Forms.Build.Tasks
}
//Obvious Built-in conversions
if (targetTypeRef.Resolve().BaseType != null && targetTypeRef.Resolve().BaseType.FullName == "System.Enum")
- yield return Instruction.Create(OpCodes.Ldc_I4, ParseEnum(targetTypeRef, str, node));
+ yield return PushParsedEnum(targetTypeRef, str, node);
else if (targetTypeRef.FullName == "System.Char")
yield return Instruction.Create(OpCodes.Ldc_I4, Char.Parse(str));
else if (targetTypeRef.FullName == "System.Byte")
@@ -174,29 +174,87 @@ namespace Xamarin.Forms.Build.Tasks
yield return Instruction.Create(OpCodes.Box, module.Import(originalTypeRef));
}
- static int ParseEnum(TypeReference enumRef, string value, IXmlLineInfo lineInfo)
+ static Instruction PushParsedEnum(TypeReference enumRef, string value, IXmlLineInfo lineInfo)
{
var enumDef = enumRef.Resolve();
if (!enumDef.IsEnum)
throw new InvalidOperationException();
- int? result = null;
+ // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
+ // https://msdn.microsoft.com/en-us/library/sbbt4032.aspx
+ byte b = 0; sbyte sb = 0; short s = 0; ushort us = 0;
+ int i = 0; uint ui = 0; long l = 0; ulong ul = 0;
+ bool found = false;
+ TypeReference typeRef = null;
- foreach (var v in value.Split(','))
- {
- foreach (var field in enumDef.Fields)
- {
+ foreach (var field in enumDef.Fields)
+ if (field.Name == "value__")
+ typeRef = field.FieldType;
+
+ if (typeRef == null)
+ throw new ArgumentException();
+
+ foreach (var v in value.Split(',')) {
+ foreach (var field in enumDef.Fields) {
if (field.Name == "value__")
continue;
- if (field.Name == v.Trim())
- result = (result ?? 0) | (int)field.Constant;
+ if (field.Name == v.Trim()) {
+ switch (typeRef.FullName) {
+ case "System.Byte":
+ b |= (byte)field.Constant;
+ break;
+ case "System.SByte":
+ if (found)
+ throw new XamlParseException($"Multi-valued enums are not valid on sbyte enum types", lineInfo);
+ sb = (sbyte)field.Constant;
+ break;
+ case "System.Int16":
+ s |= (short)field.Constant;
+ break;
+ case "System.UInt16":
+ us |= (ushort)field.Constant;
+ break;
+ case "System.Int32":
+ i |= (int)field.Constant;
+ break;
+ case "System.UInt32":
+ ui |= (uint)field.Constant;
+ break;
+ case "System.Int64":
+ l |= (long)field.Constant;
+ break;
+ case "System.UInt64":
+ ul |= (ulong)field.Constant;
+ break;
+ }
+ found = true;
+ }
}
}
- if (result.HasValue)
- return result.Value;
-
- throw new XamlParseException(string.Format("Enum value not found for {0}", value), lineInfo);
+ if (!found)
+ throw new XamlParseException($"Enum value not found for {value}", lineInfo);
+
+ switch (typeRef.FullName) {
+ case "System.Byte":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)b);
+ case "System.SByte":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)sb);
+ case "System.Int16":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)s);
+ case "System.UInt16":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)us);
+ case "System.Int32":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)i);
+ case "System.UInt32":
+ return Instruction.Create(OpCodes.Ldc_I4, (uint)ui);
+ case "System.Int64":
+ return Instruction.Create(OpCodes.Ldc_I4, (long)l);
+ case "System.UInt64":
+ return Instruction.Create(OpCodes.Ldc_I4, (ulong)ul);
+ default:
+ throw new XamlParseException($"Enum value not found for {value}", lineInfo);
+ }
}
public static IEnumerable<Instruction> PushXmlLineInfo(this INode node, ILContext context)
diff --git a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml
index da844ed0..40cf6210 100644
--- a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml
+++ b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml
@@ -83,5 +83,6 @@
<d:IgnorableElement />
</ContentView.Content>
</ContentView>
+ <local:ViewWithEnums x:Name="enums" IntEnum="Foo" ByteEnum="Bar" />
</StackLayout>
-</ContentPage> \ No newline at end of file
+</ContentPage>
diff --git a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs
index 2226402c..963fca06 100644
--- a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs
+++ b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs
@@ -13,6 +13,32 @@ namespace Xamarin.Forms.Xaml.UnitTests
}
}
+ public class MockViewWithValues : View
+ {
+ public UInt16 UShort { get; set; }
+ public decimal ADecimal { get; set; }
+ }
+
+ public enum IntEnum
+ {
+ Foo,
+ Bar,
+ Baz
+ }
+
+ public enum ByteEnum : byte
+ {
+ Foo,
+ Bar,
+ Baz
+ }
+
+ public class ViewWithEnums : View
+ {
+ public IntEnum IntEnum { get; set; }
+ public ByteEnum ByteEnum { get; set; }
+ }
+
public partial class SetValue : ContentPage
{
public SetValue ()
@@ -215,6 +241,19 @@ namespace Xamarin.Forms.Xaml.UnitTests
var page = new SetValue(useCompiledXaml);
Assert.That(page.contentview2.Content, Is.TypeOf<Label>());
}
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void NonIntEnums(bool useCompiledXaml)
+ {
+ if (useCompiledXaml) {
+ MockCompiler.Compile(typeof(SetValue));
+ return;
+ }
+ var page = new SetValue(useCompiledXaml);
+ Assert.AreEqual(IntEnum.Foo, page.enums.IntEnum);
+ Assert.AreEqual(ByteEnum.Bar, page.enums.ByteEnum);
+ }
}
}
-} \ No newline at end of file
+}