From 36fdd645b16ad61a7b85aa72b65979c7f08e7248 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 23 Jul 2021 22:10:08 +0200 Subject: [PATCH] Fixes --- .../ProxyInterfaceConsumer/IPerson.cs | 2 +- src-examples/ProxyInterfaceConsumer/Person.cs | 8 ++- src/ProxyInterfaceSourceGenerator/Context.cs | 8 +++ .../Extensions/SymbolExtensions.cs | 11 ++-- .../FileGenerators/Data.cs | 5 +- .../PartialInterfacesGenerator.cs | 60 +++++++++++++++---- .../FileGenerators/ProxyAttributeGenerator.cs | 8 +-- .../FileGenerators/ProxyClassesGenerator.cs | 16 ++--- .../ProxyInterfaceCodeGenerator.cs | 25 ++++---- .../SyntaxReceiver/ProxyData.cs | 5 +- .../SyntaxReceiver/ProxySyntaxReceiver.cs | 18 +++--- .../Utils/MemberHelper.cs | 15 +++-- 12 files changed, 112 insertions(+), 69 deletions(-) create mode 100644 src/ProxyInterfaceSourceGenerator/Context.cs diff --git a/src-examples/ProxyInterfaceConsumer/IPerson.cs b/src-examples/ProxyInterfaceConsumer/IPerson.cs index 4c75259..af7e469 100644 --- a/src-examples/ProxyInterfaceConsumer/IPerson.cs +++ b/src-examples/ProxyInterfaceConsumer/IPerson.cs @@ -1,6 +1,6 @@ namespace SourceGeneratorInterface { - [ProxyInterfaceGenerator.Proxy(typeof(SourceGeneratorInterface.Person), true)] + [ProxyInterfaceGenerator.Proxy(typeof(SourceGeneratorInterface.Person), false)] public partial interface IPerson { } diff --git a/src-examples/ProxyInterfaceConsumer/Person.cs b/src-examples/ProxyInterfaceConsumer/Person.cs index d151044..6954a2f 100644 --- a/src-examples/ProxyInterfaceConsumer/Person.cs +++ b/src-examples/ProxyInterfaceConsumer/Person.cs @@ -1,4 +1,6 @@ -namespace SourceGeneratorInterface +using Microsoft.CodeAnalysis; + +namespace SourceGeneratorInterface { public class Person { @@ -23,6 +25,10 @@ { // } + + public Compilation Compilation { get; } + + public INamedTypeSymbol MyNamedTypeSymbol { get;set; } } public class Address diff --git a/src/ProxyInterfaceSourceGenerator/Context.cs b/src/ProxyInterfaceSourceGenerator/Context.cs new file mode 100644 index 0000000..3f2a249 --- /dev/null +++ b/src/ProxyInterfaceSourceGenerator/Context.cs @@ -0,0 +1,8 @@ +using Microsoft.CodeAnalysis; + +namespace ProxyInterfaceSourceGenerator +{ + internal record Context(GeneratorExecutionContext GeneratorExecutionContext) + { + } +} \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs b/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs index 363f75f..adbf524 100644 --- a/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs +++ b/src/ProxyInterfaceSourceGenerator/Extensions/SymbolExtensions.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis; namespace ProxyInterfaceSourceGenerator.Extensions { internal static class SymbolExtensions { - public static string ToCode(this IPropertySymbol property) + public static string ToPropertyTextForInterface(this IPropertySymbol property) { string get = property.GetMethod != null ? "get; " : string.Empty; string set = property.SetMethod != null ? "set; " : string.Empty; @@ -14,7 +13,7 @@ namespace ProxyInterfaceSourceGenerator.Extensions return $"{property.Type} {property.Name} {{ {get}{set}}}"; } - public static string ToProxyCode(this IPropertySymbol property) + public static string ToPropertyTextForClass(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; @@ -22,7 +21,7 @@ namespace ProxyInterfaceSourceGenerator.Extensions return $"{property.Type} {property.Name} {{ {get}{set}}}"; } - public static string ToCode(this IMethodSymbol method) + public static string ToMethodTextForInterface(this IMethodSymbol method) { var parameters = new List(); foreach (var ps in method.Parameters) @@ -33,7 +32,7 @@ namespace ProxyInterfaceSourceGenerator.Extensions return $"{method.ReturnType} {method.Name}({string.Join(", ", parameters)})"; } - public static string ToProxyCode(this IMethodSymbol method) + public static string ToMethodTextForClass(this IMethodSymbol method) { var parameters = new List(); foreach (var ps in method.Parameters) @@ -41,7 +40,7 @@ namespace ProxyInterfaceSourceGenerator.Extensions parameters.Add($"{ps.Name}"); } - return $"{method.ToCode()} => _instance.{method.Name}({string.Join(", ", parameters)});"; + return $"{method.ToMethodTextForInterface()} => _instance.{method.Name}({string.Join(", ", parameters)});"; } } } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/Data.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/Data.cs index e6161f4..502713d 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/Data.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/Data.cs @@ -1,9 +1,6 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators { - internal record Data + internal record Data(string FileName, string Text) { - public string FileName { get; init; } - - public string Text { get; init; } } } \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs index 0b8fd44..0aa4059 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs @@ -12,10 +12,10 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators { internal class PartialInterfacesGenerator : IFilesGenerator { - private readonly GeneratorExecutionContext _context; + private readonly Context _context; private readonly IDictionary _candidateInterfaces; - public PartialInterfacesGenerator(GeneratorExecutionContext context, IDictionary candidateInterfaces) + public PartialInterfacesGenerator(Context context, IDictionary candidateInterfaces) { _context = context; _candidateInterfaces = candidateInterfaces; @@ -25,7 +25,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators { foreach (var ci in _candidateInterfaces) { - var symbol = _context.Compilation.GetTypeByMetadataName(ci.Value.TypeName); + var symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(ci.Value.TypeName); if (symbol is null) { throw new Exception($"The type '{ci.Value.TypeName}' is not found."); @@ -33,15 +33,11 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators string interfaceName = $"I{ci.Value.TypeName.Split('.').Last()}"; - yield return new Data - { - FileName = $"I{interfaceName}.cs", - Text = CreatePartialInterfaceCode(symbol, interfaceName) - }; + yield return new Data($"I{interfaceName}.cs", CreatePartialInterfaceCode(symbol, interfaceName, ci.Value.ProxyAll)); } } - private string CreatePartialInterfaceCode(INamedTypeSymbol symbol, string interfaceName) => $@"using System; + private string CreatePartialInterfaceCode(INamedTypeSymbol symbol, string interfaceName, bool proxyAll) => $@"using System; namespace {symbol.ContainingNamespace} {{ @@ -49,6 +45,10 @@ namespace {symbol.ContainingNamespace} {{ {GenerateSimpleProperties(symbol)} +{GenerateInterfaceProperties(symbol)} + +{GenerateComplexProperties(symbol, proxyAll)} + {GenerateMethods(symbol)} }} }}"; @@ -58,19 +58,57 @@ namespace {symbol.ContainingNamespace} var str = new StringBuilder(); foreach (var property in MemberHelper.GetPublicProperties(symbol, p => p.Type.IsValueType || p.Type.ToString() == "string")) { - str.AppendLine($" {property.ToCode()}"); + str.AppendLine($" {property.ToPropertyTextForInterface()}"); str.AppendLine(); } return str.ToString(); } + private string GenerateInterfaceProperties(INamedTypeSymbol symbol) + { + var str = new StringBuilder(); + foreach (var property in MemberHelper.GetPublicProperties(symbol, + p => !(p.Type.IsValueType || p.Type.ToString() == "string"), + p => p.Type.TypeKind == TypeKind.Interface) + ) + { + str.AppendLine($" {property.ToPropertyTextForInterface()}"); + str.AppendLine(); + } + + return "// GenerateInterfaceProperties";// str.ToString(); + } + + private string GenerateComplexProperties(INamedTypeSymbol symbol, bool proxyAll) + { + var filters = new List> + { + p => !(p.Type.IsValueType || p.Type.ToString() == "string"), + p => p.Type.TypeKind != TypeKind.Interface + }; + + if (proxyAll) + { + + } + + var str = new StringBuilder(); + foreach (var property in MemberHelper.GetPublicProperties(symbol, filters.ToArray())) + { + str.AppendLine($" {property.ToPropertyTextForInterface()}"); + str.AppendLine(); + } + + return "// GenerateComplexProperties";// str.ToString(); + } + private string GenerateMethods(INamedTypeSymbol symbol) { var str = new StringBuilder(); foreach (var method in MemberHelper.GetPublicMethods(symbol)) { - str.AppendLine($" {method.ToCode()};"); + str.AppendLine($" {method.ToMethodTextForInterface()};"); str.AppendLine(); } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyAttributeGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyAttributeGenerator.cs index bd65dc0..ccc27b7 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyAttributeGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyAttributeGenerator.cs @@ -6,10 +6,7 @@ public Data GenerateFile() { - return new Data - { - FileName = $"{ClassName}.cs", - Text = $@"using System; + return new Data($"{ClassName}.cs", $@"using System; namespace ProxyInterfaceGenerator {{ @@ -25,8 +22,7 @@ namespace ProxyInterfaceGenerator ProxyAll = proxyAll; }} }} -}}" - }; +}}"); } } } \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs index 0433f05..4ba1f0e 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs @@ -12,10 +12,10 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators { internal class ProxyClassesGenerator : IFilesGenerator { - private readonly GeneratorExecutionContext _context; + private readonly Context _context; private readonly IDictionary _candidateInterfaces; - public ProxyClassesGenerator(GeneratorExecutionContext context, IDictionary candidateInterfaces) + public ProxyClassesGenerator(Context context, IDictionary candidateInterfaces) { _context = context; _candidateInterfaces = candidateInterfaces; @@ -25,7 +25,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators { foreach (var ci in _candidateInterfaces) { - var symbol = _context.Compilation.GetTypeByMetadataName(ci.Value.TypeName); + var symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(ci.Value.TypeName); if (symbol is null) { throw new Exception($"The type '{ci.Value.TypeName}' is not found."); @@ -33,11 +33,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators string className = $"{ci.Value.TypeName.Split('.').Last()}"; - yield return new Data - { - FileName = $"{className}Proxy.cs", - Text = CreateProxyClassCode(symbol, className) - }; + yield return new Data($"{className}Proxy.cs", CreateProxyClassCode(symbol, className)); } } @@ -65,7 +61,7 @@ namespace {symbol.ContainingNamespace} 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($" public {property.ToPropertyTextForClass()}"); str.AppendLine(); } @@ -77,7 +73,7 @@ namespace {symbol.ContainingNamespace} var str = new StringBuilder(); foreach (var method in MemberHelper.GetPublicMethods(symbol)) { - str.AppendLine($" public {method.ToProxyCode()}"); + str.AppendLine($" public {method.ToMethodTextForClass()}"); str.AppendLine(); } diff --git a/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs b/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs index e1e1f19..b8bb66c 100644 --- a/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/ProxyInterfaceCodeGenerator.cs @@ -13,19 +13,22 @@ namespace ProxyInterfaceSourceGenerator public void Initialize(GeneratorInitializationContext context) { - //if (!System.DiagnosticsDebugger.IsAttached) - //{ - // System.DiagnosticsDebugger.Launch(); - //} + if (!System.Diagnostics.Debugger.IsAttached) + { + System.Diagnostics.Debugger.Launch(); + } context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver()); } - public void Execute(GeneratorExecutionContext context) - { - var attributeData = _proxyAttributeGenerator.GenerateFile(); - context.AddSource(attributeData.FileName, SourceText.From(attributeData.Text, Encoding.UTF8)); - if (context.SyntaxReceiver is not ProxySyntaxReceiver receiver) + public void Execute(GeneratorExecutionContext ctx) + { + var context = new Context(ctx); + + var attributeData = _proxyAttributeGenerator.GenerateFile(); + context.GeneratorExecutionContext.AddSource(attributeData.FileName, SourceText.From(attributeData.Text, Encoding.UTF8)); + + if (context.GeneratorExecutionContext.SyntaxReceiver is not ProxySyntaxReceiver receiver) { return; } @@ -33,13 +36,13 @@ namespace ProxyInterfaceSourceGenerator var partialInterfacesGenerator = new PartialInterfacesGenerator(context, receiver.CandidateInterfaces); foreach (var data in partialInterfacesGenerator.GenerateFiles()) { - context.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8)); + context.GeneratorExecutionContext.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8)); } var classesGenerator = new ProxyClassesGenerator(context, receiver.CandidateInterfaces); foreach (var data in classesGenerator.GenerateFiles()) { - context.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8)); + context.GeneratorExecutionContext.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8)); } } } diff --git a/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxyData.cs b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxyData.cs index 5334aed..d2a7545 100644 --- a/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxyData.cs +++ b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxyData.cs @@ -1,9 +1,6 @@ namespace ProxyInterfaceSourceGenerator.SyntaxReceiver { - internal record ProxyData + internal record ProxyData(string TypeName, bool ProxyAll) { - public string TypeName { get; init; } - - public bool ProxyAll { get; init; } } } \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs index 42b22fa..e391636 100644 --- a/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs +++ b/src/ProxyInterfaceSourceGenerator/SyntaxReceiver/ProxySyntaxReceiver.cs @@ -19,7 +19,7 @@ namespace ProxyInterfaceSourceGenerator.SyntaxReceiver private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, out ProxyData data) { - data = new(); + data = new(string.Empty, false); // TODO : how to check if the InterfaceDeclarationSyntax has 'partial' ? var attributeLists = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => a.Name.ToString().Equals("ProxyInterfaceGenerator.Proxy"))); @@ -28,19 +28,19 @@ namespace ProxyInterfaceSourceGenerator.SyntaxReceiver return false; } - var args = attributeLists.Attributes.FirstOrDefault()?.ArgumentList; - if (args is null) + var argumentList = attributeLists.Attributes.FirstOrDefault()?.ArgumentList; + if (argumentList is null) { return false; } - data = new() - { - TypeName = args.Arguments[0].Expression.ChildNodes().First().GetText().ToString(), - ProxyAll = bool.Parse(args.Arguments[1].Expression.ChildNodes().First().GetText().ToString()) - }; + data = new + ( + argumentList.Arguments[0].Expression.ChildNodes().First().GetText().ToString(), + bool.Parse(argumentList.Arguments[1].Expression.GetText().ToString()) + ); return true; } } -} +} \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/Utils/MemberHelper.cs b/src/ProxyInterfaceSourceGenerator/Utils/MemberHelper.cs index 58b4662..73ec85b 100644 --- a/src/ProxyInterfaceSourceGenerator/Utils/MemberHelper.cs +++ b/src/ProxyInterfaceSourceGenerator/Utils/MemberHelper.cs @@ -7,16 +7,19 @@ namespace ProxyInterfaceSourceGenerator.Utils { internal static class MemberHelper { - private static string[] ExcludedMethods = new string[] { "ToString", "GetHashCode" }; + private static string[] _excludedMethods = new string[] { "ToString", "GetHashCode" }; - public static IEnumerable GetPublicProperties(INamedTypeSymbol classSymbol, Func filter) + public static IEnumerable GetPublicProperties(INamedTypeSymbol classSymbol, params Func[] filters) { - return GetPublicMembers(classSymbol, p => p.Kind == SymbolKind.Property, filter); + var allFilters = new List>(filters); + allFilters.Add(p => p.Kind == SymbolKind.Property); + + return GetPublicMembers(classSymbol, allFilters.ToArray()); } - public static IEnumerable GetPublicMethods(INamedTypeSymbol classSymbol, Func filter = null) + public static IEnumerable GetPublicMethods(INamedTypeSymbol classSymbol, Func? filter = null) { - if (filter == null) + if (filter is null) { filter = _ => true; } @@ -24,7 +27,7 @@ namespace ProxyInterfaceSourceGenerator.Utils return GetPublicMembers(classSymbol, m => m.Kind == SymbolKind.Method, m => m.MethodKind == MethodKind.Ordinary, - m => !ExcludedMethods.Contains(m.Name), + m => !_excludedMethods.Contains(m.Name), filter); }