diff --git a/AutomaticInterface/AutomaticInterface/Builder.cs b/AutomaticInterface/AutomaticInterface/Builder.cs index 2649b8f..f430967 100644 --- a/AutomaticInterface/AutomaticInterface/Builder.cs +++ b/AutomaticInterface/AutomaticInterface/Builder.cs @@ -176,9 +176,16 @@ InterfaceBuilder codeGenerator private static string GetMethodSignature(IParameterSymbol x) { + var syntaxReference = x.DeclaringSyntaxReferences.FirstOrDefault(); + + var name = + syntaxReference != null + ? ((ParameterSyntax)syntaxReference.GetSyntax()).Identifier.Text + : x.Name; + if (!x.HasExplicitDefaultValue) { - return $"{x.Type.ToDisplayString()} {x.Name}"; + return $"{x.Type.ToDisplayString()} {name}"; } var optionalValue = x.ExplicitDefaultValue switch @@ -189,7 +196,7 @@ private static string GetMethodSignature(IParameterSymbol x) null => " = null", _ => $" = {x.ExplicitDefaultValue}" }; - return $"{x.Type.ToDisplayString()} {x.Name}{optionalValue}"; + return $"{x.Type.ToDisplayString()} {name}{optionalValue}"; } private static void AddPropertiesToInterface( @@ -204,6 +211,8 @@ InterfaceBuilder interfaceGenerator .Where(x => x.DeclaredAccessibility == Accessibility.Public) .Where(x => !x.IsStatic) .Where(x => !x.IsIndexer) + .GroupBy(x => x.Name) + .Select(g => g.First()) .ToList() .ForEach(prop => { @@ -212,6 +221,7 @@ InterfaceBuilder interfaceGenerator var name = prop.Name; var hasGet = prop.GetMethod?.DeclaredAccessibility == Accessibility.Public; var hasSet = prop.SetMethod?.DeclaredAccessibility == Accessibility.Public; + var isRef = prop.ReturnsByRef; ActivateNullableIfNeeded(interfaceGenerator, type); @@ -220,6 +230,7 @@ InterfaceBuilder interfaceGenerator type.ToDisplayString(), hasGet, hasSet, + isRef, InheritDoc ); }); diff --git a/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs b/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs index 845172d..c7d9660 100644 --- a/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs +++ b/AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs @@ -9,6 +9,7 @@ internal sealed record PropertyInfo( string Ttype, bool HasGet, bool HasSet, + bool IsRef, string Documentation ); @@ -50,10 +51,11 @@ public void AddPropertyToInterface( string ttype, bool hasGet, bool hasSet, + bool isRef, string documentation ) { - propertyInfos.Add(new(name, ttype, hasGet, hasSet, documentation)); + propertyInfos.Add(new(name, ttype, hasGet, hasSet, isRef, documentation)); } public void AddGeneric(string v) @@ -122,9 +124,10 @@ public string Build() foreach (var prop in propertyInfos) { cb.AppendAndNormalizeMultipleLines(prop.Documentation); + var @ref = prop.IsRef ? "ref " : string.Empty; var get = prop.HasGet ? "get; " : string.Empty; var set = prop.HasSet ? "set; " : string.Empty; - cb.AppendLine($"{prop.Ttype} {prop.Name} {{ {get}{set}}}"); + cb.AppendLine($"{@ref}{prop.Ttype} {prop.Name} {{ {get}{set}}}"); cb.AppendLine(""); } cb.Dedent(); diff --git a/AutomaticInterface/Tests/GeneratorTests.cs b/AutomaticInterface/Tests/GeneratorTests.cs index f528adb..6d59195 100644 --- a/AutomaticInterface/Tests/GeneratorTests.cs +++ b/AutomaticInterface/Tests/GeneratorTests.cs @@ -2066,4 +2066,148 @@ public partial interface IDemoClass """; GenerateCode(code).Should().Be(expected); } + + [Fact] + public void WorksWithRef() + { + const string code = """ + + using AutomaticInterfaceAttribute; + using System.Threading.Tasks; + + namespace AutomaticInterfaceExample; + [GenerateAutomaticInterface] + public class DemoClass + { + private string _aProperty; + public ref string AProperty => ref _aProperty; + } + + """; + + 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.Threading.Tasks; + + namespace AutomaticInterfaceExample + { + [GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + ref string AProperty { get; } + + } + } + + """; + GenerateCode(code).Should().Be(expected); + } + + [Fact] + public void WorksWithReservedNames() + { + const string code = """ + + using AutomaticInterfaceAttribute; + using System.Threading.Tasks; + + namespace AutomaticInterfaceExample; + [GenerateAutomaticInterface] + public class DemoClass + { + public void AMethod(int @event) + { + } + } + + """; + + 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.Threading.Tasks; + + namespace AutomaticInterfaceExample + { + [GeneratedCode("AutomaticInterface", "")] + public partial interface IDemoClass + { + /// + void AMethod(int @event); + + } + } + + """; + GenerateCode(code).Should().Be(expected); + } + + [Fact] + public void WorksWithNewKeyword() + { + const string code = """ + + using AutomaticInterfaceAttribute; + using System.Threading.Tasks; + + namespace AutomaticInterfaceExample; + + public abstract class FirstClass + { + public int AProperty { get; set; } + } + + [GenerateAutomaticInterface] + public partial class SecondClass : FirstClass + { + public new int AProperty { get; set; } + } + + """; + + 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.Threading.Tasks; + + namespace AutomaticInterfaceExample + { + [GeneratedCode("AutomaticInterface", "")] + public partial interface ISecondClass + { + /// + int AProperty { get; set; } + + } + } + + """; + GenerateCode(code).Should().Be(expected); + } }