From 4df35482cb85c1df95ce93021a9eb5eaed50f158 Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Fri, 17 May 2024 17:35:48 +0200 Subject: [PATCH 1/4] split generated code into multiple files --- .../src/BindingSourceGen/BindingCodeWriter.cs | 68 ++-- .../BindingSourceGenerator.cs | 8 +- .../AssertExtensions.cs | 2 + .../BindingCodeWriterTests.cs | 78 +++-- .../IntegrationTests.cs | 306 ++---------------- .../SourceGenHelpers.cs | 4 +- 6 files changed, 112 insertions(+), 354 deletions(-) diff --git a/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs b/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs index a17f20c1f467..67935288b40b 100644 --- a/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs +++ b/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs @@ -3,21 +3,11 @@ namespace Microsoft.Maui.Controls.BindingSourceGen; -public sealed class BindingCodeWriter +public static class BindingCodeWriter { public static string GeneratedCodeAttribute => $"[GeneratedCodeAttribute(\"{typeof(BindingCodeWriter).Assembly.FullName}\", \"{typeof(BindingCodeWriter).Assembly.GetName().Version}\")]"; - public string GenerateCode() - { - if (_bindings.Count == 0) - { - return string.Empty; - } - - return DoGenerateCode(); - } - - private string DoGenerateCode() => $$""" + public static string GenerateCommonCode() => $$""" //------------------------------------------------------------------------------ // // This code was generated by a .NET MAUI source generator. @@ -35,7 +25,7 @@ namespace System.Runtime.CompilerServices {{GeneratedCodeAttribute}} [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute + internal sealed class InterceptsLocationAttribute : Attribute { public InterceptsLocationAttribute(string filePath, int line, int column) { @@ -52,16 +42,11 @@ public InterceptsLocationAttribute(string filePath, int line, int column) namespace Microsoft.Maui.Controls.Generated { - using System; using System.CodeDom.Compiler; - using System.Runtime.CompilerServices; - using Microsoft.Maui.Controls.Internals; {{GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { - {{GenerateBindingMethods(indent: 2)}} - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) => mode == BindingMode.OneWayToSource || mode == BindingMode.TwoWay @@ -72,27 +57,48 @@ private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableP } """; - private readonly List _bindings = new(); + private static string GenerateBindingCode(string bindingMethodBody) => $$""" + //------------------------------------------------------------------------------ + // + // This code was generated by a .NET MAUI source generator. + // + // Changes to this file may cause incorrect behavior and will be lost if + // the code is regenerated. + // + //------------------------------------------------------------------------------ + #nullable enable - public void AddBinding(SetBindingInvocationDescription binding) + namespace Microsoft.Maui.Controls.Generated + { + using System; + using System.CodeDom.Compiler; + using System.Runtime.CompilerServices; + using Microsoft.Maui.Controls.Internals; + + internal static partial class GeneratedBindableObjectExtensions + { + {{bindingMethodBody}} + } + } + """; + + + public static string GenerateBinding(SetBindingInvocationDescription binding, int id) { if (!binding.NullableContextEnabled) { var referenceTypesConditionalAccessTransformer = new ReferenceTypesConditionalAccessTransformer(); binding = referenceTypesConditionalAccessTransformer.Transform(binding); } - _bindings.Add(binding); + + var bindingMethod = GenerateBindingMethod(binding, id); + return GenerateBindingCode(bindingMethod); } - private string GenerateBindingMethods(int indent) + private static string GenerateBindingMethod(SetBindingInvocationDescription binding, int id) { - using var builder = new BindingInterceptorCodeBuilder(indent); - - for (int i = 0; i < _bindings.Count; i++) - { - builder.AppendSetBindingInterceptor(id: i + 1, _bindings[i]); - } - + using var builder = new BindingInterceptorCodeBuilder(indent: 2); + builder.AppendSetBindingInterceptor(id: id, binding: binding); return builder.ToString(); } @@ -115,8 +121,6 @@ public BindingInterceptorCodeBuilder(int indent = 0) public void AppendSetBindingInterceptor(int id, SetBindingInvocationDescription binding) { - AppendBlankLine(); - AppendLine(GeneratedCodeAttribute); AppendInterceptorAttribute(binding.Location); Append($"public static void SetBinding{id}"); diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index e74718a0c195..ac251281aaf0 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -33,14 +33,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterSourceOutput(bindings, (spc, bindings) => { - var codeWriter = new BindingCodeWriter(); + spc.AddSource("GeneratedBindableObjectExtensionsCommon.g.cs", BindingCodeWriter.GenerateCommonCode()); - foreach (var binding in bindings) + for (int i = 0; i < bindings.Length; i++) { - codeWriter.AddBinding(binding); + spc.AddSource($"GeneratedBindableObjectExtensions{i+1}.g.cs", BindingCodeWriter.GenerateBinding(bindings[i], i + 1)); } - - spc.AddSource("GeneratedBindableObjectExtensions.g.cs", codeWriter.GenerateCode()); }); } diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/AssertExtensions.cs b/src/Controls/tests/BindingSourceGen.UnitTests/AssertExtensions.cs index 0bf594dffdd5..98be295c91fa 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/AssertExtensions.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/AssertExtensions.cs @@ -16,6 +16,8 @@ internal static void CodeIsEqual(string expectedCode, string actualCode) { Assert.Equal(expectedLine, actualLine); } + + Assert.Equal(expectedLines.Count(), actualLines.Count()); } internal static void BindingsAreEqual(SetBindingInvocationDescription expectedBinding, CodeGeneratorResult codeGeneratorResult) diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/BindingCodeWriterTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/BindingCodeWriterTests.cs index 328113c184ee..2940cc163727 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/BindingCodeWriterTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/BindingCodeWriterTests.cs @@ -7,22 +7,9 @@ namespace BindingSourceGen.UnitTests; public class BindingCodeWriterTests { [Fact] - public void BuildsWholeDocument() + public void BuildsCommonCode() { - var codeWriter = new BindingCodeWriter(); - codeWriter.AddBinding(new SetBindingInvocationDescription( - Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30), - SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsValueType: false, IsNullable: false, IsGenericParameter: false), - PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsValueType: false, IsNullable: false, IsGenericParameter: false), - Path: new EquatableArray([ - new MemberAccess("A"), - new ConditionalAccess(new MemberAccess("B")), - new ConditionalAccess(new MemberAccess("C")), - ]), - SetterOptions: new(IsWritable: true, AcceptsNullValue: false), - NullableContextEnabled: true)); - - var code = codeWriter.GenerateCode(); + var code = BindingCodeWriter.GenerateCommonCode(); AssertExtensions.CodeIsEqual( $$""" //------------------------------------------------------------------------------ @@ -42,7 +29,7 @@ namespace System.Runtime.CompilerServices {{BindingCodeWriter.GeneratedCodeAttribute}} [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute + internal sealed class InterceptsLocationAttribute : Attribute { public InterceptsLocationAttribute(string filePath, int line, int column) { @@ -50,13 +37,59 @@ public InterceptsLocationAttribute(string filePath, int line, int column) Line = line; Column = column; } - + public string FilePath { get; } public int Line { get; } public int Column { get; } } } + namespace Microsoft.Maui.Controls.Generated + { + using System.CodeDom.Compiler; + + {{BindingCodeWriter.GeneratedCodeAttribute}} + internal static partial class GeneratedBindableObjectExtensions + { + private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) + => mode == BindingMode.OneWayToSource + || mode == BindingMode.TwoWay + || (mode == BindingMode.Default + && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource + || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); + } + } + """, + code); + } + + [Fact] + public void BuildsWholeBinding() + { + var code = BindingCodeWriter.GenerateBinding(new SetBindingInvocationDescription( + Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30), + SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsValueType: false, IsNullable: false, IsGenericParameter: false), + PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsValueType: false, IsNullable: false, IsGenericParameter: false), + Path: new EquatableArray([ + new MemberAccess("A"), + new ConditionalAccess(new MemberAccess("B")), + new ConditionalAccess(new MemberAccess("C")), + ]), + SetterOptions: new(IsWritable: true, AcceptsNullValue: false), + NullableContextEnabled: true), id: 1); + + AssertExtensions.CodeIsEqual( + $$""" + //------------------------------------------------------------------------------ + // + // This code was generated by a .NET MAUI source generator. + // + // Changes to this file may cause incorrect behavior and will be lost if + // the code is regenerated. + // + //------------------------------------------------------------------------------ + #nullable enable + namespace Microsoft.Maui.Controls.Generated { using System; @@ -64,8 +97,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -115,13 +147,6 @@ public static void SetBinding1( }; bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, @@ -482,5 +507,4 @@ public static void SetBinding1( """, code); } - } diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs index a2a27e43765a..09b221ff2819 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs @@ -27,28 +27,6 @@ public void GenerateSimpleBinding() //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -56,8 +34,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -98,17 +75,10 @@ public static void SetBinding1( }; bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } [Fact] @@ -150,28 +120,6 @@ public class B //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -179,8 +127,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -229,17 +176,10 @@ public static void SetBinding1( }; bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } [Fact] @@ -282,28 +222,6 @@ public class B //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -311,8 +229,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -363,17 +280,10 @@ public static void SetBinding1( }; bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } public static IEnumerable GenerateSimpleBindingWhenNullableDisabledAndPropertyNullableData => @@ -519,28 +429,6 @@ public void GenerateSimpleBindingWhenNullableDisabledAndPropertyNullable(string //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -548,8 +436,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -598,17 +485,10 @@ public static void SetBinding1( }; bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } [Fact] @@ -665,28 +545,6 @@ public class D { //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -694,8 +552,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -745,17 +602,10 @@ public static void SetBinding1( }; bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } [Theory] @@ -812,28 +662,6 @@ public class MyPropertyClass //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -841,8 +669,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -899,17 +726,10 @@ public static void SetBinding1( bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } [Fact] @@ -964,28 +784,6 @@ public class MyPropertyClass //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -993,8 +791,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -1047,17 +844,10 @@ public static void SetBinding1( bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } [Fact] @@ -1103,28 +893,6 @@ public class Wrapper //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -1132,8 +900,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 3, 7)] @@ -1178,17 +945,10 @@ public static void SetBinding1( bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } [Fact] @@ -1238,28 +998,6 @@ public class MyPropertyClass //------------------------------------------------------------------------------ #nullable enable - namespace System.Runtime.CompilerServices - { - using System; - using System.CodeDom.Compiler; - - {{BindingCodeWriter.GeneratedCodeAttribute}} - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - FilePath = filePath; - Line = line; - Column = column; - } - - public string FilePath { get; } - public int Line { get; } - public int Column { get; } - } - } - namespace Microsoft.Maui.Controls.Generated { using System; @@ -1267,8 +1005,7 @@ namespace Microsoft.Maui.Controls.Generated using System.Runtime.CompilerServices; using Microsoft.Maui.Controls.Internals; - {{BindingCodeWriter.GeneratedCodeAttribute}} - file static class GeneratedBindableObjectExtensions + internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} @@ -1323,16 +1060,9 @@ public static void SetBinding1( bindableObject.SetBinding(bindableProperty, binding); } - - private static bool ShouldUseSetter(BindingMode mode, BindableProperty bindableProperty) - => mode == BindingMode.OneWayToSource - || mode == BindingMode.TwoWay - || (mode == BindingMode.Default - && (bindableProperty.DefaultBindingMode == BindingMode.OneWayToSource - || bindableProperty.DefaultBindingMode == BindingMode.TwoWay)); } } """, - result.GeneratedCode); + result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); } } diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs b/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs index 45e37bdd9a11..939cbe01d09a 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs @@ -7,7 +7,7 @@ internal record CodeGeneratorResult( - string GeneratedCode, + Dictionary GeneratedFiles, ImmutableArray SourceCompilationDiagnostics, ImmutableArray SourceGeneratorDiagnostics, ImmutableArray GeneratedCodeCompilationDiagnostics, @@ -47,7 +47,7 @@ internal static CodeGeneratorResult Run(string source) : null; return new CodeGeneratorResult( - GeneratedCode: generatedCode, + GeneratedFiles: result.GeneratedSources.ToDictionary(source => source.HintName, source => source.SourceText.ToString()), SourceCompilationDiagnostics: inputCompilation.GetDiagnostics(), SourceGeneratorDiagnostics: result.Diagnostics, GeneratedCodeCompilationDiagnostics: generatedCodeDiagnostic, From c5d8eafe3e2e048912a0b15d2bed96f2782986b3 Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Wed, 22 May 2024 19:41:23 +0200 Subject: [PATCH 2/4] removed collect and added tests --- .../src/BindingSourceGen/BindingCodeWriter.cs | 6 +- .../BindingSourceGenerator.cs | 17 +-- .../BindingSourceGeneratorUtilities.cs | 14 ++- .../BindingSourceGen/GeneratorDataModels.cs | 2 +- .../IncrementalGenerationTests.cs | 113 ++++++++++++++---- .../IntegrationTests.cs | 36 +++--- .../SourceGenHelpers.cs | 4 +- 7 files changed, 137 insertions(+), 55 deletions(-) diff --git a/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs b/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs index 67935288b40b..d2c18f8334d7 100644 --- a/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs +++ b/src/Controls/src/BindingSourceGen/BindingCodeWriter.cs @@ -83,7 +83,7 @@ internal static partial class GeneratedBindableObjectExtensions """; - public static string GenerateBinding(SetBindingInvocationDescription binding, int id) + public static string GenerateBinding(SetBindingInvocationDescription binding, uint id) { if (!binding.NullableContextEnabled) { @@ -95,7 +95,7 @@ public static string GenerateBinding(SetBindingInvocationDescription binding, in return GenerateBindingCode(bindingMethod); } - private static string GenerateBindingMethod(SetBindingInvocationDescription binding, int id) + private static string GenerateBindingMethod(SetBindingInvocationDescription binding, uint id) { using var builder = new BindingInterceptorCodeBuilder(indent: 2); builder.AppendSetBindingInterceptor(id: id, binding: binding); @@ -119,7 +119,7 @@ public BindingInterceptorCodeBuilder(int indent = 0) _indentedTextWriter = new IndentedTextWriter(_stringWriter, "\t") { Indent = indent }; } - public void AppendSetBindingInterceptor(int id, SetBindingInvocationDescription binding) + public void AppendSetBindingInterceptor(uint id, SetBindingInvocationDescription binding) { AppendLine(GeneratedCodeAttribute); AppendInterceptorAttribute(binding.Location); diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index ac251281aaf0..fe845ca64ca7 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -27,18 +27,19 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var bindings = bindingsWithDiagnostics .Where(static binding => !binding.HasDiagnostics) .Select(static (binding, t) => binding.Value) - .WithTrackingName(TrackingNames.Bindings) - .Collect(); + .WithTrackingName(TrackingNames.Bindings); - - context.RegisterSourceOutput(bindings, (spc, bindings) => + + context.RegisterPostInitializationOutput(spc => { spc.AddSource("GeneratedBindableObjectExtensionsCommon.g.cs", BindingCodeWriter.GenerateCommonCode()); + }); - for (int i = 0; i < bindings.Length; i++) - { - spc.AddSource($"GeneratedBindableObjectExtensions{i+1}.g.cs", BindingCodeWriter.GenerateBinding(bindings[i], i + 1)); - } + context.RegisterSourceOutput(bindings, (spc, binding) => + { + + var fileName = $"{binding.Location.FilePath}/GeneratedBindableObjectExtensions-{binding.Location.Line}-{binding.Location.Column}.g.cs"; + spc.AddSource(fileName, BindingCodeWriter.GenerateBinding(binding, BindingGenerationUtilities.ComputeSha256Hash(fileName))); }); } diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs b/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs index 9ddcbf865fa3..977ae9aaeb07 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs @@ -1,8 +1,10 @@ +using System.Security.Cryptography; +using System.Text; using Microsoft.CodeAnalysis; namespace Microsoft.Maui.Controls.BindingSourceGen; -internal static class BindingGenerationUtilities +public static class BindingGenerationUtilities { internal static bool IsTypeNullable(ITypeSymbol typeInfo, bool enabledNullable) { @@ -42,4 +44,14 @@ internal static string GetGlobalName(ITypeSymbol typeSymbol, bool isNullable, bo return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); } + + public static uint ComputeSha256Hash(string rawData) + { + using SHA256 sha256Hash = SHA256.Create(); + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + + uint hashInt = BitConverter.ToUInt32(bytes, 0); + + return hashInt; + } } diff --git a/src/Controls/src/BindingSourceGen/GeneratorDataModels.cs b/src/Controls/src/BindingSourceGen/GeneratorDataModels.cs index 81cb6545f473..1b70c45f1117 100644 --- a/src/Controls/src/BindingSourceGen/GeneratorDataModels.cs +++ b/src/Controls/src/BindingSourceGen/GeneratorDataModels.cs @@ -100,7 +100,7 @@ public interface IPathPart : IEquatable public string? PropertyName { get; } } -internal sealed record Result(T? OptionalValue, EquatableArray Diagnostics) +public sealed record Result(T? OptionalValue, EquatableArray Diagnostics) { public bool HasDiagnostics => Diagnostics.Length > 0; diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/IncrementalGenerationTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/IncrementalGenerationTests.cs index f0d12f7c81e1..9d7f25a1cdc4 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/IncrementalGenerationTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/IncrementalGenerationTests.cs @@ -1,4 +1,6 @@ +using System.Collections.Immutable; using Microsoft.CodeAnalysis; +using Microsoft.Maui.Controls.BindingSourceGen; using Xunit; namespace BindingSourceGen.UnitTests; @@ -36,7 +38,12 @@ public void DoesNotRegenerateCodeWhenNoChanges() label.SetBinding(Label.RotationProperty, static (string s) => s.Length); """; - RunGeneratorOnTwoSourcesAndVerifyResults([source], [source], reason => Assert.True(reason == IncrementalStepRunReason.Unchanged || reason == IncrementalStepRunReason.Cached)); + var results = RunGeneratorOnMultipleSourcesAndReturnSteps( + new Dictionary { { nameof(source), source } }, + new Dictionary { { nameof(source), source } }); + + var outputs = results[nameof(source)].SelectMany(step => step.Outputs); + Assert.All(outputs, output => Assert.True(output.Reason == IncrementalStepRunReason.Unchanged || output.Reason == IncrementalStepRunReason.Cached)); } [Fact] @@ -54,7 +61,12 @@ public void DoesRegenerateCodeWhenSourceChanged() label.SetBinding(Label.RotationProperty, static (string s) => s); """; - RunGeneratorOnTwoSourcesAndVerifyResults([source], [newSource], reason => Assert.True(reason == IncrementalStepRunReason.Modified)); + var results = RunGeneratorOnMultipleSourcesAndReturnSteps( + new Dictionary { { nameof(source), source } }, + new Dictionary { { nameof(source), newSource } }); + + var outputs = results[nameof(source)].SelectMany(step => step.Outputs); + Assert.All(outputs, output => Assert.True(output.Reason == IncrementalStepRunReason.Modified)); } [Fact] @@ -73,7 +85,12 @@ public void DoesRegenerateCodeWhenNewCodeInsertedAbove() label.SetBinding(Label.RotationProperty, static (string s) => s.Length); """; - RunGeneratorOnTwoSourcesAndVerifyResults([source], [newSource], reason => Assert.True(reason == IncrementalStepRunReason.Modified)); + var results = RunGeneratorOnMultipleSourcesAndReturnSteps( + new Dictionary { { nameof(source), source } }, + new Dictionary { { nameof(source), newSource } }); + + var outputs = results[nameof(source)].SelectMany(step => step.Outputs); + Assert.All(outputs, output => Assert.True(output.Reason == IncrementalStepRunReason.Modified)); } [Fact] @@ -93,7 +110,12 @@ public void DoesNotRegenerateCodeWhenNewCodeInsertedBelow() var x = 42; """; - RunGeneratorOnTwoSourcesAndVerifyResults([source], [newSource], reason => Assert.True(reason == IncrementalStepRunReason.Unchanged || reason == IncrementalStepRunReason.Cached)); + var results = RunGeneratorOnMultipleSourcesAndReturnSteps( + new Dictionary { { nameof(source), source } }, + new Dictionary { { nameof(source), newSource } }); + + var outputs = results[nameof(source)].SelectMany(step => step.Outputs); + Assert.All(outputs, output => Assert.True(output.Reason == IncrementalStepRunReason.Unchanged || output.Reason == IncrementalStepRunReason.Cached)); } [Fact] @@ -102,45 +124,93 @@ public void DoesNotRegerateCodeWhenDifferentFileEdited() var fileASource = """ using Microsoft.Maui.Controls; var label = new Label(); - label.SetBinding(Label.RotationProperty, static (string s) => s.Length); + label.SetBinding(Label.RotationProperty, static (Label l) => l.Text.Length); """; var fileBSource = """ - var x = 42; + using Microsoft.Maui.Controls; + var button = new Button(); + button.SetBinding(Button.RotationProperty, static (Button b) => b.Text.Length); """; var fileBModified = """ - var x = 43; + using Microsoft.Maui.Controls; + var button = new Button(); + button.SetBinding(Button.RotationProperty, static (Button b) => b.Text); """; - RunGeneratorOnTwoSourcesAndVerifyResults([fileASource, fileBSource], [fileASource, fileBModified], reason => Assert.True(reason == IncrementalStepRunReason.Unchanged || reason == IncrementalStepRunReason.Cached)); + var results = RunGeneratorOnMultipleSourcesAndReturnSteps( + new Dictionary { { nameof(fileASource), fileASource }, { nameof(fileBSource), fileBSource } }, + new Dictionary { { nameof(fileASource), fileASource }, { nameof(fileBSource), fileBModified } }); + + var fileAOutputs = results[nameof(fileASource)].SelectMany(step => step.Outputs); + var fileBOutputs = results[nameof(fileBSource)].SelectMany(step => step.Outputs); + Assert.All(fileAOutputs, output => Assert.True(output.Reason == IncrementalStepRunReason.Unchanged || output.Reason == IncrementalStepRunReason.Cached)); + Assert.All(fileBOutputs, output => Assert.True(output.Reason == IncrementalStepRunReason.Modified)); } - private static void RunGeneratorOnTwoSourcesAndVerifyResults(List sources, List modified, Action assert) + private static Dictionary RunGeneratorOnMultipleSourcesAndReturnSteps( + Dictionary initialSources, + Dictionary modifiedSources) { - var inputCompilation = SourceGenHelpers.CreateCompilation(sources); + var inputCompilation = SourceGenHelpers.CreateCompilation(initialSources); var cloneCompilation = inputCompilation.Clone(); var driver = SourceGenHelpers.CreateDriver(); var driverWithCachedInfo = driver.RunGenerators(inputCompilation); - var result = driverWithCachedInfo.GetRunResult().Results.Single(); - var steps = result.TrackedSteps; + var initialResult = driverWithCachedInfo.GetRunResult().Results.Single(); + var initialSteps = initialResult.TrackedSteps; - var reasons = steps.SelectMany(step => step.Value).SelectMany(x => x.Outputs).Select(x => x.Reason); - Assert.All(reasons, reason => Assert.Equal(IncrementalStepRunReason.New, reason)); + var initialReasons = initialSteps.SelectMany(step => step.Value) + .SelectMany(runStep => runStep.Outputs) + .Select(output => output.Reason); - var newCompilation = SourceGenHelpers.CreateCompilation(modified); + var newCompilation = SourceGenHelpers.CreateCompilation(modifiedSources); var newResult = driverWithCachedInfo.RunGenerators(newCompilation).GetRunResult().Results.Single(); var newSteps = newResult.TrackedSteps; - var newReasons = newSteps - .Where(step => SourceGenHelpers.StepsForComparison.Contains(step.Key)) - .SelectMany(step => step.Value) - .SelectMany(x => x.Outputs) - .Select(x => x.Reason); + // Single step runs, e.g. SourceOutput-fileA, SourceOuput-fileB + var runs = newSteps.SelectMany(step => step.Value); + - Assert.All(newReasons, reason => assert(reason)); + // Pairs . Note that a single run can be associated with multiple bindings. + // In such cases generate pair for each binding. + var bindingRunPairs = runs + .Select(run => (GetSetBindingInvocationDescription(run), run)) + .SelectMany(bindingsRunPair => bindingsRunPair.Item1.Select(binding => (binding, bindingsRunPair.run))); + + + // Sometimes the binding has more than one run of the same step associated with it. + // In such cases keep the one with Modified reason for safety. + return bindingRunPairs + .GroupBy(bindingRunPair => bindingRunPair.binding.Location.FilePath) + .ToDictionary( + x => x.Key, + x => x + .GroupBy(y => y.run.Name) + .Select(g => g + .FirstOrDefault(y => y.run.Outputs[0].Reason == IncrementalStepRunReason.Modified).run ?? g.First().run) + .ToArray()); + } + + private static SetBindingInvocationDescription[] GetSetBindingInvocationDescription(IncrementalGeneratorRunStep step) + { + var bindingCandidate = step switch + { + { Name: TrackingNames.BindingsWithDiagnostics } => step.Outputs[0].Value, + { Name: TrackingNames.Bindings } => step.Outputs[0].Value, + { Name: "SourceOutput" } => step.Inputs[0].Source.Outputs[0].Value, + _ => null + }; + + return bindingCandidate switch + { + SetBindingInvocationDescription => [(SetBindingInvocationDescription)bindingCandidate], + Result => [((Result)bindingCandidate).Value], + ImmutableArray => ((ImmutableArray)bindingCandidate).ToArray(), + _ => [] + }; } private static void CompareGeneratorOutputs(GeneratorRunResult result1, GeneratorRunResult result2) @@ -163,4 +233,3 @@ where SourceGenHelpers.StepsForComparison.Contains(stepA.Key) } } } - diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs index 09b221ff2819..f422df869988 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs @@ -39,7 +39,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 3, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-3-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -78,7 +78,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-3-7.g.cs"]); } [Fact] @@ -132,7 +132,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 6, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-6-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -179,7 +179,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-6-7.g.cs"]); } [Fact] @@ -234,7 +234,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -283,7 +283,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs"]); } public static IEnumerable GenerateSimpleBindingWhenNullableDisabledAndPropertyNullableData => @@ -441,7 +441,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -488,7 +488,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs"]); } [Fact] @@ -557,7 +557,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -605,7 +605,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs"]); } [Theory] @@ -674,7 +674,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 4, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-4-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -729,7 +729,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-4-7.g.cs"]); } [Fact] @@ -796,7 +796,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 4, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-4-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -847,7 +847,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-4-7.g.cs"]); } [Fact] @@ -904,7 +904,7 @@ internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 3, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-3-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -948,7 +948,7 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-3-7.g.cs"]); } [Fact] @@ -1010,7 +1010,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 6, 7)] - public static void SetBinding1( + public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-6-7.g.cs")}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -1063,6 +1063,6 @@ public static void SetBinding1( } } """, - result.GeneratedFiles["GeneratedBindableObjectExtensions1.g.cs"]); + result.GeneratedFiles["Path/To/Program.cs/GeneratedBindableObjectExtensions-6-7.g.cs"]); } } diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs b/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs index 939cbe01d09a..0742580e85e5 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/SourceGenHelpers.cs @@ -71,9 +71,9 @@ internal static Compilation CreateCompilation(string source) return CreateCompilationFromSyntaxTrees([CSharpSyntaxTree.ParseText(source, ParseOptions, path: @"Path\To\Program.cs")]); } - internal static Compilation CreateCompilation(List sources) + internal static Compilation CreateCompilation(Dictionary sources) { - var syntaxTrees = sources.Select(source => CSharpSyntaxTree.ParseText(source, ParseOptions, path: $@"Path\To\Program{sources.IndexOf(source)}.cs")).ToList(); + var syntaxTrees = sources.Select(s => CSharpSyntaxTree.ParseText(s.Value, ParseOptions, path: s.Key)).ToList(); return CreateCompilationFromSyntaxTrees(syntaxTrees); } } From a7ae0d8a64845b3c6a738d0e7206615fbc666bc7 Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Wed, 22 May 2024 19:58:23 +0200 Subject: [PATCH 3/4] removed unnecessary hashing function --- .../BindingSourceGen/BindingSourceGenerator.cs | 2 +- .../BindingSourceGeneratorUtilities.cs | 12 ------------ .../IntegrationTests.cs | 18 +++++++++--------- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index fe845ca64ca7..29281d0f3cf2 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -39,7 +39,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { var fileName = $"{binding.Location.FilePath}/GeneratedBindableObjectExtensions-{binding.Location.Line}-{binding.Location.Column}.g.cs"; - spc.AddSource(fileName, BindingCodeWriter.GenerateBinding(binding, BindingGenerationUtilities.ComputeSha256Hash(fileName))); + spc.AddSource(fileName, BindingCodeWriter.GenerateBinding(binding, (uint)Math.Abs(binding.Location.GetHashCode()))); }); } diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs b/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs index 977ae9aaeb07..8e4715aa1f13 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGeneratorUtilities.cs @@ -1,5 +1,3 @@ -using System.Security.Cryptography; -using System.Text; using Microsoft.CodeAnalysis; namespace Microsoft.Maui.Controls.BindingSourceGen; @@ -44,14 +42,4 @@ internal static string GetGlobalName(ITypeSymbol typeSymbol, bool isNullable, bo return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); } - - public static uint ComputeSha256Hash(string rawData) - { - using SHA256 sha256Hash = SHA256.Create(); - byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); - - uint hashInt = BitConverter.ToUInt32(bytes, 0); - - return hashInt; - } } diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs index f422df869988..cabebbc2cc41 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs @@ -39,7 +39,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 3, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-3-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -132,7 +132,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 6, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-6-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -234,7 +234,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -441,7 +441,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -557,7 +557,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-7-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -674,7 +674,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 4, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-4-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -796,7 +796,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 4, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-4-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -904,7 +904,7 @@ internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 3, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-3-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -1010,7 +1010,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 6, 7)] - public static void SetBinding{{BindingGenerationUtilities.ComputeSha256Hash("Path\\To\\Program.cs/GeneratedBindableObjectExtensions-6-7.g.cs")}}( + public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, From a67137c6eeee9a6b7f72ee144224d72116b7cccf Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Thu, 23 May 2024 09:56:24 +0200 Subject: [PATCH 4/4] extracted binding id calculation into separate variable --- .../IntegrationTests.cs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs index cabebbc2cc41..4a77d1d4428e 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/IntegrationTests.cs @@ -14,6 +14,8 @@ public void GenerateSimpleBinding() """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); + AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( $$""" @@ -39,7 +41,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 3, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -107,6 +109,7 @@ public class B """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( $$""" @@ -132,7 +135,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 6, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -209,6 +212,7 @@ public class B """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( $$""" @@ -234,7 +238,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -416,6 +420,7 @@ public class C public void GenerateSimpleBindingWhenNullableDisabledAndPropertyNullable(string source) { var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( $$""" @@ -441,7 +446,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -532,6 +537,7 @@ public class D { """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( $$""" @@ -557,7 +563,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 7, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -648,6 +654,7 @@ public class MyPropertyClass """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( @@ -674,7 +681,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 4, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -770,6 +777,7 @@ public class MyPropertyClass """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( @@ -796,7 +804,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 4, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -879,6 +887,7 @@ public class Wrapper """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( @@ -904,7 +913,7 @@ internal static partial class GeneratedBindableObjectExtensions { {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 3, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter, @@ -984,6 +993,7 @@ public class MyPropertyClass """; var result = SourceGenHelpers.Run(source); + var id = Math.Abs(result.Binding!.Location.GetHashCode()); AssertExtensions.AssertNoDiagnostics(result); AssertExtensions.CodeIsEqual( @@ -1010,7 +1020,7 @@ internal static partial class GeneratedBindableObjectExtensions {{BindingCodeWriter.GeneratedCodeAttribute}} [InterceptsLocationAttribute(@"Path\To\Program.cs", 6, 7)] - public static void SetBinding{{Math.Abs(result.Binding!.Location.GetHashCode())}}( + public static void SetBinding{{id}}( this BindableObject bindableObject, BindableProperty bindableProperty, Func getter,