diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentNamespace.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentNamespace.output index be7480c..a7191ec 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentNamespace.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentNamespace.output @@ -127,12 +127,11 @@ namespace Some.Namespace.Here1; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here1.MyEnum value) - => value switch - { - Some.Namespace.Here1.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here1.MyEnum value) => value switch + { + Some.Namespace.Here1.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here1.MyEnum value, out Int32 underlyingValue) { @@ -283,12 +282,11 @@ namespace Some.Namespace.Here2; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here2.MyEnum value) - => value switch - { - Some.Namespace.Here2.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here2.MyEnum value) => value switch + { + Some.Namespace.Here2.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here2.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentUnderlyingType.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentUnderlyingType.output index a9c9c5a..22d5c40 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentUnderlyingType.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/DifferentUnderlyingType.output @@ -127,12 +127,11 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Byte underlyingValue) { @@ -283,12 +282,11 @@ namespace Some.Namespace.Here; public static partial class MyEnum2Extensions { - public static string GetString(this Some.Namespace.Here.MyEnum2 value) - => value switch - { - Some.Namespace.Here.MyEnum2.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum2 value) => value switch + { + Some.Namespace.Here.MyEnum2.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum2 value, out UInt64 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/DisableEnumsWrapper.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/DisableEnumsWrapper.output index 04d52c3..f6c17e9 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/DisableEnumsWrapper.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/DisableEnumsWrapper.output @@ -123,12 +123,11 @@ using System.Diagnostics.CodeAnalysis; public static partial class MyEnumExtensions { - public static string GetString(this global::MyEnum value) - => value switch - { - global::MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this global::MyEnum value) => value switch + { + global::MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this global::MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/DisplayName.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/DisplayName.output index d3572c0..8687d2a 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/DisplayName.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/DisplayName.output @@ -229,14 +229,13 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.Value1 => "Value1", - Some.Namespace.Here.MyEnum.Value2 => "Value2", - Some.Namespace.Here.MyEnum.Value3 => "Value3", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.Value1 => "Value1", + Some.Namespace.Here.MyEnum.Value2 => "Value2", + Some.Namespace.Here.MyEnum.Value3 => "Value3", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/DuplicateValues.input b/Src/EnumSourceGen.Tests.CodeGen/Resources/DuplicateValues.input new file mode 100644 index 0000000..c79dc71 --- /dev/null +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/DuplicateValues.input @@ -0,0 +1,13 @@ +//This test is checks if we support duplicate values for flag enums + +namespace Some.Namespace.Here; + +[Flags] +[EnumSourceGen] +public enum Profile +{ + Unknown = 0, + WindowsLegacy = 1 << 0, + WindowsServer2022 = 1 << 8, + NewestServer = WindowsServer2022, +} \ No newline at end of file diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/DuplicateValues.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/DuplicateValues.output new file mode 100644 index 0000000..ee2663a --- /dev/null +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/DuplicateValues.output @@ -0,0 +1,235 @@ +// +#nullable enable +using System; + +namespace Some.Namespace.Here; + +[Flags] +public enum ProfileFormat : byte +{ + None = 0, + Name = 1, + Value = 2, + Default = Name | Value +} +// +#nullable enable +using System; + +namespace Some.Namespace.Here; + +public static partial class Enums +{ + public static partial class Profile + { + public const int MemberCount = 4; + public const bool IsFlagEnum = true; + + public static string[] GetMemberNames() => _names ??= new string[] { + "Unknown", + "WindowsLegacy", + "WindowsServer2022", + "NewestServer" + }; + + public static Some.Namespace.Here.Profile[] GetMemberValues() => _values ??= new Some.Namespace.Here.Profile[] { + Some.Namespace.Here.Profile.Unknown, + Some.Namespace.Here.Profile.WindowsLegacy, + Some.Namespace.Here.Profile.WindowsServer2022, + Some.Namespace.Here.Profile.NewestServer + }; + + public static Int32[] GetUnderlyingValues() => _underlyingValues ??= new Int32[] { + 0, + 1, + 256, + 256 + }; + + public static bool TryParse(string value, out Some.Namespace.Here.Profile result, Some.Namespace.Here.ProfileFormat format = Some.Namespace.Here.ProfileFormat.Default, StringComparison comparison = StringComparison.Ordinal) + { + if (format.HasFlag(Some.Namespace.Here.ProfileFormat.Name)) + { + if (value.Equals("Unknown", comparison)) + { + result = Some.Namespace.Here.Profile.Unknown; + return true; + } + + if (value.Equals("WindowsLegacy", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsLegacy; + return true; + } + + if (value.Equals("WindowsServer2022", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsServer2022; + return true; + } + + if (value.Equals("NewestServer", comparison)) + { + result = Some.Namespace.Here.Profile.NewestServer; + return true; + } + } + if (format.HasFlag(Some.Namespace.Here.ProfileFormat.Value)) + { + if (value.Equals("0", comparison)) + { + result = Some.Namespace.Here.Profile.Unknown; + return true; + } + + if (value.Equals("1", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsLegacy; + return true; + } + + if (value.Equals("256", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsServer2022; + return true; + } + + if (value.Equals("256", comparison)) + { + result = Some.Namespace.Here.Profile.NewestServer; + return true; + } + } + result = default; + return false; + } + +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER + public static bool TryParse(ReadOnlySpan value, out Some.Namespace.Here.Profile result, Some.Namespace.Here.ProfileFormat format = Some.Namespace.Here.ProfileFormat.Default, StringComparison comparison = StringComparison.Ordinal) + { + if (format.HasFlag(Some.Namespace.Here.ProfileFormat.Name)) + { + if (value.Equals("Unknown", comparison)) + { + result = Some.Namespace.Here.Profile.Unknown; + return true; + } + + if (value.Equals("WindowsLegacy", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsLegacy; + return true; + } + + if (value.Equals("WindowsServer2022", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsServer2022; + return true; + } + + if (value.Equals("NewestServer", comparison)) + { + result = Some.Namespace.Here.Profile.NewestServer; + return true; + } + } + if (format.HasFlag(Some.Namespace.Here.ProfileFormat.Value)) + { + if (value.Equals("0", comparison)) + { + result = Some.Namespace.Here.Profile.Unknown; + return true; + } + + if (value.Equals("1", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsLegacy; + return true; + } + + if (value.Equals("256", comparison)) + { + result = Some.Namespace.Here.Profile.WindowsServer2022; + return true; + } + + if (value.Equals("256", comparison)) + { + result = Some.Namespace.Here.Profile.NewestServer; + return true; + } + } + result = default; + return false; + } + + public static Some.Namespace.Here.Profile Parse(ReadOnlySpan value, Some.Namespace.Here.ProfileFormat format = Some.Namespace.Here.ProfileFormat.Default, StringComparison comparison = StringComparison.Ordinal) + { + if (!TryParse(value, out Some.Namespace.Here.Profile result, format, comparison)) + throw new ArgumentOutOfRangeException($"Invalid value: {value.ToString()}"); + + return result; + } +#endif + + public static Some.Namespace.Here.Profile Parse(string value, Some.Namespace.Here.ProfileFormat format = Some.Namespace.Here.ProfileFormat.Default, StringComparison comparison = StringComparison.Ordinal) + { + if (!TryParse(value, out Some.Namespace.Here.Profile result, format, comparison)) + throw new ArgumentOutOfRangeException($"Invalid value: {value}"); + + return result; + } + + public static bool IsDefined(Some.Namespace.Here.Profile input) + { + return unchecked(((Int32)257UL & (Int32)input) == (Int32)input); + } + + private static string[]? _names; + private static Some.Namespace.Here.Profile[]? _values; + private static Int32[]? _underlyingValues; + + } +} +// +#nullable enable +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Some.Namespace.Here; + +public static partial class ProfileExtensions +{ + public static string GetString(this Some.Namespace.Here.Profile value) => value.ToString(); + + public static bool TryGetUnderlyingValue(this Some.Namespace.Here.Profile value, out Int32 underlyingValue) + { + switch (value.ToString()) + { + case "Unknown": + underlyingValue = 0; + return true; + case "WindowsLegacy": + underlyingValue = 1; + return true; + case "WindowsServer2022": + underlyingValue = 256; + return true; + case "NewestServer": + underlyingValue = 256; + return true; + } + underlyingValue = default; + return false; + } + + public static Int32 GetUnderlyingValue(this Some.Namespace.Here.Profile value) + { + if (!TryGetUnderlyingValue(value, out Int32 underlyingValue)) + throw new ArgumentOutOfRangeException($"Invalid value: {value}"); + + return underlyingValue; + } + + public static bool IsFlagSet(this Some.Namespace.Here.Profile value, Some.Namespace.Here.Profile flag) => ((Int32)value & (Int32)flag) == (Int32)flag; +} diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassName.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassName.output index 3e77289..5d9e289 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassName.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassName.output @@ -127,12 +127,11 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassNamespace.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassNamespace.output index e9209d9..e09249d 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassNamespace.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumClassNamespace.output @@ -127,12 +127,11 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumNameOverride.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumNameOverride.output index 84e3d22..ae7ec4b 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumNameOverride.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumNameOverride.output @@ -127,12 +127,11 @@ namespace Some.Namespace.Here; public static partial class OtherEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumTransform.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumTransform.output index fb6da89..04b6500 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumTransform.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/EnumTransform.output @@ -121,12 +121,11 @@ using System.Diagnostics.CodeAnalysis; internal static partial class MyEnum1Extensions { - public static string GetString(this global::MyEnum1 value) - => value switch - { - global::MyEnum1.First => "NotFirst", - _ => value.ToString() - }; + public static string GetString(this global::MyEnum1 value) => value switch + { + global::MyEnum1.First => "NotFirst", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this global::MyEnum1 value, out Int32 underlyingValue) { @@ -271,12 +270,11 @@ using System.Diagnostics.CodeAnalysis; internal static partial class MyEnum2Extensions { - public static string GetString(this global::MyEnum2 value) - => value switch - { - global::MyEnum2.First => "FIRST", - _ => value.ToString() - }; + public static string GetString(this global::MyEnum2 value) => value switch + { + global::MyEnum2.First => "FIRST", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this global::MyEnum2 value, out Int32 underlyingValue) { @@ -421,12 +419,11 @@ using System.Diagnostics.CodeAnalysis; internal static partial class MyEnum3Extensions { - public static string GetString(this global::MyEnum3 value) - => value switch - { - global::MyEnum3.First => "Last", - _ => value.ToString() - }; + public static string GetString(this global::MyEnum3 value) => value switch + { + global::MyEnum3.First => "Last", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this global::MyEnum3 value, out Int32 underlyingValue) { @@ -571,12 +568,11 @@ using System.Diagnostics.CodeAnalysis; internal static partial class MyEnum4Extensions { - public static string GetString(this global::MyEnum4 value) - => value switch - { - global::MyEnum4.First => "fIRST", - _ => value.ToString() - }; + public static string GetString(this global::MyEnum4 value) => value switch + { + global::MyEnum4.First => "fIRST", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this global::MyEnum4 value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassName.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassName.output index 896ef21..bb508cf 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassName.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassName.output @@ -127,12 +127,11 @@ namespace Some.Namespace.Here; public static partial class MyExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassNamespace.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassNamespace.output index 7af63ae..5677091 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassNamespace.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/ExtensionClassNamespace.output @@ -127,12 +127,11 @@ namespace Test.Namespace; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.Value => "Value", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.Value => "Value", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/Flags.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/Flags.output index 02b41d6..7891590 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/Flags.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/Flags.output @@ -200,15 +200,14 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.First => "First", - Some.Namespace.Here.MyEnum.Second => "Second", - Some.Namespace.Here.MyEnum.Third => "Third", - Some.Namespace.Here.MyEnum.Other => "Other", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.First => "First", + Some.Namespace.Here.MyEnum.Second => "Second", + Some.Namespace.Here.MyEnum.Third => "Third", + Some.Namespace.Here.MyEnum.Other => "Other", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/GlobalNamespaceEnum.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/GlobalNamespaceEnum.output index ea61087..99a70af 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/GlobalNamespaceEnum.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/GlobalNamespaceEnum.output @@ -121,12 +121,11 @@ using System.Diagnostics.CodeAnalysis; public static partial class MyEnumExtensions { - public static string GetString(this global::MyEnum value) - => value switch - { - global::MyEnum.First => "First", - _ => value.ToString() - }; + public static string GetString(this global::MyEnum value) => value switch + { + global::MyEnum.First => "First", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this global::MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/InternalEnum.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/InternalEnum.output index 5a9ab7a..4201240 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/InternalEnum.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/InternalEnum.output @@ -181,14 +181,13 @@ namespace Some.Namespace.Here; internal static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.First => "First", - Some.Namespace.Here.MyEnum.Second => "Second", - Some.Namespace.Here.MyEnum.Third => "Third", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.First => "First", + Some.Namespace.Here.MyEnum.Second => "Second", + Some.Namespace.Here.MyEnum.Third => "Third", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/NestedType.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/NestedType.output index c117db7..0c53d08 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/NestedType.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/NestedType.output @@ -181,14 +181,13 @@ namespace Some.Namespace.Here; internal static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyClass.MyEnum value) - => value switch - { - Some.Namespace.Here.MyClass.MyEnum.First => "First", - Some.Namespace.Here.MyClass.MyEnum.Second => "Second", - Some.Namespace.Here.MyClass.MyEnum.Third => "Third", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyClass.MyEnum value) => value switch + { + Some.Namespace.Here.MyClass.MyEnum.First => "First", + Some.Namespace.Here.MyClass.MyEnum.Second => "Second", + Some.Namespace.Here.MyClass.MyEnum.Third => "Third", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyClass.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/OmitValue.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/OmitValue.output index 99550a5..6cf2e13 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/OmitValue.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/OmitValue.output @@ -123,14 +123,13 @@ using System.Diagnostics.CodeAnalysis; internal static partial class MyEnumExtensions { - public static string GetString(this global::MyEnum value) - => value switch - { - global::MyEnum.Value => "Value", - global::MyEnum.Omit => string.Empty, + public static string GetString(this global::MyEnum value) => value switch + { + global::MyEnum.Value => "Value", + global::MyEnum.Omit => string.Empty, global::MyEnum.OmitWithFilter => "OmitWithFilter", - _ => value.ToString() - }; + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this global::MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueExplicit.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueExplicit.output index 625854c..446e5e8 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueExplicit.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueExplicit.output @@ -181,14 +181,13 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.First => "First", - Some.Namespace.Here.MyEnum.Second => "Second", - Some.Namespace.Here.MyEnum.Third => "Third", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.First => "First", + Some.Namespace.Here.MyEnum.Second => "Second", + Some.Namespace.Here.MyEnum.Third => "Third", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueMultiple.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueMultiple.output index d160d92..a344473 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueMultiple.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueMultiple.output @@ -154,13 +154,12 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.First => "First", - Some.Namespace.Here.MyEnum.Second => "Second", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.First => "First", + Some.Namespace.Here.MyEnum.Second => "Second", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueSingle.output b/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueSingle.output index 7a15145..27373f0 100644 --- a/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueSingle.output +++ b/Src/EnumSourceGen.Tests.CodeGen/Resources/ValueSingle.output @@ -127,12 +127,11 @@ namespace Some.Namespace.Here; public static partial class MyEnumExtensions { - public static string GetString(this Some.Namespace.Here.MyEnum value) - => value switch - { - Some.Namespace.Here.MyEnum.First => "First", - _ => value.ToString() - }; + public static string GetString(this Some.Namespace.Here.MyEnum value) => value switch + { + Some.Namespace.Here.MyEnum.First => "First", + _ => value.ToString() + }; public static bool TryGetUnderlyingValue(this Some.Namespace.Here.MyEnum value, out Int32 underlyingValue) { diff --git a/Src/EnumSourceGen/Generators/EnumExtensionCode.cs b/Src/EnumSourceGen/Generators/EnumExtensionCode.cs index f5ab564..79c4320 100644 --- a/Src/EnumSourceGen/Generators/EnumExtensionCode.cs +++ b/Src/EnumSourceGen/Generators/EnumExtensionCode.cs @@ -20,95 +20,105 @@ public static string Generate(EnumSpec es) string vi = es.AccessChain[0] == Accessibility.Public ? "public" : "internal"; string ut = es.UnderlyingType; - StringBuilder sb = new StringBuilder(); - string res = $$""" -using System; -using System.Diagnostics.CodeAnalysis; -{{(ns != null ? "\nnamespace " + ns + ";\n" : null)}} -{{vi}} static partial class {{en}} -{ - public static string GetString(this {{sn}} value) - => value switch - { - {{GetString()}} - _ => value.ToString() - }; + bool containsDuplicateValue = false; + HashSet values = new HashSet(); - public static bool TryGetUnderlyingValue(this {{sn}} value, out {{ut}} underlyingValue) - { - {{PrintSwitch(TryGetUnderlyingValue())}} - underlyingValue = default; - return false; - } + foreach (var em in es.Members) + { + if (em.OmitValueData?.Exclude.HasFlag(EnumOmitExclude.GetString) == true) + continue; - public static {{ut}} GetUnderlyingValue(this {{sn}} value) - { - if (!TryGetUnderlyingValue(value, out {{ut}} underlyingValue)) - throw new ArgumentOutOfRangeException($"Invalid value: {value}"); + if (!values.Add(em.Value)) + { + containsDuplicateValue = true; + break; + } + } - return underlyingValue; - } -"""; + StringBuilder sb = new StringBuilder(); + string res = $$""" + using System; + using System.Diagnostics.CodeAnalysis; + {{(ns != null ? "\nnamespace " + ns + ";\n" : null)}} + {{vi}} static partial class {{en}} + { + public static string GetString(this {{sn}} value) => {{(containsDuplicateValue ? "value.ToString();" : $"value switch\n {{\n {GetString()}\n _ => value.ToString()\n }};")}} + + public static bool TryGetUnderlyingValue(this {{sn}} value, out {{ut}} underlyingValue) + { + {{PrintSwitch(TryGetUnderlyingValue(), containsDuplicateValue)}} + underlyingValue = default; + return false; + } + + public static {{ut}} GetUnderlyingValue(this {{sn}} value) + { + if (!TryGetUnderlyingValue(value, out {{ut}} underlyingValue)) + throw new ArgumentOutOfRangeException($"Invalid value: {value}"); + + return underlyingValue; + } + """; if (es.HasDisplay) { res += $$""" - - - public static bool TryGetDisplayName(this {{sn}} value, -#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER -[NotNullWhen(true)] -#endif -out string? displayName) - { - {{PrintSwitch(TryGetDisplayName())}} - displayName = null; - return false; - } - - public static string GetDisplayName(this {{sn}} value) - { - if (!TryGetDisplayName(value, out string? displayName)) - throw new ArgumentOutOfRangeException($"Invalid value: {value}"); - - return displayName!; - } -"""; + + + public static bool TryGetDisplayName(this {{sn}} value, + #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER + [NotNullWhen(true)] + #endif + out string? displayName) + { + {{PrintSwitch(TryGetDisplayName())}} + displayName = null; + return false; + } + + public static string GetDisplayName(this {{sn}} value) + { + if (!TryGetDisplayName(value, out string? displayName)) + throw new ArgumentOutOfRangeException($"Invalid value: {value}"); + + return displayName!; + } + """; } if (es.HasDescription) { res += $$""" - - - public static bool TryGetDescription(this {{sn}} value, -#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER -[NotNullWhen(true)] -#endif -out string? description) - { - {{PrintSwitch(TryGetDescription())}} - description = null; - return false; - } - - public static string GetDescription(this {{sn}} value) - { - if (!TryGetDescription(value, out string? description)) - throw new ArgumentOutOfRangeException($"Invalid value: {value}"); - - return description!; - } -"""; + + + public static bool TryGetDescription(this {{sn}} value, + #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER + [NotNullWhen(true)] + #endif + out string? description) + { + {{PrintSwitch(TryGetDescription())}} + description = null; + return false; + } + + public static string GetDescription(this {{sn}} value) + { + if (!TryGetDescription(value, out string? description)) + throw new ArgumentOutOfRangeException($"Invalid value: {value}"); + + return description!; + } + """; } if (es.HasFlags) { res += $$""" - - - public static bool IsFlagSet(this {{sn}} value, {{sn}} flag) => (({{ut}})value & ({{ut}})flag) == ({{ut}})flag; -"""; + + + public static bool IsFlagSet(this {{sn}} value, {{sn}} flag) => (({{ut}})value & ({{ut}})flag) == ({{ut}})flag; + """; } string GetString() @@ -125,7 +135,8 @@ string GetString() string transformed = TransformHelper.TransformName(es, em); - sb.Append(sn).Append('.').Append(em.Name).Append(" => \"").Append(transformed).Append("\",\n "); + sb.Append(sn).Append('.').Append(em.Name).Append(" => \"").Append(transformed) + .Append("\",\n "); } return sb.ToString().TrimEnd(); @@ -138,11 +149,24 @@ IEnumerable TryGetUnderlyingValue() if (em.OmitValueData?.Exclude.HasFlag(EnumOmitExclude.TryGetUnderlyingValue) == false) continue; - yield return $$""" - case {{sn}}.{{em.Name}}: - underlyingValue = {{em.Value}}; - return true; -"""; + //We default to doing a fast comparison using enum values (which is basically just integers), but in the case we have a flags enum with a duplicate value + //we must fall back to using string comparisons, otherwise there will be duplicate branches in the switch. + if (containsDuplicateValue) + { + yield return $$""" + case "{{em.Name}}": + underlyingValue = {{em.Value}}; + return true; + """; + } + else + { + yield return $$""" + case {{sn}}.{{em.Name}}: + underlyingValue = {{em.Value}}; + return true; + """; + } } } @@ -157,10 +181,10 @@ IEnumerable TryGetDisplayName() continue; yield return $$""" - case {{sn}}.{{em.Name}}: - displayName = "{{em.DisplayData.Name}}"; - return true; -"""; + case {{sn}}.{{em.Name}}: + displayName = "{{em.DisplayData.Name}}"; + return true; + """; } } @@ -175,14 +199,14 @@ IEnumerable TryGetDescription() continue; yield return $$""" - case {{sn}}.{{em.Name}}: - description = "{{em.DisplayData.Description}}"; - return true; -"""; + case {{sn}}.{{em.Name}}: + description = "{{em.DisplayData.Description}}"; + return true; + """; } } - string PrintSwitch(IEnumerable cases) + string PrintSwitch(IEnumerable cases, bool stringComparison = false) { string[] arr = cases.ToArray(); @@ -190,7 +214,12 @@ string PrintSwitch(IEnumerable cases) return string.Empty; sb.Clear(); - sb.AppendLine("switch (value)"); + + if (stringComparison) + sb.AppendLine("switch (value.ToString())"); + else + sb.AppendLine("switch (value)"); + sb.Append(Indent(2)).Append('{'); sb.AppendLine();