Skip to content

Commit c0b8ab6

Browse files
authored
Fix null-coalesce typing for ignored conditional access
1 parent da8f1ea commit c0b8ab6

3 files changed

Lines changed: 77 additions & 1 deletion

File tree

src/EntityFrameworkCore.Projectables.Generator/SyntaxRewriters/ExpressionSyntaxRewriter.NullConditionalRewrite.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,25 @@ internal partial class ExpressionSyntaxRewriter
2626
else if (_nullConditionalRewriteSupport is NullConditionalRewriteSupport.Ignore)
2727
{
2828
// Ignore the conditional access and simply visit the WhenNotNull expression
29-
return Visit(node.WhenNotNull);
29+
var rewrittenExpression = (ExpressionSyntax?)Visit(node.WhenNotNull);
30+
if (rewrittenExpression is null)
31+
{
32+
return null;
33+
}
34+
35+
var typeInfo = _semanticModel.GetTypeInfo(node);
36+
if (IsCoalesceLeftOperand(node) &&
37+
typeInfo.ConvertedType is INamedTypeSymbol { IsValueType: true, OriginalDefinition.SpecialType: SpecialType.System_Nullable_T } nullableType &&
38+
_semanticModel.GetTypeInfo(node.WhenNotNull).Type is { IsValueType: true } rewrittenType &&
39+
SymbolEqualityComparer.Default.Equals(nullableType.TypeArguments[0], rewrittenType))
40+
{
41+
return SyntaxFactory.CastExpression(
42+
SyntaxFactory.ParseTypeName(nullableType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
43+
SyntaxFactory.ParenthesizedExpression(rewrittenExpression)
44+
);
45+
}
46+
47+
return rewrittenExpression;
3048
}
3149

3250
else if (_nullConditionalRewriteSupport is NullConditionalRewriteSupport.Rewrite)
@@ -105,4 +123,19 @@ private static bool IsNullableValueType(ITypeSymbol? type)
105123
return type is { IsValueType: true } &&
106124
type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T;
107125
}
126+
127+
private static bool IsCoalesceLeftOperand(ConditionalAccessExpressionSyntax node)
128+
{
129+
ExpressionSyntax current = node;
130+
var parent = node.Parent;
131+
132+
while (parent is ParenthesizedExpressionSyntax parenthesizedExpression)
133+
{
134+
current = parenthesizedExpression;
135+
parent = parenthesizedExpression.Parent;
136+
}
137+
138+
return parent is BinaryExpressionSyntax { RawKind: (int)SyntaxKind.CoalesceExpression } coalesceExpression &&
139+
coalesceExpression.Left == current;
140+
}
108141
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// <auto-generated/>
2+
#nullable disable
3+
using EntityFrameworkCore.Projectables;
4+
5+
namespace EntityFrameworkCore.Projectables.Generated
6+
{
7+
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
8+
static class _Product_GetCost
9+
{
10+
static global::System.Linq.Expressions.Expression<global::System.Func<global::Product, decimal>> Expression()
11+
{
12+
return (global::Product @this) => (decimal? )(@this.Price.Amount) ?? 0m;
13+
}
14+
}
15+
}

tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,34 @@ class Foo {
488488
return Verifier.Verify(result.GeneratedTrees[0].ToString());
489489
}
490490

491+
[Fact]
492+
public Task NullConditionalNullCoalesceTypeConversion_WithIgnoreSupport()
493+
{
494+
var compilation = CreateCompilation(@"
495+
using EntityFrameworkCore.Projectables;
496+
497+
public class Price {
498+
public decimal Amount { get; set; }
499+
}
500+
501+
public class Product {
502+
public Price? Price { get; set; }
503+
504+
[Projectable(AllowBlockBody = true, NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)]
505+
public decimal GetCost() {
506+
return Price?.Amount ?? 0m;
507+
}
508+
}
509+
");
510+
511+
var result = RunGenerator(compilation);
512+
513+
Assert.Empty(result.Diagnostics);
514+
Assert.Single(result.GeneratedTrees);
515+
516+
return Verifier.Verify(result.GeneratedTrees[0].ToString());
517+
}
518+
491519
[Fact]
492520
public Task NullableValueType_MemberAccess_WithRewriteSupport_IsBeingRewritten()
493521
{

0 commit comments

Comments
 (0)