diff --git a/AutomaticInterface/AutomaticInterface/Builder.cs b/AutomaticInterface/AutomaticInterface/Builder.cs index dd04845..b5fa56c 100644 --- a/AutomaticInterface/AutomaticInterface/Builder.cs +++ b/AutomaticInterface/AutomaticInterface/Builder.cs @@ -11,6 +11,13 @@ public static class Builder { private const string InheritDoc = "/// "; // we use inherit doc because that should be able to fetch documentation from base classes. + private static readonly SymbolDisplayFormat MethodSignatureDisplayFormat = + new( + memberOptions: SymbolDisplayMemberOptions.IncludeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType + | SymbolDisplayParameterOptions.IncludeParamsRefOut + ); + public static string BuildInterfaceFor(ITypeSymbol typeSymbol) { if ( @@ -72,6 +79,8 @@ InterfaceBuilder codeGenerator .Where(x => x.MethodKind == MethodKind.Ordinary) .Where(x => !x.IsStatic) .Where(x => x.ContainingType.Name != nameof(Object)) + .GroupBy(x => x.ToDisplayString(MethodSignatureDisplayFormat)) + .Select(g => g.First()) .ToList() .ForEach(method => { diff --git a/AutomaticInterface/Tests/GeneratorTests.cs b/AutomaticInterface/Tests/GeneratorTests.cs index fe3ff9f..ec4de03 100644 --- a/AutomaticInterface/Tests/GeneratorTests.cs +++ b/AutomaticInterface/Tests/GeneratorTests.cs @@ -2211,4 +2211,151 @@ public partial interface ISecondClass """; GenerateCode(code).Should().Be(expected); } + + [Fact] + public void WorksWithMethodOverrides() + { + const string code = """ + + using AutomaticInterfaceAttribute; + + namespace AutomaticInterfaceExample; + + public class BaseClass + { + public virtual bool AMethod(); + } + + [GenerateAutomaticInterface] + public class DemoClass : BaseClass + { + public override bool AMethod() => return true; + } + + """; + + const string expected = """ + //-------------------------------------------------------------------------------------------------- + // + // This code was generated by a tool. + // + // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + // + //-------------------------------------------------------------------------------------------------- + + using System.CodeDom.Compiler; + using AutomaticInterfaceAttribute; + + namespace AutomaticInterfaceExample + { + [GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + bool AMethod(); + + } + } + + """; + GenerateCode(code).Should().Be(expected); + } + + [Fact] + public void WorksWithMethodShadowing() + { + const string code = """ + + using AutomaticInterfaceAttribute; + + namespace AutomaticInterfaceExample; + + public class BaseClass + { + public bool AMethod(); + } + + [GenerateAutomaticInterface] + public class DemoClass : BaseClass + { + public new bool AMethod() => return true; + } + + """; + + const string expected = """ + //-------------------------------------------------------------------------------------------------- + // + // This code was generated by a tool. + // + // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + // + //-------------------------------------------------------------------------------------------------- + + using System.CodeDom.Compiler; + using AutomaticInterfaceAttribute; + + namespace AutomaticInterfaceExample + { + [GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + bool AMethod(); + + } + } + + """; + GenerateCode(code).Should().Be(expected); + } + + [Fact] + public void WorksWithParameterDirectionOverloads() + { + const string code = """ + + using AutomaticInterfaceAttribute; + + namespace AutomaticInterfaceExample; + + [GenerateAutomaticInterface] + public class DemoClass + { + public void AMethod(int val) => return true; + + public void AMethod(ref int val) => return true; + } + + """; + + const string expected = """ + //-------------------------------------------------------------------------------------------------- + // + // This code was generated by a tool. + // + // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + // + //-------------------------------------------------------------------------------------------------- + + using System.CodeDom.Compiler; + using AutomaticInterfaceAttribute; + + namespace AutomaticInterfaceExample + { + [GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void AMethod(int val); + + /// + void AMethod(ref int val); + + } + } + + """; + GenerateCode(code).Should().Be(expected); + } }