diff --git a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs index 535b7ce..7d17691 100644 --- a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs +++ b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs @@ -62,6 +62,23 @@ public ExpressionSyntaxRewriter(INamedTypeSymbol targetTypeSymbol, NullCondition return base.VisitInvocationExpression(node); } + public override SyntaxNode? VisitInterpolation(InterpolationSyntax node) + { + // Visit the expression first + var targetExpression = (ExpressionSyntax)Visit(node.Expression); + + // Check if the expression already has parentheses + if (targetExpression is ParenthesizedExpressionSyntax) + { + return node.WithExpression(targetExpression); + } + + // Create a new expression wrapped in parentheses + var newExpression = SyntaxFactory.ParenthesizedExpression(targetExpression); + + return node.WithExpression(newExpression); + } + public override SyntaxNode? VisitConditionalAccessExpression(ConditionalAccessExpressionSyntax node) { var targetExpression = (ExpressionSyntax)Visit(node.Expression); diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithContraints_AreRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithContraints_AreRewritten.verified.txt index fb4f5f3..d000d7c 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithContraints_AreRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithContraints_AreRewritten.verified.txt @@ -14,7 +14,7 @@ namespace EntityFrameworkCore.Projectables.Generated { static global::System.Linq.Expressions.Expression, string>> Expression() { - return (global::Foo.Entity @this) => $"{@this.FirstName} {@this.LastName} {@this.SomeSubobject.SomeProp}"; + return (global::Foo.Entity @this) => $"{(@this.FirstName)} {(@this.LastName)} {(@this.SomeSubobject.SomeProp)}"; } } } \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt index 6913fb7..048a64e 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt @@ -13,7 +13,7 @@ namespace EntityFrameworkCore.Projectables.Generated { static global::System.Linq.Expressions.Expression, string>> Expression() { - return (global::Foo.Entity @this) => $"{@this.FirstName} {@this.LastName} {@this.SomeSubobject}"; + return (global::Foo.Entity @this) => $"{(@this.FirstName)} {(@this.LastName)} {(@this.SomeSubobject)}"; } } } \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt new file mode 100644 index 0000000..6e33afa --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt @@ -0,0 +1,18 @@ +// +#nullable disable +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Status + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.ValidationDate != null ? $"Validation date : ({(global::Foo.MyExtensions.ToDateString(@this.ValidationDate.Value))})" : ""; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt new file mode 100644 index 0000000..6e33afa --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt @@ -0,0 +1,18 @@ +// +#nullable disable +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Status + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.ValidationDate != null ? $"Validation date : ({(global::Foo.MyExtensions.ToDateString(@this.ValidationDate.Value))})" : ""; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs index b79842d..cef1286 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs @@ -778,6 +778,66 @@ static class C { return Verifier.Verify(result.GeneratedTrees[0].ToString()); } + + [Fact] + public Task StringInterpolationWithStaticCall_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class MyExtensions { + public static string ToDateString(this DateTime date) => date.ToString(""dd/MM/yyyy""); + } + + class C { + public DateTime? ValidationDate { get; set; } + + [Projectable] + public string Status => ValidationDate != null ? $""Validation date : ({ValidationDate.Value.ToDateString()})"" : """"; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task StringInterpolationWithParenthesis_NoParenthesisAdded() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class MyExtensions { + public static string ToDateString(this DateTime date) => date.ToString(""dd/MM/yyyy""); + } + + class C { + public DateTime? ValidationDate { get; set; } + + [Projectable] + public string Status => ValidationDate != null ? $""Validation date : ({(ValidationDate.Value.ToDateString())})"" : """"; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } [Fact] public Task NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten()