diff --git a/src-examples/ProxyInterfaceConsumer/IAddress.cs b/src-examples/ProxyInterfaceConsumer/IAddress.cs index 514c7fd..d44b0f6 100644 --- a/src-examples/ProxyInterfaceConsumer/IAddress.cs +++ b/src-examples/ProxyInterfaceConsumer/IAddress.cs @@ -1,6 +1,6 @@ namespace ProxyInterfaceConsumer { - [ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.Address))] + // [ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.Address))] public partial interface IAddress { } diff --git a/src-examples/ProxyInterfaceConsumer/IPersonT.cs b/src-examples/ProxyInterfaceConsumer/IPersonT.cs new file mode 100644 index 0000000..1327039 --- /dev/null +++ b/src-examples/ProxyInterfaceConsumer/IPersonT.cs @@ -0,0 +1,7 @@ +namespace ProxyInterfaceConsumer +{ + [ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.PersonT<>))] + public partial interface IPersonT where T : struct + { + } +} \ No newline at end of file diff --git a/src-examples/ProxyInterfaceConsumer/IPersonTT.cs b/src-examples/ProxyInterfaceConsumer/IPersonTT.cs new file mode 100644 index 0000000..e9c63ee --- /dev/null +++ b/src-examples/ProxyInterfaceConsumer/IPersonTT.cs @@ -0,0 +1,16 @@ +namespace ProxyInterfaceConsumer +{ + [ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.PersonT<,>))] + public partial interface IPersonT + where T1 : struct + where T2 : class, new() + { + } + + [ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.PersonTT<,>))] + public partial interface IPersonTT + where T1 : struct + where T2 : class, new() + { + } +} \ No newline at end of file diff --git a/src-examples/ProxyInterfaceConsumer/Person.cs b/src-examples/ProxyInterfaceConsumer/Person.cs index 98ff536..84efcc1 100644 --- a/src-examples/ProxyInterfaceConsumer/Person.cs +++ b/src-examples/ProxyInterfaceConsumer/Person.cs @@ -27,6 +27,13 @@ namespace ProxyInterfaceConsumer public IMyInterface MyInterface { get; set; } + public bool TMethod(int x, T1 t1, T2 t2) + where T1 : struct + where T2 : class, new() + { + return true; + } + public int DefaultValue(int x = 100) { return x + 1; diff --git a/src-examples/ProxyInterfaceConsumer/PersonT.cs b/src-examples/ProxyInterfaceConsumer/PersonT.cs new file mode 100644 index 0000000..e7fdeef --- /dev/null +++ b/src-examples/ProxyInterfaceConsumer/PersonT.cs @@ -0,0 +1,12 @@ +namespace ProxyInterfaceConsumer +{ + public class PersonT where T: struct + { + public T TVal { get; set; } + + public T Call(int x, T t) + { + return default; + } + } +} \ No newline at end of file diff --git a/src-examples/ProxyInterfaceConsumer/PersonTT.cs b/src-examples/ProxyInterfaceConsumer/PersonTT.cs new file mode 100644 index 0000000..fcd4f69 --- /dev/null +++ b/src-examples/ProxyInterfaceConsumer/PersonTT.cs @@ -0,0 +1,28 @@ +namespace ProxyInterfaceConsumer +{ + public class PersonT + where T1 : struct + where T2 : class, new() + { + public T1 TVal1 { get; set; } + + public T2 TVal2 { get; set; } + + public void Call(int x, T1 t1, T2 t2) + { + } + } + + public class PersonTT + where T1 : struct + where T2 : class, new() + { + public T1 TVal1 { get; set; } + + public T2 TVal2 { get; set; } + + public void Call(int x, T1 t1, T2 t2) + { + } + } +} \ No newline at end of file diff --git a/src-examples/ProxyInterfaceConsumer/Program.cs b/src-examples/ProxyInterfaceConsumer/Program.cs index 24a131e..674e1f3 100644 --- a/src-examples/ProxyInterfaceConsumer/Program.cs +++ b/src-examples/ProxyInterfaceConsumer/Program.cs @@ -14,45 +14,31 @@ namespace ProxyInterfaceConsumer public static void Main() { - var c = new Clazz - { - Name = "n" - }; - var cp = new ClazzProxy(c); - - var t = new Test(); - t.Cs = new List { c }; - - var tp = new TestProxy(t); - tp.Cs = new List { cp }; - - Console.WriteLine(JsonSerializer.Serialize(t, JsonSerializerOptions)); + IPersonT pT = new PersonTProxy(new PersonT()); + pT.TVal = 1; + Console.WriteLine(JsonSerializer.Serialize(pT, JsonSerializerOptions)); Console.WriteLine(new string('-', 80)); + IPersonTT pTT = new PersonTTProxy(new PersonTT()); + pTT.TVal1 = 42; + pTT.TVal2 = new Program(); + Console.WriteLine(JsonSerializer.Serialize(pTT, JsonSerializerOptions)); + Console.WriteLine(new string('-', 80)); IPerson p = new PersonProxy(new Person()); p.Name = "test"; Console.WriteLine("DefaultValue " + p.DefaultValue()); Console.WriteLine("DefaultValue " + p.DefaultValue(42)); - var ap = new AddressProxy(new Address { HouseNumber = 42 }); - p.Address = ap; - var add = p.AddAddress(ap); - Console.WriteLine("add = " + JsonSerializer.Serialize(add, JsonSerializerOptions)); - p.AddAddress(new AddressProxy(new Address { HouseNumber = 1000 })); + //var ap = new AddressProxy(new Address { HouseNumber = 42 }); + //p.Address = ap; + //var add = p.AddAddress(ap); + //Console.WriteLine("add = " + JsonSerializer.Serialize(add, JsonSerializerOptions)); + //p.AddAddress(new AddressProxy(new Address { HouseNumber = 1000 })); - //p.MyNamedTypeSymbol = null; - //p.Compilation = null; - //p.Add("x"); - //p.Void(); Console.WriteLine(JsonSerializer.Serialize(p, JsonSerializerOptions)); - - //GeneratorExecutionContext g = new GeneratorExecutionContext(); - //IGeneratorExecutionContext gc = new GeneratorExecutionContextProxy(g); - //int y = 9; } } - public struct Test { public int Id { get; set; } diff --git a/src-examples/ProxyInterfaceConsumerViaNuGet/PersonProxy2.cs b/src-examples/ProxyInterfaceConsumerViaNuGet/PersonProxy2.cs index 017ad30..d600ae6 100644 --- a/src-examples/ProxyInterfaceConsumerViaNuGet/PersonProxy2.cs +++ b/src-examples/ProxyInterfaceConsumerViaNuGet/PersonProxy2.cs @@ -73,7 +73,7 @@ namespace ProxyInterfaceConsumer ProxyInterfaceConsumer.Address b_; ProxyInterfaceConsumer.Address c_ = _mapper.Map(c); var result_30316242 = _Instance.In_Out_Ref2(in a_, out b_, ref c_); - b = _mapper.Map(_b); + b = _mapper.Map(b_); return result_30316242; } diff --git a/src/ProxyInterfaceSourceGenerator/Context.cs b/src/ProxyInterfaceSourceGenerator/Context.cs index d289fdc..d8b7e6b 100644 --- a/src/ProxyInterfaceSourceGenerator/Context.cs +++ b/src/ProxyInterfaceSourceGenerator/Context.cs @@ -9,7 +9,7 @@ namespace ProxyInterfaceSourceGenerator { public GeneratorExecutionContext GeneratorExecutionContext { get; init; } - public List GeneratedData { get; } = new List(); + // public List GeneratedData { get; } = new List(); public IDictionary CandidateInterfaces { get; init; } diff --git a/src/ProxyInterfaceSourceGenerator/Extensions/MethodSymbolExtensions.cs b/src/ProxyInterfaceSourceGenerator/Extensions/MethodSymbolExtensions.cs new file mode 100644 index 0000000..cfd03a6 --- /dev/null +++ b/src/ProxyInterfaceSourceGenerator/Extensions/MethodSymbolExtensions.cs @@ -0,0 +1,14 @@ +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace ProxyInterfaceSourceGenerator.Extensions +{ + internal static class MethodSymbolExtensions + { + public static string GetMethodNameWithOptionalTypeParameters(this IMethodSymbol method) => + !method.IsGenericMethod ? method.Name : $"{method.Name}<{string.Join(", ", method.TypeParameters.Select(tp => tp.Name))}>"; + + public static string GetWhereStatement(this IMethodSymbol method) => + !method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereStatement())); + } +} \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/Extensions/NamedTypeSymbolExtensions.cs b/src/ProxyInterfaceSourceGenerator/Extensions/NamedTypeSymbolExtensions.cs new file mode 100644 index 0000000..239e11f --- /dev/null +++ b/src/ProxyInterfaceSourceGenerator/Extensions/NamedTypeSymbolExtensions.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace ProxyInterfaceSourceGenerator.Extensions +{ + internal static class NamedTypeSymbolExtensions + { + /// + /// See https://www.codeproject.com/Articles/861548/Roslyn-Code-Analysis-in-Easy-Samples-Part + /// + public static string GetFullTypeString(this INamedTypeSymbol namedTypeSymbol) + { + var str = new StringBuilder(namedTypeSymbol.Name); + + if (namedTypeSymbol.TypeArguments.Count() > 0) + { + str.AppendFormat("<{0}>", string.Join(", ", namedTypeSymbol.TypeArguments.OfType().Select(typeArg => typeArg.GetFullTypeString()))); + } + + return str.ToString(); + } + + public static string ResolveInterfaceNameWithOptionalTypeConstraints(this INamedTypeSymbol namedTypeSymbol, string interfaceName) + { + if (!namedTypeSymbol.IsGenericType) + { + return interfaceName; + } + + var str = new StringBuilder($"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>"); + + foreach (var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType()) + { + str.Append(typeParameterSymbol.GetWhereStatement()); + } + + return str.ToString(); + } + + /// + /// See https://stackoverflow.com/questions/24157101/roslyns-gettypebymetadataname-and-generic-types + /// + public static string ResolveProxyClassName(this INamedTypeSymbol namedTypeSymbol) + { + return !namedTypeSymbol.IsGenericType ? + $"{namedTypeSymbol.Name}Proxy" : + $"{namedTypeSymbol.Name}Proxy<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>"; + } + } +} \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/Extensions/SyntaxNodeUtils.cs b/src/ProxyInterfaceSourceGenerator/Extensions/SyntaxNodeUtils.cs index 4aadfca..fb2c780 100644 --- a/src/ProxyInterfaceSourceGenerator/Extensions/SyntaxNodeUtils.cs +++ b/src/ProxyInterfaceSourceGenerator/Extensions/SyntaxNodeUtils.cs @@ -5,7 +5,7 @@ namespace ProxyInterfaceSourceGenerator.Extensions internal static class SyntaxNodeUtils { // https://stackoverflow.com/questions/20458457/getting-class-fullname-including-namespace-from-roslyn-classdeclarationsyntax - public static bool TryGetParentSyntax(this SyntaxNode syntaxNode, out T result) where T : SyntaxNode + public static bool TryGetParentSyntax(this SyntaxNode? syntaxNode, out T? result) where T : SyntaxNode { result = null; diff --git a/src/ProxyInterfaceSourceGenerator/Extensions/TypeParameterSymbolExtensions.cs b/src/ProxyInterfaceSourceGenerator/Extensions/TypeParameterSymbolExtensions.cs new file mode 100644 index 0000000..eb764d1 --- /dev/null +++ b/src/ProxyInterfaceSourceGenerator/Extensions/TypeParameterSymbolExtensions.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace ProxyInterfaceSourceGenerator.Extensions +{ + internal static class TypeParameterSymbolExtensions + { + /// + /// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2 + /// + public static string GetWhereStatement(this ITypeParameterSymbol typeParameterSymbol) + { + var constraints = new List(); + if (typeParameterSymbol.HasReferenceTypeConstraint) + { + constraints.Add("class"); + } + + if (typeParameterSymbol.HasValueTypeConstraint) + { + constraints.Add("struct"); + } + + if (typeParameterSymbol.HasConstructorConstraint) + { + constraints.Add("new()"); + } + + constraints.AddRange(typeParameterSymbol.ConstraintTypes.OfType().Select(contstraintType => contstraintType.GetFullTypeString())); + + if (!constraints.Any()) + { + return string.Empty; + } + + return $" where {typeParameterSymbol.Name} : {string.Join(", ", constraints)}"; + } + } +} \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs index 0abc602..36bcec8 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -// using AnyOfTypes; using Microsoft.CodeAnalysis; namespace ProxyInterfaceSourceGenerator.FileGenerators @@ -30,7 +29,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators var typeSymbolAsString = typeSymbol.ToString(); - var existing = _context.CandidateInterfaces.Values.FirstOrDefault(x => x.TypeName == typeSymbolAsString); + var existing = _context.CandidateInterfaces.Values.FirstOrDefault(x => x.RawTypeName == typeSymbolAsString); if (existing is not null) { if (!_context.ReplacedTypes.ContainsKey(typeSymbolAsString)) @@ -48,7 +47,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators foreach (var typeArgument in namedTypedSymbol.TypeArguments) { var typeArgumentAsString = typeArgument.ToString(); - var exist = _context.CandidateInterfaces.Values.FirstOrDefault(x => x.TypeName == typeArgumentAsString); + var exist = _context.CandidateInterfaces.Values.FirstOrDefault(x => x.RawTypeName == typeArgumentAsString); if (exist is not null) { isReplaced = true; @@ -68,13 +67,13 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators return typeSymbolAsString; } - protected INamedTypeSymbol GetType(string name) + protected INamedTypeSymbol GetNamedTypeSymbolByFullName(string fullName) { // The GetTypeByMetadataName method returns null if no type matches the full name or if 2 or more types (in different assemblies) match the full name. - var symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name); + var symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(fullName); if (symbol is null) { - throw new Exception($"The type '{name}' is not found."); + throw new Exception($"The type '{fullName}' is not found."); } return symbol; diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs index 1f40da6..301dc4a 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; +using System.Linq; using System.Text; using Microsoft.CodeAnalysis; using ProxyInterfaceSourceGenerator.Enums; using ProxyInterfaceSourceGenerator.Extensions; +using ProxyInterfaceSourceGenerator.SyntaxReceiver; using ProxyInterfaceSourceGenerator.Utils; namespace ProxyInterfaceSourceGenerator.FileGenerators @@ -18,72 +20,62 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators { foreach (var ci in _context.CandidateInterfaces) { - yield return GenerateFile(ci.Value.Namespace, ci.Value.InterfaceName, ci.Value.TypeName, ci.Value.ProxyAll); + yield return GenerateFile(ci.Value); } } - private FileData GenerateFile(string ns, string interfaceName, string typeName, bool proxyAll) + private FileData GenerateFile(ProxyData pd) { - var symbol = GetType(typeName); + var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName); + var interfaceName = targetClassSymbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName); var file = new FileData( - $"{interfaceName}.cs", - CreatePartialInterfaceCode(ns, symbol, interfaceName, proxyAll) + $"{pd.FileName}.cs", + CreatePartialInterfaceCode(pd.Namespace, targetClassSymbol, interfaceName, pd.ProxyAll) ); - _context.GeneratedData.Add(new() { InterfaceName = interfaceName, ClassName = null, FileData = file }); + // _context.GeneratedData.Add(new() { InterfaceName = interfaceName, ClassName = null, FileData = file }); return file; } - private string CreatePartialInterfaceCode(string ns, INamedTypeSymbol symbol, string interfaceName, bool proxyAll) => $@"using System; + private string CreatePartialInterfaceCode(string ns, INamedTypeSymbol targetClassSymbol, string interfaceName, bool proxyAll) => $@"using System; namespace {ns} {{ public partial interface {interfaceName} {{ -{GenerateProperties(symbol, proxyAll)} +{GenerateProperties(targetClassSymbol, proxyAll)} -{GenerateMethods(symbol)} +{GenerateMethods(targetClassSymbol)} }} }}"; - private string GenerateProperties(INamedTypeSymbol symbol, bool proxyAll) + private string GenerateProperties(INamedTypeSymbol targetClassSymbol, bool proxyAll) { var str = new StringBuilder(); - foreach (var property in MemberHelper.GetPublicProperties(symbol)) + foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol)) { - switch (property.GetTypeEnum()) + var type = GetPropertyType(property, out var isReplaced); + if (isReplaced) { - case TypeEnum.ValueTypeOrString: - case TypeEnum.Interface: - str.AppendLine($" {property.ToPropertyText()}"); - str.AppendLine(); - break; - - default: - var type = GetPropertyType(property, out var isReplaced); - if (isReplaced) - { - str.AppendLine($" {property.ToPropertyText(type)}"); - } - else - { - str.AppendLine($" {property.ToPropertyText()}"); - } - str.AppendLine(); - break; + str.AppendLine($" {property.ToPropertyText(type)}"); } + else + { + str.AppendLine($" {property.ToPropertyText()}"); + } + str.AppendLine(); } return str.ToString(); } - private string GenerateMethods(INamedTypeSymbol symbol) + private string GenerateMethods(INamedTypeSymbol targetClassSymbol) { var str = new StringBuilder(); - foreach (var method in MemberHelper.GetPublicMethods(symbol)) + foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol)) { var methodParameters = new List(); foreach (var ps in method.Parameters) @@ -91,8 +83,8 @@ namespace {ns} var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString(); methodParameters.Add($"{ps.GetParamsPrefix()}{ps.GetRefPrefix()}{type} {ps.GetSanitizedName()}{ps.GetDefaultValue()}"); } - - str.AppendLine($" {GetReplacedType(method.ReturnType, out _)} {method.Name}({string.Join(", ", methodParameters)});"); + + str.AppendLine($" {GetReplacedType(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()};"); str.AppendLine(); } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs index f70d78e..202731a 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs @@ -5,6 +5,7 @@ using System.Text; using Microsoft.CodeAnalysis; using ProxyInterfaceSourceGenerator.Enums; using ProxyInterfaceSourceGenerator.Extensions; +using ProxyInterfaceSourceGenerator.SyntaxReceiver; using ProxyInterfaceSourceGenerator.Utils; namespace ProxyInterfaceSourceGenerator.FileGenerators @@ -19,38 +20,41 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators { foreach (var ci in _context.CandidateInterfaces) { - yield return GenerateFile(ci.Value.Namespace, ci.Value.InterfaceName, ci.Value.ClassName, ci.Value.TypeName, ci.Value.ProxyAll); + yield return GenerateFile(ci.Value); //.Namespace, ci.Value.InterfaceName, ci.Value.ClassName, ci.Value.TypeName, ci.Value.ProxyAll); } } - private FileData GenerateFile(string ns, string interfaceName, string className, string typeName, bool proxyAll) + private FileData GenerateFile(ProxyData pd) { - var symbol = GetType(typeName); + var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName); + var interfaceName = targetClassSymbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName); + var className = targetClassSymbol.ResolveProxyClassName(); + var constructorName = $"{targetClassSymbol.Name}Proxy"; var file = new FileData( - $"{className}Proxy.cs", - CreateProxyClassCode(ns, symbol, interfaceName, className, proxyAll) + $"{pd.FileName}Proxy.cs", + CreateProxyClassCode(pd.Namespace, targetClassSymbol, interfaceName, className, constructorName) ); - _context.GeneratedData.Add(new() { InterfaceName = interfaceName, ClassName = className, FileData = file }); + // _context.GeneratedData.Add(new() { InterfaceName = interfaceName, ClassName = pd.ClassName, FileData = file }); return file; } - private string CreateProxyClassCode(string ns, INamedTypeSymbol symbol, string interfaceName, string className, bool proxyAll) => $@"using System; + private string CreateProxyClassCode(string ns, INamedTypeSymbol targetClassSymbol, string interfaceName, string className, string constructorName) => $@"using System; using AutoMapper; namespace {ns} {{ - public class {className}Proxy : {interfaceName} + public class {className} : {interfaceName} {{ - public {symbol} _Instance {{ get; }} + public {targetClassSymbol} _Instance {{ get; }} -{GeneratePublicProperties(symbol, proxyAll)} +{GeneratePublicProperties(targetClassSymbol, false)} -{GeneratePublicMethods(symbol)} +{GeneratePublicMethods(targetClassSymbol)} - public {className}Proxy({symbol} instance) + public {constructorName}({targetClassSymbol} instance) {{ _Instance = instance; @@ -86,43 +90,31 @@ namespace {ns} return str.ToString(); } - private string GeneratePublicProperties(INamedTypeSymbol symbol, bool proxyAll) + private string GeneratePublicProperties(INamedTypeSymbol targetClassSymbol, bool proxyAll) { var str = new StringBuilder(); - foreach (var property in MemberHelper.GetPublicProperties(symbol)) + foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol)) { - switch (property.GetTypeEnum()) + var type = GetPropertyType(property, out var isReplaced); + if (isReplaced) { - case TypeEnum.ValueTypeOrString: - case TypeEnum.Interface: - str.AppendLine($" public {property.ToPropertyTextForClass()}"); - str.AppendLine(); - break; - - default: - var type = GetPropertyType(property, out var isReplaced); - if (isReplaced) - { - str.AppendLine($" public {property.ToPropertyTextForClass(type)}"); - } - else - { - str.AppendLine($" public {property.ToPropertyTextForClass()}"); - } - str.AppendLine(); - break; + str.AppendLine($" public {property.ToPropertyTextForClass(type)}"); } - + else + { + str.AppendLine($" public {property.ToPropertyTextForClass()}"); + } + str.AppendLine(); } return str.ToString(); } - private string GeneratePublicMethods(INamedTypeSymbol symbol) + private string GeneratePublicMethods(INamedTypeSymbol targetClassSymbol) { var str = new StringBuilder(); - foreach (var method in MemberHelper.GetPublicMethods(symbol)) + foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol)) { var methodParameters = new List(); var invokeParameters = new List(); @@ -137,7 +129,7 @@ namespace {ns} string returnTypeAsString = GetReplacedType(method.ReturnType, out var returnIsReplaced); - str.AppendLine($" public {returnTypeAsString} {method.Name}({string.Join(", ", methodParameters)})"); + str.AppendLine($" public {returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()}"); str.AppendLine(" {"); foreach (var ps in method.Parameters) { @@ -165,11 +157,11 @@ namespace {ns} if (returnTypeAsString == "void") { - str.AppendLine($" _Instance.{method.Name}({string.Join(", ", invokeParameters)});"); + str.AppendLine($" _Instance.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});"); } else { - str.AppendLine($" var {alternateReturnVariableName} = _Instance.{method.Name}({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/SyntaxReceiver/ProxyData.cs b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxyData.cs index 58cc050..411b5c7 100644 --- a/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxyData.cs +++ b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxyData.cs @@ -1,9 +1,7 @@ -using System.Linq; - -namespace ProxyInterfaceSourceGenerator.SyntaxReceiver +namespace ProxyInterfaceSourceGenerator.SyntaxReceiver { - internal record ProxyData(string Namespace, string InterfaceName, string TypeName, bool ProxyAll) + internal record ProxyData(string Namespace, string InterfaceName, string RawTypeName, string TypeName, bool ProxyAll) { - public string ClassName => TypeName.Split('.').Last(); + public string FileName => TypeName.Replace('.', '_').Replace('`', '_'); } } \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs index a03e901..7b9e6a8 100644 --- a/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs +++ b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs @@ -1,28 +1,28 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using ProxyInterfaceSourceGenerator.Extensions; - -namespace ProxyInterfaceSourceGenerator.SyntaxReceiver -{ - internal class ProxySyntaxReceiver : ISyntaxReceiver - { - private static readonly string[] Modifiers = new[] { "public", "partial" }; - - public IDictionary CandidateInterfaces { get; } = new Dictionary(); - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax && TryGet(interfaceDeclarationSyntax, out var data)) - { - CandidateInterfaces.Add(interfaceDeclarationSyntax, data); - } - } - - private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, out ProxyData data) - { - data = new(string.Empty, string.Empty, string.Empty, false); +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using ProxyInterfaceSourceGenerator.Extensions; + +namespace ProxyInterfaceSourceGenerator.SyntaxReceiver +{ + internal class ProxySyntaxReceiver : ISyntaxReceiver + { + private static readonly string[] Modifiers = new[] { "public", "partial" }; + + public IDictionary CandidateInterfaces { get; } = new Dictionary(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax && TryGet(interfaceDeclarationSyntax, out var data)) + { + CandidateInterfaces.Add(interfaceDeclarationSyntax, data); + } + } + + private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, out ProxyData data) + { + data = new(string.Empty, string.Empty, string.Empty, string.Empty, false); if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Count() != 0) { @@ -30,33 +30,43 @@ namespace ProxyInterfaceSourceGenerator.SyntaxReceiver return false; } - var attributeLists = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => a.Name.ToString().Equals("ProxyInterfaceGenerator.Proxy"))); - if (attributeLists is null) - { - return false; - } - - var argumentList = attributeLists.Attributes.FirstOrDefault()?.ArgumentList; - if (argumentList is null) - { - return false; - } - - string ns = string.Empty; - if (SyntaxNodeUtils.TryGetParentSyntax(interfaceDeclarationSyntax, out NamespaceDeclarationSyntax namespaceDeclarationSyntax)) - { - ns = namespaceDeclarationSyntax.Name.ToString(); - } - - data = new - ( - ns, - interfaceDeclarationSyntax.Identifier.ToString(), - ((TypeOfExpressionSyntax)argumentList.Arguments[0].Expression).Type.ToString(), - false //bool.Parse(argumentList.Arguments[1].Expression.GetText().ToString()) - ); - - return true; - } - } + var attributeLists = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => a.Name.ToString().Equals("ProxyInterfaceGenerator.Proxy"))); + if (attributeLists is null) + { + return false; + } + + var argumentList = attributeLists.Attributes.FirstOrDefault()?.ArgumentList; + if (argumentList is null) + { + return false; + } + + string ns = string.Empty; + if (SyntaxNodeUtils.TryGetParentSyntax(interfaceDeclarationSyntax, out NamespaceDeclarationSyntax namespaceDeclarationSyntax)) + { + ns = namespaceDeclarationSyntax.Name.ToString(); + } + + string rawTypename = ((TypeOfExpressionSyntax)argumentList.Arguments[0].Expression).Type.ToString(); + + data = new + ( + ns, + interfaceDeclarationSyntax.Identifier.ToString(), + rawTypename, + ResolveType(rawTypename), + false //bool.Parse(argumentList.Arguments[1].Expression.GetText().ToString()) + ); + + return true; + } + + private static string ResolveType(string typeName) + { + return !(typeName.Contains('<') && typeName.Contains('>')) ? + typeName : + $"{typeName.Replace("<", string.Empty).Replace(">", string.Empty).Replace(",", string.Empty).Trim()}`{typeName.Count(c => c == ',') + 1}"; + } + } } \ No newline at end of file