diff --git a/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj b/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj index e03d7d7..5efb0d5 100644 --- a/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj +++ b/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj @@ -25,7 +25,7 @@ MIT True latest-Recommended - 5.1.1 + 5.1.2 README.md true 1701;1702;NU5128 diff --git a/AutomaticInterface/AutomaticInterface/Builder.cs b/AutomaticInterface/AutomaticInterface/Builder.cs index 9b167ca..0a61b40 100644 --- a/AutomaticInterface/AutomaticInterface/Builder.cs +++ b/AutomaticInterface/AutomaticInterface/Builder.cs @@ -15,7 +15,8 @@ private static string InheritDoc(ISymbol source) => private static readonly SymbolDisplayFormat FullyQualifiedDisplayFormat = new( genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - memberOptions: SymbolDisplayMemberOptions.IncludeParameters, + memberOptions: SymbolDisplayMemberOptions.IncludeParameters + | SymbolDisplayMemberOptions.IncludeContainingType, parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut | SymbolDisplayParameterOptions.IncludeDefaultValue @@ -27,6 +28,20 @@ private static string InheritDoc(ISymbol source) => | SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers ); + /// + /// We do need to be able to group shadowing and new methods/events into a single entry, hence this is missing SymbolDisplayMemberOptions.IncludeContainingType + /// + private static readonly SymbolDisplayFormat FullyQualifiedDisplayFormatForGrouping = + new( + genericsOptions: FullyQualifiedDisplayFormat.GenericsOptions, + memberOptions: FullyQualifiedDisplayFormat.MemberOptions + & ~SymbolDisplayMemberOptions.IncludeContainingType, + parameterOptions: FullyQualifiedDisplayFormat.ParameterOptions, + typeQualificationStyle: FullyQualifiedDisplayFormat.TypeQualificationStyle, + globalNamespaceStyle: FullyQualifiedDisplayFormat.GlobalNamespaceStyle, + miscellaneousOptions: FullyQualifiedDisplayFormat.MiscellaneousOptions + ); + public static string BuildInterfaceFor(ITypeSymbol typeSymbol) { if ( @@ -91,7 +106,7 @@ private static void AddMethodsToInterface(List members, InterfaceBuilde .Where(x => x.MethodKind == MethodKind.Ordinary) .Where(x => x.ContainingType.Name != nameof(Object)) .Where(x => !HasIgnoreAttribute(x)) - .GroupBy(x => x.ToDisplayString(FullyQualifiedDisplayFormat)) + .GroupBy(x => x.ToDisplayString(FullyQualifiedDisplayFormatForGrouping)) .Select(g => g.First()) .ToList() .ForEach(method => AddMethod(codeGenerator, method)); @@ -182,7 +197,7 @@ private static void AddEventsToInterface(List members, InterfaceBuilder members .Where(x => x.Kind == SymbolKind.Event) .OfType() - .GroupBy(x => x.ToDisplayString(FullyQualifiedDisplayFormat)) + .GroupBy(x => x.ToDisplayString(FullyQualifiedDisplayFormatForGrouping)) .Select(g => g.First()) .ToList() .ForEach(evt => diff --git a/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs b/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs index 2e60a05..b43b128 100644 --- a/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs +++ b/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs @@ -121,7 +121,9 @@ public string Build() cb.Indent(); foreach (var method in methodInfos) + { BuildMethod(cb, method); + } cb.Dedent(); diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnums.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnums.verified.txt new file mode 100644 index 0000000..90b8ad7 --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnums.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnumsAsReturnType.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnumsAsReturnType.verified.txt new file mode 100644 index 0000000..3f0a56c --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnumsAsReturnType.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + global::AutomaticInterfaceExample.EnumWithByteType MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnumsProperties.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnumsProperties.verified.txt new file mode 100644 index 0000000..d3cdbdd --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithByteEnumsProperties.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + global::AutomaticInterfaceExample.EnumWithByteType SomeProperty { get; set; } + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-byte.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-byte.verified.txt new file mode 100644 index 0000000..90b8ad7 --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-byte.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-int.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-int.verified.txt new file mode 100644 index 0000000..90b8ad7 --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-int.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-long.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-long.verified.txt new file mode 100644 index 0000000..90b8ad7 --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum-long.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum.received.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum.received.txt new file mode 100644 index 0000000..90b8ad7 --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum.received.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum.verified.txt new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnum.verified.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithEnumsAsReturnType.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnumsAsReturnType.verified.txt new file mode 100644 index 0000000..3f0a56c --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithEnumsAsReturnType.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + global::AutomaticInterfaceExample.EnumWithByteType MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.WorksWithFlagEnum.verified.txt b/AutomaticInterface/Tests/Enums/Enums.WorksWithFlagEnum.verified.txt new file mode 100644 index 0000000..90b8ad7 --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.WorksWithFlagEnum.verified.txt @@ -0,0 +1,18 @@ +//-------------------------------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +//-------------------------------------------------------------------------------------------------- + +namespace AutomaticInterfaceExample +{ + [global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void MethodWithDefaultParameter(global::AutomaticInterfaceExample.EnumWithByteType a = global::AutomaticInterfaceExample.EnumWithByteType.B); + + } +} diff --git a/AutomaticInterface/Tests/Enums/Enums.cs b/AutomaticInterface/Tests/Enums/Enums.cs new file mode 100644 index 0000000..cbced1e --- /dev/null +++ b/AutomaticInterface/Tests/Enums/Enums.cs @@ -0,0 +1,101 @@ +namespace Tests.Enums; + +public class Enums +{ + [Theory] + [InlineData("byte")] + [InlineData("int")] + [InlineData("long")] + public async Task WorksWithEnum(string enumName) + { + var code = $$""" + + using AutomaticInterface; + using System; + + namespace AutomaticInterfaceExample; + + public enum EnumWithByteType : {{enumName}} { A = 1, B = 2, C = 3 }; + + [GenerateAutomaticInterface] + public class DemoClass + { + public void MethodWithDefaultParameter(EnumWithByteType a = EnumWithByteType.B) { } + } + + """; + + await Verify(Infrastructure.GenerateCode(code)) + .UseMethodName($"{nameof(WorksWithEnum)}-{enumName}"); + } + + [Fact] + public async Task WorksWithFlagEnum() + { + const string code = """ + + using AutomaticInterface; + using System; + + namespace AutomaticInterfaceExample; + + [Flags] + public enum EnumWithByteType { A = 1, B = 2, C = 3 }; + + [GenerateAutomaticInterface] + public class DemoClass + { + public void MethodWithDefaultParameter(EnumWithByteType a = EnumWithByteType.B) { } + } + + """; + + await Verify(Infrastructure.GenerateCode(code)); + } + + [Fact] + public async Task WorksWithEnumsAsReturnType() + { + const string code = """ + + using AutomaticInterface; + using System; + + namespace AutomaticInterfaceExample; + + public enum EnumWithByteType { A = 1, B = 2, C = 3 }; + + [GenerateAutomaticInterface] + public class DemoClass + { + public EnumWithByteType MethodWithDefaultParameter(EnumWithByteType a = EnumWithByteType.B) { return a; } + } + + """; + + await Verify(Infrastructure.GenerateCode(code)); + } + + [Fact] + public async Task WorksWithByteEnumsProperties() + { + const string code = """ + + using AutomaticInterface; + using System; + + namespace AutomaticInterfaceExample; + + public enum EnumWithByteType : byte { A = 1, B = 2, C = 3 }; + + [GenerateAutomaticInterface] + public class DemoClass + { + public EnumWithByteType SomeProperty { get; set; } + } + + """; + + await Verify(Infrastructure.GenerateCode(code)); + } +} diff --git a/README.md b/README.md index a3a834d..4bf2e76 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,10 @@ Note that we use [Verify](https://github.com/VerifyTests/Verify) for testing. It ## Changelog +### 5.1.2 + +- Fixing enums in method signatures + ### 5.1.1 - Emit `new()` type constraints on generic type parameters; emit `params` keyword for method parameters. Thanks, @simonmckenzie!