From 45cec73b3fd520de2d0dd6f84cc0aae1b7efbd8e Mon Sep 17 00:00:00 2001 From: Beakona Date: Sun, 27 Mar 2022 23:40:36 +0200 Subject: [PATCH] cosmetics --- AutoInterface.sln | 7 +- .../AutoInterfaceSample.csproj | 11 +- AutoInterfaceSample/Program.cs | 4 +- .../AutoInterfaceAttribute.cs | 2 +- .../AutoInterfaceTemplateAttribute.cs | 2 +- .../BeaKona.AutoInterfaceAttributes.csproj | 9 + .../AutoInterfaceRecord.cs | 37 +- .../AutoInterfaceSourceGenerator.cs | 969 ++++++----- .../AutoInterfaceTargets.cs | 23 - .../BeaKona.AutoInterfaceGenerator.csproj | 16 +- .../CSharpCodeTextWriter.cs | 1473 ++++++++--------- BeaKona.AutoInterfaceGenerator/Globals.cs | 4 + BeaKona.AutoInterfaceGenerator/Helpers.cs | 41 +- .../ICodeTextWriter.cs | 44 +- .../IEnumerableExtensions.cs | 38 +- BeaKona.AutoInterfaceGenerator/IMemberInfo.cs | 20 +- .../INamedTypeSymbolExtensions.cs | 25 +- .../ISourceTextGenerator.cs | 9 +- .../ITypeSymbolExtensions.cs | 72 +- BeaKona.AutoInterfaceGenerator/ScopeInfo.cs | 139 +- .../SemanticFacts.cs | 204 ++- .../SourceBuilder.cs | 338 ++-- .../SourceBuilderOptions.cs | 13 +- .../Templates/EventModel.cs | 15 +- .../Templates/IEventModel.cs | 11 +- .../Templates/IIndexerModel.cs | 11 +- .../Templates/ILocalExpressionModel.cs | 11 +- .../ILocalPropertyExpressionModel.cs | 15 +- .../Templates/IMethodModel.cs | 19 +- .../Templates/IPropertyModel.cs | 15 +- .../Templates/IRootModel.cs | 13 +- .../Templates/IndexerModel.cs | 11 +- .../Templates/MethodModel.cs | 23 +- .../Templates/ModelLoader.cs | 253 ++- .../Templates/PartialEventModel.cs | 13 +- .../Templates/PartialIndexerModel.cs | 13 +- .../Templates/PartialMethodModel.cs | 13 +- .../Templates/PartialPropertyModel.cs | 13 +- .../Templates/PartialTemplate.cs | 96 +- .../Templates/PropertyModel.cs | 27 +- .../Templates/StandaloneModel.cs | 21 +- .../Templates/TemplateDefinition.cs | 79 +- .../Templates/TemplatedSourceGenerator.cs | 74 +- .../BeaKona.AutoInterfaceGeneratorTest.csproj | 27 - .../GeneratorTests.cs | 53 - TestInterfaces/Interfaces.cs | 4 +- TestInterfaces/TestInterfaces.csproj | 2 +- 47 files changed, 2065 insertions(+), 2267 deletions(-) delete mode 100644 BeaKona.AutoInterfaceGenerator/AutoInterfaceTargets.cs create mode 100644 BeaKona.AutoInterfaceGenerator/Globals.cs delete mode 100644 BeaKona.AutoInterfaceGeneratorTest/BeaKona.AutoInterfaceGeneratorTest.csproj delete mode 100644 BeaKona.AutoInterfaceGeneratorTest/GeneratorTests.cs diff --git a/AutoInterface.sln b/AutoInterface.sln index fcb35b4..c091297 100644 --- a/AutoInterface.sln +++ b/AutoInterface.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 17.1.32319.34 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeaKona.AutoInterfaceGenerator", "BeaKona.AutoInterfaceGenerator\BeaKona.AutoInterfaceGenerator.csproj", "{FF7DF2CF-FA1C-4655-B451-B6FD1E374E3A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeaKona.AutoInterfaceGeneratorTest", "BeaKona.AutoInterfaceGeneratorTest\BeaKona.AutoInterfaceGeneratorTest.csproj", "{5879D401-B910-4377-BD93-DFAF5CCCAAD0}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoInterfaceSample", "AutoInterfaceSample\AutoInterfaceSample.csproj", "{D80AD027-6463-4CBB-91B5-4952AE0204B3}" ProjectSection(ProjectDependencies) = postProject {FF7DF2CF-FA1C-4655-B451-B6FD1E374E3A} = {FF7DF2CF-FA1C-4655-B451-B6FD1E374E3A} @@ -19,7 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeaKona.AutoInterfaceAttributes", "BeaKona.AutoInterfaceAttributes\BeaKona.AutoInterfaceAttributes.csproj", "{8EB5E4A3-F09E-42A8-9846-C000B2D5286C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeaKona.AutoInterfaceAttributes", "BeaKona.AutoInterfaceAttributes\BeaKona.AutoInterfaceAttributes.csproj", "{8EB5E4A3-F09E-42A8-9846-C000B2D5286C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -31,9 +29,6 @@ Global {FF7DF2CF-FA1C-4655-B451-B6FD1E374E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF7DF2CF-FA1C-4655-B451-B6FD1E374E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF7DF2CF-FA1C-4655-B451-B6FD1E374E3A}.Release|Any CPU.Build.0 = Release|Any CPU - {5879D401-B910-4377-BD93-DFAF5CCCAAD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5879D401-B910-4377-BD93-DFAF5CCCAAD0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5879D401-B910-4377-BD93-DFAF5CCCAAD0}.Release|Any CPU.ActiveCfg = Release|Any CPU {D80AD027-6463-4CBB-91B5-4952AE0204B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D80AD027-6463-4CBB-91B5-4952AE0204B3}.Debug|Any CPU.Build.0 = Debug|Any CPU {D80AD027-6463-4CBB-91B5-4952AE0204B3}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/AutoInterfaceSample/AutoInterfaceSample.csproj b/AutoInterfaceSample/AutoInterfaceSample.csproj index d869359..1fc863c 100644 --- a/AutoInterfaceSample/AutoInterfaceSample.csproj +++ b/AutoInterfaceSample/AutoInterfaceSample.csproj @@ -1,8 +1,8 @@ - + Exe - net5.0 + net6.0 enable @@ -14,9 +14,10 @@ - - - + + + + diff --git a/AutoInterfaceSample/Program.cs b/AutoInterfaceSample/Program.cs index 2fe5b57..c4e3aa8 100644 --- a/AutoInterfaceSample/Program.cs +++ b/AutoInterfaceSample/Program.cs @@ -41,8 +41,8 @@ public class Program public static void Main() { //System.Diagnostics.Debug.WriteLine(BeaKona.Output.Debug_Person.Info); - IPrintable p = new Person(); - p.Print1(); + //IPrintable p = new Person(); + //p.Print1(); } } diff --git a/BeaKona.AutoInterfaceAttributes/AutoInterfaceAttribute.cs b/BeaKona.AutoInterfaceAttributes/AutoInterfaceAttribute.cs index d38f6c4..f534d86 100644 --- a/BeaKona.AutoInterfaceAttributes/AutoInterfaceAttribute.cs +++ b/BeaKona.AutoInterfaceAttributes/AutoInterfaceAttribute.cs @@ -21,4 +21,4 @@ public AutoInterfaceAttribute(Type type) public string? TemplateLanguage { get; set; } public string? TemplateBody { get; set; } public string? TemplateFileName { get; set; } -} \ No newline at end of file +} diff --git a/BeaKona.AutoInterfaceAttributes/AutoInterfaceTemplateAttribute.cs b/BeaKona.AutoInterfaceAttributes/AutoInterfaceTemplateAttribute.cs index fc158cd..3805a66 100644 --- a/BeaKona.AutoInterfaceAttributes/AutoInterfaceTemplateAttribute.cs +++ b/BeaKona.AutoInterfaceAttributes/AutoInterfaceTemplateAttribute.cs @@ -17,4 +17,4 @@ public AutoInterfaceTemplateAttribute(AutoInterfaceTargets targets) public string? Language { get; set; } public string? Body { get; set; } public string? FileName { get; set; } -} \ No newline at end of file +} diff --git a/BeaKona.AutoInterfaceAttributes/BeaKona.AutoInterfaceAttributes.csproj b/BeaKona.AutoInterfaceAttributes/BeaKona.AutoInterfaceAttributes.csproj index 3e9faaf..1364a38 100644 --- a/BeaKona.AutoInterfaceAttributes/BeaKona.AutoInterfaceAttributes.csproj +++ b/BeaKona.AutoInterfaceAttributes/BeaKona.AutoInterfaceAttributes.csproj @@ -4,6 +4,15 @@ netstandard2.0 latest enable + BeaKona.AutoInterfaceAttributes + BeaKona + Shared BeaKona.AutoInterface source generator attributes. + false + MIT + https://github.com/beakona/AutoInterface + git + 1.0.0 + False diff --git a/BeaKona.AutoInterfaceGenerator/AutoInterfaceRecord.cs b/BeaKona.AutoInterfaceGenerator/AutoInterfaceRecord.cs index c4bfef9..003a8ef 100644 --- a/BeaKona.AutoInterfaceGenerator/AutoInterfaceRecord.cs +++ b/BeaKona.AutoInterfaceGenerator/AutoInterfaceRecord.cs @@ -1,25 +1,22 @@ using BeaKona.AutoInterfaceGenerator.Templates; -using Microsoft.CodeAnalysis; -using System.Collections.Generic; -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +internal sealed class AutoInterfaceRecord : IMemberInfo { - internal sealed class AutoInterfaceRecord : IMemberInfo + public AutoInterfaceRecord(ISymbol member, ITypeSymbol receiverType, INamedTypeSymbol interfaceType, TemplateDefinition? template, List templateParts) { - public AutoInterfaceRecord(ISymbol member, ITypeSymbol receiverType, INamedTypeSymbol interfaceType, TemplateDefinition? template, List templateParts) - { - this.Member = member; - this.ReceiverType = receiverType; - this.InterfaceType = interfaceType; - this.Template = template; - this.TemplateParts = templateParts?.ToArray() ?? new PartialTemplate[0]; - } - - public ISymbol Member { get; } - public ITypeSymbol ReceiverType { get; } - public INamedTypeSymbol InterfaceType { get; } - public TemplateDefinition? Template { get; } - public PartialTemplate[] TemplateParts { get; } - public bool CastRequired => this.InterfaceType.Equals(this.ReceiverType, SymbolEqualityComparer.Default) == false; + this.Member = member; + this.ReceiverType = receiverType; + this.InterfaceType = interfaceType; + this.Template = template; + this.TemplateParts = templateParts?.ToArray() ?? new PartialTemplate[0]; } -} \ No newline at end of file + + public ISymbol Member { get; } + public ITypeSymbol ReceiverType { get; } + public INamedTypeSymbol InterfaceType { get; } + public TemplateDefinition? Template { get; } + public PartialTemplate[] TemplateParts { get; } + public bool CastRequired => this.InterfaceType.Equals(this.ReceiverType, SymbolEqualityComparer.Default) == false; +} diff --git a/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs b/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs index 0b7bb1e..1c5b64d 100644 --- a/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs +++ b/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs @@ -1,710 +1,705 @@ using BeaKona.AutoInterfaceGenerator.Templates; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Text.RegularExpressions; -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +[Generator] +public class AutoInterfaceSourceGenerator : ISourceGenerator { - [Generator] - public class AutoInterfaceSourceGenerator : ISourceGenerator + public void Initialize(GeneratorInitializationContext context) { - public void Initialize(GeneratorInitializationContext context) - { - // Register a syntax receiver that will be created for each generation pass - context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); - } + // Register a syntax receiver that will be created for each generation pass + context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); + } - public void Execute(GeneratorExecutionContext context) + public void Execute(GeneratorExecutionContext context) + { + Compilation compilation = context.Compilation; + if (compilation is CSharpCompilation) { - Compilation compilation = context.Compilation; - if (compilation is CSharpCompilation) + //retrieve the populated receiver + if (context.SyntaxReceiver is SyntaxReceiver receiver) { - //retrieve the populated receiver - if (context.SyntaxReceiver is SyntaxReceiver receiver) + // get newly bound attribute + if (compilation.GetTypeByMetadataName(typeof(AutoInterfaceAttribute).FullName) is INamedTypeSymbol autoInterfaceAttributeSymbol && compilation.GetTypeByMetadataName(typeof(AutoInterfaceTemplateAttribute).FullName) is INamedTypeSymbol autoInterfaceTemplateAttributeSymbol) { - // get newly bound attribute - if (compilation.GetTypeByMetadataName(typeof(AutoInterfaceAttribute).FullName) is INamedTypeSymbol autoInterfaceAttributeSymbol && compilation.GetTypeByMetadataName(typeof(AutoInterfaceTemplateAttribute).FullName) is INamedTypeSymbol autoInterfaceTemplateAttributeSymbol) - { - // loop over the candidates, and keep the ones that are actually annotated - List records = new(); + // loop over the candidates, and keep the ones that are actually annotated + List records = new(); - foreach (MemberDeclarationSyntax candidate in receiver.Candidates) + foreach (MemberDeclarationSyntax candidate in receiver.Candidates) + { + SemanticModel model = compilation.GetSemanticModel(candidate.SyntaxTree); + if (candidate is FieldDeclarationSyntax fieldSyntax) { - SemanticModel model = compilation.GetSemanticModel(candidate.SyntaxTree); - if (candidate is FieldDeclarationSyntax fieldSyntax) + foreach (VariableDeclaratorSyntax variableSyntax in fieldSyntax.Declaration.Variables) { - foreach (VariableDeclaratorSyntax variableSyntax in fieldSyntax.Declaration.Variables) + // get symbol being declared by the member, and keep it if its annotated + if (model.GetDeclaredSymbol(variableSyntax) is IFieldSymbol field) { - // get symbol being declared by the member, and keep it if its annotated - if (model.GetDeclaredSymbol(variableSyntax) is IFieldSymbol field) - { - records.AddRange(CollectRecords(context, field, field.Type, autoInterfaceAttributeSymbol, autoInterfaceTemplateAttributeSymbol)); - } + records.AddRange(CollectRecords(context, field, field.Type, autoInterfaceAttributeSymbol, autoInterfaceTemplateAttributeSymbol)); } } - else if (candidate is PropertyDeclarationSyntax propertySyntax) + } + else if (candidate is PropertyDeclarationSyntax propertySyntax) + { + // get symbol being declared by the member, and keep it if its annotated + if (model.GetDeclaredSymbol(propertySyntax) is IPropertySymbol property) { - // get symbol being declared by the member, and keep it if its annotated - if (model.GetDeclaredSymbol(propertySyntax) is IPropertySymbol property) + if (property.IsWriteOnly) { - if (property.IsWriteOnly) - { - Helpers.ReportDiagnostic(context, "BK-AG06", nameof(AutoInterfaceResource.AG06_title), nameof(AutoInterfaceResource.AG06_message), nameof(AutoInterfaceResource.AG06_description), DiagnosticSeverity.Error, property, - property.Name); - continue; - } - - records.AddRange(CollectRecords(context, property, property.Type, autoInterfaceAttributeSymbol, autoInterfaceTemplateAttributeSymbol)); + Helpers.ReportDiagnostic(context, "BK-AG06", nameof(AutoInterfaceResource.AG06_title), nameof(AutoInterfaceResource.AG06_message), nameof(AutoInterfaceResource.AG06_description), DiagnosticSeverity.Error, property, + property.Name); + continue; } + + records.AddRange(CollectRecords(context, property, property.Type, autoInterfaceAttributeSymbol, autoInterfaceTemplateAttributeSymbol)); } } + } - // group elements by the containing class, and generate the source - foreach (IGrouping recordsByContainingType in records.GroupBy(i => i.Member.ContainingType)) - { - INamedTypeSymbol containingType = recordsByContainingType.Key; + // group elements by the containing class, and generate the source + foreach (IGrouping recordsByContainingType in records.GroupBy(i => i.Member.ContainingType, SymbolEqualityComparer.Default)) + { + INamedTypeSymbol containingType = recordsByContainingType.Key; - if (containingType.IsPartial() == false) - { - Helpers.ReportDiagnostic(context, "BK-AG01", nameof(AutoInterfaceResource.AG01_title), nameof(AutoInterfaceResource.AG01_message), nameof(AutoInterfaceResource.AG01_description), DiagnosticSeverity.Error, containingType, - containingType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); - continue; - } + if (containingType.IsPartial() == false) + { + Helpers.ReportDiagnostic(context, "BK-AG01", nameof(AutoInterfaceResource.AG01_title), nameof(AutoInterfaceResource.AG01_message), nameof(AutoInterfaceResource.AG01_description), DiagnosticSeverity.Error, containingType, + containingType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + continue; + } - if (containingType.IsStatic) - { - Helpers.ReportDiagnostic(context, "BK-AG02", nameof(AutoInterfaceResource.AG02_title), nameof(AutoInterfaceResource.AG02_message), nameof(AutoInterfaceResource.AG02_description), DiagnosticSeverity.Error, containingType, - containingType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); - continue; - } + if (containingType.IsStatic) + { + Helpers.ReportDiagnostic(context, "BK-AG02", nameof(AutoInterfaceResource.AG02_title), nameof(AutoInterfaceResource.AG02_message), nameof(AutoInterfaceResource.AG02_description), DiagnosticSeverity.Error, containingType, + containingType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + continue; + } - if (containingType.TypeKind != TypeKind.Class && containingType.TypeKind != TypeKind.Struct) - { - Helpers.ReportDiagnostic(context, "BK-AG08", nameof(AutoInterfaceResource.AG08_title), nameof(AutoInterfaceResource.AG08_message), nameof(AutoInterfaceResource.AG08_description), DiagnosticSeverity.Error, recordsByContainingType.First().Member); - continue; - } + if (containingType.TypeKind != TypeKind.Class && containingType.TypeKind != TypeKind.Struct) + { + Helpers.ReportDiagnostic(context, "BK-AG08", nameof(AutoInterfaceResource.AG08_title), nameof(AutoInterfaceResource.AG08_message), nameof(AutoInterfaceResource.AG08_description), DiagnosticSeverity.Error, recordsByContainingType.First().Member); + continue; + } - try - { - string? code = AutoInterfaceSourceGenerator.ProcessClass(context, compilation, containingType, recordsByContainingType); - if (code != null) - { - string name = containingType.Arity > 0 ? $"{containingType.Name}_{containingType.Arity}" : containingType.Name; - //GeneratePreview(context, name, code); - context.AddSource($"{name}_AutoInterface.cs", SourceText.From(code, Encoding.UTF8)); - } - } - catch (Exception ex) + try + { + string? code = AutoInterfaceSourceGenerator.ProcessClass(context, compilation, containingType, recordsByContainingType); + if (code != null) { - Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, containingType, - ex.ToString().Replace("\r", "").Replace("\n", "")); + string name = containingType.Arity > 0 ? $"{containingType.Name}_{containingType.Arity}" : containingType.Name; + //GeneratePreview(context, name, code); + context.AddSource($"{name}_AutoInterface.cs", SourceText.From(code, Encoding.UTF8)); } } + catch (Exception ex) + { + Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, containingType, + ex.ToString().Replace("\r", "").Replace("\n", "")); + } } } } } + } - //private static void GeneratePreview(GeneratorExecutionContext context, string name, string code) - //{ - // StringBuilder output = new(); - // output.AppendLine("namespace BeaKona.Output {"); - // output.AppendLine($"public static class Debug_{name}"); - // output.AppendLine("{"); - // output.AppendLine($"public static readonly string Info = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(\"{Convert.ToBase64String(Encoding.UTF8.GetBytes(code ?? ""))}\"));"); - // output.AppendLine("}"); - // output.AppendLine("}"); - // context.AddSource($"Output_Debug_{name}.cs", SourceText.From(output.ToString(), Encoding.UTF8)); - //} - - private static List CollectRecords(GeneratorExecutionContext context, ISymbol symbol, ITypeSymbol receiverType, INamedTypeSymbol autoInterfaceAttributeSymbol, INamedTypeSymbol autoInterfaceTemplateAttributeSymbol) - { - List templateParts = new(); - Dictionary> danglingInterfaceTypesBySymbols = new(SymbolEqualityComparer.Default); + //private static void GeneratePreview(GeneratorExecutionContext context, string name, string code) + //{ + // StringBuilder output = new(); + // output.AppendLine("namespace BeaKona.Output {"); + // output.AppendLine($"public static class Debug_{name}"); + // output.AppendLine("{"); + // output.AppendLine($"public static readonly string Info = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(\"{Convert.ToBase64String(Encoding.UTF8.GetBytes(code ?? ""))}\"));"); + // output.AppendLine("}"); + // output.AppendLine("}"); + // context.AddSource($"Output_Debug_{name}.cs", SourceText.From(output.ToString(), Encoding.UTF8)); + //} + + private static List CollectRecords(GeneratorExecutionContext context, ISymbol symbol, ITypeSymbol receiverType, INamedTypeSymbol autoInterfaceAttributeSymbol, INamedTypeSymbol autoInterfaceTemplateAttributeSymbol) + { + List templateParts = new(); + Dictionary> danglingInterfaceTypesBySymbols = new(SymbolEqualityComparer.Default); - foreach (AttributeData attribute in symbol.GetAttributes()) + foreach (AttributeData attribute in symbol.GetAttributes()) + { + if (attribute.AttributeClass != null && attribute.AttributeClass.Equals(autoInterfaceTemplateAttributeSymbol, SymbolEqualityComparer.Default)) { - if (attribute.AttributeClass != null && attribute.AttributeClass.Equals(autoInterfaceTemplateAttributeSymbol, SymbolEqualityComparer.Default)) - { - ITypeSymbol? type = receiverType.WithNullableAnnotation(NullableAnnotation.NotAnnotated); + ITypeSymbol? type = receiverType.WithNullableAnnotation(NullableAnnotation.NotAnnotated); - AutoInterfaceTargets memberTargets = (AutoInterfaceTargets)Convert.ToInt32(attribute.ConstructorArguments[0].Value); + AutoInterfaceTargets memberTargets = (AutoInterfaceTargets)Convert.ToInt32(attribute.ConstructorArguments[0].Value); - if (type.TypeKind == TypeKind.Interface) + if (type.TypeKind == TypeKind.Interface) + { + if (receiverType.Equals(type, SymbolEqualityComparer.Default) || receiverType.AllInterfaces.Contains(type, SymbolEqualityComparer.Default)) { - if (receiverType.Equals(type, SymbolEqualityComparer.Default) || receiverType.AllInterfaces.Contains(type, SymbolEqualityComparer.Default)) + if (type is INamedTypeSymbol interfaceType) { - if (type is INamedTypeSymbol interfaceType) - { - string? templateBody = null; - string? templateFileName = null; - string? templateLanguage = null; - string? memberFilter = null; + string? templateBody = null; + string? templateFileName = null; + string? templateLanguage = null; + string? memberFilter = null; - #region collect named arguments [only one argument for now] + #region collect named arguments [only one argument for now] - foreach (KeyValuePair arg in attribute.NamedArguments) + foreach (KeyValuePair arg in attribute.NamedArguments) + { + switch (arg.Key) { - switch (arg.Key) - { - case "FileName": + case "FileName": + { + if (arg.Value.Value is string s) { - if (arg.Value.Value is string s) - { - templateFileName = s; - } + templateFileName = s; } - break; - case "Body": + } + break; + case "Body": + { + if (arg.Value.Value is string s) { - if (arg.Value.Value is string s) - { - templateBody = s; - } + templateBody = s; } - break; - case "Language": + } + break; + case "Language": + { + if (arg.Value.Value is string s) { - if (arg.Value.Value is string s) - { - templateLanguage = s; - } + templateLanguage = s; } - break; - case "Filter": + } + break; + case "Filter": + { + if (arg.Value.Value is string s) { - if (arg.Value.Value is string s) - { - memberFilter = s; - } + memberFilter = s; } - break; - } + } + break; } + } - #endregion + #endregion - if (templateBody != null && templateBody.Trim().Length > 0) + if (templateBody != null && templateBody.Trim().Length > 0) + { + if (templateFileName != null && templateFileName.Trim().Length > 0) { - if (templateFileName != null && templateFileName.Trim().Length > 0) - { - Helpers.ReportDiagnostic(context, "BK-AG12", nameof(AutoInterfaceResource.AG12_title), nameof(AutoInterfaceResource.AG12_message), nameof(AutoInterfaceResource.AG12_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() - ); - continue; - } + Helpers.ReportDiagnostic(context, "BK-AG12", nameof(AutoInterfaceResource.AG12_title), nameof(AutoInterfaceResource.AG12_message), nameof(AutoInterfaceResource.AG12_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() + ); + continue; + } - Regex? rxMemberFilter = null; - if (memberFilter != null && memberFilter.Length > 0) + Regex? rxMemberFilter = null; + if (memberFilter != null && memberFilter.Length > 0) + { + try { - try - { - rxMemberFilter = new Regex(memberFilter, RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); - } - catch - { - Helpers.ReportDiagnostic(context, "BK-AG15", nameof(AutoInterfaceResource.AG15_title), nameof(AutoInterfaceResource.AG15_message), nameof(AutoInterfaceResource.AG15_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - memberFilter); - continue; - } + rxMemberFilter = new Regex(memberFilter, RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); } - - templateParts.Add(new PartialTemplate(memberTargets, rxMemberFilter, new TemplateDefinition(templateLanguage ?? "scriban", templateBody.Trim()))); - if (danglingInterfaceTypesBySymbols.TryGetValue(symbol, out HashSet interfaceTypes) == false) + catch { - danglingInterfaceTypesBySymbols[symbol] = interfaceTypes = new HashSet(SymbolEqualityComparer.Default); + Helpers.ReportDiagnostic(context, "BK-AG15", nameof(AutoInterfaceResource.AG15_title), nameof(AutoInterfaceResource.AG15_message), nameof(AutoInterfaceResource.AG15_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + memberFilter); + continue; } - - interfaceTypes.Add(interfaceType); } - else if (templateFileName != null && templateFileName.Trim().Length > 0) + + templateParts.Add(new PartialTemplate(memberTargets, rxMemberFilter, new TemplateDefinition(templateLanguage ?? "scriban", templateBody.Trim()))); + if (danglingInterfaceTypesBySymbols.TryGetValue(symbol, out HashSet interfaceTypes) == false) { - string? content = null; + danglingInterfaceTypesBySymbols[symbol] = interfaceTypes = new HashSet(SymbolEqualityComparer.Default); + } - AdditionalText? file = context.AdditionalFiles.FirstOrDefault(i => i.Path.EndsWith(templateFileName)); - if (file != null) - { - content = file.GetText()?.ToString()?.Trim(); - if (content == null) - { - content = ""; - } - } - else + interfaceTypes.Add(interfaceType); + } + else if (templateFileName != null && templateFileName.Trim().Length > 0) + { + string? content = null; + + AdditionalText? file = context.AdditionalFiles.FirstOrDefault(i => i.Path.EndsWith(templateFileName)); + if (file != null) + { + content = file.GetText()?.ToString()?.Trim(); + if (content == null) { - Helpers.ReportDiagnostic(context, "BK-AG11", nameof(AutoInterfaceResource.AG11_title), nameof(AutoInterfaceResource.AG11_message), nameof(AutoInterfaceResource.AG11_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - templateFileName); - continue; + content = ""; } + } + else + { + Helpers.ReportDiagnostic(context, "BK-AG11", nameof(AutoInterfaceResource.AG11_title), nameof(AutoInterfaceResource.AG11_message), nameof(AutoInterfaceResource.AG11_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + templateFileName); + continue; + } - if (string.IsNullOrEmpty(templateLanguage)) + if (string.IsNullOrEmpty(templateLanguage)) + { + string extension = Path.GetExtension(templateFileName).ToLowerInvariant(); + if (extension.StartsWith(".")) { - string extension = Path.GetExtension(templateFileName).ToLowerInvariant(); - if (extension.StartsWith(".")) - { - extension = extension.Substring(1); - } - templateLanguage = extension; + extension = extension.Substring(1); } + templateLanguage = extension; + } - Regex? rxMemberFilter = null; - if (memberFilter != null && memberFilter.Length > 0) + Regex? rxMemberFilter = null; + if (memberFilter != null && memberFilter.Length > 0) + { + try { - try - { - rxMemberFilter = new Regex(memberFilter, RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); - } - catch - { - Helpers.ReportDiagnostic(context, "BK-AG15", nameof(AutoInterfaceResource.AG15_title), nameof(AutoInterfaceResource.AG15_message), nameof(AutoInterfaceResource.AG15_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - memberFilter); - continue; - } + rxMemberFilter = new Regex(memberFilter, RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); } - - templateParts.Add(new PartialTemplate(memberTargets, rxMemberFilter, new TemplateDefinition(templateLanguage ?? "scriban", content))); - if (danglingInterfaceTypesBySymbols.TryGetValue(symbol, out HashSet interfaceTypes) == false) + catch { - danglingInterfaceTypesBySymbols[symbol] = interfaceTypes = new HashSet(SymbolEqualityComparer.Default); + Helpers.ReportDiagnostic(context, "BK-AG15", nameof(AutoInterfaceResource.AG15_title), nameof(AutoInterfaceResource.AG15_message), nameof(AutoInterfaceResource.AG15_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + memberFilter); + continue; } - - interfaceTypes.Add(interfaceType); } - else + + templateParts.Add(new PartialTemplate(memberTargets, rxMemberFilter, new TemplateDefinition(templateLanguage ?? "scriban", content))); + if (danglingInterfaceTypesBySymbols.TryGetValue(symbol, out HashSet interfaceTypes) == false) { - Helpers.ReportDiagnostic(context, "BK-AG14", nameof(AutoInterfaceResource.AG14_title), nameof(AutoInterfaceResource.AG14_message), nameof(AutoInterfaceResource.AG14_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() - ); - continue; + danglingInterfaceTypesBySymbols[symbol] = interfaceTypes = new HashSet(SymbolEqualityComparer.Default); } + + interfaceTypes.Add(interfaceType); } else { - Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - 157834); + Helpers.ReportDiagnostic(context, "BK-AG14", nameof(AutoInterfaceResource.AG14_title), nameof(AutoInterfaceResource.AG14_message), nameof(AutoInterfaceResource.AG14_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() + ); continue; } } else { - Helpers.ReportDiagnostic(context, "BK-AG04", nameof(AutoInterfaceResource.AG04_title), nameof(AutoInterfaceResource.AG04_message), nameof(AutoInterfaceResource.AG04_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - receiverType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + 157834); continue; } } else { - Helpers.ReportDiagnostic(context, "BK-AG03", nameof(AutoInterfaceResource.AG03_title), nameof(AutoInterfaceResource.AG03_message), nameof(AutoInterfaceResource.AG03_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + Helpers.ReportDiagnostic(context, "BK-AG04", nameof(AutoInterfaceResource.AG04_title), nameof(AutoInterfaceResource.AG04_message), nameof(AutoInterfaceResource.AG04_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + receiverType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); continue; } } + else + { + Helpers.ReportDiagnostic(context, "BK-AG03", nameof(AutoInterfaceResource.AG03_title), nameof(AutoInterfaceResource.AG03_message), nameof(AutoInterfaceResource.AG03_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + continue; + } } + } - List records = new(); + List records = new(); - foreach (AttributeData attribute in symbol.GetAttributes()) + foreach (AttributeData attribute in symbol.GetAttributes()) + { + if (attribute.AttributeClass != null && attribute.AttributeClass.Equals(autoInterfaceAttributeSymbol, SymbolEqualityComparer.Default)) { - if (attribute.AttributeClass != null && attribute.AttributeClass.Equals(autoInterfaceAttributeSymbol, SymbolEqualityComparer.Default)) - { - ITypeSymbol? type = null; - bool? includeBaseInterfaces = null; + ITypeSymbol? type = null; + bool? includeBaseInterfaces = null; - if (attribute.ConstructorArguments.Length == 0) - { - type = receiverType.WithNullableAnnotation(NullableAnnotation.NotAnnotated); - } - else + if (attribute.ConstructorArguments.Length == 0) + { + type = receiverType.WithNullableAnnotation(NullableAnnotation.NotAnnotated); + } + else + { + if (attribute.ConstructorArguments[0].Value is ITypeSymbol targetType) { - if (attribute.ConstructorArguments[0].Value is ITypeSymbol targetType) - { - type = targetType; - } + type = targetType; } + } - if (type == null) - { - Helpers.ReportDiagnostic(context, "BK-AG07", nameof(AutoInterfaceResource.AG07_title), nameof(AutoInterfaceResource.AG07_message), nameof(AutoInterfaceResource.AG07_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax()); - continue; - } - else if (type.TypeKind == TypeKind.Interface) + if (type == null) + { + Helpers.ReportDiagnostic(context, "BK-AG07", nameof(AutoInterfaceResource.AG07_title), nameof(AutoInterfaceResource.AG07_message), nameof(AutoInterfaceResource.AG07_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax()); + continue; + } + else if (type.TypeKind == TypeKind.Interface) + { + if (receiverType.Equals(type, SymbolEqualityComparer.Default) || receiverType.AllInterfaces.Contains(type, SymbolEqualityComparer.Default)) { - if (receiverType.Equals(type, SymbolEqualityComparer.Default) || receiverType.AllInterfaces.Contains(type, SymbolEqualityComparer.Default)) + if (type is INamedTypeSymbol interfaceType) { - if (type is INamedTypeSymbol interfaceType) - { - string? templateBody = null; - string? templateFileName = null; - string? templateLanguage = null; + string? templateBody = null; + string? templateFileName = null; + string? templateLanguage = null; - #region collect named arguments + #region collect named arguments - foreach (KeyValuePair arg in attribute.NamedArguments) + foreach (KeyValuePair arg in attribute.NamedArguments) + { + switch (arg.Key) { - switch (arg.Key) - { - case "TemplateFileName": + case "TemplateFileName": + { + if (arg.Value.Value is string s) { - if (arg.Value.Value is string s) - { - templateFileName = s; - } + templateFileName = s; } - break; - case "TemplateBody": + } + break; + case "TemplateBody": + { + if (arg.Value.Value is string s) { - if (arg.Value.Value is string s) - { - templateBody = s; - } + templateBody = s; } - break; - case "TemplateLanguage": + } + break; + case "TemplateLanguage": + { + if (arg.Value.Value is string s) { - if (arg.Value.Value is string s) - { - templateLanguage = s; - } + templateLanguage = s; } - break; - case "IncludeBaseInterfaces": + } + break; + case "IncludeBaseInterfaces": + { + if (arg.Value.Value is bool b) { - if (arg.Value.Value is bool b) - { - includeBaseInterfaces = b; - } + includeBaseInterfaces = b; } - break; - } + } + break; } + } - #endregion + #endregion - TemplateDefinition? template = null; - if (templateBody != null && templateBody.Trim().Length > 0) + TemplateDefinition? template = null; + if (templateBody != null && templateBody.Trim().Length > 0) + { + if (templateFileName != null && templateFileName.Trim().Length > 0) { - if (templateFileName != null && templateFileName.Trim().Length > 0) - { - Helpers.ReportDiagnostic(context, "BK-AG12", nameof(AutoInterfaceResource.AG12_title), nameof(AutoInterfaceResource.AG12_message), nameof(AutoInterfaceResource.AG12_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() - ); - continue; - } - - template = new TemplateDefinition(templateLanguage ?? "scriban", templateBody.Trim()); + Helpers.ReportDiagnostic(context, "BK-AG12", nameof(AutoInterfaceResource.AG12_title), nameof(AutoInterfaceResource.AG12_message), nameof(AutoInterfaceResource.AG12_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() + ); + continue; } - else if (templateFileName != null && templateFileName.Trim().Length > 0) - { - string? content = null; - AdditionalText? file = context.AdditionalFiles.FirstOrDefault(i => i.Path.EndsWith(templateFileName)); - if (file != null) - { - content = file.GetText()?.ToString()?.Trim(); - if (content == null) - { - content = ""; - } - } - else - { - Helpers.ReportDiagnostic(context, "BK-AG11", nameof(AutoInterfaceResource.AG11_title), nameof(AutoInterfaceResource.AG11_message), nameof(AutoInterfaceResource.AG11_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - templateFileName); - continue; - } + template = new TemplateDefinition(templateLanguage ?? "scriban", templateBody.Trim()); + } + else if (templateFileName != null && templateFileName.Trim().Length > 0) + { + string? content = null; - if (string.IsNullOrEmpty(templateLanguage)) + AdditionalText? file = context.AdditionalFiles.FirstOrDefault(i => i.Path.EndsWith(templateFileName)); + if (file != null) + { + content = file.GetText()?.ToString()?.Trim(); + if (content == null) { - string extension = Path.GetExtension(templateFileName).ToLowerInvariant(); - if (extension.StartsWith(".")) - { - extension = extension.Substring(1); - } - templateLanguage = extension; + content = ""; } + } + else + { + Helpers.ReportDiagnostic(context, "BK-AG11", nameof(AutoInterfaceResource.AG11_title), nameof(AutoInterfaceResource.AG11_message), nameof(AutoInterfaceResource.AG11_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + templateFileName); + continue; + } - if (templateParts.Count > 0) + if (string.IsNullOrEmpty(templateLanguage)) + { + string extension = Path.GetExtension(templateFileName).ToLowerInvariant(); + if (extension.StartsWith(".")) { - Helpers.ReportDiagnostic(context, "BK-AG13", nameof(AutoInterfaceResource.AG13_title), nameof(AutoInterfaceResource.AG13_message), nameof(AutoInterfaceResource.AG13_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() - ); - continue; + extension = extension.Substring(1); } - - template = new TemplateDefinition(templateLanguage ?? "scriban", content); + templateLanguage = extension; } - danglingInterfaceTypesBySymbols.Remove(symbol); - records.Add(new AutoInterfaceRecord(symbol, receiverType, interfaceType, template, templateParts)); - if (includeBaseInterfaces.GetValueOrDefault(false)) + if (templateParts.Count > 0) { - foreach (INamedTypeSymbol baseInterfaceType in interfaceType.AllInterfaces) - { - records.Add(new AutoInterfaceRecord(symbol, receiverType, baseInterfaceType, template, templateParts)); - } + Helpers.ReportDiagnostic(context, "BK-AG13", nameof(AutoInterfaceResource.AG13_title), nameof(AutoInterfaceResource.AG13_message), nameof(AutoInterfaceResource.AG13_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() + ); + continue; } + + template = new TemplateDefinition(templateLanguage ?? "scriban", content); } - else + + danglingInterfaceTypesBySymbols.Remove(symbol); + records.Add(new AutoInterfaceRecord(symbol, receiverType, interfaceType, template, templateParts)); + if (includeBaseInterfaces.GetValueOrDefault(false)) { - Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - 157834); - continue; + foreach (INamedTypeSymbol baseInterfaceType in interfaceType.AllInterfaces) + { + records.Add(new AutoInterfaceRecord(symbol, receiverType, baseInterfaceType, template, templateParts)); + } } } else { - Helpers.ReportDiagnostic(context, "BK-AG04", nameof(AutoInterfaceResource.AG04_title), nameof(AutoInterfaceResource.AG04_message), nameof(AutoInterfaceResource.AG04_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - receiverType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + 157834); continue; } } else { - Helpers.ReportDiagnostic(context, "BK-AG03", nameof(AutoInterfaceResource.AG03_title), nameof(AutoInterfaceResource.AG03_message), nameof(AutoInterfaceResource.AG03_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), - type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + Helpers.ReportDiagnostic(context, "BK-AG04", nameof(AutoInterfaceResource.AG04_title), nameof(AutoInterfaceResource.AG04_message), nameof(AutoInterfaceResource.AG04_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + receiverType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); continue; } } - } - - foreach (KeyValuePair> danglingInterfaceTypes in danglingInterfaceTypesBySymbols) - { - foreach (INamedTypeSymbol interfaceType in danglingInterfaceTypes.Value) + else { - records.Add(new AutoInterfaceRecord(danglingInterfaceTypes.Key, receiverType, interfaceType, null, templateParts)); + Helpers.ReportDiagnostic(context, "BK-AG03", nameof(AutoInterfaceResource.AG03_title), nameof(AutoInterfaceResource.AG03_message), nameof(AutoInterfaceResource.AG03_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), + type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); + continue; } } - - return records; } - private static string? ProcessClass(GeneratorExecutionContext context, Compilation compilation, INamedTypeSymbol type, IEnumerable infos) + foreach (KeyValuePair> danglingInterfaceTypes in danglingInterfaceTypesBySymbols) { - ScopeInfo scope = new(type); + foreach (INamedTypeSymbol interfaceType in danglingInterfaceTypes.Value) + { + records.Add(new AutoInterfaceRecord(danglingInterfaceTypes.Key, receiverType, interfaceType, null, templateParts)); + } + } - SourceBuilder builder = new(); + return records; + } - ICodeTextWriter writer = new CSharpCodeTextWriter(context, compilation); - bool anyReasonToEmitSourceFile = false; - bool error = false; + private static string? ProcessClass(GeneratorExecutionContext context, Compilation compilation, INamedTypeSymbol type, IEnumerable infos) + { + ScopeInfo scope = new(type); - //bool isNullable = compilation.Options.NullableContextOptions == NullableContextOptions.Enable; - builder.AppendLine("#nullable enable"); - builder.AppendLine(); - writer.WriteNamespaceBeginning(builder, type.ContainingNamespace); + SourceBuilder builder = new(); - List containingTypes = new(); - for (INamedTypeSymbol? ct = type.ContainingType; ct != null; ct = ct.ContainingType) - { - containingTypes.Insert(0, ct); - } + ICodeTextWriter writer = new CSharpCodeTextWriter(context, compilation); + bool anyReasonToEmitSourceFile = false; + bool error = false; - foreach (INamedTypeSymbol ct in containingTypes) - { - builder.AppendIndentation(); - writer.WriteTypeDeclarationBeginning(builder, ct, new ScopeInfo(ct)); - builder.AppendLine(); - builder.AppendIndentation(); - builder.AppendLine('{'); - builder.IncrementIndentation(); - } + //bool isNullable = compilation.Options.NullableContextOptions == NullableContextOptions.Enable; + builder.AppendLine("#nullable enable"); + builder.AppendLine(); + writer.WriteNamespaceBeginning(builder, type.ContainingNamespace); + + List containingTypes = new(); + for (INamedTypeSymbol? ct = type.ContainingType; ct != null; ct = ct.ContainingType) + { + containingTypes.Insert(0, ct); + } + foreach (INamedTypeSymbol ct in containingTypes) + { builder.AppendIndentation(); - writer.WriteTypeDeclarationBeginning(builder, type, scope); - { - bool first = true; - foreach (INamedTypeSymbol missingInterfaceType in infos.Select(i => i.InterfaceType).Where(i => type.AllInterfaces.Contains(i, SymbolEqualityComparer.Default) == false).ToHashSet()) - { - builder.Append(first ? " : " : ", "); - first = false; - writer.WriteTypeReference(builder, missingInterfaceType, scope); - } - } + writer.WriteTypeDeclarationBeginning(builder, ct, new ScopeInfo(ct)); builder.AppendLine(); builder.AppendIndentation(); builder.AppendLine('{'); builder.IncrementIndentation(); + } + + builder.AppendIndentation(); + writer.WriteTypeDeclarationBeginning(builder, type, scope); + { + bool first = true; + foreach (INamedTypeSymbol missingInterfaceType in infos.Select(i => i.InterfaceType).Where(i => type.AllInterfaces.Contains(i, SymbolEqualityComparer.Default) == false).ToHashSet()) + { + builder.Append(first ? " : " : ", "); + first = false; + writer.WriteTypeReference(builder, missingInterfaceType, scope); + } + } + builder.AppendLine(); + builder.AppendIndentation(); + builder.AppendLine('{'); + builder.IncrementIndentation(); - bool separatorRequired = false; + bool separatorRequired = false; - foreach (IGrouping group in infos.GroupBy(i => i.InterfaceType)) + foreach (IGrouping group in infos.GroupBy(i => i.InterfaceType, SymbolEqualityComparer.Default)) + { + ISourceTextGenerator? generator = null; + foreach (IMemberInfo reference in group) { - ISourceTextGenerator? generator = null; - foreach (IMemberInfo reference in group) + if (reference.Template is TemplateDefinition td) { - if (reference.Template is TemplateDefinition td) + if (generator is TemplatedSourceTextGenerator g) { - if (generator is TemplatedSourceTextGenerator g) + if (g.Template.Equals(td) == false) { - if (g.Template.Equals(td) == false) - { - error = true; - Helpers.ReportDiagnostic(context, "BK-AG10", nameof(AutoInterfaceResource.AG10_title), nameof(AutoInterfaceResource.AG10_message), nameof(AutoInterfaceResource.AG10_description), DiagnosticSeverity.Error, reference.Member); - continue; - } - } - else - { - generator = new TemplatedSourceTextGenerator(td); + error = true; + Helpers.ReportDiagnostic(context, "BK-AG10", nameof(AutoInterfaceResource.AG10_title), nameof(AutoInterfaceResource.AG10_message), nameof(AutoInterfaceResource.AG10_description), DiagnosticSeverity.Error, reference.Member); + continue; } } + else + { + generator = new TemplatedSourceTextGenerator(td); + } } + } - INamedTypeSymbol @interface = group.Key; - List references = group.DistinctBy(i => i.Member).ToList(); + INamedTypeSymbol @interface = group.Key; + List references = group.DistinctBy(i => i.Member).ToList(); - if (generator != null) - { - StandaloneModel model = new(); + if (generator != null) + { + StandaloneModel model = new(); - model.Load(writer, builder, @interface, scope, references); + model.Load(writer, builder, @interface, scope, references); - MethodModel CreateMethod(IMethodSymbol method) - { - MethodModel m = new(); - m.Load(writer, builder, method, scope, references); - return m; - } + MethodModel CreateMethod(IMethodSymbol method) + { + MethodModel m = new(); + m.Load(writer, builder, method, scope, references); + return m; + } - PropertyModel CreateProperty(IPropertySymbol property) - { - PropertyModel m = new(); - m.Load(writer, builder, property, scope, references); - return m; - } + PropertyModel CreateProperty(IPropertySymbol property) + { + PropertyModel m = new(); + m.Load(writer, builder, property, scope, references); + return m; + } - IndexerModel CreateIndexer(IPropertySymbol indexer) - { - IndexerModel m = new(); - m.Load(writer, builder, indexer, scope, references); - return m; - } + IndexerModel CreateIndexer(IPropertySymbol indexer) + { + IndexerModel m = new(); + m.Load(writer, builder, indexer, scope, references); + return m; + } - EventModel CreateEvent(IEventSymbol @event) - { - EventModel m = new(); - m.Load(writer, builder, @event, scope, references); - return m; - } + EventModel CreateEvent(IEventSymbol @event) + { + EventModel m = new(); + m.Load(writer, builder, @event, scope, references); + return m; + } + + model.Methods.AddRange(@interface.GetMethods().Where(i => type.IsMemberImplemented(i) == false).Select(CreateMethod)); + model.Properties.AddRange(@interface.GetProperties().Where(i => type.IsMemberImplemented(i) == false).Select(CreateProperty)); + model.Indexers.AddRange(@interface.GetIndexers().Where(i => type.IsMemberImplemented(i) == false).Select(CreateIndexer)); + model.Events.AddRange(@interface.GetEvents().Where(i => type.IsMemberImplemented(i) == false).Select(CreateEvent)); - model.Methods.AddRange(@interface.GetMethods().Where(i => type.IsMemberImplemented(i) == false).Select(CreateMethod)); - model.Properties.AddRange(@interface.GetProperties().Where(i => type.IsMemberImplemented(i) == false).Select(CreateProperty)); - model.Indexers.AddRange(@interface.GetIndexers().Where(i => type.IsMemberImplemented(i) == false).Select(CreateIndexer)); - model.Events.AddRange(@interface.GetEvents().Where(i => type.IsMemberImplemented(i) == false).Select(CreateEvent)); + generator.Emit(writer, builder, model, ref separatorRequired); + anyReasonToEmitSourceFile = true; - generator.Emit(writer, builder, model, ref separatorRequired); + if (separatorRequired) + { + builder.AppendLine(); + separatorRequired = false; + } + } + else + { + foreach (IMethodSymbol method in @interface.GetMethods().Where(i => type.IsMemberImplemented(i) == false)) + { anyReasonToEmitSourceFile = true; if (separatorRequired) { builder.AppendLine(); - separatorRequired = false; } + writer.WriteMethodDefinition(builder, method, scope, @interface, references); + separatorRequired = true; } - else - { - foreach (IMethodSymbol method in @interface.GetMethods().Where(i => type.IsMemberImplemented(i) == false)) - { - anyReasonToEmitSourceFile = true; - if (separatorRequired) - { - builder.AppendLine(); - } - writer.WriteMethodDefinition(builder, method, scope, @interface, references); - separatorRequired = true; - } + foreach (IPropertySymbol property in @interface.GetProperties().Where(i => type.IsMemberImplemented(i) == false)) + { + anyReasonToEmitSourceFile = true; - foreach (IPropertySymbol property in @interface.GetProperties().Where(i => type.IsMemberImplemented(i) == false)) + if (separatorRequired) { - anyReasonToEmitSourceFile = true; - - if (separatorRequired) - { - builder.AppendLine(); - } - - writer.WritePropertyDefinition(builder, property, scope, @interface, references); - separatorRequired = true; + builder.AppendLine(); } - foreach (IPropertySymbol indexer in @interface.GetIndexers().Where(i => type.IsMemberImplemented(i) == false)) - { - anyReasonToEmitSourceFile = true; + writer.WritePropertyDefinition(builder, property, scope, @interface, references); + separatorRequired = true; + } - if (separatorRequired) - { - builder.AppendLine(); - } + foreach (IPropertySymbol indexer in @interface.GetIndexers().Where(i => type.IsMemberImplemented(i) == false)) + { + anyReasonToEmitSourceFile = true; - writer.WritePropertyDefinition(builder, indexer, scope, @interface, references); - separatorRequired = true; + if (separatorRequired) + { + builder.AppendLine(); } - foreach (IEventSymbol @event in @interface.GetEvents().Where(i => type.IsMemberImplemented(i) == false)) - { - anyReasonToEmitSourceFile = true; + writer.WritePropertyDefinition(builder, indexer, scope, @interface, references); + separatorRequired = true; + } - if (separatorRequired) - { - builder.AppendLine(); - } + foreach (IEventSymbol @event in @interface.GetEvents().Where(i => type.IsMemberImplemented(i) == false)) + { + anyReasonToEmitSourceFile = true; - writer.WriteEventDefinition(builder, @event, scope, @interface, references); - separatorRequired = true; + if (separatorRequired) + { + builder.AppendLine(); } + + writer.WriteEventDefinition(builder, @event, scope, @interface, references); + separatorRequired = true; } } + } + + builder.DecrementIndentation(); + builder.AppendIndentation(); + builder.AppendLine('}'); + for (int i = 0; i < containingTypes.Count; i++) + { builder.DecrementIndentation(); builder.AppendIndentation(); builder.AppendLine('}'); + } - for (int i = 0; i < containingTypes.Count; i++) - { - builder.DecrementIndentation(); - builder.AppendIndentation(); - builder.AppendLine('}'); - } + if (type.ContainingNamespace != null && type.ContainingNamespace.ConstituentNamespaces.Length > 0) + { + builder.DecrementIndentation(); + builder.AppendIndentation(); + builder.AppendLine('}'); + } - if (type.ContainingNamespace != null && type.ContainingNamespace.ConstituentNamespaces.Length > 0) - { - builder.DecrementIndentation(); - builder.AppendIndentation(); - builder.AppendLine('}'); - } + return error == false && anyReasonToEmitSourceFile ? builder.ToString() : null; + } - return error == false && anyReasonToEmitSourceFile ? builder.ToString() : null; - } + /// + /// Created on demand before each generation pass + /// + private class SyntaxReceiver : ISyntaxReceiver + { + public List Candidates { get; } = new(); /// - /// Created on demand before each generation pass + /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation /// - private class SyntaxReceiver : ISyntaxReceiver + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { - public List Candidates { get; } = new(); - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + if (syntaxNode is MemberDeclarationSyntax memberDeclarationSyntax && memberDeclarationSyntax.AttributeLists.Count > 0) { - if (syntaxNode is MemberDeclarationSyntax memberDeclarationSyntax && memberDeclarationSyntax.AttributeLists.Count > 0) + if (memberDeclarationSyntax.Parent is TypeDeclarationSyntax) { - if (memberDeclarationSyntax.Parent is TypeDeclarationSyntax) + // any field or property with at least one attribute is a candidate for source generation + if (memberDeclarationSyntax is FieldDeclarationSyntax || memberDeclarationSyntax is PropertyDeclarationSyntax) { - // any field or property with at least one attribute is a candidate for source generation - if (memberDeclarationSyntax is FieldDeclarationSyntax || memberDeclarationSyntax is PropertyDeclarationSyntax) - { - this.Candidates.Add(memberDeclarationSyntax); - } + this.Candidates.Add(memberDeclarationSyntax); } } } } } -} \ No newline at end of file +} diff --git a/BeaKona.AutoInterfaceGenerator/AutoInterfaceTargets.cs b/BeaKona.AutoInterfaceGenerator/AutoInterfaceTargets.cs deleted file mode 100644 index c41e8c0..0000000 --- a/BeaKona.AutoInterfaceGenerator/AutoInterfaceTargets.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace BeaKona.AutoInterfaceGenerator -{ - //keep this synchronized with injected code - [Flags] - internal enum AutoInterfaceTargets : byte - { - Method = 0x01, - PropertyGetter = 0x02, - PropertySetter = 0x04, - IndexerGetter = 0x08, - IndexerSetter = 0x10, - EventAdder = 0x20, - EventRemover = 0x40, - Property = PropertyGetter | PropertySetter, - Indexer = IndexerGetter | IndexerSetter, - Event = EventAdder | EventRemover, - Getter = PropertyGetter | IndexerGetter, - Setter = PropertySetter | IndexerSetter, - All = Method | Property | Indexer | Event, - } -} diff --git a/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj b/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj index 9c8d077..05d9037 100644 --- a/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj +++ b/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj @@ -22,15 +22,15 @@ - - + + - + - + @@ -50,10 +50,10 @@ - - - - + + + + diff --git a/BeaKona.AutoInterfaceGenerator/CSharpCodeTextWriter.cs b/BeaKona.AutoInterfaceGenerator/CSharpCodeTextWriter.cs index d13858f..ab19b2f 100644 --- a/BeaKona.AutoInterfaceGenerator/CSharpCodeTextWriter.cs +++ b/BeaKona.AutoInterfaceGenerator/CSharpCodeTextWriter.cs @@ -1,368 +1,343 @@ using BeaKona.AutoInterfaceGenerator.Templates; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Linq; -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +internal sealed class CSharpCodeTextWriter : ICodeTextWriter { - internal sealed class CSharpCodeTextWriter : ICodeTextWriter + public CSharpCodeTextWriter(GeneratorExecutionContext context, Compilation compilation) { - public CSharpCodeTextWriter(GeneratorExecutionContext context, Compilation compilation) - { - this.Context = context; - this.Compilation = compilation; - } + this.Context = context; + this.Compilation = compilation; + } - public GeneratorExecutionContext Context { get; } - public Compilation Compilation { get; } + public GeneratorExecutionContext Context { get; } + public Compilation Compilation { get; } - public void WriteTypeReference(SourceBuilder builder, ITypeSymbol type, ScopeInfo scope) + public void WriteTypeReference(SourceBuilder builder, ITypeSymbol type, ScopeInfo scope) + { + if (scope.TryGetAlias(type, out string? typeName)) { - if (scope.TryGetAlias(type, out string? typeName)) + if (typeName != null) { - if (typeName != null) + builder.Append(typeName); + } + } + else + { + bool processed = false; + if (type.SpecialType != SpecialType.None) + { + processed = true; + switch (type.SpecialType) { - builder.Append(typeName); + default: processed = false; break; + case SpecialType.System_Object: builder.Append("object"); break; + case SpecialType.System_Void: builder.Append("void"); break; + case SpecialType.System_Boolean: builder.Append("bool"); break; + case SpecialType.System_Char: builder.Append("char"); break; + case SpecialType.System_SByte: builder.Append("sbyte"); break; + case SpecialType.System_Byte: builder.Append("byte"); break; + case SpecialType.System_Int16: builder.Append("short"); break; + case SpecialType.System_UInt16: builder.Append("ushort"); break; + case SpecialType.System_Int32: builder.Append("int"); break; + case SpecialType.System_UInt32: builder.Append("uint"); break; + case SpecialType.System_Int64: builder.Append("long"); break; + case SpecialType.System_UInt64: builder.Append("ulong"); break; + case SpecialType.System_Decimal: builder.Append("decimal"); break; + case SpecialType.System_Single: builder.Append("float"); break; + case SpecialType.System_Double: builder.Append("double"); break; + //case SpecialType.System_Half: builder.Append("half"); break; + case SpecialType.System_String: builder.Append("string"); break; } } - else + + if (processed == false) { - bool processed = false; - if (type.SpecialType != SpecialType.None) + if (type is IArrayTypeSymbol array) { - processed = true; - switch (type.SpecialType) + this.WriteTypeReference(builder, array.ElementType, scope); + builder.Append('['); + for (int i = 1; i < array.Rank; i++) { - default: processed = false; break; - case SpecialType.System_Object: builder.Append("object"); break; - case SpecialType.System_Void: builder.Append("void"); break; - case SpecialType.System_Boolean: builder.Append("bool"); break; - case SpecialType.System_Char: builder.Append("char"); break; - case SpecialType.System_SByte: builder.Append("sbyte"); break; - case SpecialType.System_Byte: builder.Append("byte"); break; - case SpecialType.System_Int16: builder.Append("short"); break; - case SpecialType.System_UInt16: builder.Append("ushort"); break; - case SpecialType.System_Int32: builder.Append("int"); break; - case SpecialType.System_UInt32: builder.Append("uint"); break; - case SpecialType.System_Int64: builder.Append("long"); break; - case SpecialType.System_UInt64: builder.Append("ulong"); break; - case SpecialType.System_Decimal: builder.Append("decimal"); break; - case SpecialType.System_Single: builder.Append("float"); break; - case SpecialType.System_Double: builder.Append("double"); break; - //case SpecialType.System_Half: builder.Append("half"); break; - case SpecialType.System_String: builder.Append("string"); break; + builder.Append(','); } + builder.Append(']'); } - - if (processed == false) + else { - if (type is IArrayTypeSymbol array) + static bool IsTupleWithAliases(INamedTypeSymbol tuple) + { + return tuple.TupleElements.Any(i => i.CorrespondingTupleField != null && i.Equals(i.CorrespondingTupleField, SymbolEqualityComparer.Default) == false); + } + + if (type.IsTupleType && type is INamedTypeSymbol tupleType && IsTupleWithAliases(tupleType)) { - this.WriteTypeReference(builder, array.ElementType, scope); - builder.Append('['); - for (int i = 1; i < array.Rank; i++) + builder.Append('('); + bool first = true; + foreach (IFieldSymbol field in tupleType.TupleElements) { - builder.Append(','); + if (first) + { + first = false; + } + else + { + builder.Append(", "); + } + this.WriteTypeReference(builder, field.Type, scope); + builder.Append(' '); + this.WriteIdentifier(builder, field); } - builder.Append(']'); + builder.Append(')'); + } + else if (type is INamedTypeSymbol nt && SemanticFacts.IsNullableT(this.Compilation, nt)) + { + this.WriteTypeReference(builder, nt.TypeArguments[0], scope); } else { - static bool IsTupleWithAliases(INamedTypeSymbol tuple) - { - return tuple.TupleElements.Any(i => i.CorrespondingTupleField != null && i.Equals(i.CorrespondingTupleField, SymbolEqualityComparer.Default) == false); - } - - if (type.IsTupleType && type is INamedTypeSymbol tupleType && IsTupleWithAliases(tupleType)) + if (type is ITypeParameterSymbol == false) { - builder.Append('('); - bool first = true; - foreach (IFieldSymbol field in tupleType.TupleElements) + if (type.Equals(scope.Type, SymbolEqualityComparer.Default) == false) { - if (first) + string? alias = SemanticFacts.ResolveAssemblyAlias(this.Compilation, type.ContainingAssembly); + ISymbol[] symbols; + if (alias == null) { - first = false; + symbols = SemanticFacts.GetRelativeSymbols(type, scope.Type); } else { - builder.Append(", "); + symbols = SemanticFacts.GetContainingSymbols(type, false); + builder.Append(alias); + builder.Append("::"); + builder.RegisterAlias(alias); } - this.WriteTypeReference(builder, field.Type, scope); - builder.Append(' '); - this.WriteIdentifier(builder, field); - } - builder.Append(')'); - } - else if (type is INamedTypeSymbol nt && SemanticFacts.IsNullableT(this.Compilation, nt)) - { - this.WriteTypeReference(builder, nt.TypeArguments[0], scope); - } - else - { - if (type is ITypeParameterSymbol == false) - { - if (type.Equals(scope.Type, SymbolEqualityComparer.Default) == false) + + foreach (ISymbol symbol in symbols) { - string? alias = SemanticFacts.ResolveAssemblyAlias(this.Compilation, type.ContainingAssembly); - ISymbol[] symbols; - if (alias == null) - { - symbols = SemanticFacts.GetRelativeSymbols(type, scope.Type); - } - else - { - symbols = SemanticFacts.GetContainingSymbols(type, false); - builder.Append(alias); - builder.Append("::"); - builder.RegisterAlias(alias); - } + this.WriteIdentifier(builder, symbol); - foreach (ISymbol symbol in symbols) + if (symbol is INamedTypeSymbol snt && snt.IsGenericType) { - this.WriteIdentifier(builder, symbol); - - if (symbol is INamedTypeSymbol snt && snt.IsGenericType) - { - builder.Append('<'); - this.WriteTypeArgumentsDefinition(builder, snt.TypeArguments, scope); - builder.Append('>'); - } - - builder.Append('.'); + builder.Append('<'); + this.WriteTypeArgumentsDefinition(builder, snt.TypeArguments, scope); + builder.Append('>'); } + + builder.Append('.'); } } + } - this.WriteIdentifier(builder, type); + this.WriteIdentifier(builder, type); + { + if (type is INamedTypeSymbol tnt && tnt.IsGenericType) { - if (type is INamedTypeSymbol tnt && tnt.IsGenericType) - { - builder.Append('<'); - this.WriteTypeArgumentsDefinition(builder, tnt.TypeArguments, scope); - builder.Append('>'); - } + builder.Append('<'); + this.WriteTypeArgumentsDefinition(builder, tnt.TypeArguments, scope); + builder.Append('>'); } } } } } + } - if (type.NullableAnnotation == NullableAnnotation.Annotated) - { - builder.Append('?'); - } + if (type.NullableAnnotation == NullableAnnotation.Annotated) + { + builder.Append('?'); } + } - public void WriteTypeArgumentsCall(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope) + public void WriteTypeArgumentsCall(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope) + { + bool first = true; + foreach (ITypeSymbol t in typeArguments) { - bool first = true; - foreach (ITypeSymbol t in typeArguments) + if (first) { - if (first) - { - first = false; - } - else - { - builder.Append(", "); - } + first = false; + } + else + { + builder.Append(", "); + } - if (scope.TryGetAlias(t, out string? alias)) - { - if (alias != null) - { - builder.Append(alias); - } - } - else + if (scope.TryGetAlias(t, out string? alias)) + { + if (alias != null) { - this.WriteIdentifier(builder, t); + builder.Append(alias); } } + else + { + this.WriteIdentifier(builder, t); + } } + } - public void WriteTypeArgumentsDefinition(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope) + public void WriteTypeArgumentsDefinition(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope) + { + bool first = true; + foreach (ITypeSymbol t in typeArguments) { - bool first = true; - foreach (ITypeSymbol t in typeArguments) + if (first) { - if (first) - { - first = false; - } - else - { - builder.Append(", "); - } - this.WriteTypeReference(builder, t, scope); + first = false; } + else + { + builder.Append(", "); + } + this.WriteTypeReference(builder, t, scope); } + } - public void WriteParameterDefinition(SourceBuilder builder, ScopeInfo scope, IEnumerable parameters) + public void WriteParameterDefinition(SourceBuilder builder, ScopeInfo scope, IEnumerable parameters) + { + bool first = true; + foreach (IParameterSymbol parameter in parameters) { - bool first = true; - foreach (IParameterSymbol parameter in parameters) + if (first) { - if (first) - { - first = false; - } - else - { - builder.Append(", "); - } - - if (parameter.IsParams) - { - builder.Append("params"); - builder.Append(' '); - } - else - { - this.WriteRefKind(builder, parameter.RefKind); - builder.AppendSpaceIfNeccessary(); - } + first = false; + } + else + { + builder.Append(", "); + } - this.WriteTypeReference(builder, parameter.Type, scope); + if (parameter.IsParams) + { + builder.Append("params"); builder.Append(' '); - this.WriteIdentifier(builder, parameter); - //if (parameter.HasExplicitDefaultValue) - //{ - // builder.Append(" = "); - // builder.Append(parameter.ExplicitDefaultValue ?? "default"); - //} } - } - - public void WriteCallParameters(SourceBuilder builder, IEnumerable parameters) - { - bool first = true; - foreach (IParameterSymbol parameter in parameters) + else { - if (first) - { - first = false; - } - else - { - builder.Append(", "); - } this.WriteRefKind(builder, parameter.RefKind); builder.AppendSpaceIfNeccessary(); - this.WriteIdentifier(builder, parameter); } + + this.WriteTypeReference(builder, parameter.Type, scope); + builder.Append(' '); + this.WriteIdentifier(builder, parameter); + //if (parameter.HasExplicitDefaultValue) + //{ + // builder.Append(" = "); + // builder.Append(parameter.ExplicitDefaultValue ?? "default"); + //} } + } - public void WriteMethodDefinition(SourceBuilder builder, IMethodSymbol method, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references) + public void WriteCallParameters(SourceBuilder builder, IEnumerable parameters) + { + bool first = true; + foreach (IParameterSymbol parameter in parameters) { - ScopeInfo methodScope = new(scope); - - if (method.IsGenericMethod) + if (first) { - methodScope.CreateAliases(method.TypeArguments); + first = false; } + else + { + builder.Append(", "); + } + this.WriteRefKind(builder, parameter.RefKind); + builder.AppendSpaceIfNeccessary(); + this.WriteIdentifier(builder, parameter); + } + } - (bool isAsync, bool methodReturnsValue) = SemanticFacts.IsAsyncAndGetReturnType(this.Compilation, method); + public void WriteMethodDefinition(SourceBuilder builder, IMethodSymbol method, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references) + { + ScopeInfo methodScope = new(scope); - PartialTemplate? template = this.GetMatchedTemplates(references, AutoInterfaceTargets.Method, method.Name); + if (method.IsGenericMethod) + { + methodScope.CreateAliases(method.TypeArguments); + } - int rcount = references.Count(); - bool canUseAsync = template != null || rcount > 1; - bool returnsValue = (isAsync && methodReturnsValue == false) ? canUseAsync == false : methodReturnsValue; + (bool isAsync, bool methodReturnsValue) = SemanticFacts.IsAsyncAndGetReturnType(this.Compilation, method); - builder.AppendIndentation(); - if (isAsync && canUseAsync && (template != null || rcount > 1)) - { - builder.Append("async"); - builder.Append(' '); - } - this.WriteTypeReference(builder, method.ReturnType, methodScope); + PartialTemplate? template = this.GetMatchedTemplates(references, AutoInterfaceTargets.Method, method.Name); + + int rcount = references.Count(); + bool canUseAsync = template != null || rcount > 1; + bool returnsValue = (isAsync && methodReturnsValue == false) ? canUseAsync == false : methodReturnsValue; + + builder.AppendIndentation(); + if (isAsync && canUseAsync && (template != null || rcount > 1)) + { + builder.Append("async"); builder.Append(' '); - this.WriteTypeReference(builder, @interface, scope); - builder.Append('.'); - this.WriteIdentifier(builder, method); - if (method.IsGenericMethod) - { - builder.Append('<'); - this.WriteTypeArgumentsCall(builder, method.TypeArguments, methodScope); - builder.Append('>'); - } - builder.Append('('); - this.WriteParameterDefinition(builder, methodScope, method.Parameters); - builder.Append(")"); + } + this.WriteTypeReference(builder, method.ReturnType, methodScope); + builder.Append(' '); + this.WriteTypeReference(builder, @interface, scope); + builder.Append('.'); + this.WriteIdentifier(builder, method); + if (method.IsGenericMethod) + { + builder.Append('<'); + this.WriteTypeArgumentsCall(builder, method.TypeArguments, methodScope); + builder.Append('>'); + } + builder.Append('('); + this.WriteParameterDefinition(builder, methodScope, method.Parameters); + builder.Append(")"); - if (rcount == 1 && template == null) - { - builder.Append(" => "); - this.WriteMethodCall(builder, references.First(), method, methodScope, false, SemanticFacts.IsNullable(this.Compilation, method.ReturnType), true); - builder.AppendLine(';'); - } - else + if (rcount == 1 && template == null) + { + builder.Append(" => "); + this.WriteMethodCall(builder, references.First(), method, methodScope, false, SemanticFacts.IsNullable(this.Compilation, method.ReturnType), true); + builder.AppendLine(';'); + } + else + { + builder.AppendLine(); + builder.AppendIndentation(); + builder.AppendLine('{'); + builder.IncrementIndentation(); + try { - builder.AppendLine(); - builder.AppendIndentation(); - builder.AppendLine('{'); - builder.IncrementIndentation(); - try + if (template != null) { - if (template != null) - { - TemplatedSourceTextGenerator generator = new(template.Template); + TemplatedSourceTextGenerator generator = new(template.Template); - PartialMethodModel model = new(); - model.Load(this, builder, @interface, scope, references); - model.Load(this, builder, method, methodScope, references); + PartialMethodModel model = new(); + model.Load(this, builder, @interface, scope, references); + model.Load(this, builder, method, methodScope, references); - bool separatorRequired = false; - generator.Emit(this, builder, model, ref separatorRequired); - if (separatorRequired) - { - builder.AppendLine(); - } + bool separatorRequired = false; + generator.Emit(this, builder, model, ref separatorRequired); + if (separatorRequired) + { + builder.AppendLine(); } - else + } + else + { + if (isAsync && canUseAsync) { - if (isAsync && canUseAsync) { + int index = 0; + foreach (IMemberInfo reference in references) { - int index = 0; - foreach (IMemberInfo reference in references) - { - builder.AppendIndentation(); - builder.Append("var temp"); - builder.Append(index); - builder.Append(" = "); - this.WriteMethodCall(builder, reference, method, methodScope, false, false, false); - builder.Append(".ConfigureAwait(false)"); - builder.AppendLine(';'); - index++; - } - } - { - int index = 0; - foreach (IMemberInfo reference in references) - { - bool last = index + 1 == rcount; - - builder.AppendIndentation(); - if (returnsValue && last) - { - builder.Append("return"); - builder.Append(' '); - } - - builder.Append("await temp"); - builder.Append(index); - builder.AppendLine(';'); - index++; - } + builder.AppendIndentation(); + builder.Append("var temp"); + builder.Append(index); + builder.Append(" = "); + this.WriteMethodCall(builder, reference, method, methodScope, false, false, false); + builder.Append(".ConfigureAwait(false)"); + builder.AppendLine(';'); + index++; } } - else { int index = 0; foreach (IMemberInfo reference in references) @@ -376,238 +351,131 @@ public void WriteMethodDefinition(SourceBuilder builder, IMethodSymbol method, S builder.Append(' '); } - this.WriteMethodCall(builder, reference, method, methodScope, false, SemanticFacts.IsNullable(this.Compilation, method.ReturnType), true); + builder.Append("await temp"); + builder.Append(index); builder.AppendLine(';'); index++; } } } - } - finally - { - builder.DecrementIndentation(); - } - builder.AppendIndentation(); - builder.AppendLine('}'); - } - } - - public void WritePropertyDefinition(SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references) - { - AutoInterfaceTargets getterTarget, setterTarget; - if (property.IsIndexer) - { - getterTarget = AutoInterfaceTargets.IndexerGetter; - setterTarget = AutoInterfaceTargets.IndexerSetter; - } - else - { - getterTarget = AutoInterfaceTargets.PropertyGetter; - setterTarget = AutoInterfaceTargets.PropertySetter; - } - - PartialTemplate? getterTemplate = this.GetMatchedTemplates(references, getterTarget, property.IsIndexer ? "this" : property.Name); - PartialTemplate? setterTemplate = this.GetMatchedTemplates(references, setterTarget, property.IsIndexer ? "this" : property.Name); - - builder.AppendIndentation(); - this.WriteTypeReference(builder, property.Type, scope); - builder.Append(' '); - this.WriteTypeReference(builder, @interface, scope); - builder.Append('.'); - - if (property.IsIndexer) - { - builder.Append("this["); - this.WriteParameterDefinition(builder, scope, property.Parameters); - builder.Append(']'); - } - else - { - this.WriteIdentifier(builder, property); - } - - if (property.SetMethod == null && getterTemplate == null) - { - builder.Append(" => "); - this.WritePropertyCall(builder, references.First(), property, scope, SemanticFacts.IsNullable(this.Compilation, property.Type), true); - builder.AppendLine(';'); - } - else - { - builder.AppendLine(); - builder.AppendIndentation(); - builder.AppendLine('{'); - builder.IncrementIndentation(); - try - { - if (references.Count() == 1 && getterTemplate == null && setterTemplate == null) - { - IMemberInfo reference = references.First(); - - if (property.GetMethod is not null) - { - builder.AppendIndentation(); - builder.Append("get => "); - this.WritePropertyCall(builder, reference, property, scope, SemanticFacts.IsNullable(this.Compilation, property.Type), true); - builder.AppendLine(';'); - } - if (property.SetMethod is not null) - { - builder.AppendIndentation(); - builder.Append("set => "); - this.WritePropertyCall(builder, reference, property, scope, false, false); - builder.AppendLine(" = value;"); - } - } else { - if (property.GetMethod is not null) + int index = 0; + foreach (IMemberInfo reference in references) { - builder.AppendIndentation(); - if (getterTemplate != null) - { - builder.AppendLine("get"); - builder.AppendIndentation(); - builder.AppendLine('{'); - builder.IncrementIndentation(); - try - { - TemplatedSourceTextGenerator generator = new(getterTemplate.Template); + bool last = index + 1 == rcount; - IPropertyModel model = property.IsIndexer ? new PartialIndexerModel() : (IPropertyModel)new PartialPropertyModel(); - if (model is IRootModel rootModel) - { - rootModel.Load(this, builder, @interface, scope, references); - } - model.Load(this, builder, property, scope, references); - - bool separatorRequired = false; - generator.Emit(this, builder, model, ref separatorRequired); - if (separatorRequired) - { - builder.AppendLine(); - } - } - finally - { - builder.DecrementIndentation(); - } - builder.AppendIndentation(); - builder.AppendLine('}'); - } - else - { - builder.Append("get => "); - this.WritePropertyCall(builder, references.Last(), property, scope, SemanticFacts.IsNullable(this.Compilation, property.Type), true); - builder.AppendLine(';'); - } - } - if (property.SetMethod is not null) - { - builder.AppendIndentation(); - builder.AppendLine("set"); builder.AppendIndentation(); - builder.AppendLine('{'); - builder.IncrementIndentation(); - try - { - if (setterTemplate != null) - { - TemplatedSourceTextGenerator generator = new(setterTemplate.Template); - IPropertyModel model = property.IsIndexer ? new PartialIndexerModel() : (IPropertyModel)new PartialPropertyModel(); - if (model is IRootModel rootModel) - { - rootModel.Load(this, builder, @interface, scope, references); - } - model.Load(this, builder, property, scope, references); - - bool separatorRequired = false; - generator.Emit(this, builder, model, ref separatorRequired); - if (separatorRequired) - { - builder.AppendLine(); - } - } - else - { - foreach (IMemberInfo reference in references) - { - builder.AppendIndentation(); - this.WritePropertyCall(builder, reference, property, scope, false, false); - builder.AppendLine(" = value;"); - } - } - } - finally + if (returnsValue && last) { - builder.DecrementIndentation(); + builder.Append("return"); + builder.Append(' '); } - builder.AppendIndentation(); - builder.AppendLine('}'); + + this.WriteMethodCall(builder, reference, method, methodScope, false, SemanticFacts.IsNullable(this.Compilation, method.ReturnType), true); + builder.AppendLine(';'); + index++; } } } - finally - { - builder.DecrementIndentation(); - } - builder.AppendIndentation(); - builder.AppendLine('}'); } + finally + { + builder.DecrementIndentation(); + } + builder.AppendIndentation(); + builder.AppendLine('}'); } + } - public void WriteEventDefinition(SourceBuilder builder, IEventSymbol @event, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references) + public void WritePropertyDefinition(SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references) + { + AutoInterfaceTargets getterTarget, setterTarget; + if (property.IsIndexer) + { + getterTarget = AutoInterfaceTargets.IndexerGetter; + setterTarget = AutoInterfaceTargets.IndexerSetter; + } + else { - PartialTemplate? adderTemplate = this.GetMatchedTemplates(references, AutoInterfaceTargets.EventAdder, @event.Name); - PartialTemplate? removerTemplate = this.GetMatchedTemplates(references, AutoInterfaceTargets.EventRemover, @event.Name); + getterTarget = AutoInterfaceTargets.PropertyGetter; + setterTarget = AutoInterfaceTargets.PropertySetter; + } - builder.AppendIndentation(); - builder.Append("event"); - builder.Append(' '); - this.WriteTypeReference(builder, @event.Type, scope); - builder.Append(' '); - this.WriteTypeReference(builder, @interface, scope); - builder.Append('.'); - this.WriteIdentifier(builder, @event); + PartialTemplate? getterTemplate = this.GetMatchedTemplates(references, getterTarget, property.IsIndexer ? "this" : property.Name); + PartialTemplate? setterTemplate = this.GetMatchedTemplates(references, setterTarget, property.IsIndexer ? "this" : property.Name); + + builder.AppendIndentation(); + this.WriteTypeReference(builder, property.Type, scope); + builder.Append(' '); + this.WriteTypeReference(builder, @interface, scope); + builder.Append('.'); + + if (property.IsIndexer) + { + builder.Append("this["); + this.WriteParameterDefinition(builder, scope, property.Parameters); + builder.Append(']'); + } + else + { + this.WriteIdentifier(builder, property); + } + + if (property.SetMethod == null && getterTemplate == null) + { + builder.Append(" => "); + this.WritePropertyCall(builder, references.First(), property, scope, SemanticFacts.IsNullable(this.Compilation, property.Type), true); + builder.AppendLine(';'); + } + else + { builder.AppendLine(); builder.AppendIndentation(); builder.AppendLine('{'); builder.IncrementIndentation(); try { - if (references.Count() == 1 && adderTemplate == null && removerTemplate == null) + if (references.Count() == 1 && getterTemplate == null && setterTemplate == null) { IMemberInfo reference = references.First(); - builder.AppendIndentation(); - builder.Append("add => "); - this.WriteMemberReference(builder, reference, scope, false, false); - builder.Append('.'); - this.WriteIdentifier(builder, @event); - builder.AppendLine(" += value;"); - builder.AppendIndentation(); - builder.Append("remove => "); - this.WriteMemberReference(builder, reference, scope, false, false); - builder.Append('.'); - this.WriteIdentifier(builder, @event); - builder.AppendLine(" -= value;"); + + if (property.GetMethod is not null) + { + builder.AppendIndentation(); + builder.Append("get => "); + this.WritePropertyCall(builder, reference, property, scope, SemanticFacts.IsNullable(this.Compilation, property.Type), true); + builder.AppendLine(';'); + } + if (property.SetMethod is not null) + { + builder.AppendIndentation(); + builder.Append("set => "); + this.WritePropertyCall(builder, reference, property, scope, false, false); + builder.AppendLine(" = value;"); + } } else { - if (@event.AddMethod != null) + if (property.GetMethod is not null) { builder.AppendIndentation(); - builder.AppendLine("add"); - builder.AppendIndentation(); - builder.AppendLine('{'); - builder.IncrementIndentation(); - try + if (getterTemplate != null) { - if (adderTemplate != null) + builder.AppendLine("get"); + builder.AppendIndentation(); + builder.AppendLine('{'); + builder.IncrementIndentation(); + try { - TemplatedSourceTextGenerator generator = new(adderTemplate.Template); - PartialEventModel model = new(); - model.Load(this, builder, @interface, scope, references); - model.Load(this, builder, @event, scope, references); + TemplatedSourceTextGenerator generator = new(getterTemplate.Template); + + IPropertyModel model = property.IsIndexer ? new PartialIndexerModel() : (IPropertyModel)new PartialPropertyModel(); + if (model is IRootModel rootModel) + { + rootModel.Load(this, builder, @interface, scope, references); + } + model.Load(this, builder, property, scope, references); bool separatorRequired = false; generator.Emit(this, builder, model, ref separatorRequired); @@ -616,40 +484,38 @@ public void WriteEventDefinition(SourceBuilder builder, IEventSymbol @event, Sco builder.AppendLine(); } } - else + finally { - foreach (IMemberInfo reference in references) - { - builder.AppendIndentation(); - this.WriteMemberReference(builder, reference, scope, false, false); - builder.Append('.'); - this.WriteIdentifier(builder, @event); - builder.AppendLine(" += value;"); - } + builder.DecrementIndentation(); } + builder.AppendIndentation(); + builder.AppendLine('}'); } - finally + else { - builder.DecrementIndentation(); + builder.Append("get => "); + this.WritePropertyCall(builder, references.Last(), property, scope, SemanticFacts.IsNullable(this.Compilation, property.Type), true); + builder.AppendLine(';'); } - builder.AppendIndentation(); - builder.AppendLine('}'); } - if (@event.RemoveMethod != null) + if (property.SetMethod is not null) { builder.AppendIndentation(); - builder.AppendLine("remove"); + builder.AppendLine("set"); builder.AppendIndentation(); builder.AppendLine('{'); builder.IncrementIndentation(); try { - if (removerTemplate != null) + if (setterTemplate != null) { - TemplatedSourceTextGenerator generator = new(removerTemplate.Template); - PartialEventModel model = new(); - model.Load(this, builder, @interface, scope, references); - model.Load(this, builder, @event, scope, references); + TemplatedSourceTextGenerator generator = new(setterTemplate.Template); + IPropertyModel model = property.IsIndexer ? new PartialIndexerModel() : (IPropertyModel)new PartialPropertyModel(); + if (model is IRootModel rootModel) + { + rootModel.Load(this, builder, @interface, scope, references); + } + model.Load(this, builder, property, scope, references); bool separatorRequired = false; generator.Emit(this, builder, model, ref separatorRequired); @@ -663,10 +529,8 @@ public void WriteEventDefinition(SourceBuilder builder, IEventSymbol @event, Sco foreach (IMemberInfo reference in references) { builder.AppendIndentation(); - this.WriteMemberReference(builder, reference, scope, false, false); - builder.Append('.'); - this.WriteIdentifier(builder, @event); - builder.AppendLine(" -= value;"); + this.WritePropertyCall(builder, reference, property, scope, false, false); + builder.AppendLine(" = value;"); } } } @@ -686,342 +550,473 @@ public void WriteEventDefinition(SourceBuilder builder, IEventSymbol @event, Sco builder.AppendIndentation(); builder.AppendLine('}'); } + } - public void WriteTypeDeclarationBeginning(SourceBuilder builder, INamedTypeSymbol type, ScopeInfo scope) + public void WriteEventDefinition(SourceBuilder builder, IEventSymbol @event, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references) + { + PartialTemplate? adderTemplate = this.GetMatchedTemplates(references, AutoInterfaceTargets.EventAdder, @event.Name); + PartialTemplate? removerTemplate = this.GetMatchedTemplates(references, AutoInterfaceTargets.EventRemover, @event.Name); + + builder.AppendIndentation(); + builder.Append("event"); + builder.Append(' '); + this.WriteTypeReference(builder, @event.Type, scope); + builder.Append(' '); + this.WriteTypeReference(builder, @interface, scope); + builder.Append('.'); + this.WriteIdentifier(builder, @event); + builder.AppendLine(); + builder.AppendIndentation(); + builder.AppendLine('{'); + builder.IncrementIndentation(); + try { - builder.Append("partial"); - builder.Append(' '); - if (type.TypeKind == TypeKind.Class) - { - bool isRecord = type.DeclaringSyntaxReferences.Any(i => i.GetSyntax() is RecordDeclarationSyntax); - builder.Append(isRecord ? "record" : "class"); - } - else if (type.TypeKind == TypeKind.Struct) - { - builder.Append("struct"); - } - else if (type.TypeKind == TypeKind.Interface) + if (references.Count() == 1 && adderTemplate == null && removerTemplate == null) { - builder.Append("interface"); + IMemberInfo reference = references.First(); + builder.AppendIndentation(); + builder.Append("add => "); + this.WriteMemberReference(builder, reference, scope, false, false); + builder.Append('.'); + this.WriteIdentifier(builder, @event); + builder.AppendLine(" += value;"); + builder.AppendIndentation(); + builder.Append("remove => "); + this.WriteMemberReference(builder, reference, scope, false, false); + builder.Append('.'); + this.WriteIdentifier(builder, @event); + builder.AppendLine(" -= value;"); } else { - throw new NotSupportedException(nameof(WriteTypeDeclarationBeginning)); - } - builder.Append(' '); - this.WriteTypeReference(builder, type, scope); - } - - public void WriteNamespaceBeginning(SourceBuilder builder, INamespaceSymbol @namespace) - { - if (@namespace != null && @namespace.ConstituentNamespaces.Length > 0) - { - List containingNamespaces = new(); - for (INamespaceSymbol? ct = @namespace; ct != null && ct.IsGlobalNamespace == false; ct = ct.ContainingNamespace) + if (@event.AddMethod != null) { - containingNamespaces.Insert(0, ct); + builder.AppendIndentation(); + builder.AppendLine("add"); + builder.AppendIndentation(); + builder.AppendLine('{'); + builder.IncrementIndentation(); + try + { + if (adderTemplate != null) + { + TemplatedSourceTextGenerator generator = new(adderTemplate.Template); + PartialEventModel model = new(); + model.Load(this, builder, @interface, scope, references); + model.Load(this, builder, @event, scope, references); + + bool separatorRequired = false; + generator.Emit(this, builder, model, ref separatorRequired); + if (separatorRequired) + { + builder.AppendLine(); + } + } + else + { + foreach (IMemberInfo reference in references) + { + builder.AppendIndentation(); + this.WriteMemberReference(builder, reference, scope, false, false); + builder.Append('.'); + this.WriteIdentifier(builder, @event); + builder.AppendLine(" += value;"); + } + } + } + finally + { + builder.DecrementIndentation(); + } + builder.AppendIndentation(); + builder.AppendLine('}'); } - - if (containingNamespaces.Count > 0) + if (@event.RemoveMethod != null) { builder.AppendIndentation(); - builder.Append("namespace"); - builder.Append(' '); - builder.AppendLine(string.Join(".", containingNamespaces.Select(i => GetSourceIdentifier(i)))); + builder.AppendLine("remove"); builder.AppendIndentation(); builder.AppendLine('{'); builder.IncrementIndentation(); + try + { + if (removerTemplate != null) + { + TemplatedSourceTextGenerator generator = new(removerTemplate.Template); + PartialEventModel model = new(); + model.Load(this, builder, @interface, scope, references); + model.Load(this, builder, @event, scope, references); + + bool separatorRequired = false; + generator.Emit(this, builder, model, ref separatorRequired); + if (separatorRequired) + { + builder.AppendLine(); + } + } + else + { + foreach (IMemberInfo reference in references) + { + builder.AppendIndentation(); + this.WriteMemberReference(builder, reference, scope, false, false); + builder.Append('.'); + this.WriteIdentifier(builder, @event); + builder.AppendLine(" -= value;"); + } + } + } + finally + { + builder.DecrementIndentation(); + } + builder.AppendIndentation(); + builder.AppendLine('}'); } } } + finally + { + builder.DecrementIndentation(); + } + builder.AppendIndentation(); + builder.AppendLine('}'); + } + + public void WriteTypeDeclarationBeginning(SourceBuilder builder, INamedTypeSymbol type, ScopeInfo scope) + { + builder.Append("partial"); + builder.Append(' '); + if (type.TypeKind == TypeKind.Class) + { + bool isRecord = type.DeclaringSyntaxReferences.Any(i => i.GetSyntax() is RecordDeclarationSyntax); + builder.Append(isRecord ? "record" : "class"); + } + else if (type.TypeKind == TypeKind.Struct) + { + builder.Append("struct"); + } + else if (type.TypeKind == TypeKind.Interface) + { + builder.Append("interface"); + } + else + { + throw new NotSupportedException(nameof(WriteTypeDeclarationBeginning)); + } + builder.Append(' '); + this.WriteTypeReference(builder, type, scope); + } - public void WriteHolderReference(SourceBuilder builder, ISymbol member, ScopeInfo scope) + public void WriteNamespaceBeginning(SourceBuilder builder, INamespaceSymbol @namespace) + { + if (@namespace != null && @namespace.ConstituentNamespaces.Length > 0) { - if (member.IsStatic) + List containingNamespaces = new(); + for (INamespaceSymbol? ct = @namespace; ct != null && ct.IsGlobalNamespace == false; ct = ct.ContainingNamespace) { - this.WriteTypeReference(builder, member.ContainingType, scope); + containingNamespaces.Insert(0, ct); } - else + + if (containingNamespaces.Count > 0) { - builder.Append("this"); + builder.AppendIndentation(); + builder.Append("namespace"); + builder.Append(' '); + builder.AppendLine(string.Join(".", containingNamespaces.Select(i => GetSourceIdentifier(i)))); + builder.AppendIndentation(); + builder.AppendLine('{'); + builder.IncrementIndentation(); } } + } + + public void WriteHolderReference(SourceBuilder builder, ISymbol member, ScopeInfo scope) + { + if (member.IsStatic) + { + this.WriteTypeReference(builder, member.ContainingType, scope); + } + else + { + builder.Append("this"); + } + } - public void WriteMemberReference(SourceBuilder builder, IMemberInfo item, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing) + public void WriteMemberReference(SourceBuilder builder, IMemberInfo item, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing) + { + bool expressionIsNullable; + if (item.CastRequired) { - bool expressionIsNullable; - if (item.CastRequired) - { - builder.Append('('); - this.WriteHolderReference(builder, item.Member, scope); - builder.Append('.'); - this.WriteIdentifier(builder, item.Member); - builder.Append(" as "); - this.WriteTypeReference(builder, item.InterfaceType.WithNullableAnnotation(NullableAnnotation.NotAnnotated), scope); - builder.Append(')'); + builder.Append('('); + this.WriteHolderReference(builder, item.Member, scope); + builder.Append('.'); + this.WriteIdentifier(builder, item.Member); + builder.Append(" as "); + this.WriteTypeReference(builder, item.InterfaceType.WithNullableAnnotation(NullableAnnotation.NotAnnotated), scope); + builder.Append(')'); + + expressionIsNullable = true; + } + else + { + this.WriteHolderReference(builder, item.Member, scope); + builder.Append('.'); + this.WriteIdentifier(builder, item.Member); + + expressionIsNullable = SemanticFacts.IsNullable(this.Compilation, item.ReceiverType); + } - expressionIsNullable = true; + if (allowCoalescing) + { + if (expressionIsNullable) + { + builder.Append(typeIsNullable ? '?' : '!'); } else { - this.WriteHolderReference(builder, item.Member, scope); - builder.Append('.'); - this.WriteIdentifier(builder, item.Member); - - expressionIsNullable = SemanticFacts.IsNullable(this.Compilation, item.ReceiverType); + if (typeIsNullable) + { + builder.Append('?'); + } } - - if (allowCoalescing) + } + else + { + if (expressionIsNullable) { - if (expressionIsNullable) + if (typeIsNullable) { - builder.Append(typeIsNullable ? '?' : '!'); + //? builder.Append('E'); } else { - if (typeIsNullable) - { - builder.Append('?'); - } + builder.Append('!'); } } else { - if (expressionIsNullable) + if (typeIsNullable) { - if (typeIsNullable) - { - //? builder.Append('E'); - } - else - { - builder.Append('!'); - } + //builder.Append('G'); } else { - if (typeIsNullable) - { - //builder.Append('G'); - } - else - { - //empty or ! - } + //empty or ! } } } + } - public void WritePropertyCall(SourceBuilder builder, IMemberInfo reference, IPropertySymbol property, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing) + public void WritePropertyCall(SourceBuilder builder, IMemberInfo reference, IPropertySymbol property, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing) + { + this.WriteMemberReference(builder, reference, scope, typeIsNullable, allowCoalescing); + if (property.IsIndexer) { - this.WriteMemberReference(builder, reference, scope, typeIsNullable, allowCoalescing); - if (property.IsIndexer) - { - builder.Append('['); - this.WriteCallParameters(builder, property.Parameters); - builder.Append(']'); - } - else - { - builder.Append('.'); - this.WriteIdentifier(builder, property); - } + builder.Append('['); + this.WriteCallParameters(builder, property.Parameters); + builder.Append(']'); } - - public void WriteMethodCall(SourceBuilder builder, IMemberInfo item, IMethodSymbol method, ScopeInfo scope, bool async, bool typeIsNullable, bool allowCoalescing) + else { - if (async) - { - builder.Append("await"); - builder.Append(' '); - } - this.WriteMemberReference(builder, item, scope, typeIsNullable, allowCoalescing); builder.Append('.'); - this.WriteIdentifier(builder, method); - if (method.IsGenericMethod) - { - builder.Append('<'); - this.WriteTypeArgumentsCall(builder, method.TypeArguments, scope); - builder.Append('>'); - } - builder.Append('('); - this.WriteCallParameters(builder, method.Parameters); - builder.Append(")"); + this.WriteIdentifier(builder, property); } + } - public void WriteIdentifier(SourceBuilder builder, ISymbol symbol) + public void WriteMethodCall(SourceBuilder builder, IMemberInfo item, IMethodSymbol method, ScopeInfo scope, bool async, bool typeIsNullable, bool allowCoalescing) + { + if (async) { - builder.Append(this.GetSourceIdentifier(symbol)); + builder.Append("await"); + builder.Append(' '); } - - public void WriteRefKind(SourceBuilder builder, RefKind kind) + this.WriteMemberReference(builder, item, scope, typeIsNullable, allowCoalescing); + builder.Append('.'); + this.WriteIdentifier(builder, method); + if (method.IsGenericMethod) { - switch (kind) - { - default: throw new NotSupportedException(nameof(WriteRefKind)); - case RefKind.None: break; - case RefKind.In: builder.Append("in"); break; - case RefKind.Out: builder.Append("out"); break; - case RefKind.Ref: builder.Append("ref"); break; - } + builder.Append('<'); + this.WriteTypeArgumentsCall(builder, method.TypeArguments, scope); + builder.Append('>'); } + builder.Append('('); + this.WriteCallParameters(builder, method.Parameters); + builder.Append(")"); + } - #region helper members + public void WriteIdentifier(SourceBuilder builder, ISymbol symbol) + { + builder.Append(this.GetSourceIdentifier(symbol)); + } - private PartialTemplate? GetMatchedTemplates(IEnumerable references, AutoInterfaceTargets target, string name) + public void WriteRefKind(SourceBuilder builder, RefKind kind) + { + switch (kind) { - IEnumerable<(PartialTemplate template, ISymbol reference)> matched = references.SelectMany(i => i.TemplateParts.Where(j => j.MemberTargets.HasFlag(target)).Where(j => j.FilterMatch(name)).Select(j => (j, i.Member))); - return PartialTemplate.PickTemplate(this.Context, matched, name); + default: throw new NotSupportedException(nameof(WriteRefKind)); + case RefKind.None: break; + case RefKind.In: builder.Append("in"); break; + case RefKind.Out: builder.Append("out"); break; + case RefKind.Ref: builder.Append("ref"); break; } + } - private string GetSourceIdentifier(ISymbol symbol) + #region helper members + + private PartialTemplate? GetMatchedTemplates(IEnumerable references, AutoInterfaceTargets target, string name) + { + IEnumerable<(PartialTemplate template, ISymbol reference)> matched = references.SelectMany(i => i.TemplateParts.Where(j => j.MemberTargets.HasFlag(target)).Where(j => j.FilterMatch(name)).Select(j => (j, i.Member))); + return PartialTemplate.PickTemplate(this.Context, matched, name); + } + + private string GetSourceIdentifier(ISymbol symbol) + { + if (symbol is IPropertySymbol propertySymbol && propertySymbol.IsIndexer) { - if (symbol is IPropertySymbol propertySymbol && propertySymbol.IsIndexer) - { - return "this"; - } - else if (symbol is INamespaceSymbol ns) - { - return ns.Name; - //return string.Join("+", ns.ConstituentNamespaces.Select(i => i.Name)); - //return $"<{@namespace.Name};{symbol}>" + this.GetSourceIdentifier(@namespace.Name); - } - else if (symbol.DeclaringSyntaxReferences.Length == 0) - { - return symbol.Name; - } - else + return "this"; + } + else if (symbol is INamespaceSymbol ns) + { + return ns.Name; + //return string.Join("+", ns.ConstituentNamespaces.Select(i => i.Name)); + //return $"<{@namespace.Name};{symbol}>" + this.GetSourceIdentifier(@namespace.Name); + } + else if (symbol.DeclaringSyntaxReferences.Length == 0) + { + return symbol.Name; + } + else + { + foreach (SyntaxReference syntaxReference in symbol.DeclaringSyntaxReferences) { - foreach (SyntaxReference syntaxReference in symbol.DeclaringSyntaxReferences) + SyntaxNode syntax = syntaxReference.GetSyntax(); + if (syntax is BaseTypeDeclarationSyntax type) { - SyntaxNode syntax = syntaxReference.GetSyntax(); - if (syntax is BaseTypeDeclarationSyntax type) - { - return this.GetSourceIdentifier(type.Identifier); - } - else if (syntax is MethodDeclarationSyntax method) - { - return this.GetSourceIdentifier(method.Identifier); - } - else if (syntax is ParameterSyntax parameter) - { - return this.GetSourceIdentifier(parameter.Identifier); - } - else if (syntax is VariableDeclaratorSyntax variableDeclarator) - { - return this.GetSourceIdentifier(variableDeclarator.Identifier); - } - else if (syntax is VariableDeclarationSyntax variableDeclaration) - { - if (variableDeclaration.Variables.Any(i => i.Identifier.IsVerbatimIdentifier())) - { - return "@" + symbol; - } - else - { - return symbol.ToString(); - } - } - else if (syntax is BaseFieldDeclarationSyntax field) - { - if (field.Declaration.Variables.Any(i => i.Identifier.IsVerbatimIdentifier())) - { - return "@" + symbol; - } - else - { - return symbol.ToString(); - } - } - else if (syntax is PropertyDeclarationSyntax property) - { - return this.GetSourceIdentifier(property.Identifier); - } - else if (syntax is IndexerDeclarationSyntax) - { - throw new InvalidOperationException("trying to resolve indexer name"); - } - else if (syntax is EventDeclarationSyntax @event) - { - return this.GetSourceIdentifier(@event.Identifier); - } - else if (syntax is TypeParameterSyntax typeParameter) - { - return this.GetSourceIdentifier(typeParameter.Identifier); - } - else if (syntax is TupleTypeSyntax) + return this.GetSourceIdentifier(type.Identifier); + } + else if (syntax is MethodDeclarationSyntax method) + { + return this.GetSourceIdentifier(method.Identifier); + } + else if (syntax is ParameterSyntax parameter) + { + return this.GetSourceIdentifier(parameter.Identifier); + } + else if (syntax is VariableDeclaratorSyntax variableDeclarator) + { + return this.GetSourceIdentifier(variableDeclarator.Identifier); + } + else if (syntax is VariableDeclarationSyntax variableDeclaration) + { + if (variableDeclaration.Variables.Any(i => i.Identifier.IsVerbatimIdentifier())) { - return symbol.Name; + return "@" + symbol; } - else if (syntax is TupleElementSyntax tupleElement) + else { - return this.GetSourceIdentifier(tupleElement.Identifier); + return symbol.ToString(); } - else if (syntax is NamespaceDeclarationSyntax @namespace) + } + else if (syntax is BaseFieldDeclarationSyntax field) + { + if (field.Declaration.Variables.Any(i => i.Identifier.IsVerbatimIdentifier())) { - throw new NotSupportedException(syntax.GetType().ToString()); + return "@" + symbol; } else { - throw new NotSupportedException(syntax.GetType().ToString()); + return symbol.ToString(); } } - - throw new NotSupportedException(); + else if (syntax is PropertyDeclarationSyntax property) + { + return this.GetSourceIdentifier(property.Identifier); + } + else if (syntax is IndexerDeclarationSyntax) + { + throw new InvalidOperationException("trying to resolve indexer name"); + } + else if (syntax is EventDeclarationSyntax @event) + { + return this.GetSourceIdentifier(@event.Identifier); + } + else if (syntax is TypeParameterSyntax typeParameter) + { + return this.GetSourceIdentifier(typeParameter.Identifier); + } + else if (syntax is TupleTypeSyntax) + { + return symbol.Name; + } + else if (syntax is TupleElementSyntax tupleElement) + { + return this.GetSourceIdentifier(tupleElement.Identifier); + } + else if (syntax is NamespaceDeclarationSyntax @namespace) + { + throw new NotSupportedException(syntax.GetType().ToString()); + } + else + { + throw new NotSupportedException(syntax.GetType().ToString()); + } } + + throw new NotSupportedException(); } + } - private string GetSourceIdentifier(SyntaxToken identifier) + private string GetSourceIdentifier(SyntaxToken identifier) + { + if (identifier.IsVerbatimIdentifier()) { - if (identifier.IsVerbatimIdentifier()) - { - return "@" + identifier.ValueText; - } - else - { - return identifier.ValueText; - } + return "@" + identifier.ValueText; + } + else + { + return identifier.ValueText; } + } - private string GetSourceIdentifier(NameSyntax name) + private string GetSourceIdentifier(NameSyntax name) + { + if (name is SimpleNameSyntax simpleName) { - if (name is SimpleNameSyntax simpleName) - { - return this.GetSourceIdentifier(simpleName.Identifier); - } - else if (name is QualifiedNameSyntax qualifiedName) + return this.GetSourceIdentifier(simpleName.Identifier); + } + else if (name is QualifiedNameSyntax qualifiedName) + { + string left = this.GetSourceIdentifier(qualifiedName.Left); + string right = this.GetSourceIdentifier(qualifiedName.Right); + if (string.IsNullOrEmpty(left)) { - string left = this.GetSourceIdentifier(qualifiedName.Left); - string right = this.GetSourceIdentifier(qualifiedName.Right); - if (string.IsNullOrEmpty(left)) + if (string.IsNullOrEmpty(right)) { - if (string.IsNullOrEmpty(right)) - { - throw new NotSupportedException("both are null_or_empty."); - } - else - { - return right; - } + throw new NotSupportedException("both are null_or_empty."); } else { - if (string.IsNullOrEmpty(right)) - { - return left; - } - else - { - return left + "." + right; - } + return right; } } else { - throw new NotSupportedException(name.GetType().ToString()); + if (string.IsNullOrEmpty(right)) + { + return left; + } + else + { + return left + "." + right; + } } } - - #endregion + else + { + throw new NotSupportedException(name.GetType().ToString()); + } } -} \ No newline at end of file + + #endregion +} diff --git a/BeaKona.AutoInterfaceGenerator/Globals.cs b/BeaKona.AutoInterfaceGenerator/Globals.cs new file mode 100644 index 0000000..edc4fbc --- /dev/null +++ b/BeaKona.AutoInterfaceGenerator/Globals.cs @@ -0,0 +1,4 @@ +global using Microsoft.CodeAnalysis; +global using System; +global using System.Collections.Generic; +global using System.Linq; diff --git a/BeaKona.AutoInterfaceGenerator/Helpers.cs b/BeaKona.AutoInterfaceGenerator/Helpers.cs index 035da0f..f523a70 100644 --- a/BeaKona.AutoInterfaceGenerator/Helpers.cs +++ b/BeaKona.AutoInterfaceGenerator/Helpers.cs @@ -1,29 +1,26 @@ -using Microsoft.CodeAnalysis; +namespace BeaKona.AutoInterfaceGenerator; -namespace BeaKona.AutoInterfaceGenerator +public static class Helpers { - public static class Helpers + public static void ReportDiagnostic(GeneratorExecutionContext context, string id, string title, string message, string description, DiagnosticSeverity severity, SyntaxNode? node, params object?[] messageArgs) { - public static void ReportDiagnostic(GeneratorExecutionContext context, string id, string title, string message, string description, DiagnosticSeverity severity, SyntaxNode? node, params object?[] messageArgs) - { - Helpers.ReportDiagnostic(context, id, title, message, description, severity, node?.GetLocation(), messageArgs); - } + Helpers.ReportDiagnostic(context, id, title, message, description, severity, node?.GetLocation(), messageArgs); + } - public static void ReportDiagnostic(GeneratorExecutionContext context, string id, string title, string message, string description, DiagnosticSeverity severity, ISymbol? member, params object?[] messageArgs) - { - Helpers.ReportDiagnostic(context, id, title, message, description, severity, member != null && member.Locations.Length > 0 ? member.Locations[0] : null, messageArgs); - } + public static void ReportDiagnostic(GeneratorExecutionContext context, string id, string title, string message, string description, DiagnosticSeverity severity, ISymbol? member, params object?[] messageArgs) + { + Helpers.ReportDiagnostic(context, id, title, message, description, severity, member != null && member.Locations.Length > 0 ? member.Locations[0] : null, messageArgs); + } - public static void ReportDiagnostic(GeneratorExecutionContext context, string id, string title, string message, string description, DiagnosticSeverity severity, Location? location, params object?[] messageArgs) - { - LocalizableString ltitle = new LocalizableResourceString(title, AutoInterfaceResource.ResourceManager, typeof(AutoInterfaceResource)); - LocalizableString lmessage = new LocalizableResourceString(message, AutoInterfaceResource.ResourceManager, typeof(AutoInterfaceResource)); - LocalizableString? ldescription = new LocalizableResourceString(description, AutoInterfaceResource.ResourceManager, typeof(AutoInterfaceResource)); - string category = typeof(AutoInterfaceSourceGenerator).Namespace; - string? link = "https://github.com/beakona/AutoInterface"; - DiagnosticDescriptor dd = new(id, ltitle, lmessage, category, severity, true, ldescription, link, WellKnownDiagnosticTags.NotConfigurable); - Diagnostic d = Diagnostic.Create(dd, location, messageArgs); - context.ReportDiagnostic(d); - } + public static void ReportDiagnostic(GeneratorExecutionContext context, string id, string title, string message, string description, DiagnosticSeverity severity, Location? location, params object?[] messageArgs) + { + LocalizableString ltitle = new LocalizableResourceString(title, AutoInterfaceResource.ResourceManager, typeof(AutoInterfaceResource)); + LocalizableString lmessage = new LocalizableResourceString(message, AutoInterfaceResource.ResourceManager, typeof(AutoInterfaceResource)); + LocalizableString? ldescription = new LocalizableResourceString(description, AutoInterfaceResource.ResourceManager, typeof(AutoInterfaceResource)); + string category = typeof(AutoInterfaceSourceGenerator).Namespace; + string? link = "https://github.com/beakona/AutoInterface"; + DiagnosticDescriptor dd = new(id, ltitle, lmessage, category, severity, true, ldescription, link, WellKnownDiagnosticTags.NotConfigurable); + Diagnostic d = Diagnostic.Create(dd, location, messageArgs); + context.ReportDiagnostic(d); } } diff --git a/BeaKona.AutoInterfaceGenerator/ICodeTextWriter.cs b/BeaKona.AutoInterfaceGenerator/ICodeTextWriter.cs index fd60dca..fbc8142 100644 --- a/BeaKona.AutoInterfaceGenerator/ICodeTextWriter.cs +++ b/BeaKona.AutoInterfaceGenerator/ICodeTextWriter.cs @@ -1,42 +1,38 @@ -using Microsoft.CodeAnalysis; -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator; -namespace BeaKona.AutoInterfaceGenerator +internal interface ICodeTextWriter { - internal interface ICodeTextWriter - { - Compilation Compilation { get; } + Compilation Compilation { get; } - void WriteTypeReference(SourceBuilder builder, ITypeSymbol type, ScopeInfo scope); + void WriteTypeReference(SourceBuilder builder, ITypeSymbol type, ScopeInfo scope); - void WriteTypeArgumentsCall(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope); + void WriteTypeArgumentsCall(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope); - void WriteTypeArgumentsDefinition(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope); + void WriteTypeArgumentsDefinition(SourceBuilder builder, IEnumerable typeArguments, ScopeInfo scope); - void WriteParameterDefinition(SourceBuilder builder, ScopeInfo scope, IEnumerable parameters); + void WriteParameterDefinition(SourceBuilder builder, ScopeInfo scope, IEnumerable parameters); - void WriteCallParameters(SourceBuilder builder, IEnumerable parameters); + void WriteCallParameters(SourceBuilder builder, IEnumerable parameters); - void WriteMethodDefinition(SourceBuilder builder, IMethodSymbol method, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references); + void WriteMethodDefinition(SourceBuilder builder, IMethodSymbol method, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references); - void WritePropertyDefinition(SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references); + void WritePropertyDefinition(SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references); - void WriteEventDefinition(SourceBuilder builder, IEventSymbol @event, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references); + void WriteEventDefinition(SourceBuilder builder, IEventSymbol @event, ScopeInfo scope, INamedTypeSymbol @interface, IEnumerable references); - void WriteTypeDeclarationBeginning(SourceBuilder builder, INamedTypeSymbol type, ScopeInfo scope); + void WriteTypeDeclarationBeginning(SourceBuilder builder, INamedTypeSymbol type, ScopeInfo scope); - void WriteNamespaceBeginning(SourceBuilder builder, INamespaceSymbol @namespace); + void WriteNamespaceBeginning(SourceBuilder builder, INamespaceSymbol @namespace); - void WriteHolderReference(SourceBuilder builder, ISymbol member, ScopeInfo scope); + void WriteHolderReference(SourceBuilder builder, ISymbol member, ScopeInfo scope); - void WriteMemberReference(SourceBuilder builder, IMemberInfo reference, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing); + void WriteMemberReference(SourceBuilder builder, IMemberInfo reference, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing); - void WritePropertyCall(SourceBuilder builder, IMemberInfo reference, IPropertySymbol property, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing); + void WritePropertyCall(SourceBuilder builder, IMemberInfo reference, IPropertySymbol property, ScopeInfo scope, bool typeIsNullable, bool allowCoalescing); - void WriteMethodCall(SourceBuilder builder, IMemberInfo reference, IMethodSymbol method, ScopeInfo scope, bool async, bool typeIsNullable, bool allowCoalescing); + void WriteMethodCall(SourceBuilder builder, IMemberInfo reference, IMethodSymbol method, ScopeInfo scope, bool async, bool typeIsNullable, bool allowCoalescing); - void WriteIdentifier(SourceBuilder builder, ISymbol symbol); + void WriteIdentifier(SourceBuilder builder, ISymbol symbol); - void WriteRefKind(SourceBuilder builder, RefKind kind); - } -} \ No newline at end of file + void WriteRefKind(SourceBuilder builder, RefKind kind); +} diff --git a/BeaKona.AutoInterfaceGenerator/IEnumerableExtensions.cs b/BeaKona.AutoInterfaceGenerator/IEnumerableExtensions.cs index 4701302..a7e54ef 100644 --- a/BeaKona.AutoInterfaceGenerator/IEnumerableExtensions.cs +++ b/BeaKona.AutoInterfaceGenerator/IEnumerableExtensions.cs @@ -1,32 +1,28 @@ -using System; -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator; -namespace BeaKona.AutoInterfaceGenerator +internal static class IEnumerableExtensions { - internal static class IEnumerableExtensions + public static HashSet ToHashSet(this IEnumerable @this) { - public static HashSet ToHashSet(this IEnumerable @this) + if (@this == null) { - if (@this == null) - { - return new HashSet(); - } - else - { - return new HashSet(@this); - } + return new HashSet(); } - - public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) + else { - HashSet seenKeys = new(); + return new HashSet(@this); + } + } - foreach (TSource element in source) + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) + { + HashSet seenKeys = new(); + + foreach (TSource element in source) + { + if (seenKeys.Add(keySelector(element))) { - if (seenKeys.Add(keySelector(element))) - { - yield return element; - } + yield return element; } } } diff --git a/BeaKona.AutoInterfaceGenerator/IMemberInfo.cs b/BeaKona.AutoInterfaceGenerator/IMemberInfo.cs index 36c759c..c4da8f2 100644 --- a/BeaKona.AutoInterfaceGenerator/IMemberInfo.cs +++ b/BeaKona.AutoInterfaceGenerator/IMemberInfo.cs @@ -1,15 +1,13 @@ using BeaKona.AutoInterfaceGenerator.Templates; -using Microsoft.CodeAnalysis; -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +internal interface IMemberInfo { - internal interface IMemberInfo - { - ISymbol Member { get; } - ITypeSymbol ReceiverType { get; } - INamedTypeSymbol InterfaceType { get; } - TemplateDefinition? Template { get; } - PartialTemplate[] TemplateParts { get; } - bool CastRequired { get; } - } + ISymbol Member { get; } + ITypeSymbol ReceiverType { get; } + INamedTypeSymbol InterfaceType { get; } + TemplateDefinition? Template { get; } + PartialTemplate[] TemplateParts { get; } + bool CastRequired { get; } } diff --git a/BeaKona.AutoInterfaceGenerator/INamedTypeSymbolExtensions.cs b/BeaKona.AutoInterfaceGenerator/INamedTypeSymbolExtensions.cs index 5e2d584..118e3e1 100644 --- a/BeaKona.AutoInterfaceGenerator/INamedTypeSymbolExtensions.cs +++ b/BeaKona.AutoInterfaceGenerator/INamedTypeSymbolExtensions.cs @@ -1,26 +1,23 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Linq; -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +internal static class INamedTypeSymbolExtensions { - internal static class INamedTypeSymbolExtensions + public static bool IsPartial(this ITypeSymbol @this) { - public static bool IsPartial(this ITypeSymbol @this) + foreach (SyntaxReference syntax in @this.DeclaringSyntaxReferences) { - foreach (SyntaxReference syntax in @this.DeclaringSyntaxReferences) + if (syntax.GetSyntax() is MemberDeclarationSyntax declaration) { - if (syntax.GetSyntax() is MemberDeclarationSyntax declaration) + if (declaration.Modifiers.Any(i => i.IsKind(SyntaxKind.PartialKeyword))) { - if (declaration.Modifiers.Any(i => i.IsKind(SyntaxKind.PartialKeyword))) - { - return true; - } + return true; } } - - return false; } + + return false; } } diff --git a/BeaKona.AutoInterfaceGenerator/ISourceTextGenerator.cs b/BeaKona.AutoInterfaceGenerator/ISourceTextGenerator.cs index 0afe177..58dabf9 100644 --- a/BeaKona.AutoInterfaceGenerator/ISourceTextGenerator.cs +++ b/BeaKona.AutoInterfaceGenerator/ISourceTextGenerator.cs @@ -1,7 +1,6 @@ -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +internal interface ISourceTextGenerator { - internal interface ISourceTextGenerator - { - void Emit(ICodeTextWriter writer, SourceBuilder builder, object? model, ref bool separatorRequired); - } + void Emit(ICodeTextWriter writer, SourceBuilder builder, object? model, ref bool separatorRequired); } diff --git a/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs b/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs index 1dcef53..2d388c6 100644 --- a/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs +++ b/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs @@ -1,71 +1,67 @@ -using Microsoft.CodeAnalysis; -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator; -namespace BeaKona.AutoInterfaceGenerator +internal static class ITypeSymbolExtensions { - internal static class ITypeSymbolExtensions + public static IEnumerable GetMethods(this ITypeSymbol @this) { - public static IEnumerable GetMethods(this ITypeSymbol @this) + foreach (ISymbol member in @this.GetMembers()) { - foreach (ISymbol member in @this.GetMembers()) + if (member is IMethodSymbol method) { - if (member is IMethodSymbol method) + if (method.MethodKind == MethodKind.Ordinary) { - if (method.MethodKind == MethodKind.Ordinary) - { - yield return method; - } + yield return method; } } } + } - public static IEnumerable GetProperties(this ITypeSymbol @this) + public static IEnumerable GetProperties(this ITypeSymbol @this) + { + foreach (ISymbol member in @this.GetMembers()) { - foreach (ISymbol member in @this.GetMembers()) + if (member is IPropertySymbol property) { - if (member is IPropertySymbol property) + if (property.IsIndexer == false) { - if (property.IsIndexer == false) - { - yield return property; - } + yield return property; } } } + } - public static IEnumerable GetIndexers(this ITypeSymbol @this) + public static IEnumerable GetIndexers(this ITypeSymbol @this) + { + foreach (ISymbol member in @this.GetMembers()) { - foreach (ISymbol member in @this.GetMembers()) + if (member is IPropertySymbol property) { - if (member is IPropertySymbol property) + if (property.IsIndexer) { - if (property.IsIndexer) - { - yield return property; - } + yield return property; } } } + } - public static IEnumerable GetEvents(this ITypeSymbol @this) + public static IEnumerable GetEvents(this ITypeSymbol @this) + { + foreach (ISymbol member in @this.GetMembers()) { - foreach (ISymbol member in @this.GetMembers()) + if (member is IEventSymbol @event) { - if (member is IEventSymbol @event) - { - yield return @event; - } + yield return @event; } } + } - public static bool IsMemberImplemented(this ITypeSymbol @this, ISymbol member) + public static bool IsMemberImplemented(this ITypeSymbol @this, ISymbol member) + { + if (@this.FindImplementationForInterfaceMember(member) is IMethodSymbol memberImplementation) { - if (@this.FindImplementationForInterfaceMember(member) is IMethodSymbol memberImplementation) - { - return memberImplementation.ContainingType.Equals(@this, SymbolEqualityComparer.Default) && memberImplementation.MethodKind == MethodKind.ExplicitInterfaceImplementation; - } - - return false; + return memberImplementation.ContainingType.Equals(@this, SymbolEqualityComparer.Default) && memberImplementation.MethodKind == MethodKind.ExplicitInterfaceImplementation; } + + return false; } } diff --git a/BeaKona.AutoInterfaceGenerator/ScopeInfo.cs b/BeaKona.AutoInterfaceGenerator/ScopeInfo.cs index 3a04f12..129a9d8 100644 --- a/BeaKona.AutoInterfaceGenerator/ScopeInfo.cs +++ b/BeaKona.AutoInterfaceGenerator/ScopeInfo.cs @@ -1,100 +1,95 @@ -using Microsoft.CodeAnalysis; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; +using System.Collections.Immutable; using System.Globalization; -using System.Linq; using System.Text.RegularExpressions; -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +internal sealed class ScopeInfo { - internal sealed class ScopeInfo + public ScopeInfo(ITypeSymbol type) { - public ScopeInfo(ITypeSymbol type) - { - this.Type = type; - this.usedTypeArguments = new HashSet(ScopeInfo.AllTypeArguments(type).Select(i => i.Name)); - } + this.Type = type; + this.usedTypeArguments = new HashSet(ScopeInfo.AllTypeArguments(type).Select(i => i.Name)); + } - public ScopeInfo(ScopeInfo parentScope) - { - this.Type = parentScope.Type; - this.usedTypeArguments = new HashSet(parentScope.usedTypeArguments); - } + public ScopeInfo(ScopeInfo parentScope) + { + this.Type = parentScope.Type; + this.usedTypeArguments = new HashSet(parentScope.usedTypeArguments); + } - public ITypeSymbol Type { get; } + public ITypeSymbol Type { get; } - private readonly HashSet usedTypeArguments; - private readonly Dictionary aliasTypeParameterNameByCanonicalType = new(SymbolEqualityComparer.Default); + private readonly HashSet usedTypeArguments; + private readonly Dictionary aliasTypeParameterNameByCanonicalType = new(SymbolEqualityComparer.Default); - private static ImmutableList AllTypeArguments(ISymbol symbol) - { - List types = new(); + private static ImmutableList AllTypeArguments(ISymbol symbol) + { + List types = new(); - for (ISymbol s = symbol; s != null; s = s.ContainingType) + for (ISymbol s = symbol; s != null; s = s.ContainingType) + { + if (s is INamedTypeSymbol ts) { - if (s is INamedTypeSymbol ts) - { - types.AddRange(ts.TypeArguments); - } - else if (s is IMethodSymbol m) - { - types.AddRange(m.TypeArguments); - } + types.AddRange(ts.TypeArguments); + } + else if (s is IMethodSymbol m) + { + types.AddRange(m.TypeArguments); } - - return types.ToImmutableList(); } - public void CreateAliases(ImmutableArray typeArguments) + return types.ToImmutableList(); + } + + public void CreateAliases(ImmutableArray typeArguments) + { + foreach (ITypeSymbol t in typeArguments) { - foreach (ITypeSymbol t in typeArguments) + if (this.aliasTypeParameterNameByCanonicalType.ContainsKey(t)) + { + throw new InvalidOperationException(); + } + + if (this.usedTypeArguments.Contains(t.Name)) { - if (this.aliasTypeParameterNameByCanonicalType.ContainsKey(t)) + if (ScopeInfo.TrySplitAsBaseNameAndInteger(t.Name, out string? baseName, out int? index) == false) { - throw new InvalidOperationException(); + baseName = t.Name; + index = 0; } - - if (this.usedTypeArguments.Contains(t.Name)) + string typeName; + do { - if (ScopeInfo.TrySplitAsBaseNameAndInteger(t.Name, out string? baseName, out int? index) == false) - { - baseName = t.Name; - index = 0; - } - string typeName; - do - { - typeName = $"{baseName}{++index}"; - } - while (this.usedTypeArguments.Contains(typeName)); - this.aliasTypeParameterNameByCanonicalType.Add(t, typeName); + typeName = $"{baseName}{++index}"; } + while (this.usedTypeArguments.Contains(typeName)); + this.aliasTypeParameterNameByCanonicalType.Add(t, typeName); } } + } - public bool TryGetAlias(ITypeSymbol symbol, /*[NotNullWhen(true)]*/ out string? alias) - { - return this.aliasTypeParameterNameByCanonicalType.TryGetValue(symbol, out alias); - } + public bool TryGetAlias(ITypeSymbol symbol, /*[NotNullWhen(true)]*/ out string? alias) + { + return this.aliasTypeParameterNameByCanonicalType.TryGetValue(symbol, out alias); + } - private static readonly Regex rxSplitter = new(@"^\s*(?\w+)(?\d+)\s*$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.CultureInvariant); + private static readonly Regex rxSplitter = new(@"^\s*(?\w+)(?\d+)\s*$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.CultureInvariant); - private static bool TrySplitAsBaseNameAndInteger(string name, /*[NotNullWhen(true)]*/ out string? baseName, /*[NotNullWhen(true)]*/ out int? value) + private static bool TrySplitAsBaseNameAndInteger(string name, /*[NotNullWhen(true)]*/ out string? baseName, /*[NotNullWhen(true)]*/ out int? value) + { + Match m = rxSplitter.Match(name); + if (m.Success) { - Match m = rxSplitter.Match(name); - if (m.Success) - { - baseName = m.Groups["n"].Value; - value = int.Parse(m.Groups["v"].Value, CultureInfo.InvariantCulture); - return true; - } - else - { - baseName = null; - value = null; - return false; - } + baseName = m.Groups["n"].Value; + value = int.Parse(m.Groups["v"].Value, CultureInfo.InvariantCulture); + return true; + } + else + { + baseName = null; + value = null; + return false; } } -} \ No newline at end of file +} diff --git a/BeaKona.AutoInterfaceGenerator/SemanticFacts.cs b/BeaKona.AutoInterfaceGenerator/SemanticFacts.cs index b4570c3..6f403a4 100644 --- a/BeaKona.AutoInterfaceGenerator/SemanticFacts.cs +++ b/BeaKona.AutoInterfaceGenerator/SemanticFacts.cs @@ -1,152 +1,146 @@ -using Microsoft.CodeAnalysis; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; +namespace BeaKona.AutoInterfaceGenerator; -namespace BeaKona.AutoInterfaceGenerator +internal static class SemanticFacts { - internal static class SemanticFacts + public static string? ResolveAssemblyAlias(Compilation compilation, IAssemblySymbol assembly) { - public static string? ResolveAssemblyAlias(Compilation compilation, IAssemblySymbol assembly) + //MetadataReferenceProperties.GlobalAlias + if (compilation.GetMetadataReference(assembly) is MetadataReference mr) { - //MetadataReferenceProperties.GlobalAlias - if (compilation.GetMetadataReference(assembly) is MetadataReference mr) + foreach (string alias in mr.Properties.Aliases) { - foreach (string alias in mr.Properties.Aliases) + if (string.IsNullOrEmpty(alias) == false) { - if (string.IsNullOrEmpty(alias) == false) - { - return alias; - } + return alias; } } - - return null; } - public static ISymbol[] GetRelativeSymbols(ITypeSymbol type, ITypeSymbol scope) - { - ISymbol[] typeSymbols = GetContainingSymbols(type, false); - ISymbol[] scopeSymbols = GetContainingSymbols(scope, true); - - int count = Math.Min(typeSymbols.Length, scopeSymbols.Length); - for (int i = 0; i < count; i++) - { - if (typeSymbols[i].Equals(scopeSymbols[i], SymbolEqualityComparer.Default) == false) - { - int remaining = typeSymbols.Length - i; - if (remaining > 0) - { - ISymbol[] result = new ISymbol[remaining]; - Array.Copy(typeSymbols, i, result, 0, result.Length); - return result; - } - else - { - break; - } - } - } + return null; + } - return new ISymbol[0]; - } + public static ISymbol[] GetRelativeSymbols(ITypeSymbol type, ITypeSymbol scope) + { + ISymbol[] typeSymbols = GetContainingSymbols(type, false); + ISymbol[] scopeSymbols = GetContainingSymbols(scope, true); - public static ISymbol[] GetContainingSymbols(ITypeSymbol type, bool includeSelf) + int count = Math.Min(typeSymbols.Length, scopeSymbols.Length); + for (int i = 0; i < count; i++) { - List symbols = new(); - - for (ISymbol t = includeSelf ? type : type.ContainingSymbol; t != null; t = t.ContainingSymbol) + if (typeSymbols[i].Equals(scopeSymbols[i], SymbolEqualityComparer.Default) == false) { - if (t is IModuleSymbol || t is IAssemblySymbol) + int remaining = typeSymbols.Length - i; + if (remaining > 0) { - break; + ISymbol[] result = new ISymbol[remaining]; + Array.Copy(typeSymbols, i, result, 0, result.Length); + return result; } - if (t is INamespaceSymbol tn && tn.IsGlobalNamespace) + else { break; } - symbols.Insert(0, t); } + } - return symbols.ToArray(); + return new ISymbol[0]; + } + + public static ISymbol[] GetContainingSymbols(ITypeSymbol type, bool includeSelf) + { + List symbols = new(); + + for (ISymbol t = includeSelf ? type : type.ContainingSymbol; t != null; t = t.ContainingSymbol) + { + if (t is IModuleSymbol || t is IAssemblySymbol) + { + break; + } + if (t is INamespaceSymbol tn && tn.IsGlobalNamespace) + { + break; + } + symbols.Insert(0, t); } - internal static (bool isAsync, bool returnsValue) IsAsyncAndGetReturnType(Compilation compilation, IMethodSymbol method) + return symbols.ToArray(); + } + + internal static (bool isAsync, bool returnsValue) IsAsyncAndGetReturnType(Compilation compilation, IMethodSymbol method) + { + bool isAsync = false; + bool returnsValue = false; + if (method.ReturnType is INamedTypeSymbol returnType) { - bool isAsync = false; - bool returnsValue = false; - if (method.ReturnType is INamedTypeSymbol returnType) + if (returnType.IsGenericType) { - if (returnType.IsGenericType) + if (returnType.IsUnboundGenericType == false) { - if (returnType.IsUnboundGenericType == false) - { - returnType = returnType.ConstructUnboundGenericType(); - } - INamedTypeSymbol? symbolTask1 = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1")?.ConstructUnboundGenericType(); - INamedTypeSymbol? symbolValueTask1 = compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask`1")?.ConstructUnboundGenericType(); - if (symbolTask1 != null && returnType.Equals(symbolTask1, SymbolEqualityComparer.Default) || symbolValueTask1 != null && returnType.Equals(symbolValueTask1, SymbolEqualityComparer.Default)) - { - isAsync = true; - returnsValue = true; - } + returnType = returnType.ConstructUnboundGenericType(); } - else + INamedTypeSymbol? symbolTask1 = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1")?.ConstructUnboundGenericType(); + INamedTypeSymbol? symbolValueTask1 = compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask`1")?.ConstructUnboundGenericType(); + if (symbolTask1 != null && returnType.Equals(symbolTask1, SymbolEqualityComparer.Default) || symbolValueTask1 != null && returnType.Equals(symbolValueTask1, SymbolEqualityComparer.Default)) { - INamedTypeSymbol? symbolTask = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); - INamedTypeSymbol? symbolValueTask = compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask"); - if (symbolTask != null && returnType.Equals(symbolTask, SymbolEqualityComparer.Default) || symbolValueTask != null && returnType.Equals(symbolValueTask, SymbolEqualityComparer.Default)) - { - isAsync = true; - returnsValue = false; - } + isAsync = true; + returnsValue = true; } } - if (isAsync == false) + else { - returnsValue = method.ReturnsVoid == false; + INamedTypeSymbol? symbolTask = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); + INamedTypeSymbol? symbolValueTask = compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask"); + if (symbolTask != null && returnType.Equals(symbolTask, SymbolEqualityComparer.Default) || symbolValueTask != null && returnType.Equals(symbolValueTask, SymbolEqualityComparer.Default)) + { + isAsync = true; + returnsValue = false; + } } + } + if (isAsync == false) + { + returnsValue = method.ReturnsVoid == false; + } - return (isAsync, returnsValue); + return (isAsync, returnsValue); + } + + public static bool IsNullable(Compilation compilation, ITypeSymbol type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); } - public static bool IsNullable(Compilation compilation, ITypeSymbol type) + if (type.NullableAnnotation == NullableAnnotation.Annotated) { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } + return true; + } + else if (type is INamedTypeSymbol namedType) + { + return SemanticFacts.IsNullableT(compilation, namedType); + } - if (type.NullableAnnotation == NullableAnnotation.Annotated) - { - return true; - } - else if (type is INamedTypeSymbol namedType) - { - return SemanticFacts.IsNullableT(compilation, namedType); - } + return false; + } - return false; + public static bool IsNullableT(Compilation compilation, INamedTypeSymbol type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); } - public static bool IsNullableT(Compilation compilation, INamedTypeSymbol type) + if (type.IsValueType) { - if (type == null) + if (type.IsGenericType && type.IsUnboundGenericType == false) { - throw new ArgumentNullException(nameof(type)); - } + INamedTypeSymbol symbolNullableT = compilation.GetSpecialType(SpecialType.System_Nullable_T); - if (type.IsValueType) - { - if (type.IsGenericType && type.IsUnboundGenericType == false) - { - INamedTypeSymbol symbolNullableT = compilation.GetSpecialType(SpecialType.System_Nullable_T); - - return symbolNullableT.ConstructUnboundGenericType().Equals(type.ConstructUnboundGenericType(), SymbolEqualityComparer.Default); - } + return symbolNullableT.ConstructUnboundGenericType().Equals(type.ConstructUnboundGenericType(), SymbolEqualityComparer.Default); } - - return false; } + + return false; } } diff --git a/BeaKona.AutoInterfaceGenerator/SourceBuilder.cs b/BeaKona.AutoInterfaceGenerator/SourceBuilder.cs index f54c90c..8601237 100644 --- a/BeaKona.AutoInterfaceGenerator/SourceBuilder.cs +++ b/BeaKona.AutoInterfaceGenerator/SourceBuilder.cs @@ -1,238 +1,234 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Text; -namespace BeaKona.AutoInterfaceGenerator +namespace BeaKona.AutoInterfaceGenerator; + +internal sealed class SourceBuilder { - internal sealed class SourceBuilder + public SourceBuilder() : this(SourceBuilderOptions.Default) { - public SourceBuilder() : this(SourceBuilderOptions.Default) - { - } + } - public SourceBuilder(SourceBuilderOptions options) - { - this.Options = options; - } + public SourceBuilder(SourceBuilderOptions options) + { + this.Options = options; + } - private SourceBuilder(SourceBuilder owner, SourceBuilderOptions options) : this(options) - { - this.owner = owner; - } + private SourceBuilder(SourceBuilder owner, SourceBuilderOptions options) : this(options) + { + this.owner = owner; + } - private readonly SourceBuilder? owner; + private readonly SourceBuilder? owner; - public SourceBuilderOptions Options { get; } + public SourceBuilderOptions Options { get; } - private readonly List elements = new(); - private readonly HashSet aliases = new(); + private readonly List elements = new(); + private readonly HashSet aliases = new(); - public void Clear() + public void Clear() + { + this.elements.Clear(); + } + + public void RegisterAlias(string alias) + { + if (this.owner != null) { - this.elements.Clear(); + this.owner.RegisterAlias(alias); } - - public void RegisterAlias(string alias) + else { - if (this.owner != null) - { - this.owner.RegisterAlias(alias); - } - else - { - this.aliases.Add(alias); - } + this.aliases.Add(alias); } + } - public void AppendLine() => this.elements.Add(new LineSeparatorMarker()); + public void AppendLine() => this.elements.Add(new LineSeparatorMarker()); - public void AppendLine(string? text) + public void AppendLine(string? text) + { + if (text != null) { - if (text != null) - { - this.Append(text); - } - this.AppendLine(); + this.Append(text); } + this.AppendLine(); + } - public void AppendLine(char c) - { - this.Append(c); - this.AppendLine(); - } + public void AppendLine(char c) + { + this.Append(c); + this.AppendLine(); + } - public void Append(string text) + public void Append(string text) + { + if (text != null) { - if (text != null) - { - this.elements.Add(text); - } + this.elements.Add(text); } + } - public void Append(object? value) + public void Append(object? value) + { + if (value != null) { - if (value != null) - { - this.Append(value.ToString()); - } + this.Append(value.ToString()); } + } - public void Append(char c) => this.elements.Add(c); + public void Append(char c) => this.elements.Add(c); - public void AppendSeparated(string text) + public void AppendSeparated(string text) + { + if (text != null) { - if (text != null) - { - this.AppendSpaceIfNeccessary(); - this.Append(text); - } + this.AppendSpaceIfNeccessary(); + this.Append(text); } + } - public void AppendSpaceIfNeccessary() - { - this.elements.Add(new FlexibleSpaceMarker()); - } + public void AppendSpaceIfNeccessary() + { + this.elements.Add(new FlexibleSpaceMarker()); + } - private int currentDepth = 0; + private int currentDepth = 0; - public void IncrementIndentation() => this.currentDepth++; + public void IncrementIndentation() => this.currentDepth++; - public void DecrementIndentation() + public void DecrementIndentation() + { + if (this.currentDepth > 0) { - if (this.currentDepth > 0) - { - this.currentDepth--; - } + this.currentDepth--; } + } - public void AppendIndentation() - { - this.elements.Add(new IndentationMarker(this.currentDepth)); - } + public void AppendIndentation() + { + this.elements.Add(new IndentationMarker(this.currentDepth)); + } - public SourceBuilder AppendNewBuilder(bool register = true) + public SourceBuilder AppendNewBuilder(bool register = true) + { + SourceBuilder builder = new(this, this.Options); + if (register) { - SourceBuilder builder = new(this, this.Options); - if (register) - { - this.elements.Add(builder); - } - return builder; + this.elements.Add(builder); } + return builder; + } - public SourceBuilder AppendBuilder(Action builder) + public SourceBuilder AppendBuilder(Action builder) + { + if (builder != null) { - if (builder != null) - { - SourceBuilder sb = this.AppendNewBuilder(); - builder(sb); - } - return this; + SourceBuilder sb = this.AppendNewBuilder(); + builder(sb); } + return this; + } - public override string ToString() + public override string ToString() + { + StringBuilder text = new(); + foreach (string alias in this.aliases.OrderByDescending(i => i)) { - StringBuilder text = new(); - foreach (string alias in this.aliases.OrderByDescending(i => i)) - { - text.Append("extern alias "); - text.Append(alias); - text.AppendLine(";"); - } - this.Write(text); - return text.ToString(); + text.Append("extern alias "); + text.Append(alias); + text.AppendLine(";"); } + this.Write(text); + return text.ToString(); + } - private void Write(StringBuilder builder) + private void Write(StringBuilder builder) + { + Dictionary? cache = null; + foreach (object? element in this.elements) { - Dictionary? cache = null; - foreach (object? element in this.elements) + if (element != null) { - if (element != null) + switch (element) { - switch (element) - { - default: throw new NotSupportedException(nameof(Write)); - case string text: - builder.Append(text); - break; - case char ch: - builder.Append(ch); - break; - case LineSeparatorMarker: - builder.Append(this.Options.NewLine); - break; - case IndentationMarker indentation: + default: throw new NotSupportedException(nameof(Write)); + case string text: + builder.Append(text); + break; + case char ch: + builder.Append(ch); + break; + case LineSeparatorMarker: + builder.Append(this.Options.NewLine); + break; + case IndentationMarker indentation: + { + if (cache == null) { - if (cache == null) - { - cache = new Dictionary(); - } - int depth = indentation.Depth; - if (cache.TryGetValue(depth, out string value) == false) + cache = new Dictionary(); + } + int depth = indentation.Depth; + if (cache.TryGetValue(depth, out string value) == false) + { + StringBuilder sb = new(); + for (int i = 0; i < depth; i++) { - StringBuilder sb = new(); - for (int i = 0; i < depth; i++) - { - sb.Append(this.Options.Identation); - } - cache[depth] = value = sb.ToString(); + sb.Append(this.Options.Identation); } - builder.Append(value); - break; + cache[depth] = value = sb.ToString(); } - case FlexibleSpaceMarker: + builder.Append(value); + break; + } + case FlexibleSpaceMarker: + { + if (builder.Length > 0) { - if (builder.Length > 0) + char c = builder[builder.Length - 1]; + switch (c) { - char c = builder[builder.Length - 1]; - switch (c) - { - case ' ': - case '\t': - case '\r': - case '\n': - case '(': - case '[': - case '{': - case ')': - case ']': - case '}': - case ';': - break; - default: - builder.Append(' '); - break; - } + case ' ': + case '\t': + case '\r': + case '\n': + case '(': + case '[': + case '{': + case ')': + case ']': + case '}': + case ';': + break; + default: + builder.Append(' '); + break; } - - break; } - case SourceBuilder sb: - sb.Append(builder); + break; - } + } + case SourceBuilder sb: + sb.Append(builder); + break; } } } + } - private class LineSeparatorMarker - { - } + private class LineSeparatorMarker + { + } - private class IndentationMarker + private class IndentationMarker + { + public IndentationMarker(int depth) { - public IndentationMarker(int depth) - { - this.Depth = depth; - } - - public readonly int Depth; + this.Depth = depth; } - private class FlexibleSpaceMarker - { - } + public readonly int Depth; + } + + private class FlexibleSpaceMarker + { } } diff --git a/BeaKona.AutoInterfaceGenerator/SourceBuilderOptions.cs b/BeaKona.AutoInterfaceGenerator/SourceBuilderOptions.cs index 0a7a749..8e485ab 100644 --- a/BeaKona.AutoInterfaceGenerator/SourceBuilderOptions.cs +++ b/BeaKona.AutoInterfaceGenerator/SourceBuilderOptions.cs @@ -1,12 +1,9 @@ -using System; +namespace BeaKona.AutoInterfaceGenerator; -namespace BeaKona.AutoInterfaceGenerator +internal class SourceBuilderOptions { - internal class SourceBuilderOptions - { - public string Identation { get; set; } = " "; - public string NewLine { get; set; } = Environment.NewLine; + public string Identation { get; set; } = " "; + public string NewLine { get; set; } = Environment.NewLine; - public static SourceBuilderOptions Default { get; } = new SourceBuilderOptions(); - } + public static SourceBuilderOptions Default { get; } = new SourceBuilderOptions(); } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/EventModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/EventModel.cs index 7fb189a..d77868f 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/EventModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/EventModel.cs @@ -1,13 +1,10 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class EventModel : IEventModel { - internal class EventModel : IEventModel - { - public string? Name { get; set; } - public string? Type { get; set; } + public string? Name { get; set; } + public string? Type { get; set; } - public List Expressions { get; } = new List(); - public string? Expression => this.Expressions.Count > 0 ? this.Expressions[0] : null; - } + public List Expressions { get; } = new List(); + public string? Expression => this.Expressions.Count > 0 ? this.Expressions[0] : null; } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/IEventModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/IEventModel.cs index dd42093..ba0a50a 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/IEventModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/IEventModel.cs @@ -1,8 +1,7 @@ -namespace BeaKona.AutoInterfaceGenerator.Templates +namespace BeaKona.AutoInterfaceGenerator.Templates; + +internal interface IEventModel : ILocalExpressionModel { - internal interface IEventModel : ILocalExpressionModel - { - string? Name { get; set; } - string? Type { get; set; } - } + string? Name { get; set; } + string? Type { get; set; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/IIndexerModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/IIndexerModel.cs index 185dc4e..9c87383 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/IIndexerModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/IIndexerModel.cs @@ -1,8 +1,7 @@ -namespace BeaKona.AutoInterfaceGenerator.Templates +namespace BeaKona.AutoInterfaceGenerator.Templates; + +internal interface IIndexerModel : IPropertyModel { - internal interface IIndexerModel : IPropertyModel - { - string? ParametersDefinition { get; set; } - string? CallParameters { get; set; } - } + string? ParametersDefinition { get; set; } + string? CallParameters { get; set; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/ILocalExpressionModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/ILocalExpressionModel.cs index 52c7347..a3a8f18 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/ILocalExpressionModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/ILocalExpressionModel.cs @@ -1,10 +1,7 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal interface ILocalExpressionModel { - internal interface ILocalExpressionModel - { - List Expressions { get; } - string? Expression { get; } - } + List Expressions { get; } + string? Expression { get; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/ILocalPropertyExpressionModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/ILocalPropertyExpressionModel.cs index 3608e5a..a3752f6 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/ILocalPropertyExpressionModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/ILocalPropertyExpressionModel.cs @@ -1,13 +1,10 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal interface ILocalPropertyExpressionModel : ILocalExpressionModel { - internal interface ILocalPropertyExpressionModel : ILocalExpressionModel - { - List GetExpressions { get; } - string? GetExpression { get; } + List GetExpressions { get; } + string? GetExpression { get; } - List SetExpressions { get; } - string? SetExpression { get; } - } + List SetExpressions { get; } + string? SetExpression { get; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/IMethodModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/IMethodModel.cs index 73465c5..8210f9a 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/IMethodModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/IMethodModel.cs @@ -1,12 +1,11 @@ -namespace BeaKona.AutoInterfaceGenerator.Templates +namespace BeaKona.AutoInterfaceGenerator.Templates; + +internal interface IMethodModel : ILocalExpressionModel { - internal interface IMethodModel : ILocalExpressionModel - { - string? Name { get; set; } - string? ArgumentsDefinition { get; set; } - string? CallArguments { get; set; } - string? ReturnType { get; set; } - bool IsAsync { get; set; } - bool ReturnExpected { get; set; } - } + string? Name { get; set; } + string? ArgumentsDefinition { get; set; } + string? CallArguments { get; set; } + string? ReturnType { get; set; } + bool IsAsync { get; set; } + bool ReturnExpected { get; set; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/IPropertyModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/IPropertyModel.cs index 8552b3e..0012c13 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/IPropertyModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/IPropertyModel.cs @@ -1,10 +1,9 @@ -namespace BeaKona.AutoInterfaceGenerator.Templates +namespace BeaKona.AutoInterfaceGenerator.Templates; + +internal interface IPropertyModel : ILocalPropertyExpressionModel { - internal interface IPropertyModel : ILocalPropertyExpressionModel - { - string? Name { get; set; } - string? Type { get; set; } - bool HaveGetter { get; set; } - bool HaveSetter { get; set; } - } + string? Name { get; set; } + string? Type { get; set; } + bool HaveGetter { get; set; } + bool HaveSetter { get; set; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/IRootModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/IRootModel.cs index 3fc081b..4533c16 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/IRootModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/IRootModel.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal interface IRootModel { - internal interface IRootModel - { - string? Interface { get; set; } + string? Interface { get; set; } - List References { get; } - string? Reference { get; } - } + List References { get; } + string? Reference { get; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/IndexerModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/IndexerModel.cs index a027e27..8beaa92 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/IndexerModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/IndexerModel.cs @@ -1,8 +1,7 @@ -namespace BeaKona.AutoInterfaceGenerator.Templates +namespace BeaKona.AutoInterfaceGenerator.Templates; + +internal class IndexerModel : PropertyModel, IIndexerModel { - internal class IndexerModel : PropertyModel, IIndexerModel - { - public string? ParametersDefinition { get; set; } - public string? CallParameters { get; set; } - } + public string? ParametersDefinition { get; set; } + public string? CallParameters { get; set; } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/MethodModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/MethodModel.cs index ddfe95d..9760662 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/MethodModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/MethodModel.cs @@ -1,17 +1,14 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class MethodModel : IMethodModel { - internal class MethodModel : IMethodModel - { - public string? Name { get; set; } - public string? ArgumentsDefinition { get; set; } - public string? CallArguments { get; set; } - public string? ReturnType { get; set; } - public bool IsAsync { get; set; } - public bool ReturnExpected { get; set; } + public string? Name { get; set; } + public string? ArgumentsDefinition { get; set; } + public string? CallArguments { get; set; } + public string? ReturnType { get; set; } + public bool IsAsync { get; set; } + public bool ReturnExpected { get; set; } - public List Expressions { get; } = new List(); - public string? Expression => this.Expressions.Count > 0 ? this.Expressions[0] : null; - } + public List Expressions { get; } = new List(); + public string? Expression => this.Expressions.Count > 0 ? this.Expressions[0] : null; } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/ModelLoader.cs b/BeaKona.AutoInterfaceGenerator/Templates/ModelLoader.cs index f299fd2..8d37d52 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/ModelLoader.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/ModelLoader.cs @@ -1,173 +1,168 @@ -using Microsoft.CodeAnalysis; -using System.Collections.Generic; -using System.Linq; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal static class ModelLoader { - internal static class ModelLoader + public static void Load(this IMethodModel @this, ICodeTextWriter writer, SourceBuilder builder, IMethodSymbol method, ScopeInfo scope, IEnumerable references) { - public static void Load(this IMethodModel @this, ICodeTextWriter writer, SourceBuilder builder, IMethodSymbol method, ScopeInfo scope, IEnumerable references) + var methodScope = new ScopeInfo(scope); + + if (method.IsGenericMethod) { - ScopeInfo methodScope = new ScopeInfo(scope); + methodScope.CreateAliases(method.TypeArguments); + } + + (bool isAsync, bool methodReturnsValue) = SemanticFacts.IsAsyncAndGetReturnType(writer.Compilation, method); + bool canUseAsync = true; + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteIdentifier(builder2, method); if (method.IsGenericMethod) { - methodScope.CreateAliases(method.TypeArguments); + builder2.Append('<'); + writer.WriteTypeArgumentsCall(builder2, method.TypeArguments, methodScope); + builder2.Append('>'); } + @this.Name = builder2.ToString(); + } - (bool isAsync, bool methodReturnsValue) = SemanticFacts.IsAsyncAndGetReturnType(writer.Compilation, method); - bool canUseAsync = true; + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteTypeReference(builder2, method.ReturnType, methodScope); + @this.ReturnType = builder2.ToString(); + } - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteIdentifier(builder2, method); - if (method.IsGenericMethod) - { - builder2.Append('<'); - writer.WriteTypeArgumentsCall(builder2, method.TypeArguments, methodScope); - builder2.Append('>'); - } - @this.Name = builder2.ToString(); - } + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteParameterDefinition(builder2, methodScope, method.Parameters); + @this.ArgumentsDefinition = builder2.ToString(); + } - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteTypeReference(builder2, method.ReturnType, methodScope); - @this.ReturnType = builder2.ToString(); - } + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteCallParameters(builder2, method.Parameters); + @this.CallArguments = builder2.ToString(); + } - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteParameterDefinition(builder2, methodScope, method.Parameters); - @this.ArgumentsDefinition = builder2.ToString(); - } + @this.IsAsync = isAsync && canUseAsync; + @this.ReturnExpected = (isAsync && methodReturnsValue == false) ? canUseAsync == false : methodReturnsValue; + foreach (IMemberInfo reference in references) + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + if (isAsync && canUseAsync) { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteCallParameters(builder2, method.Parameters); - @this.CallArguments = builder2.ToString(); + writer.WriteMethodCall(builder2, reference, method, methodScope, false, false, false); } - - @this.IsAsync = isAsync && canUseAsync; - @this.ReturnExpected = (isAsync && methodReturnsValue == false) ? canUseAsync == false : methodReturnsValue; - - foreach (IMemberInfo reference in references) + else { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - if (isAsync && canUseAsync) - { - writer.WriteMethodCall(builder2, reference, method, methodScope, false, false, false); - } - else - { - writer.WriteMethodCall(builder2, reference, method, methodScope, false, SemanticFacts.IsNullable(writer.Compilation, method.ReturnType), true); - } - @this.Expressions.Add(builder2.ToString()); + writer.WriteMethodCall(builder2, reference, method, methodScope, false, SemanticFacts.IsNullable(writer.Compilation, method.ReturnType), true); } + @this.Expressions.Add(builder2.ToString()); } + } - public static void Load(this IPropertyModel @this, ICodeTextWriter writer, SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, IEnumerable references) + public static void Load(this IPropertyModel @this, ICodeTextWriter writer, SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, IEnumerable references) + { { - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteIdentifier(builder2, property); - @this.Name = builder2.ToString(); - } - - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteTypeReference(builder2, property.Type, scope); - @this.Type = builder2.ToString(); - } + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteIdentifier(builder2, property); + @this.Name = builder2.ToString(); + } - @this.HaveGetter = property.GetMethod != null; - @this.HaveSetter = property.SetMethod != null; + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteTypeReference(builder2, property.Type, scope); + @this.Type = builder2.ToString(); + } - foreach (IMemberInfo reference in references) - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WritePropertyCall(builder2, reference, property, scope, SemanticFacts.IsNullable(writer.Compilation, property.Type), false); - @this.Expressions.Add(builder2.ToString()); - } + @this.HaveGetter = property.GetMethod != null; + @this.HaveSetter = property.SetMethod != null; - if (@this is ILocalPropertyExpressionModel this2) - { - this2.Load(writer, builder, property, scope, references); - } + foreach (IMemberInfo reference in references) + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WritePropertyCall(builder2, reference, property, scope, SemanticFacts.IsNullable(writer.Compilation, property.Type), false); + @this.Expressions.Add(builder2.ToString()); } - public static void Load(this ILocalPropertyExpressionModel @this, ICodeTextWriter writer, SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, IEnumerable references) + if (@this is ILocalPropertyExpressionModel this2) { - foreach (IMemberInfo reference in references) - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WritePropertyCall(builder2, reference, property, scope, SemanticFacts.IsNullable(writer.Compilation, property.Type), true); - @this.GetExpressions.Add(builder2.ToString()); - } + this2.Load(writer, builder, property, scope, references); + } + } - foreach (IMemberInfo reference in references) - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WritePropertyCall(builder2, reference, property, scope, false, false); - @this.SetExpressions.Add(builder2.ToString()); - } + public static void Load(this ILocalPropertyExpressionModel @this, ICodeTextWriter writer, SourceBuilder builder, IPropertySymbol property, ScopeInfo scope, IEnumerable references) + { + foreach (IMemberInfo reference in references) + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WritePropertyCall(builder2, reference, property, scope, SemanticFacts.IsNullable(writer.Compilation, property.Type), true); + @this.GetExpressions.Add(builder2.ToString()); } - public static void Load(this IIndexerModel @this, ICodeTextWriter writer, SourceBuilder builder, IPropertySymbol indexer, ScopeInfo scope, IEnumerable references) + foreach (IMemberInfo reference in references) { - (@this as IPropertyModel).Load(writer, builder, indexer, scope, references); + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WritePropertyCall(builder2, reference, property, scope, false, false); + @this.SetExpressions.Add(builder2.ToString()); + } + } - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteParameterDefinition(builder2, scope, indexer.Parameters); - @this.ParametersDefinition = builder2.ToString(); - } + public static void Load(this IIndexerModel @this, ICodeTextWriter writer, SourceBuilder builder, IPropertySymbol indexer, ScopeInfo scope, IEnumerable references) + { + (@this as IPropertyModel).Load(writer, builder, indexer, scope, references); - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteCallParameters(builder2, indexer.Parameters); - @this.CallParameters = builder2.ToString(); - } + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteParameterDefinition(builder2, scope, indexer.Parameters); + @this.ParametersDefinition = builder2.ToString(); } - public static void Load(this IEventModel @this, ICodeTextWriter writer, SourceBuilder builder, IEventSymbol @event, ScopeInfo scope, IEnumerable references) { - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteIdentifier(builder2, @event); - @this.Name = builder2.ToString(); - } + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteCallParameters(builder2, indexer.Parameters); + @this.CallParameters = builder2.ToString(); + } + } - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteTypeReference(builder2, @event.Type, scope); - @this.Type = builder2.ToString(); - } + public static void Load(this IEventModel @this, ICodeTextWriter writer, SourceBuilder builder, IEventSymbol @event, ScopeInfo scope, IEnumerable references) + { + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteIdentifier(builder2, @event); + @this.Name = builder2.ToString(); + } - foreach (IMemberInfo reference in references) - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteMemberReference(builder2, reference, scope, false, false); - builder2.Append('.'); - writer.WriteIdentifier(builder2, @event); - @this.Expressions.Add(builder2.ToString()); - } + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteTypeReference(builder2, @event.Type, scope); + @this.Type = builder2.ToString(); } - public static void Load(this IRootModel @this, ICodeTextWriter writer, SourceBuilder builder, INamedTypeSymbol @interface, ScopeInfo scope, IEnumerable references) + foreach (IMemberInfo reference in references) { - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteTypeReference(builder2, @interface, scope); - @this.Interface = builder2.ToString(); - } + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteMemberReference(builder2, reference, scope, false, false); + builder2.Append('.'); + writer.WriteIdentifier(builder2, @event); + @this.Expressions.Add(builder2.ToString()); + } + } - @this.References.AddRange(references.Select(delegate (IMemberInfo member) - { - SourceBuilder builder2 = builder.AppendNewBuilder(false); - writer.WriteIdentifier(builder2, member.Member); - return builder2.ToString(); - })); + public static void Load(this IRootModel @this, ICodeTextWriter writer, SourceBuilder builder, INamedTypeSymbol @interface, ScopeInfo scope, IEnumerable references) + { + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteTypeReference(builder2, @interface, scope); + @this.Interface = builder2.ToString(); } + + @this.References.AddRange(references.Select(delegate (IMemberInfo member) + { + SourceBuilder builder2 = builder.AppendNewBuilder(false); + writer.WriteIdentifier(builder2, member.Member); + return builder2.ToString(); + })); } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/PartialEventModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/PartialEventModel.cs index df54f60..6ef4b19 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/PartialEventModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/PartialEventModel.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class PartialEventModel : EventModel, IRootModel { - internal class PartialEventModel : EventModel, IRootModel - { - public string? Interface { get; set; } + public string? Interface { get; set; } - public List References { get; } = new List(); - public string? Reference => this.References.Count > 0 ? this.References[0] : null; - } + public List References { get; } = new List(); + public string? Reference => this.References.Count > 0 ? this.References[0] : null; } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/PartialIndexerModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/PartialIndexerModel.cs index a1bc701..519ad75 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/PartialIndexerModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/PartialIndexerModel.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class PartialIndexerModel : IndexerModel, IRootModel { - internal class PartialIndexerModel : IndexerModel, IRootModel - { - public string? Interface { get; set; } + public string? Interface { get; set; } - public List References { get; } = new List(); - public string? Reference => this.References.Count > 0 ? this.References[0] : null; - } + public List References { get; } = new List(); + public string? Reference => this.References.Count > 0 ? this.References[0] : null; } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/PartialMethodModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/PartialMethodModel.cs index 3718b49..1b04fbe 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/PartialMethodModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/PartialMethodModel.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class PartialMethodModel : MethodModel, IRootModel { - internal class PartialMethodModel : MethodModel, IRootModel - { - public string? Interface { get; set; } + public string? Interface { get; set; } - public List References { get; } = new List(); - public string? Reference => this.References.Count > 0 ? this.References[0] : null; - } + public List References { get; } = new List(); + public string? Reference => this.References.Count > 0 ? this.References[0] : null; } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/PartialPropertyModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/PartialPropertyModel.cs index 961c246..e009d85 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/PartialPropertyModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/PartialPropertyModel.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class PartialPropertyModel : PropertyModel, IRootModel { - internal class PartialPropertyModel : PropertyModel, IRootModel - { - public string? Interface { get; set; } + public string? Interface { get; set; } - public List References { get; } = new List(); - public string? Reference => this.References.Count > 0 ? this.References[0] : null; - } + public List References { get; } = new List(); + public string? Reference => this.References.Count > 0 ? this.References[0] : null; } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/PartialTemplate.cs b/BeaKona.AutoInterfaceGenerator/Templates/PartialTemplate.cs index aea43dc..5e00428 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/PartialTemplate.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/PartialTemplate.cs @@ -1,65 +1,61 @@ -using Microsoft.CodeAnalysis; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; -namespace BeaKona.AutoInterfaceGenerator.Templates +namespace BeaKona.AutoInterfaceGenerator.Templates; + +internal class PartialTemplate { - internal class PartialTemplate + public PartialTemplate(AutoInterfaceTargets memberTargets, Regex? memberFilter, TemplateDefinition template) { - public PartialTemplate(AutoInterfaceTargets memberTargets, Regex? memberFilter, TemplateDefinition template) - { - this.MemberTargets = memberTargets; - this.MemberFilter = memberFilter; - this.Template = template; - } + this.MemberTargets = memberTargets; + this.MemberFilter = memberFilter; + this.Template = template; + } - public AutoInterfaceTargets MemberTargets; - public Regex? MemberFilter; - public TemplateDefinition Template; + public AutoInterfaceTargets MemberTargets; + public Regex? MemberFilter; + public TemplateDefinition Template; - public bool FilterMatch(string name) => this.MemberFilter == null || this.MemberFilter.IsMatch(name); + public bool FilterMatch(string name) => this.MemberFilter == null || this.MemberFilter.IsMatch(name); - public static PartialTemplate? PickTemplate(GeneratorExecutionContext context, IEnumerable<(PartialTemplate template, ISymbol reference)> templates, string name) - { - (PartialTemplate template, ISymbol reference)[] ts = templates.ToArray(); + public static PartialTemplate? PickTemplate(GeneratorExecutionContext context, IEnumerable<(PartialTemplate template, ISymbol reference)> templates, string name) + { + (PartialTemplate template, ISymbol reference)[] ts = templates.ToArray(); - switch (ts.Length) - { - case 0: return null; - case 1: return ts[0].template; - case 2: - if (ts[0].template.MemberFilter != null) + switch (ts.Length) + { + case 0: return null; + case 1: return ts[0].template; + case 2: + if (ts[0].template.MemberFilter != null) + { + if (ts[1].template.MemberFilter != null) + { + Helpers.ReportDiagnostic(context, "BK-AG16", nameof(AutoInterfaceResource.AG16_title), nameof(AutoInterfaceResource.AG16_message), nameof(AutoInterfaceResource.AG16_description), DiagnosticSeverity.Error, ts[0].reference, + name); + return null; + } + else + { + return ts[0].template; + } + } + else + { + if (ts[1].template.MemberFilter != null) { - if (ts[1].template.MemberFilter != null) - { - Helpers.ReportDiagnostic(context, "BK-AG16", nameof(AutoInterfaceResource.AG16_title), nameof(AutoInterfaceResource.AG16_message), nameof(AutoInterfaceResource.AG16_description), DiagnosticSeverity.Error, ts[0].reference, - name); - return null; - } - else - { - return ts[0].template; - } + return ts[1].template; } else { - if (ts[1].template.MemberFilter != null) - { - return ts[1].template; - } - else - { - Helpers.ReportDiagnostic(context, "BK-AG16", nameof(AutoInterfaceResource.AG16_title), nameof(AutoInterfaceResource.AG16_message), nameof(AutoInterfaceResource.AG16_description), DiagnosticSeverity.Error, ts[0].reference, - name); - return null; - } + Helpers.ReportDiagnostic(context, "BK-AG16", nameof(AutoInterfaceResource.AG16_title), nameof(AutoInterfaceResource.AG16_message), nameof(AutoInterfaceResource.AG16_description), DiagnosticSeverity.Error, ts[0].reference, + name); + return null; } - default: - Helpers.ReportDiagnostic(context, "BK-AG16", nameof(AutoInterfaceResource.AG16_title), nameof(AutoInterfaceResource.AG16_message), nameof(AutoInterfaceResource.AG16_description), DiagnosticSeverity.Error, ts[0].reference, - name); - return null; - } + } + default: + Helpers.ReportDiagnostic(context, "BK-AG16", nameof(AutoInterfaceResource.AG16_title), nameof(AutoInterfaceResource.AG16_message), nameof(AutoInterfaceResource.AG16_description), DiagnosticSeverity.Error, ts[0].reference, + name); + return null; } } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/PropertyModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/PropertyModel.cs index fe2f27d..4d2e952 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/PropertyModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/PropertyModel.cs @@ -1,21 +1,18 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class PropertyModel : IPropertyModel { - internal class PropertyModel : IPropertyModel - { - public string? Name { get; set; } - public string? Type { get; set; } - public bool HaveGetter { get; set; } - public bool HaveSetter { get; set; } + public string? Name { get; set; } + public string? Type { get; set; } + public bool HaveGetter { get; set; } + public bool HaveSetter { get; set; } - public List Expressions { get; } = new List(); - public string? Expression => this.Expressions.Count > 0 ? this.Expressions[0] : null; + public List Expressions { get; } = new List(); + public string? Expression => this.Expressions.Count > 0 ? this.Expressions[0] : null; - public List GetExpressions { get; } = new List(); - public string? GetExpression => this.GetExpressions.Count > 0 ? this.GetExpressions[0] : null; + public List GetExpressions { get; } = new List(); + public string? GetExpression => this.GetExpressions.Count > 0 ? this.GetExpressions[0] : null; - public List SetExpressions { get; } = new List(); - public string? SetExpression => this.SetExpressions.Count > 0 ? this.SetExpressions[0] : null; - } + public List SetExpressions { get; } = new List(); + public string? SetExpression => this.SetExpressions.Count > 0 ? this.SetExpressions[0] : null; } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/StandaloneModel.cs b/BeaKona.AutoInterfaceGenerator/Templates/StandaloneModel.cs index dec0344..86ae308 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/StandaloneModel.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/StandaloneModel.cs @@ -1,17 +1,14 @@ -using System.Collections.Generic; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class StandaloneModel : IRootModel { - internal class StandaloneModel : IRootModel - { - public string? Interface { get; set; } + public string? Interface { get; set; } - public List References { get; } = new List(); - public string? Reference => this.References.Count > 0 ? this.References[0] : null; + public List References { get; } = new List(); + public string? Reference => this.References.Count > 0 ? this.References[0] : null; - public List Methods { get; } = new List(); - public List Properties { get; } = new List(); - public List Indexers { get; } = new List(); - public List Events { get; } = new List(); - } + public List Methods { get; } = new List(); + public List Properties { get; } = new List(); + public List Indexers { get; } = new List(); + public List Events { get; } = new List(); } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/TemplateDefinition.cs b/BeaKona.AutoInterfaceGenerator/Templates/TemplateDefinition.cs index e7e8ff4..5615493 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/TemplateDefinition.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/TemplateDefinition.cs @@ -1,58 +1,55 @@ -using System; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class TemplateDefinition : IEquatable { - internal class TemplateDefinition : IEquatable + public TemplateDefinition(string language, string body) { - public TemplateDefinition(string language, string body) - { - this.Language = language ?? ""; - this.Body = body ?? ""; - } + this.Language = language ?? ""; + this.Body = body ?? ""; + } - public string Language { get; } - public string Body { get; } + public string Language { get; } + public string Body { get; } - public bool Equals(TemplateDefinition other) + public bool Equals(TemplateDefinition other) + { + if (other == null) { - if (other == null) - { - return false; - } - - if (this == other) - { - return true; - } - - if (this.Language != other.Language) - { - return false; - } - - if (this.Body != other.Body) - { - return false; - } + return false; + } + if (this == other) + { return true; } - public override bool Equals(object obj) + if (this.Language != other.Language) { - if (obj is TemplateDefinition o) - { - return this.Equals(o); - } - else - { - return false; - } + return false; } - public override int GetHashCode() + if (this.Body != other.Body) { - return this.GetType().GetHashCode() + this.Language.GetHashCode() + this.Body.GetHashCode(); + return false; } + + return true; + } + + public override bool Equals(object obj) + { + if (obj is TemplateDefinition o) + { + return this.Equals(o); + } + else + { + return false; + } + } + + public override int GetHashCode() + { + return this.GetType().GetHashCode() + this.Language.GetHashCode() + this.Body.GetHashCode(); } } diff --git a/BeaKona.AutoInterfaceGenerator/Templates/TemplatedSourceGenerator.cs b/BeaKona.AutoInterfaceGenerator/Templates/TemplatedSourceGenerator.cs index e115847..fbe44a2 100644 --- a/BeaKona.AutoInterfaceGenerator/Templates/TemplatedSourceGenerator.cs +++ b/BeaKona.AutoInterfaceGenerator/Templates/TemplatedSourceGenerator.cs @@ -1,55 +1,51 @@ -using System; -using System.Linq; +namespace BeaKona.AutoInterfaceGenerator.Templates; -namespace BeaKona.AutoInterfaceGenerator.Templates +internal class TemplatedSourceTextGenerator : ISourceTextGenerator { - internal class TemplatedSourceTextGenerator : ISourceTextGenerator + public TemplatedSourceTextGenerator(TemplateDefinition template) { - public TemplatedSourceTextGenerator(TemplateDefinition template) + this.Template = template; + } + + public TemplateDefinition Template { get; } + + public void Emit(ICodeTextWriter writer, SourceBuilder builder, object? model, ref bool separatorRequired) + { + Scriban.Template? template = (this.Template.Language ?? "").ToLowerInvariant() switch { - this.Template = template; + "scriban" => Scriban.Template.Parse(this.Template.Body), + "liquid" => Scriban.Template.ParseLiquid(this.Template.Body), + _ => null, + }; + + if (template == null) + { + throw new NotSupportedException($"Template language '{this.Template.Language}' is not supported."); } - public TemplateDefinition Template { get; } + string text = template.Render(model); + + string[] lines = text.Split(new string[] { "\r\n", "\n\r", "\n", "\r" }, StringSplitOptions.None); - public void Emit(ICodeTextWriter writer, SourceBuilder builder, object? model, ref bool separatorRequired) + static bool HasNoContent(string line) => line.Trim().Length <= 0; + + foreach (string line in lines.SkipWhile(HasNoContent).Reverse().SkipWhile(HasNoContent).Reverse()) { - Scriban.Template? template = (this.Template.Language ?? "").ToLowerInvariant() switch + if (separatorRequired) { - "scriban" => Scriban.Template.Parse(this.Template.Body), - "liquid" => Scriban.Template.ParseLiquid(this.Template.Body), - _ => null, - }; + builder.AppendLine(); + separatorRequired = false; + } - if (template == null) + if (line.Trim().Length > 0) { - throw new NotSupportedException($"Template language '{this.Template.Language}' is not supported."); + builder.AppendIndentation(); + builder.Append(line.TrimEnd()); + separatorRequired = true; } - - string text = template.Render(model); - - string[] lines = text.Split(new string[] { "\r\n", "\n\r", "\n", "\r" }, StringSplitOptions.None); - - static bool HasNoContent(string line) => line.Trim().Length <= 0; - - foreach (string line in lines.SkipWhile(HasNoContent).Reverse().SkipWhile(HasNoContent).Reverse()) + else { - if (separatorRequired) - { - builder.AppendLine(); - separatorRequired = false; - } - - if (line.Trim().Length > 0) - { - builder.AppendIndentation(); - builder.Append(line.TrimEnd()); - separatorRequired = true; - } - else - { - separatorRequired = true; - } + separatorRequired = true; } } } diff --git a/BeaKona.AutoInterfaceGeneratorTest/BeaKona.AutoInterfaceGeneratorTest.csproj b/BeaKona.AutoInterfaceGeneratorTest/BeaKona.AutoInterfaceGeneratorTest.csproj deleted file mode 100644 index 6cc1321..0000000 --- a/BeaKona.AutoInterfaceGeneratorTest/BeaKona.AutoInterfaceGeneratorTest.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - net5.0 - false - enable - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/BeaKona.AutoInterfaceGeneratorTest/GeneratorTests.cs b/BeaKona.AutoInterfaceGeneratorTest/GeneratorTests.cs deleted file mode 100644 index 64d8c0b..0000000 --- a/BeaKona.AutoInterfaceGeneratorTest/GeneratorTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -using BeaKona.AutoInterfaceGenerator; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection; -using Xunit; - -namespace BeaKona.AutoInterfaceGeneratorTest -{ - public class GeneratorTests - { - [Fact] - public void SimpleGeneratorTest() - { - string source = @" -namespace MyTest -{ - public class Program - { - public static void Main() - { - //dummy... for now - } - } -} -"; - - Compilation comp = CreateCompilation(source); - Compilation newComp = RunGenerators(comp, out ImmutableArray generatorDiags, new AutoInterfaceSourceGenerator()); - IEnumerable generatedTrees = newComp.RemoveSyntaxTrees(comp.SyntaxTrees).SyntaxTrees; - - Assert.Single(generatedTrees); - Assert.Empty(generatorDiags); - Assert.Empty(newComp.GetDiagnostics()); - } - - private static Compilation CreateCompilation(string source, OutputKind outputKind = OutputKind.ConsoleApplication) - => CSharpCompilation.Create("compilation", - new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)) }, - new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) }, - new CSharpCompilationOptions(outputKind)); - - private static GeneratorDriver CreateDriver(Compilation c, params ISourceGenerator[] generators) => CSharpGeneratorDriver.Create(generators, parseOptions: (CSharpParseOptions)c.SyntaxTrees.First().Options); - - private static Compilation RunGenerators(Compilation c, out ImmutableArray diagnostics, params ISourceGenerator[] generators) - { - CreateDriver(c, generators).RunGeneratorsAndUpdateCompilation(c, out Compilation? d, out diagnostics); - return d; - } - } -} \ No newline at end of file diff --git a/TestInterfaces/Interfaces.cs b/TestInterfaces/Interfaces.cs index 03487ba..8f36d5e 100644 --- a/TestInterfaces/Interfaces.cs +++ b/TestInterfaces/Interfaces.cs @@ -1,6 +1,4 @@ -using System; - -namespace TestInterfaces.A.B +namespace TestInterfaces.A.B { public interface ITestable { diff --git a/TestInterfaces/TestInterfaces.csproj b/TestInterfaces/TestInterfaces.csproj index f208d30..dbc1517 100644 --- a/TestInterfaces/TestInterfaces.csproj +++ b/TestInterfaces/TestInterfaces.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0