diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs index 90a83bd..14e31dd 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs @@ -7,6 +7,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness static void Main() { new NullPropagation().TestNotCoalescing(); + new NullPropagation().TestNullableBoolInChain(); #if CS72 new NullPropagation().TestRefStructNotCoalescing(); #endif @@ -15,6 +16,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness class MyClass { public string Text; + public bool? Flag; } void TestNotCoalescing() @@ -29,6 +31,26 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness return c != null ? c.Text : "Hello"; } + void TestNullableBoolInChain() + { + Console.WriteLine("TestNullableBoolInChain:"); + foreach (MyClass c in new[] { null, new MyClass(), new MyClass { Flag = false }, new MyClass { Flag = true } }) + { + Console.WriteLine(EqualsTrue(c)); + Console.WriteLine(GetValueOrDefaultToString(c) ?? ""); + } + } + + bool EqualsTrue(MyClass c) + { + return c?.Flag == true; + } + + string GetValueOrDefaultToString(MyClass c) + { + return c?.Flag.GetValueOrDefault().ToString(); + } + #if CS72 ref struct ByRefLikeStruct { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs index 063dab6..c2f9201 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs @@ -32,6 +32,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty public readonly MyStruct ReadonlyStructField; public string Text; public MyClass Field; + public bool? NullableBool; public MyClass Property { get; set; } public MyClass this[int index] => null; public MyClass Method(int arg) @@ -380,5 +381,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty return x?.ToString(); #endif } + + private static bool Issue3702(MyClass c) + { + return c?.NullableBool.GetValueOrDefault() ?? false; + } + + private static string Issue3702ToString(MyClass c) + { + return c?.NullableBool.GetValueOrDefault().ToString(); + } } } diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index bad908d..0371d7a 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -26,6 +26,7 @@ using System.Text; using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Syntax; +using ICSharpCode.Decompiler.CSharp.Transforms; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.Semantics; @@ -594,7 +595,8 @@ namespace ICSharpCode.Decompiler.CSharp if (settings.LiftNullables && method.Name == "GetValueOrDefault" && method.DeclaringType.IsKnownType(KnownTypeCode.NullableOfT) && method.DeclaringType.TypeArguments[0].IsKnownType(KnownTypeCode.Boolean) - && argumentList.Length == 0) + && argumentList.Length == 0 + && !IntroduceQueryExpressions.IsNullConditional(target)) { argumentList.CheckNoNamedOrOptionalArguments(); return new BinaryOperatorExpression( diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs index c9c5064..57580b1 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs @@ -380,7 +380,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } } - bool IsNullConditional(Expression target) => target switch { + internal static bool IsNullConditional(Expression target) => target switch { UnaryOperatorExpression { Operator: UnaryOperatorType.NullConditional } => true, MemberReferenceExpression member => IsNullConditional(member.Target), InvocationExpression invocation => IsNullConditional(invocation.Target),