From 307bc1a015b9a440128014657fb1c08d1020e25c Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Wed, 2 Feb 2022 09:01:51 +0100 Subject: [PATCH] Add support for static properties and methods (#28) * x * Add support for static properties and methods. --- .../Extensions/PropertySymbolExtensions.cs | 21 +++++++--- .../FileGenerators/BaseGenerator.cs | 4 +- .../FileGenerators/ProxyClassesGenerator.cs | 21 ++++++---- .../Model/ClassSymbol.cs | 2 +- ...eGeneratorTests.Source.IPersonExtends.g.cs | 4 +- ...eratorTests.Source.PersonExtendsProxy.g.cs | 40 +++++++++++-------- ...urceGeneratorTests.Source.PersonProxy.g.cs | 29 +++++++------- .../ProxyInterfaceSourceGeneratorTest.cs | 4 ++ .../Source/Human.cs | 7 +--- .../Source/IPerson.cs | 2 +- .../Source/PersonExtends.cs | 7 ++++ 11 files changed, 87 insertions(+), 54 deletions(-) diff --git a/src/ProxyInterfaceSourceGenerator/Extensions/PropertySymbolExtensions.cs b/src/ProxyInterfaceSourceGenerator/Extensions/PropertySymbolExtensions.cs index 1fb24c9..b4a1046 100644 --- a/src/ProxyInterfaceSourceGenerator/Extensions/PropertySymbolExtensions.cs +++ b/src/ProxyInterfaceSourceGenerator/Extensions/PropertySymbolExtensions.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis; using ProxyInterfaceSourceGenerator.Enums; +using ProxyInterfaceSourceGenerator.Model; namespace ProxyInterfaceSourceGenerator.Extensions; @@ -18,18 +19,26 @@ internal static class PropertySymbolExtensions return $"{type} {property.GetSanitizedName()} {{ {get}{set}}}"; } - public static string ToPropertyTextForClass(this IPropertySymbol property) + public static string ToPropertyTextForClass(this IPropertySymbol property, ClassSymbol targetClassSymbol) { - var get = property.GetMethod != null ? $"get => _Instance.{property.GetSanitizedName()}; " : string.Empty; - var set = property.SetMethod != null ? $"set => _Instance.{property.GetSanitizedName()} = value; " : string.Empty; + string instance = !property.IsStatic ? + "_Instance" : + $"{targetClassSymbol.Symbol}"; + + var get = property.GetMethod != null ? $"get => {instance}.{property.GetSanitizedName()}; " : string.Empty; + var set = property.SetMethod != null ? $"set => {instance}.{property.GetSanitizedName()} = value; " : string.Empty; return $"{property.Type} {property.GetSanitizedName()} {{ {get}{set}}}"; } - public static string ToPropertyTextForClass(this IPropertySymbol property, string overrideType) + public static string ToPropertyTextForClass(this IPropertySymbol property, ClassSymbol targetClassSymbol, string overrideType) { - var get = property.GetMethod != null ? $"get => _mapper.Map<{overrideType}>(_Instance.{property.GetSanitizedName()}); " : string.Empty; - var set = property.SetMethod != null ? $"set => _Instance.{property.GetSanitizedName()} = _mapper.Map<{property.Type}>(value); " : string.Empty; + string instance = !property.IsStatic ? + "_Instance" : + $"{targetClassSymbol.Symbol}"; + + var get = property.GetMethod != null ? $"get => _mapper.Map<{overrideType}>({instance}.{property.GetSanitizedName()}); " : string.Empty; + var set = property.SetMethod != null ? $"set => {instance}.{property.GetSanitizedName()} = _mapper.Map<{property.Type}>(value); " : string.Empty; return $"{overrideType} {property.GetSanitizedName()} {{ {get}{set}}}"; } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs index 619be08..448cc94 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs @@ -75,7 +75,7 @@ internal abstract class BaseGenerator var symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name); if (symbol is not null) { - return new ClassSymbol(symbol, symbol.GetBaseTypes()); + return new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList()); } if (usings is not null) @@ -85,7 +85,7 @@ internal abstract class BaseGenerator symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName($"{@using}.{name}"); if (symbol is not null) { - return new ClassSymbol(symbol, symbol.GetBaseTypes()); + return new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList()); } } } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs index 9dde281..bc8e942 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs @@ -1,5 +1,6 @@ using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using ProxyInterfaceSourceGenerator.Enums; using ProxyInterfaceSourceGenerator.Extensions; using ProxyInterfaceSourceGenerator.Model; @@ -18,11 +19,11 @@ internal class ProxyClassesGenerator : BaseGenerator, IFilesGenerator { foreach (var ci in Context.CandidateInterfaces) { - yield return GenerateFile(ci.Value); + yield return GenerateFile(ci.Value, Context.CandidateInterfaces); } } - private FileData GenerateFile(ProxyData pd) + private FileData GenerateFile(ProxyData pd, IDictionary candidateInterfaces) { var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName, pd.Usings); var interfaceName = targetClassSymbol.Symbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName); @@ -58,7 +59,7 @@ using AutoMapper; namespace {ns} {{ - public class {className} : {interfaceName} + public partial class {className} : {interfaceName} {{ public {targetClassSymbol.Symbol} _Instance {{ get; }} @@ -79,6 +80,7 @@ namespace {ns} }} }} {(SupportsNullable ? "#nullable disable" : string.Empty)}"; + private string GeneratePrivateAutoMapper() { return Context.ReplacedTypes.Count == 0 ? string.Empty : " private readonly IMapper _mapper;"; @@ -114,11 +116,11 @@ namespace {ns} var type = GetPropertyType(property, out var isReplaced); if (isReplaced) { - str.AppendLine($" public {property.ToPropertyTextForClass(type)}"); + str.AppendLine($" public {property.ToPropertyTextForClass(targetClassSymbol, type)}"); } else { - str.AppendLine($" public {property.ToPropertyTextForClass()}"); + str.AppendLine($" public {property.ToPropertyTextForClass(targetClassSymbol)}"); } str.AppendLine(); } @@ -168,15 +170,20 @@ namespace {ns} #pragma warning disable RS1024 // Compare symbols correctly int hash = method.ReturnType.GetHashCode(); #pragma warning restore RS1024 // Compare symbols correctly + var alternateReturnVariableName = $"result_{Math.Abs(hash)}"; + string instance = !method.IsStatic ? + "_Instance" : + $"{targetClassSymbol.Symbol}"; + if (returnTypeAsString == "void") { - str.AppendLine($" _Instance.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});"); + str.AppendLine($" {instance}.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});"); } else { - str.AppendLine($" var {alternateReturnVariableName} = _Instance.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});"); + str.AppendLine($" var {alternateReturnVariableName} = {instance}.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});"); } foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out)) diff --git a/src/ProxyInterfaceSourceGenerator/Model/ClassSymbol.cs b/src/ProxyInterfaceSourceGenerator/Model/ClassSymbol.cs index 06cfee2..4a418f0 100644 --- a/src/ProxyInterfaceSourceGenerator/Model/ClassSymbol.cs +++ b/src/ProxyInterfaceSourceGenerator/Model/ClassSymbol.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis; namespace ProxyInterfaceSourceGenerator.Model; -internal record ClassSymbol(INamedTypeSymbol Symbol, List BaseTypes) +internal record ClassSymbol(INamedTypeSymbol Symbol, List BaseTypes, List Interfaces) { public override string ToString() { diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.IPersonExtends.g.cs b/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.IPersonExtends.g.cs index 523ae49..d4b35e3 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.IPersonExtends.g.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.IPersonExtends.g.cs @@ -14,6 +14,8 @@ namespace ProxyInterfaceSourceGeneratorTests.Source { public partial interface IPersonExtends { + string StaticString { get; set; } + string Name { get; set; } string? StringNullable { get; set; } @@ -24,9 +26,9 @@ namespace ProxyInterfaceSourceGeneratorTests.Source bool IsAlive { get; set; } - bool X { get; set; } + string StaticMethod(int x, string y); void Void(); diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonExtendsProxy.g.cs b/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonExtendsProxy.g.cs index 8bcce3f..2a5d10d 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonExtendsProxy.g.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonExtendsProxy.g.cs @@ -13,10 +13,12 @@ using AutoMapper; namespace ProxyInterfaceSourceGeneratorTests.Source { - public class PersonExtendsProxy : IPersonExtends + public partial class PersonExtendsProxy : IPersonExtends { public ProxyInterfaceSourceGeneratorTests.Source.PersonExtends _Instance { get; } + public string StaticString { get => ProxyInterfaceSourceGeneratorTests.Source.PersonExtends.StaticString; set => ProxyInterfaceSourceGeneratorTests.Source.PersonExtends.StaticString = value; } + public string Name { get => _Instance.Name; set => _Instance.Name = value; } public string? StringNullable { get => _Instance.StringNullable; set => _Instance.StringNullable = value; } @@ -27,9 +29,15 @@ namespace ProxyInterfaceSourceGeneratorTests.Source public bool IsAlive { get => _Instance.IsAlive; set => _Instance.IsAlive = value; } - public bool X { get => _Instance.X; set => _Instance.X = value; } + public string StaticMethod(int x, string y) + { + int x_ = x; + string y_ = y; + var result_6851397 = ProxyInterfaceSourceGeneratorTests.Source.PersonExtends.StaticMethod(x_, y_); + return result_6851397; + } public void Void() { @@ -39,8 +47,8 @@ namespace ProxyInterfaceSourceGeneratorTests.Source public string HelloWorld(string name) { string name_ = name; - var result_58477331 = _Instance.HelloWorld(name_); - return result_58477331; + var result_6851397 = _Instance.HelloWorld(name_); + return result_6851397; } public void WithParams(params string[] values) @@ -53,15 +61,15 @@ namespace ProxyInterfaceSourceGeneratorTests.Source { string s_ = s; string @string_ = @string; - var result_58477331 = _Instance.Add(s_, @string_); - return result_58477331; + var result_6851397 = _Instance.Add(s_, @string_); + return result_6851397; } public int DefaultValue(int x = 100) { int x_ = x; - var result_42930144 = _Instance.DefaultValue(x_); - return result_42930144; + var result_3873514 = _Instance.DefaultValue(x_); + return result_3873514; } public void In_Out_Ref1(in int a, out int b, ref int c) @@ -78,26 +86,26 @@ namespace ProxyInterfaceSourceGeneratorTests.Source int x_ = x; T1 t1_ = t1; T2 t2_ = t2; - var result_38995950 = _Instance.Generic2(x_, t1_, t2_); - return result_38995950; + var result_14331071 = _Instance.Generic2(x_, t1_, t2_); + return result_14331071; } public System.Threading.Tasks.Task Method1Async() { - var result_51708797 = _Instance.Method1Async(); - return result_51708797; + var result_39535275 = _Instance.Method1Async(); + return result_39535275; } public System.Threading.Tasks.Task Method2Async() { - var result_1620952573 = _Instance.Method2Async(); - return result_1620952573; + var result_772784336 = _Instance.Method2Async(); + return result_772784336; } public System.Threading.Tasks.Task Method3Async() { - var result_1636499760 = _Instance.Method3Async(); - return result_1636499760; + var result_769806453 = _Instance.Method3Async(); + return result_769806453; } diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonProxy.g.cs b/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonProxy.g.cs index 8025ed0..9e09b36 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonProxy.g.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/Destination/ProxyInterfaceSourceGeneratorTests.Source.PersonProxy.g.cs @@ -35,8 +35,8 @@ namespace ProxyInterfaceSourceGeneratorTests.Source public string HelloWorld(string name) { string name_ = name; - var result_56365455 = _Instance.HelloWorld(name_); - return result_56365455; + var result_37309470 = _Instance.HelloWorld(name_); + return result_37309470; } public void WithParams(params string[] values) @@ -49,15 +49,15 @@ namespace ProxyInterfaceSourceGeneratorTests.Source { string s_ = s; string @string_ = @string; - var result_56365455 = _Instance.Add(s_, @string_); - return result_56365455; + var result_37309470 = _Instance.Add(s_, @string_); + return result_37309470; } public int DefaultValue(int x = 100) { int x_ = x; - var result_39875940 = _Instance.DefaultValue(x_); - return result_39875940; + var result_24216618 = _Instance.DefaultValue(x_); + return result_24216618; } public void In_Out_Ref1(in int a, out int b, ref int c) @@ -74,26 +74,26 @@ namespace ProxyInterfaceSourceGeneratorTests.Source int x_ = x; T1 t1_ = t1; T2 t2_ = t2; - var result_41799290 = _Instance.Generic2(x_, t1_, t2_); - return result_41799290; + var result_60333940 = _Instance.Generic2(x_, t1_, t2_); + return result_60333940; } public System.Threading.Tasks.Task Method1Async() { - var result_32599313 = _Instance.Method1Async(); - return result_32599313; + var result_2292327 = _Instance.Method1Async(); + return result_2292327; } public System.Threading.Tasks.Task Method2Async() { - var result_1620495907 = _Instance.Method2Async(); - return result_1620495907; + var result_1229624901 = _Instance.Method2Async(); + return result_1229624901; } public System.Threading.Tasks.Task Method3Async() { - var result_1604006392 = _Instance.Method3Async(); - return result_1604006392; + var result_1242717753 = _Instance.Method3Async(); + return result_1242717753; } @@ -108,6 +108,7 @@ namespace ProxyInterfaceSourceGeneratorTests.Source } + public bool IsAlive { get; set; } } } #nullable disable \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs index c291b0b..9a4e200 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using AnyOfTypes; @@ -6,6 +7,7 @@ using CSharp.SourceGenerators.Extensions.Models; using FluentAssertions; using ProxyInterfaceSourceGenerator; using Xunit; +using Xunit.Sdk; namespace ProxyInterfaceSourceGeneratorTests { @@ -109,6 +111,8 @@ namespace ProxyInterfaceSourceGeneratorTests result.Valid.Should().BeTrue(); result.Files.Should().HaveCount(5); + throw new Exception(); + // Assert attribute var attribute = result.Files[0].SyntaxTree; attribute.FilePath.Should().EndWith(attributeFilename); diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs index 05eeaae..7adb348 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs @@ -1,12 +1,7 @@ namespace ProxyInterfaceSourceGeneratorTests.Source { - public class Human : Animal + public class Human { public bool IsAlive { get; set; } } - - public class Animal - { - public bool X { get; set; } - } } \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/IPerson.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/IPerson.cs index 7ca6065..9d9c6e3 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/Source/IPerson.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/IPerson.cs @@ -1,6 +1,6 @@ namespace ProxyInterfaceSourceGeneratorTests.Source { - public partial interface IPerson + public partial interface IPerson : IHuman { } } \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/PersonExtends.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/PersonExtends.cs index 712898a..4ded778 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/Source/PersonExtends.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/PersonExtends.cs @@ -4,6 +4,13 @@ namespace ProxyInterfaceSourceGeneratorTests.Source { public class PersonExtends : Human { + public static string StaticMethod(int x, string y) + { + return "test"; + } + + public static string StaticString { get; set; } = "500"; + public string Name { get; set; } public string? StringNullable { get; set; }