From 0ac9cfea0879a57cb9db19edf72b008fad75504d Mon Sep 17 00:00:00 2001 From: avtc Date: Tue, 30 Apr 2024 13:23:01 +0300 Subject: [PATCH 1/6] Ignore class members with [IgnoreAutomaticInterface] attribute --- .../AutomaticInterfaceGenerator.cs | 1 + .../AutomaticInterface/Builder.cs | 9 ++++ .../IgnoreAutomaticInterfaceAttribute.cs | 10 ++++ AutomaticInterface/Tests/GeneratorTests.cs | 47 +++++++++++++++++++ README.md | 3 ++ 5 files changed, 70 insertions(+) create mode 100644 AutomaticInterface/AutomaticInterfaceAttribute/IgnoreAutomaticInterfaceAttribute.cs diff --git a/AutomaticInterface/AutomaticInterface/AutomaticInterfaceGenerator.cs b/AutomaticInterface/AutomaticInterface/AutomaticInterfaceGenerator.cs index 14b2c44..ac27513 100644 --- a/AutomaticInterface/AutomaticInterface/AutomaticInterfaceGenerator.cs +++ b/AutomaticInterface/AutomaticInterface/AutomaticInterfaceGenerator.cs @@ -10,6 +10,7 @@ namespace AutomaticInterface; public class AutomaticInterfaceGenerator : IIncrementalGenerator { public const string DefaultAttributeName = "GenerateAutomaticInterface"; + public const string IgnoreAutomaticInterfaceAttributeName = "IgnoreAutomaticInterface"; public void Initialize(IncrementalGeneratorInitializationContext context) { diff --git a/AutomaticInterface/AutomaticInterface/Builder.cs b/AutomaticInterface/AutomaticInterface/Builder.cs index dd04845..72dad17 100644 --- a/AutomaticInterface/AutomaticInterface/Builder.cs +++ b/AutomaticInterface/AutomaticInterface/Builder.cs @@ -72,6 +72,7 @@ InterfaceBuilder codeGenerator .Where(x => x.MethodKind == MethodKind.Ordinary) .Where(x => !x.IsStatic) .Where(x => x.ContainingType.Name != nameof(Object)) + .Where(x => !HasIgnoreAttribute(x)) .ToList() .ForEach(method => { @@ -162,6 +163,7 @@ InterfaceBuilder codeGenerator .OfType() .Where(x => x.DeclaredAccessibility == Accessibility.Public) .Where(x => !x.IsStatic) + .Where(x => !HasIgnoreAttribute(x)) .ToList() .ForEach(evt => { @@ -235,6 +237,7 @@ InterfaceBuilder interfaceGenerator .Where(x => x.DeclaredAccessibility == Accessibility.Public) .Where(x => !x.IsStatic) .Where(x => !x.IsIndexer) + .Where(x => !HasIgnoreAttribute(x)) .GroupBy(x => x.Name) .Select(g => g.First()) .ToList() @@ -260,6 +263,12 @@ InterfaceBuilder interfaceGenerator }); } + private static bool HasIgnoreAttribute(ISymbol x) + { + return x.GetAttributes() + .Any(a => a.AttributeClass != null && a.AttributeClass.Name.Contains(AutomaticInterfaceGenerator.IgnoreAutomaticInterfaceAttributeName)); + } + private static string GetDocumentationForClass(CSharpSyntaxNode classSyntax) { if (!classSyntax.HasLeadingTrivia) diff --git a/AutomaticInterface/AutomaticInterfaceAttribute/IgnoreAutomaticInterfaceAttribute.cs b/AutomaticInterface/AutomaticInterfaceAttribute/IgnoreAutomaticInterfaceAttribute.cs new file mode 100644 index 0000000..8869e77 --- /dev/null +++ b/AutomaticInterface/AutomaticInterfaceAttribute/IgnoreAutomaticInterfaceAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace AutomaticInterfaceAttribute +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)] + public class IgnoreAutomaticInterfaceAttribute : Attribute + { + public IgnoreAutomaticInterfaceAttribute() { } + } +} diff --git a/AutomaticInterface/Tests/GeneratorTests.cs b/AutomaticInterface/Tests/GeneratorTests.cs index fe3ff9f..bb21145 100644 --- a/AutomaticInterface/Tests/GeneratorTests.cs +++ b/AutomaticInterface/Tests/GeneratorTests.cs @@ -713,6 +713,53 @@ public partial interface IDemoClass GenerateCode(code).Should().Be(expected); } + [Fact] + public void IgnoresMembersAttributedWithSkip() + { + const string code = """ + + using AutomaticInterfaceAttribute; + using System.IO; + + namespace AutomaticInterfaceExample + { + + [GenerateAutomaticInterface] + class DemoClass + { + [IgnoreAutomaticInterface] public string Hello1(string x, int y, double z){return x;} + [IgnoreAutomaticInterface] public string Hello2 { get; set; } + [IgnoreAutomaticInterface] public event EventHandler Hello3; + } + } + + """; + + 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; + using System.IO; + + namespace AutomaticInterfaceExample + { + [GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + } + } + + """; + GenerateCode(code).Should().Be(expected); + } + [Fact] public void AddsDescriptionFromMethodToInterface() { diff --git a/README.md b/README.md index dfdf1cf..6539ecd 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,9 @@ namespace AutomaticInterfaceExample public string OnlyGet { get; } // included, get and set are copied to the interface when public + [IgnoreAutomaticInterface] + public string OnlyGet { get; } // ignored with help of attribute + /// /// Method Documentation will be copied /// From 870046988636853301c45db4db77bd2c06d4cbf8 Mon Sep 17 00:00:00 2001 From: Christian Sauer Date: Sun, 4 Aug 2024 18:34:36 +0200 Subject: [PATCH 2/6] fix missues due to previous merge --- .../AutomaticInterface/Builder.cs | 19 +++- AutomaticInterface/Tests/GeneratorTests.cs | 98 +++++++++++++++++++ 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/AutomaticInterface/AutomaticInterface/Builder.cs b/AutomaticInterface/AutomaticInterface/Builder.cs index 72dad17..123698c 100644 --- a/AutomaticInterface/AutomaticInterface/Builder.cs +++ b/AutomaticInterface/AutomaticInterface/Builder.cs @@ -11,6 +11,12 @@ 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 MethodDisplayFormatForDeduplication = + new( + memberOptions: SymbolDisplayMemberOptions.IncludeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType + ); + public static string BuildInterfaceFor(ITypeSymbol typeSymbol) { if ( @@ -71,8 +77,10 @@ InterfaceBuilder codeGenerator .Where(x => x.DeclaredAccessibility == Accessibility.Public) .Where(x => x.MethodKind == MethodKind.Ordinary) .Where(x => !x.IsStatic) - .Where(x => x.ContainingType.Name != nameof(Object)) .Where(x => !HasIgnoreAttribute(x)) + .Where(x => x.ContainingType.Name != nameof(Object)) + .GroupBy(x => x.ToDisplayString(MethodDisplayFormatForDeduplication)) + .Select(g => g.First()) .ToList() .ForEach(method => { @@ -266,7 +274,12 @@ InterfaceBuilder interfaceGenerator private static bool HasIgnoreAttribute(ISymbol x) { return x.GetAttributes() - .Any(a => a.AttributeClass != null && a.AttributeClass.Name.Contains(AutomaticInterfaceGenerator.IgnoreAutomaticInterfaceAttributeName)); + .Any(a => + a.AttributeClass != null + && a.AttributeClass.Name.Contains( + AutomaticInterfaceGenerator.IgnoreAutomaticInterfaceAttributeName + ) + ); } private static string GetDocumentationForClass(CSharpSyntaxNode classSyntax) @@ -314,7 +327,7 @@ NamespaceDeclarationSyntax ndSyntax ); } - return [..allUsings.Select(x => x.ToString())]; + return [.. allUsings.Select(x => x.ToString())]; } private static string GetGeneric(TypeDeclarationSyntax classSyntax) diff --git a/AutomaticInterface/Tests/GeneratorTests.cs b/AutomaticInterface/Tests/GeneratorTests.cs index bb21145..e8c71bf 100644 --- a/AutomaticInterface/Tests/GeneratorTests.cs +++ b/AutomaticInterface/Tests/GeneratorTests.cs @@ -2258,4 +2258,102 @@ 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); + } } From 7a8d021ff308a81e4d5d9d06d1b1e19288969d85 Mon Sep 17 00:00:00 2001 From: Christian Sauer Date: Sun, 4 Aug 2024 18:34:54 +0200 Subject: [PATCH 3/6] update csharpier --- .config/dotnet-tools.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 93d8488..155e425 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,10 +3,11 @@ "isRoot": true, "tools": { "csharpier": { - "version": "0.27.1", + "version": "0.28.2", "commands": [ "dotnet-csharpier" - ] + ], + "rollForward": false } } } \ No newline at end of file From 6878309d2cfb7008ffdd0a721cd89247ea971e5b Mon Sep 17 00:00:00 2001 From: Simon McKenzie Date: Sat, 15 Jun 2024 20:32:14 +1000 Subject: [PATCH 4/6] Update deduplication so it won't merge overloads that only differ by parameter direction --- .../AutomaticInterface/Builder.cs | 5 +- AutomaticInterface/Tests/GeneratorTests.cs | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/AutomaticInterface/AutomaticInterface/Builder.cs b/AutomaticInterface/AutomaticInterface/Builder.cs index 123698c..5d36fc1 100644 --- a/AutomaticInterface/AutomaticInterface/Builder.cs +++ b/AutomaticInterface/AutomaticInterface/Builder.cs @@ -11,10 +11,11 @@ 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 MethodDisplayFormatForDeduplication = + private static readonly SymbolDisplayFormat MethodSignatureDisplayFormat = new( memberOptions: SymbolDisplayMemberOptions.IncludeParameters, parameterOptions: SymbolDisplayParameterOptions.IncludeType + | SymbolDisplayParameterOptions.IncludeParamsRefOut ); public static string BuildInterfaceFor(ITypeSymbol typeSymbol) @@ -79,7 +80,7 @@ InterfaceBuilder codeGenerator .Where(x => !x.IsStatic) .Where(x => !HasIgnoreAttribute(x)) .Where(x => x.ContainingType.Name != nameof(Object)) - .GroupBy(x => x.ToDisplayString(MethodDisplayFormatForDeduplication)) + .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 e8c71bf..9b72fee 100644 --- a/AutomaticInterface/Tests/GeneratorTests.cs +++ b/AutomaticInterface/Tests/GeneratorTests.cs @@ -2356,4 +2356,53 @@ public partial interface IDemoClass """; 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); + } } From 6a4fd47dc8a3313e9cc4425a7f7203a683714bc3 Mon Sep 17 00:00:00 2001 From: Christian Sauer Date: Sun, 4 Aug 2024 18:21:21 +0200 Subject: [PATCH 5/6] add docs for the changes --- .../AutomaticInterface/AutomaticInterface.csproj | 2 +- README.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj b/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj index 0506e61..1c4fac4 100644 --- a/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj +++ b/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj @@ -25,7 +25,7 @@ MIT True latest-Recommended - 2.3.0 + 2.4.0 README.md true 1701;1702;NU5128 diff --git a/README.md b/README.md index 6539ecd..17ffce1 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,9 @@ Should be simply a build and run Tests ## Changelog +### 2.40. +- Now prevents duplicates when overriding or shadowing methods (`new void DoSomething()`). Thanks simonmckenzie! + ### 2.3.0 - Now supports methods with `ref / in / out` parameters. Thanks mohummedibrahim From a602ecc46da1398a28f41d2eda8fc34934b68f5c Mon Sep 17 00:00:00 2001 From: Christian Sauer Date: Sun, 4 Aug 2024 18:36:42 +0200 Subject: [PATCH 6/6] version 2.5 --- .../AutomaticInterface/AutomaticInterface.csproj | 2 +- README.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj b/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj index 1c4fac4..6c760ad 100644 --- a/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj +++ b/AutomaticInterface/AutomaticInterface/AutomaticInterface.csproj @@ -25,7 +25,7 @@ MIT True latest-Recommended - 2.4.0 + 2.5.0 README.md true 1701;1702;NU5128 diff --git a/README.md b/README.md index 17ffce1..f250eb9 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ Please make sure that you run [CSharpier](https://csharpier.com/) on the code fo - roflmuffin for PRs - mohummedibrahim for code and idea - simonmckenzie for PR +- avtc for PR ## Run tests @@ -170,6 +171,9 @@ Should be simply a build and run Tests ## Changelog +### 2.40. +- Now can ignore class members with [IgnoreAutomaticInterface] attribute. Thanks avtc! + ### 2.40. - Now prevents duplicates when overriding or shadowing methods (`new void DoSomething()`). Thanks simonmckenzie!