From e10ee075a42bc49ba1d7812143f37a511ea80698 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 22 Apr 2024 16:43:17 +0200 Subject: [PATCH 1/9] Add benchmark for source-generated SetBinding --- .../SourceGeneratedBindingBenchmarker.cs | 71 +++++++++++++++++++ .../tests/Benchmarks/Core.Benchmarks.csproj | 9 +++ 2 files changed, 80 insertions(+) create mode 100644 src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs diff --git a/src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs b/src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs new file mode 100644 index 000000000000..c675d5c21302 --- /dev/null +++ b/src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs @@ -0,0 +1,71 @@ +#nullable enable +using System; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Microsoft.Maui.Benchmarks +{ + [MemoryDiagnoser] + public class SourceGeneratedBindingBenchmarker + { + // Avoids the warning: + // The minimum observed iteration time is 10.1000 us which is very small. It's recommended to increase it to at least 100.0000 ms using more operations. + const int Iterations = 10; + + public class MyObject : BindableObject + { + public static readonly BindableProperty NameProperty = BindableProperty.Create(nameof(Name), typeof(string), typeof(MyObject)); + + public string Name + { + get { return (string)GetValue(NameProperty); } + set { SetValue(NameProperty, value); } + } + + public MyObject? Child { get; set; } + + public List Children { get; private set; } = new List(); + } + + readonly MyObject Source = new() + { + Name = "A", + Child = new() { Name = "A.Child" }, + Children = + { + new() { Name = "A.Children[0]" }, + new() { Name = "A.Children[1]" }, + } + }; + readonly MyObject Target = new() { Name = "B" }; + + [Benchmark] + public void SourceGeneratedBindName() + { + for (int i = 0; i < Iterations; i++) + { + Target.SetBinding(MyObject.NameProperty, static (MyObject o) => o.Name, source: Source, mode: BindingMode.OneWay); + } + } + + [Benchmark] + public void SourceGeneratedBindChild() + { + for (int i = 0; i < Iterations; i++) + { + Target.SetBinding(MyObject.NameProperty, static (MyObject o) => o.Child?.Name, source: Source, mode: BindingMode.OneWay); + } + } + + [Benchmark] + public void SourceGeneratedBindChildIndexer() + { + for (int i = 0; i < Iterations; i++) + { + Target.SetBinding(MyObject.NameProperty, static (MyObject o) => o.Children[0].Name, source: Source, mode: BindingMode.OneWay); + } + } + } +} diff --git a/src/Core/tests/Benchmarks/Core.Benchmarks.csproj b/src/Core/tests/Benchmarks/Core.Benchmarks.csproj index 406cee0b2477..25abd7883830 100644 --- a/src/Core/tests/Benchmarks/Core.Benchmarks.csproj +++ b/src/Core/tests/Benchmarks/Core.Benchmarks.csproj @@ -3,6 +3,8 @@ Exe $(_MauiDotNetTfm) + true + $(InterceptorsPreviewNamespaces);Microsoft.Maui.Controls.Generated @@ -17,4 +19,11 @@ + + + + From dcacb6ca7f1c689223de3dbed869d6e6b2a7043f Mon Sep 17 00:00:00 2001 From: GitHub Actions Autoformatter Date: Mon, 22 Apr 2024 14:45:49 +0000 Subject: [PATCH 2/9] Auto-format source code --- .../Benchmarks/SourceGeneratedBindingBenchmarker.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs b/src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs index c675d5c21302..b2de536b155f 100644 --- a/src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs +++ b/src/Core/tests/Benchmarks/Benchmarks/SourceGeneratedBindingBenchmarker.cs @@ -40,7 +40,7 @@ public string Name } }; readonly MyObject Target = new() { Name = "B" }; - + [Benchmark] public void SourceGeneratedBindName() { @@ -49,7 +49,7 @@ public void SourceGeneratedBindName() Target.SetBinding(MyObject.NameProperty, static (MyObject o) => o.Name, source: Source, mode: BindingMode.OneWay); } } - + [Benchmark] public void SourceGeneratedBindChild() { @@ -58,7 +58,7 @@ public void SourceGeneratedBindChild() Target.SetBinding(MyObject.NameProperty, static (MyObject o) => o.Child?.Name, source: Source, mode: BindingMode.OneWay); } } - + [Benchmark] public void SourceGeneratedBindChildIndexer() { From 67838d0114e45aa4f9774a1547b376f0343a08be Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Tue, 23 Apr 2024 10:46:11 +0200 Subject: [PATCH 3/9] improve overload diagnostics tests --- .../DiagnosticsTests.cs | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs index f18bd777e9e2..1158564294e2 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs @@ -4,7 +4,7 @@ namespace BindingSourceGen.UnitTests; public class DiagnosticsTests { - [Fact(Skip = "Improve detecting overloads")] + [Fact] public void ReportsErrorWhenGetterIsNotLambda() { var source = """ @@ -36,7 +36,7 @@ public void ReportsErrorWhenLambdaBodyIsNotExpression() } [Fact] - public void ReportsWarningWhenUsingDifferentSetBindingOverload() + public void DoesNotReportWarningWhenUsingOverloadWithBindingClass() { var source = """ using Microsoft.Maui.Controls; @@ -46,11 +46,25 @@ public void ReportsWarningWhenUsingDifferentSetBindingOverload() """; var result = SourceGenHelpers.Run(source); - - Assert.Single(result.SourceGeneratorDiagnostics); - Assert.Equal("BSG0004", result.SourceGeneratorDiagnostics[0].Id); + Assert.Empty(result.SourceGeneratorDiagnostics); } + [Fact] + public void DoesNotReportWarningWhenUsingOverloadWithStringPath() + { + var source = """ + using Microsoft.Maui.Controls; + var label = new Label(); + var slider = new Slider(); + + label.BindingContext = slider; + label.SetBinding(Label.ScaleProperty, "Value"); + """; + + var result = SourceGenHelpers.Run(source); + Assert.Empty(result.SourceGeneratorDiagnostics); + } + [Fact] public void ReportsUnableToResolvePathWhenUsingMethodCall() { From 122e42f0a028cd4aad1f6a81753d8a2ee19f2278 Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Tue, 23 Apr 2024 11:13:45 +0200 Subject: [PATCH 4/9] added more complex overload tests --- .../DiagnosticsTests.cs | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs index 1158564294e2..e83cf0e7ee18 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs @@ -36,7 +36,7 @@ public void ReportsErrorWhenLambdaBodyIsNotExpression() } [Fact] - public void DoesNotReportWarningWhenUsingOverloadWithBindingClass() + public void DoesNotReportWarningWhenUsingOverloadWithBindingClassDeclaredInInvocation() { var source = """ using Microsoft.Maui.Controls; @@ -50,7 +50,22 @@ public void DoesNotReportWarningWhenUsingOverloadWithBindingClass() } [Fact] - public void DoesNotReportWarningWhenUsingOverloadWithStringPath() + public void DoesNotReportWarningWhenUsingOverloadWithBindingClassPassedAsVariable() + { + var source = """ + using Microsoft.Maui.Controls; + var label = new Label(); + var slider = new Slider(); + var binding = new Binding("Value", source: slider); + label.SetBinding(Label.ScaleProperty, binding); + """; + + var result = SourceGenHelpers.Run(source); + Assert.Empty(result.SourceGeneratorDiagnostics); + } + + [Fact] + public void DoesNotReportWarningWhenUsingOverloadWithStringConstantPath() { var source = """ using Microsoft.Maui.Controls; @@ -64,6 +79,23 @@ public void DoesNotReportWarningWhenUsingOverloadWithStringPath() var result = SourceGenHelpers.Run(source); Assert.Empty(result.SourceGeneratorDiagnostics); } + + [Fact] + public void DoesNotReportWarningWhenUsingOverloadWithStringVariablePath() + { + var source = """ + using Microsoft.Maui.Controls; + var label = new Label(); + var slider = new Slider(); + + label.BindingContext = slider; + var str = "Value"; + label.SetBinding(Label.ScaleProperty, str); + """; + + var result = SourceGenHelpers.Run(source); + Assert.Empty(result.SourceGeneratorDiagnostics); + } [Fact] public void ReportsUnableToResolvePathWhenUsingMethodCall() From 8248cc2d4ad897bb5b96d2a975e601ac9456af54 Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Tue, 23 Apr 2024 11:15:04 +0200 Subject: [PATCH 5/9] improve predicate method filtering --- src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index c05a208c1b7d..85b8714ad0a0 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -49,7 +49,10 @@ static bool IsSetBindingMethod(SyntaxNode node) { return node is InvocationExpressionSyntax invocation && invocation.Expression is MemberAccessExpressionSyntax method - && method.Name.Identifier.Text == "SetBinding"; + && method.Name.Identifier.Text == "SetBinding" + && invocation.ArgumentList.Arguments.Count >= 2 + && invocation.ArgumentList.Arguments[1].Expression is not LiteralExpressionSyntax + && invocation.ArgumentList.Arguments[1].Expression is not ObjectCreationExpressionSyntax; } static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext context, CancellationToken t) From 03722c6359d0d88b004d0a0cc9d2c2c500288b74 Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Tue, 23 Apr 2024 11:48:50 +0200 Subject: [PATCH 6/9] improved diagnostics on overload detection --- .../BindingSourceGenerator.cs | 19 +++++++++++-------- .../BindingSourceGen/DiagnosticsFactory.cs | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index 85b8714ad0a0..1e855bc5fbda 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -109,15 +109,18 @@ static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext private static EquatableArray VerifyCorrectOverload(InvocationExpressionSyntax invocation, GeneratorSyntaxContext context, CancellationToken t) { var argumentList = invocation.ArgumentList.Arguments; - if (argumentList.Count < 2) - { - return new EquatableArray([DiagnosticsFactory.SuboptimalSetBindingOverload(invocation.GetLocation())]); - } + var secondArgument = argumentList[1].Expression; - var getter = argumentList[1].Expression; - if (getter is not LambdaExpressionSyntax) - { - return new EquatableArray([DiagnosticsFactory.SuboptimalSetBindingOverload(getter.GetLocation())]); + if (secondArgument is IdentifierNameSyntax) { + var type = context.SemanticModel.GetTypeInfo(secondArgument, cancellationToken: t).Type; + if (type != null && type.Name == "Func") + { + return new EquatableArray([DiagnosticsFactory.GetterIsNotLambda(secondArgument.GetLocation())]); + } + else // String and Binding + { + return new EquatableArray([DiagnosticsFactory.SuboptimalSetBindingOverload(secondArgument.GetLocation())]); + } } return []; diff --git a/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs b/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs index e72c6fe2de90..f15054184565 100644 --- a/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs +++ b/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs @@ -56,7 +56,7 @@ public static DiagnosticInfo SuboptimalSetBindingOverload(Location location) title: "SetBinding with string path", messageFormat: "TODO: consider using SetBinding overload with a lambda getter", category: "Usage", - defaultSeverity: DiagnosticSeverity.Warning, - isEnabledByDefault: true), + defaultSeverity: DiagnosticSeverity.Hidden, + isEnabledByDefault: false), location); } From 996ce094effe88433ade1e232396d702204c9c7b Mon Sep 17 00:00:00 2001 From: GitHub Actions Autoformatter Date: Tue, 23 Apr 2024 09:50:52 +0000 Subject: [PATCH 7/9] Auto-format source code --- .../BindingSourceGenerator.cs | 3 +- .../BindingSourceGen/DiagnosticsFactory.cs | 94 +++++++------- .../DiagnosticsTests.cs | 122 +++++++++--------- 3 files changed, 110 insertions(+), 109 deletions(-) diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index 1e855bc5fbda..27aa7f0c7fc8 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -111,7 +111,8 @@ private static EquatableArray VerifyCorrectOverload(InvocationEx var argumentList = invocation.ArgumentList.Arguments; var secondArgument = argumentList[1].Expression; - if (secondArgument is IdentifierNameSyntax) { + if (secondArgument is IdentifierNameSyntax) + { var type = context.SemanticModel.GetTypeInfo(secondArgument, cancellationToken: t).Type; if (type != null && type.Name == "Func") { diff --git a/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs b/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs index f15054184565..68e3aeac0030 100644 --- a/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs +++ b/src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs @@ -4,59 +4,59 @@ namespace Microsoft.Maui.Controls.BindingSourceGen; public sealed record DiagnosticInfo { - public DiagnosticInfo(DiagnosticDescriptor descriptor, Location? location) - { - Descriptor = descriptor; - Location = location is not null ? SourceCodeLocation.CreateFrom(location) : null; - } + public DiagnosticInfo(DiagnosticDescriptor descriptor, Location? location) + { + Descriptor = descriptor; + Location = location is not null ? SourceCodeLocation.CreateFrom(location) : null; + } - public DiagnosticDescriptor Descriptor { get; } - public SourceCodeLocation? Location { get; } + public DiagnosticDescriptor Descriptor { get; } + public SourceCodeLocation? Location { get; } } internal static class DiagnosticsFactory { - public static DiagnosticInfo UnableToResolvePath(Location location) - => new( - new DiagnosticDescriptor( - id: "BSG0001", - title: "Unable to resolve path", - messageFormat: "TODO: unable to resolve path", - category: "Usage", - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true), - location); + public static DiagnosticInfo UnableToResolvePath(Location location) + => new( + new DiagnosticDescriptor( + id: "BSG0001", + title: "Unable to resolve path", + messageFormat: "TODO: unable to resolve path", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true), + location); - public static DiagnosticInfo GetterIsNotLambda(Location location) - => new( - new DiagnosticDescriptor( - id: "BSG0002", - title: "Getter must be a lambda", - messageFormat: "TODO: getter must be a lambda", - category: "Usage", - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true), - location); + public static DiagnosticInfo GetterIsNotLambda(Location location) + => new( + new DiagnosticDescriptor( + id: "BSG0002", + title: "Getter must be a lambda", + messageFormat: "TODO: getter must be a lambda", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true), + location); - public static DiagnosticInfo GetterLambdaBodyIsNotExpression(Location location) - => new( - new DiagnosticDescriptor( - id: "BSG0003", - title: "Getter lambda's body must be an expression", - messageFormat: "TODO: getter lambda's body must be an expression", - category: "Usage", - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true), - location); + public static DiagnosticInfo GetterLambdaBodyIsNotExpression(Location location) + => new( + new DiagnosticDescriptor( + id: "BSG0003", + title: "Getter lambda's body must be an expression", + messageFormat: "TODO: getter lambda's body must be an expression", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true), + location); - public static DiagnosticInfo SuboptimalSetBindingOverload(Location location) - => new( - new DiagnosticDescriptor( - id: "BSG0004", - title: "SetBinding with string path", - messageFormat: "TODO: consider using SetBinding overload with a lambda getter", - category: "Usage", - defaultSeverity: DiagnosticSeverity.Hidden, - isEnabledByDefault: false), - location); + public static DiagnosticInfo SuboptimalSetBindingOverload(Location location) + => new( + new DiagnosticDescriptor( + id: "BSG0004", + title: "SetBinding with string path", + messageFormat: "TODO: consider using SetBinding overload with a lambda getter", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Hidden, + isEnabledByDefault: false), + location); } diff --git a/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs b/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs index e83cf0e7ee18..a759a90b8e00 100644 --- a/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs +++ b/src/Controls/tests/BindingSourceGen.UnitTests/DiagnosticsTests.cs @@ -4,10 +4,10 @@ namespace BindingSourceGen.UnitTests; public class DiagnosticsTests { - [Fact] - public void ReportsErrorWhenGetterIsNotLambda() - { - var source = """ + [Fact] + public void ReportsErrorWhenGetterIsNotLambda() + { + var source = """ using System; using Microsoft.Maui.Controls; var label = new Label(); @@ -15,44 +15,44 @@ public void ReportsErrorWhenGetterIsNotLambda() label.SetBinding(Label.RotationProperty, getter); """; - var result = SourceGenHelpers.Run(source); - Assert.Single(result.SourceGeneratorDiagnostics); - Assert.Equal("BSG0002", result.SourceGeneratorDiagnostics[0].Id); - } + var result = SourceGenHelpers.Run(source); + Assert.Single(result.SourceGeneratorDiagnostics); + Assert.Equal("BSG0002", result.SourceGeneratorDiagnostics[0].Id); + } - [Fact] - public void ReportsErrorWhenLambdaBodyIsNotExpression() - { - var source = """ + [Fact] + public void ReportsErrorWhenLambdaBodyIsNotExpression() + { + var source = """ using Microsoft.Maui.Controls; var label = new Label(); label.SetBinding(Label.RotationProperty, static (Button b) => { return b.Text.Length; }); """; - var result = SourceGenHelpers.Run(source); + var result = SourceGenHelpers.Run(source); - Assert.Single(result.SourceGeneratorDiagnostics); - Assert.Equal("BSG0003", result.SourceGeneratorDiagnostics[0].Id); - } + Assert.Single(result.SourceGeneratorDiagnostics); + Assert.Equal("BSG0003", result.SourceGeneratorDiagnostics[0].Id); + } - [Fact] - public void DoesNotReportWarningWhenUsingOverloadWithBindingClassDeclaredInInvocation() - { - var source = """ + [Fact] + public void DoesNotReportWarningWhenUsingOverloadWithBindingClassDeclaredInInvocation() + { + var source = """ using Microsoft.Maui.Controls; var label = new Label(); var slider = new Slider(); label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider)); """; - var result = SourceGenHelpers.Run(source); - Assert.Empty(result.SourceGeneratorDiagnostics); - } + var result = SourceGenHelpers.Run(source); + Assert.Empty(result.SourceGeneratorDiagnostics); + } - [Fact] - public void DoesNotReportWarningWhenUsingOverloadWithBindingClassPassedAsVariable() - { - var source = """ + [Fact] + public void DoesNotReportWarningWhenUsingOverloadWithBindingClassPassedAsVariable() + { + var source = """ using Microsoft.Maui.Controls; var label = new Label(); var slider = new Slider(); @@ -60,14 +60,14 @@ public void DoesNotReportWarningWhenUsingOverloadWithBindingClassPassedAsVariabl label.SetBinding(Label.ScaleProperty, binding); """; - var result = SourceGenHelpers.Run(source); - Assert.Empty(result.SourceGeneratorDiagnostics); - } + var result = SourceGenHelpers.Run(source); + Assert.Empty(result.SourceGeneratorDiagnostics); + } - [Fact] - public void DoesNotReportWarningWhenUsingOverloadWithStringConstantPath() - { - var source = """ + [Fact] + public void DoesNotReportWarningWhenUsingOverloadWithStringConstantPath() + { + var source = """ using Microsoft.Maui.Controls; var label = new Label(); var slider = new Slider(); @@ -76,14 +76,14 @@ public void DoesNotReportWarningWhenUsingOverloadWithStringConstantPath() label.SetBinding(Label.ScaleProperty, "Value"); """; - var result = SourceGenHelpers.Run(source); - Assert.Empty(result.SourceGeneratorDiagnostics); - } + var result = SourceGenHelpers.Run(source); + Assert.Empty(result.SourceGeneratorDiagnostics); + } - [Fact] - public void DoesNotReportWarningWhenUsingOverloadWithStringVariablePath() - { - var source = """ + [Fact] + public void DoesNotReportWarningWhenUsingOverloadWithStringVariablePath() + { + var source = """ using Microsoft.Maui.Controls; var label = new Label(); var slider = new Slider(); @@ -93,14 +93,14 @@ public void DoesNotReportWarningWhenUsingOverloadWithStringVariablePath() label.SetBinding(Label.ScaleProperty, str); """; - var result = SourceGenHelpers.Run(source); - Assert.Empty(result.SourceGeneratorDiagnostics); - } - - [Fact] - public void ReportsUnableToResolvePathWhenUsingMethodCall() - { - var source = """ + var result = SourceGenHelpers.Run(source); + Assert.Empty(result.SourceGeneratorDiagnostics); + } + + [Fact] + public void ReportsUnableToResolvePathWhenUsingMethodCall() + { + var source = """ using Microsoft.Maui.Controls; double GetRotation(Button b) => b.Rotation; @@ -109,16 +109,16 @@ public void ReportsUnableToResolvePathWhenUsingMethodCall() label.SetBinding(Label.RotationProperty, (Button b) => GetRotation(b)); """; - var result = SourceGenHelpers.Run(source); + var result = SourceGenHelpers.Run(source); - Assert.Single(result.SourceGeneratorDiagnostics); - Assert.Equal("BSG0001", result.SourceGeneratorDiagnostics[0].Id); - } + Assert.Single(result.SourceGeneratorDiagnostics); + Assert.Equal("BSG0001", result.SourceGeneratorDiagnostics[0].Id); + } - [Fact] - public void ReportsUnableToResolvePathWhenUsingMultidimensionalArray() - { - var source = """ + [Fact] + public void ReportsUnableToResolvePathWhenUsingMultidimensionalArray() + { + var source = """ using Microsoft.Maui.Controls; var label = new Label(); @@ -126,9 +126,9 @@ public void ReportsUnableToResolvePathWhenUsingMultidimensionalArray() label.SetBinding(Label.RotationProperty, (Button b) => array[0, 0]); """; - var result = SourceGenHelpers.Run(source); + var result = SourceGenHelpers.Run(source); - Assert.Single(result.SourceGeneratorDiagnostics); - Assert.Equal("BSG0001", result.SourceGeneratorDiagnostics[0].Id); - } + Assert.Single(result.SourceGeneratorDiagnostics); + Assert.Equal("BSG0001", result.SourceGeneratorDiagnostics[0].Id); + } } From 6695a32efa1c7ffac1a0d4de43f98725bc28f6c6 Mon Sep 17 00:00:00 2001 From: Jeremi Kurdek Date: Tue, 23 Apr 2024 12:44:22 +0200 Subject: [PATCH 8/9] add ArgumentOutOfRangeException --- src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index 27aa7f0c7fc8..9e402e5078ce 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -109,6 +109,12 @@ static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext private static EquatableArray VerifyCorrectOverload(InvocationExpressionSyntax invocation, GeneratorSyntaxContext context, CancellationToken t) { var argumentList = invocation.ArgumentList.Arguments; + + if (argumentList.Count < 2) + { + throw new ArgumentOutOfRangeException(nameof(invocation)); + } + var secondArgument = argumentList[1].Expression; if (secondArgument is IdentifierNameSyntax) From 53bc87994b56e5898a3ccb22a322fda5d052cfae Mon Sep 17 00:00:00 2001 From: GitHub Actions Autoformatter Date: Tue, 23 Apr 2024 10:47:34 +0000 Subject: [PATCH 9/9] Auto-format source code --- src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs index 9e402e5078ce..8391c9cc9dc5 100644 --- a/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs +++ b/src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs @@ -109,7 +109,7 @@ static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext private static EquatableArray VerifyCorrectOverload(InvocationExpressionSyntax invocation, GeneratorSyntaxContext context, CancellationToken t) { var argumentList = invocation.ArgumentList.Arguments; - + if (argumentList.Count < 2) { throw new ArgumentOutOfRangeException(nameof(invocation));