diff --git a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs
index ab86497..0c53cc2 100644
--- a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs
+++ b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs
@@ -74,28 +74,40 @@ namespace EntityFrameworkCore.Projectables.Generator
_context.ReportDiagnostic(diagnostic);
}
- return _nullConditionalRewriteSupport switch {
- NullConditionalRewriteSupport.Ignore => Visit(node.WhenNotNull),
- NullConditionalRewriteSupport.Rewrite =>
- SyntaxFactory.ConditionalExpression(
+ else if (_nullConditionalRewriteSupport is NullConditionalRewriteSupport.Ignore)
+ {
+ // Ignore the conditional accesss and simply visit the WhenNotNull expression
+ return Visit(node.WhenNotNull);
+ }
+
+ else if (_nullConditionalRewriteSupport is NullConditionalRewriteSupport.Rewrite)
+ {
+ var whenNotNullSymbol = _semanticModel.GetSymbolInfo(node.WhenNotNull).Symbol as IPropertySymbol;
+ var typeInfo = _semanticModel.GetTypeInfo(node);
+
+ // Do not translate until we can resolve the target type
+ if (typeInfo.ConvertedType is not null)
+ {
+ // Translate null-conditional into a conditional expression
+ return SyntaxFactory.ConditionalExpression(
SyntaxFactory.BinaryExpression(
SyntaxKind.NotEqualsExpression,
- targetExpression
- .WithTrailingTrivia(SyntaxFactory.Whitespace(" ")),
+ targetExpression.WithTrailingTrivia(SyntaxFactory.Whitespace(" ")),
+ SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression).WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
+ ).WithTrailingTrivia(SyntaxFactory.Whitespace(" ")),
+ SyntaxFactory.ParenthesizedExpression(
+ (ExpressionSyntax)Visit(node.WhenNotNull)
+ ).WithLeadingTrivia(SyntaxFactory.Whitespace(" ")).WithTrailingTrivia(SyntaxFactory.Whitespace(" ")),
+ SyntaxFactory.CastExpression(
+ SyntaxFactory.ParseName(typeInfo.ConvertedType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)
- .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
- )
- .WithTrailingTrivia(SyntaxFactory.Whitespace(" ")),
- SyntaxFactory.ParenthesizedExpression(
- (ExpressionSyntax)Visit(node.WhenNotNull)
- )
- .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
- .WithTrailingTrivia(SyntaxFactory.Whitespace(" ")),
- SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)
- .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
- ),
- _ => base.VisitConditionalAccessExpression(node)
- };
+ ).WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
+ ).WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia());
+ }
+ }
+
+ return base.VisitConditionalAccessExpression(node);
+
}
public override SyntaxNode? VisitMemberBindingExpression(MemberBindingExpressionSyntax node)
@@ -147,15 +159,13 @@ namespace EntityFrameworkCore.Projectables.Generator
var symbol = _semanticModel.GetSymbolInfo(node).Symbol;
if (symbol is not null)
{
- var operation = node switch {
- { Parent: { } parent } when parent.IsKind(SyntaxKind.InvocationExpression) => _semanticModel.GetOperation(node.Parent),
+ var operation = node switch { { Parent: { } parent } when parent.IsKind(SyntaxKind.InvocationExpression) => _semanticModel.GetOperation(node.Parent),
_ => _semanticModel.GetOperation(node!)
};
if (operation is IMemberReferenceOperation memberReferenceOperation)
{
- var memberAccessCanBeQualified = node switch {
- { Parent: { Parent: { } parent } } when parent.IsKind(SyntaxKind.ObjectInitializerExpression) => false,
+ var memberAccessCanBeQualified = node switch { { Parent: { Parent: { } parent } } when parent.IsKind(SyntaxKind.ObjectInitializerExpression) => false,
_ => true
};
@@ -169,7 +179,7 @@ namespace EntityFrameworkCore.Projectables.Generator
node.WithoutLeadingTrivia()
).WithLeadingTrivia(node.GetLeadingTrivia());
}
-
+
// if this operation is targeting a static member on our targetType implicitly
if (memberReferenceOperation.Instance is null && SymbolEqualityComparer.Default.Equals(memberReferenceOperation.Member.ContainingType, _targetTypeSymbol))
{
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullConditionalNullCoalesceTypeConversion.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullConditionalNullCoalesceTypeConversion.verified.txt
new file mode 100644
index 0000000..f4b5dcf
--- /dev/null
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullConditionalNullCoalesceTypeConversion.verified.txt
@@ -0,0 +1,16 @@
+//
+using EntityFrameworkCore.Projectables;
+
+namespace EntityFrameworkCore.Projectables.Generated
+#nullable disable
+{
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ public static class _Foo_SomeNumber
+ {
+ public static System.Linq.Expressions.Expression> Expression()
+ {
+ return (global::Foo fancyClass) =>
+ fancyClass != null ? (fancyClass.FancyNumber ) : (int?)null ?? 3;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
index 85e8d58..4535132 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
@@ -14,7 +14,7 @@ namespace EntityFrameworkCore.Projectables.Generated
public static System.Linq.Expressions.Expression> Expression()
{
return (global::Foo.EntityExtensions.Entity entity) =>
- entity != null ? (entity.RelatedEntities != null ? (entity.RelatedEntities[0]) : null) : null;
+ entity != null ? (entity.RelatedEntities != null ? (entity.RelatedEntities[0]) : (global::Foo.EntityExtensions.Entity)null) : (global::Foo.EntityExtensions.Entity)null;
}
}
}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
index 3d55c17..e3d5466 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
@@ -13,7 +13,7 @@ namespace EntityFrameworkCore.Projectables.Generated
public static System.Linq.Expressions.Expression> Expression()
{
return (string input) =>
- input != null ? (input.Length) : null;
+ input != null ? (input.Length) : (int?)null;
}
}
}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt
index ce9d542..40a4027 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt
@@ -14,7 +14,7 @@ namespace EntityFrameworkCore.Projectables.Generated
public static System.Linq.Expressions.Expression> Expression()
{
return (global::Foo.EntityExtensions.Entity entity) =>
- entity.FullName != null ? (entity.FullName.Substring(entity.FullName != null ? (entity.FullName.IndexOf(' ') ) : null?? 0)) : null;
+ entity.FullName != null ? (entity.FullName.Substring(entity.FullName != null ? (entity.FullName.IndexOf(' ') ) : (int?)null ?? 0)) : (string)null;
}
}
}
\ No newline at end of file
diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
index 6c58d92..5a3c009 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt
@@ -13,7 +13,7 @@ namespace EntityFrameworkCore.Projectables.Generated
public static System.Linq.Expressions.Expression> Expression()
{
return (string input) =>
- input != null ? (input[0]) : null;
+ input != null ? (input[0]) : (char?)null;
}
}
}
\ 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 10a6cec..e75ec62 100644
--- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
+++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
@@ -1542,6 +1542,30 @@ namespace One.Two {
return Verifier.Verify(result.GeneratedTrees[0].ToString());
}
+ [Fact]
+ public Task NullConditionalNullCoalesceTypeConversion()
+ {
+ // issue: https://github.com/koenbeuk/EntityFrameworkCore.Projectables/issues/48
+
+ var compilation = CreateCompilation(@"
+using EntityFrameworkCore.Projectables;
+
+class Foo {
+ public int? FancyNumber { get; set; }
+
+ [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)]
+ public static int SomeNumber(Foo fancyClass) => fancyClass?.FancyNumber ?? 3;
+}
+");
+
+ var result = RunGenerator(compilation);
+
+ Assert.Empty(result.Diagnostics);
+ Assert.Single(result.GeneratedTrees);
+
+ return Verifier.Verify(result.GeneratedTrees[0].ToString());
+ }
+
#region Helpers
Compilation CreateCompilation(string source, bool expectedToCompile = true)