diff --git a/src-examples/ProxyInterfaceConsumer/Program.cs b/src-examples/ProxyInterfaceConsumer/Program.cs index 5a82864..c7cfe32 100644 --- a/src-examples/ProxyInterfaceConsumer/Program.cs +++ b/src-examples/ProxyInterfaceConsumer/Program.cs @@ -1,11 +1,15 @@ -namespace SourceGeneratorInterface +using System; + +namespace SourceGeneratorInterface { public class Program { public static void Main() { - IPerson ip = null; - //var i = ip.Id; + PersonProxy p = new PersonProxy(new Person()); + p.Name = "test"; + p.Add("x"); + Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(p)); } } } diff --git a/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs b/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs index 645cbc7..363f75f 100644 --- a/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs +++ b/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text; using Microsoft.CodeAnalysis; namespace ProxyInterfaceSourceGenerator.Extensions @@ -13,6 +14,14 @@ namespace ProxyInterfaceSourceGenerator.Extensions return $"{property.Type} {property.Name} {{ {get}{set}}}"; } + public static string ToProxyCode(this IPropertySymbol property) + { + string get = property.GetMethod != null ? $"get => _instance.{property.Name}; " : string.Empty; + string set = property.SetMethod != null ? $"set => _instance.{property.Name} = value; " : string.Empty; + + return $"{property.Type} {property.Name} {{ {get}{set}}}"; + } + public static string ToCode(this IMethodSymbol method) { var parameters = new List(); @@ -21,7 +30,18 @@ namespace ProxyInterfaceSourceGenerator.Extensions parameters.Add($"{ps.Type} {ps.Name}"); } - return $"{method.ReturnType} {method.Name}({string.Join(", ", parameters)});"; + return $"{method.ReturnType} {method.Name}({string.Join(", ", parameters)})"; + } + + public static string ToProxyCode(this IMethodSymbol method) + { + var parameters = new List(); + foreach (var ps in method.Parameters) + { + parameters.Add($"{ps.Name}"); + } + + return $"{method.ToCode()} => _instance.{method.Name}({string.Join(", ", parameters)});"; } } } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs index f1ec882..873282e 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs @@ -22,13 +22,13 @@ namespace ClassLibrarySourceGen public IEnumerable GenerateFiles() { - foreach (var x in _candidateInterfaces) + foreach (var ci in _candidateInterfaces) { - string interfaceName = $"I{x.Value.Split('.').Last()}"; + string interfaceName = $"I{ci.Value.Split('.').Last()}"; yield return new Data { FileName = $"I{interfaceName}.cs", - Text = CreatePartialInterfaceCode(_context.Compilation.GetTypeByMetadataName(x.Value), interfaceName) + Text = CreatePartialInterfaceCode(_context.Compilation.GetTypeByMetadataName(ci.Value), interfaceName) }; } } @@ -62,7 +62,7 @@ namespace {symbol.ContainingNamespace} var str = new StringBuilder(); foreach (var method in MemberHelper.GetPublicMethods(symbol)) { - str.AppendLine($" {method.ToCode()}"); + str.AppendLine($" {method.ToCode()};"); str.AppendLine(); } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs new file mode 100644 index 0000000..434eb8b --- /dev/null +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using ProxyInterfaceSourceGenerator.Extensions; +using ProxyInterfaceSourceGenerator.FileGenerators; +using ProxyInterfaceSourceGenerator.Utils; + +namespace ClassLibrarySourceGen +{ + internal class ProxyClassesGenerator : IFilesGenerator + { + private readonly GeneratorExecutionContext _context; + private readonly IDictionary _candidateInterfaces; + + public ProxyClassesGenerator(GeneratorExecutionContext context, IDictionary candidateInterfaces) + { + _context = context; + _candidateInterfaces = candidateInterfaces; + } + + public IEnumerable GenerateFiles() + { + foreach (var ci in _candidateInterfaces) + { + string interfaceName = $"{ci.Value.Split('.').Last()}"; + yield return new Data + { + FileName = $"{interfaceName}Proxy.cs", + Text = CreateProxyClassCode(_context.Compilation.GetTypeByMetadataName(ci.Value), interfaceName) + }; + } + } + + private string CreateProxyClassCode(INamedTypeSymbol symbol, string interfaceName) => $@"using System; + +namespace {symbol.ContainingNamespace} +{{ + public class {interfaceName}Proxy : I{interfaceName} + {{ + private {interfaceName} _instance; + + public {interfaceName}Proxy({interfaceName} instance) + {{ + _instance = instance; + }} + +{GenerateSimpleProperties(symbol)} + +{GenerateMethods(symbol)} + }} +}}"; //{GenerateMethods(symbol)} + + + + private string GenerateSimpleProperties(INamedTypeSymbol symbol) + { + var str = new StringBuilder(); + foreach (var property in MemberHelper.GetPublicProperties(symbol, p => p.Type.IsValueType || p.Type.ToString() == "string")) + { + str.AppendLine($" public {property.ToProxyCode()}"); + str.AppendLine(); + } + + return str.ToString(); + } + + private string GenerateMethods(INamedTypeSymbol symbol) + { + var str = new StringBuilder(); + foreach (var method in MemberHelper.GetPublicMethods(symbol)) + { + str.AppendLine($" public {method.ToProxyCode()}"); + str.AppendLine(); + } + + return str.ToString(); + } + } +} \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs b/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs index 15e9376..f0619a6 100644 --- a/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs @@ -15,10 +15,10 @@ namespace ProxyInterfaceSourceGenerator public void Initialize(GeneratorInitializationContext context) { - if (!Debugger.IsAttached) - { - Debugger.Launch(); - } + //if (!Debugger.IsAttached) + //{ + // Debugger.Launch(); + //} context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver()); } @@ -35,9 +35,14 @@ namespace ProxyInterfaceSourceGenerator var p = context.Compilation.GetTypeByMetadataName("SourceGeneratorInterface.Person"); var ec = context.Compilation.GetTypeByMetadataName("Microsoft.CodeAnalysis.GeneratorExecutionContext"); - var generator = new PartialInterfacesGenerator(context, receiver.CandidateInterfaces); + var partialInterfacesGenerator = new PartialInterfacesGenerator(context, receiver.CandidateInterfaces); + foreach (var data in partialInterfacesGenerator.GenerateFiles()) + { + context.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8)); + } - foreach (var data in generator.GenerateFiles()) + var classesGenerator = new ProxyClassesGenerator(context, receiver.CandidateInterfaces); + foreach (var data in classesGenerator.GenerateFiles()) { context.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8)); } @@ -49,6 +54,11 @@ namespace ProxyInterfaceSourceGenerator public int Id { get; set; } public Clazz C { get; } + + public int Add(string s) + { + return 600; + } } public sealed class Clazz @@ -61,6 +71,8 @@ namespace ProxyInterfaceSourceGenerator int Id { get; set; } IClazz C { get; } + + int Add(string s); } public interface IClazz @@ -88,6 +100,8 @@ namespace ProxyInterfaceSourceGenerator } public IClazz C => _clazz; + + public int Add(string s) => _instance.Add(s); } public class ClazzMock : IClazz @@ -99,11 +113,7 @@ namespace ProxyInterfaceSourceGenerator _instance = instance; } - public string Name - { - get => _instance.Name; - set => _instance.Name = value; - } + public string Name { get => _instance.Name; set => _instance.Name = value; } } public interface IPrintable