diff options
author | Stephane Delcroix <stephane@delcroix.org> | 2016-12-01 22:26:05 +0100 |
---|---|---|
committer | Stephane Delcroix <stephane@delcroix.org> | 2016-12-01 23:29:38 +0100 |
commit | 68027394ba02895e466ff41f5395e8df3666e278 (patch) | |
tree | 1174f6212deeb0b5a4a49884fff1f4b052376d0c | |
parent | 6217c08c127b2b8846d61c5221e088161035bbee (diff) | |
download | xamarin-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.cs | 84 | ||||
-rw-r--r-- | Xamarin.Forms.Xaml.UnitTests/SetValue.xaml | 3 | ||||
-rw-r--r-- | Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs | 41 |
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 +} |