Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Binding source generator #21725

Merged
merged 47 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
7b61154
Add new public API SetBinding<TSource, TProperty>
simonrozsival Mar 4, 2024
632979b
Add source generator skeleton
simonrozsival Mar 5, 2024
403f476
Setup unit tests for binding intermediate representation
jkurdek Mar 26, 2024
f9747a3
Added basic nullability support
jkurdek Mar 29, 2024
a4b9335
Remove unnecessary Id from the binding record
simonrozsival Apr 2, 2024
62f613e
Generate casts
simonrozsival Apr 2, 2024
e5343a5
Split index and member access
simonrozsival Apr 3, 2024
5d719ca
Cleanup
simonrozsival Apr 3, 2024
dd8112f
Update test case
simonrozsival Apr 3, 2024
6b325ae
Cleanup
simonrozsival Apr 4, 2024
e9093af
Fix the semantic of conditional access
simonrozsival Apr 5, 2024
5298785
add as-cast suport to source generator
jkurdek Apr 4, 2024
d1fed61
improve nullability check
jkurdek Apr 4, 2024
c8130cf
specify params in tests only when not default
jkurdek Apr 4, 2024
c0b7da6
simplify diagnostics
jkurdek Apr 4, 2024
7e82570
move path parser to separate class
jkurdek Apr 4, 2024
7f3f2bb
small cleanup
jkurdek Apr 4, 2024
491a91e
Get nullability right in binding representation tests
jkurdek Apr 5, 2024
1bf4cad
Fix path parse to work with improved tests
jkurdek Apr 5, 2024
0355390
Integration tests (#14)
jkurdek Apr 8, 2024
d00f0d8
Implement setters (#16)
simonrozsival Apr 9, 2024
b4bf3e0
Simplify indexes (#18)
simonrozsival Apr 9, 2024
97721da
Fix overload check (#20)
jkurdek Apr 9, 2024
8617d5b
Implement detection of writable properties (#19)
simonrozsival Apr 9, 2024
1f733e2
Add TODOs to change arrays to equatable arrays
simonrozsival Apr 9, 2024
b375a60
Add projects to solutions
simonrozsival Apr 9, 2024
85d0a40
Try to run unit tests in CI
simonrozsival Apr 10, 2024
8708c17
Added custom indexer support
jkurdek Apr 11, 2024
78502ca
Fix typo
simonrozsival Apr 16, 2024
d2befa0
Avoid allocating line separators array
simonrozsival Apr 16, 2024
2039bb0
Hide the new SetBinding overload from editor suggestions for now
simonrozsival Apr 17, 2024
08f55d6
Incremental generation tests
jkurdek Apr 16, 2024
89dfa15
replaced array with equatable array
jkurdek Apr 19, 2024
df57581
Added source information + formatting
jkurdek Apr 19, 2024
6d6887e
added third party licenses
jkurdek Apr 19, 2024
4cb21c1
Add benchmark for source-generated SetBinding (#25)
simonrozsival Apr 23, 2024
19b6885
Improve diagnostic messages
simonrozsival Apr 23, 2024
f02cce5
Improved incrementality testing (#28)
jkurdek Apr 29, 2024
2f35e7e
Add C-Style casts support (#26)
jkurdek Apr 30, 2024
2cb89e8
Cleanup (#29)
simonrozsival Apr 30, 2024
0835449
Improved nullable support (#30)
jkurdek May 14, 2024
55e1aa2
Simplify building setter
simonrozsival May 14, 2024
44c0167
cleaned up methods in BindingSourceGeneratorUtilities
jkurdek May 17, 2024
296c5e0
replaced tuples with Result<T>
jkurdek May 17, 2024
1054597
simplified naming
jkurdek May 17, 2024
1f88a39
Fix and improve unit test project
simonrozsival Jun 4, 2024
afabedc
Fix bad conflict resolution in solution file
simonrozsival Jun 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
simplify diagnostics
  • Loading branch information
jkurdek authored and simonrozsival committed Jun 4, 2024
commit c0b7da687785562c1624df34db9503a53e0a4e59
24 changes: 8 additions & 16 deletions src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,13 @@ static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext

if (methodSymbolInfo.Symbol is not IMethodSymbol methodSymbol) //TODO: Do we need this check?
{
diagnostics.Add(Diagnostic.Create(
DiagnosticsDescriptors.UnableToResolvePath, method.GetLocation()));
return new BindingDiagnosticsWrapper(null, diagnostics.ToArray());
return new BindingDiagnosticsWrapper(null, [DiagnosticsFactory.UnableToResolvePath(method.GetLocation())]);
}

// Check whether we are using correct overload
if (methodSymbol.Parameters.Length < 2 || methodSymbol.Parameters[1].Type.Name != "Func")
{
diagnostics.Add(Diagnostic.Create(
DiagnosticsDescriptors.SuboptimalSetBindingOverload, method.GetLocation()));
return new BindingDiagnosticsWrapper(null, diagnostics.ToArray());
return new BindingDiagnosticsWrapper(null, [DiagnosticsFactory.SuboptimalSetBindingOverload(method.GetLocation())]);
}

var argumentList = invocation.ArgumentList.Arguments;
Expand All @@ -84,17 +80,13 @@ static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext
//Check if getter is a lambda
if (getter is not LambdaExpressionSyntax lambda)
{
diagnostics.Add(Diagnostic.Create(
DiagnosticsDescriptors.GetterIsNotLambda, getter.GetLocation()));
return new BindingDiagnosticsWrapper(null, diagnostics.ToArray());
return new BindingDiagnosticsWrapper(null, [DiagnosticsFactory.GetterIsNotLambda(getter.GetLocation())]);
}

//Check if lambda body is an expression
if (lambda.Body is not ExpressionSyntax)
{
diagnostics.Add(Diagnostic.Create(
DiagnosticsDescriptors.GetterLambdaBodyIsNotExpression, lambda.Body.GetLocation()));
return new BindingDiagnosticsWrapper(null, diagnostics.ToArray());
return new BindingDiagnosticsWrapper(null, [DiagnosticsFactory.GetterLambdaBodyIsNotExpression(lambda.Body.GetLocation())]);
}

var lambdaSymbol = context.SemanticModel.GetSymbolInfo(lambda, cancellationToken: t).Symbol as IMethodSymbol ?? throw new Exception("Unable to resolve lambda symbol");
Expand All @@ -113,9 +105,7 @@ static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext

if (!correctlyParsed)
{
diagnostics.Add(Diagnostic.Create(
DiagnosticsDescriptors.UnableToResolvePath, lambda.Body.GetLocation(), lambda.Body.ToString()));
return new BindingDiagnosticsWrapper(null, diagnostics.ToArray());
return new BindingDiagnosticsWrapper(null, [DiagnosticsFactory.UnableToResolvePath(lambda.Body.GetLocation())]);
}

// Sometimes analysing just the return type of the lambda is not enough. TODO: Refactor
Expand All @@ -132,7 +122,7 @@ static BindingDiagnosticsWrapper GetBindingForGeneration(GeneratorSyntaxContext
);
return new BindingDiagnosticsWrapper(codeWriterBinding, diagnostics.ToArray());
}
static bool ParsePath(CSharpSyntaxNode? expressionSyntax, bool enabledNullable, GeneratorSyntaxContext context, List<IPathPart> parts, bool isNodeNullable = false, object? index = null)
static bool ParsePath(CSharpSyntaxNode? expressionSyntax, bool enabledNullable, GeneratorSyntaxContext context, List<IPathPart> parts, bool isNodeNullable = false)
{
if (expressionSyntax is IdentifierNameSyntax identifier)
{
Expand Down Expand Up @@ -290,6 +280,8 @@ internal static TypeDescription CreateTypeNameFromITypeSymbol(ITypeSymbol typeSy

return (false, typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
}

private static BindingDiagnosticsWrapper ReportDiagnostics(Diagnostic[] diagnostics) => new(null, diagnostics);
}

public sealed record BindingDiagnosticsWrapper(
Expand Down
38 changes: 0 additions & 38 deletions src/Controls/src/BindingSourceGen/DiagnosticsDescriptors.cs

This file was deleted.

50 changes: 50 additions & 0 deletions src/Controls/src/BindingSourceGen/DiagnosticsFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Microsoft.CodeAnalysis;

namespace Microsoft.Maui.Controls.BindingSourceGen;

internal static class DiagnosticsFactory
{
public static Diagnostic UnableToResolvePath(Location location)
=> Diagnostic.Create(
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 Diagnostic GetterIsNotLambda(Location location)
=> Diagnostic.Create(
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 Diagnostic GetterLambdaBodyIsNotExpression(Location location)
=> Diagnostic.Create(
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 Diagnostic SuboptimalSetBindingOverload(Location location)
=> Diagnostic.Create(
new DiagnosticDescriptor(
id: "BSG0004",
title: "SetBinding with string path",
messageFormat: "TODO: consider using SetBinding overload with a lambda getter",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true),
location);
}