File: src\Analyzers\CSharp\Tests\UseNullPropagation\UseNullPropagationTests.cs
Web Access
Project: src\src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Features.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.UseNullPropagation;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseNullPropagation;
 
using VerifyCS = CSharpCodeFixVerifier<
    CSharpUseNullPropagationDiagnosticAnalyzer,
    CSharpUseNullPropagationCodeFixProvider>;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsUseNullPropagation)]
public partial class UseNullPropagationTests
{
    private static async Task TestInRegularAndScript1Async(string testCode, string fixedCode, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
    {
        await new VerifyCS.Test
        {
            TestCode = testCode,
            FixedCode = fixedCode,
            // code action is currently generating invalid trees.  Specifically, it transforms `x.Y()` into `x.?Y()`
            // by just rewriting `x.Y` into `x?.Y`.  That is not correct.  the RHS of the `?` should `.Y()` not
            // `.Y`.
            CodeActionValidationMode = CodeActionValidationMode.None,
            LanguageVersion = LanguageVersion.CSharp9,
            TestState =
            {
                OutputKind = outputKind,
            },
        }.RunAsync();
    }
 
    private static async Task TestMissingInRegularAndScriptAsync(string testCode, LanguageVersion languageVersion = LanguageVersion.CSharp9)
    {
        await new VerifyCS.Test
        {
            TestCode = testCode,
            FixedCode = testCode,
            LanguageVersion = languageVersion,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestLeft_Equals()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o == null ? null : o.ToString()|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestLeft_Equals_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    [|if|] (o != null)
                        o.ToString();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_WithBlock()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    [|if|] (o != null)
                    {
                        o.ToString();
                    }
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_NotWithElse()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    if (o != null)
                        o.ToString();
                    else
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_NotWithMultipleStatements()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    if (o != null)
                    {
                        o.ToString();
                        o.ToString();
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestLeft_Equals_IfStatement_TopLevel()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            object o = null;
            [|if|] (o != null)
                o.ToString();
            """,
            """
            using System;
 
            object o = null;
            o?.ToString();
            """, OutputKind.ConsoleApplication);
    }
 
    [Fact]
    public async Task TestLeft_IsNull()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o is null ? null : o.ToString()|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestLeft_IsNotNull()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o is not null ? o.ToString() : null|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestLeft_IsNotNull_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    [|if|] (o is not null)
                        o.ToString();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnCSharp5()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o == null ? null : o.ToString();
                }
            }
            """, LanguageVersion.CSharp5);
    }
 
    [Fact]
    public async Task TestMissingOnCSharp5_IfStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    if (o != null)
                        o.ToString();
                }
            }
            """, LanguageVersion.CSharp5);
    }
 
    [Fact]
    public async Task TestRight_Equals()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|null == o ? null : o.ToString()|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestRight_Equals_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    [|if|] (null != o)
                                o.ToString();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestLeft_NotEquals()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o != null ? o.ToString() : null|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWithNullableType()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|c != null ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWithNullableType_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] (c != null)
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWithNullableTypeAndObjectCast()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|(object)c != null ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWithNullableTypeAndObjectCast_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] ((object)c != null)
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestRight_NotEquals()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|null != o ? o.ToString() : null|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIndexer()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o == null ? null : {|CS0021:o[0]|}|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?{|CS0021:[0]|};
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIndexer_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    [|if|] (o != null)
                        {|CS0021:o[0]|}.ToString();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    o?{|CS0021:[0]|}.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestConditionalAccess()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o == null ? null : o.{|CS1061:B|}?.C|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?{|CS1061:.B|}?.C;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestConditionalAccess_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    [|if|](o != null)
                        o.{|CS1061:B|}?.C();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    o?{|CS1061:.B|}?.C();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMemberAccess()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o == null ? null : o.{|CS1061:B|}|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?{|CS1061:.B|};
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMemberAccess_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    [|if|] (o != null)
                        o.{|CS1061:B|}();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    o?{|CS1061:.B|}();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnSimpleMatch()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o == null ? null : o;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnSimpleMatch_IfStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    if (o != null)
                        {|CS0201:o|};
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestParenthesizedCondition()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|(o == null) ? null : o.ToString()|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestFixAll1()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v1 = [|o == null ? null : o.ToString()|];
                    var v2 = [|o != null ? o.ToString() : null|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v1 = o?.ToString();
                    var v2 = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestFixAll2()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o1, object o2)
                {
                    var v1 = [|o1 == null ? null : o1.{|CS1501:ToString|}([|o2 == null ? null : o2.ToString()|])|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o1, object o2)
                {
                    var v1 = o1?{|CS1501:.ToString|}(o2?.ToString());
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15505")]
    public async Task TestOtherValueIsNotNull1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = {|CS0173:o == null ? 0 : o.ToString()|};
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15505")]
    public async Task TestOtherValueIsNotNull2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = {|CS0173:o != null ? o.ToString() : 0|};
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/16287")]
    public async Task TestMethodGroup()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    Action<string> a = c != null ? c.M : (Action<string>)null;
                }
            }
            class C { public void M(string s) { } }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17623")]
    public async Task TestInExpressionTree()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            using System.Linq.Expressions;
 
            class Program
            {
                void Main(string s)
                {
                    Method<string>(t => s != null ? s.ToString() : null); // works
                }
 
                public void Method<T>(Expression<Func<T, string>> functor)
                {
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17623")]
    [WorkItem("https://github.com/dotnet/roslyn/issues/33992")]
    public async Task TestInExpressionTree2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System.Linq;
 
            class C
            {
                void Main()
                {
                    _ = from item in Enumerable.Empty<(int? x, int? y)?>().AsQueryable()
                        select item == null ? null : item.Value.x;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17623")]
    [WorkItem("https://github.com/dotnet/roslyn/issues/33992")]
    public async Task TestInExpressionTree3()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System.Linq;
 
            class C
            {
                void Main()
                {
                    _ = from item in Enumerable.Empty<(int? x, int? y)?>().AsQueryable()
                        where (item == null ? null : item.Value.x) > 0
                        select item;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17623")]
    [WorkItem("https://github.com/dotnet/roslyn/issues/33992")]
    public async Task TestInExpressionTree4()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System.Linq;
 
            class C
            {
                void Main()
                {
                    _ = from item in Enumerable.Empty<(int? x, int? y)?>().AsQueryable()
                        let x = item == null ? null : item.Value.x
                        select x;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19774")]
    public async Task TestNullableMemberAccess()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void Main(DateTime? toDate)
                {
                    var v = [|toDate == null ? null : toDate.Value.ToString("yyyy/MM/ dd")|];
                }
            }
            """,
 
            """
            using System;
 
            class C
            {
                void Main(DateTime? toDate)
                {
                    var v = toDate?.ToString("yyyy/MM/ dd");
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19774")]
    public async Task TestNullableMemberAccess_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void Main(DateTime? toDate)
                {
                    [|if|] (toDate != null)
                        toDate.Value.ToString("yyyy/MM/ dd");
                }
            }
            """,
 
            """
            using System;
 
            class C
            {
                void Main(DateTime? toDate)
                {
                    toDate?.ToString("yyyy/MM/ dd");
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19774")]
    public async Task TestNullableElementAccess()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            struct S
            {
                public string this[int i] => "";
            }
 
            class C
            {
                void Main(S? s)
                {
                    var x = [|s == null ? null : s.Value[0]|];
                }
            }
            """,
 
            """
            using System;
 
            struct S
            {
                public string this[int i] => "";
            }
 
            class C
            {
                void Main(S? s)
                {
                    var x = s?[0];
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndIsNull()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|c is null ? null : c.f|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndIsNotNull()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|c is not null ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndIsNotNull_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] (c is not null)
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndIsType()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c is C ? null : c.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndIsType_IfStatement1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    if (c is C)
                        c.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndIsType_IfStatement2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    if (c is C d)
                        c.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndIsType_IfStatement3()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    if (c is not C)
                        c.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestIsOtherConstant()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(string s)
                {
                    int? x = s is "" ? null : (int?)s.Length;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEquals1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|ReferenceEquals(c, null) ? null : c.f|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEquals1_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] (!ReferenceEquals(c, null))
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEquals2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|ReferenceEquals(null, c) ? null : c.f|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEquals2_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] (!ReferenceEquals(null, c))
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsOtherValue1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = ReferenceEquals(c, other) ? null : c.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsOtherValue1_IfStatement1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    if (ReferenceEquals(c, other))
                        c.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsOtherValue1_IfStatement2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    if (!ReferenceEquals(c, other))
                        c.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsOtherValue2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = ReferenceEquals(other, c) ? null : c.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsWithObject1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|object.ReferenceEquals(c, null) ? null : c.f|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsWithObject1_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] (!object.ReferenceEquals(c, null))
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsWithObject2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|object.ReferenceEquals(null, c) ? null : c.f|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsWithObject2_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] (!object.ReferenceEquals(null, c))
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsOtherValueWithObject1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = object.ReferenceEquals(c, other) ? null : c.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndReferenceEqualsOtherValueWithObject2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = object.ReferenceEquals(other, c) ? null : c.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndNotIsNull()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!(c is null) ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndNotIsNotNull()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!(c is not null) ? null : c.f|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndNotIsType()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = !(c is C) ? c.f : null;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndNotIsOtherConstant()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(string s)
                {
                    int? x = !(s is "") ? (int?)s.Length : null;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEquals1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!ReferenceEquals(c, null) ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEquals2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!ReferenceEquals(null, c) ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEqualsOtherValue1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = !ReferenceEquals(c, other) ? c.f : null;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEqualsOtherValue2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = !ReferenceEquals(other, c) ? c.f : null;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEqualsWithObject1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!object.ReferenceEquals(c, null) ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEqualsWithObject2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!object.ReferenceEquals(null, c) ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEqualsOtherValueWithObject1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = !object.ReferenceEquals(c, other) ? c.f : null;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestWithNullableTypeAndLogicalNotReferenceEqualsOtherValueWithObject2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = !object.ReferenceEquals(other, c) ? c.f : null;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestEqualsWithLogicalNot()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!(c == null) ? c.f : null|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestEqualsWithLogicalNot_IfStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    [|if|] (!(c == null))
                        c.f?.ToString();
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    c?.f?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestNotEqualsWithLogicalNot()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = [|!(c != null) ? null : c.f|];
                }
            }
            """,
            """
            class C
            {
                public int? f;
                void M(C c)
                {
                    int? x = c?.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestEqualsOtherValueWithLogicalNot()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = !(c == other) ? c.f : null;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23043")]
    public async Task TestNotEqualsOtherValueWithLogicalNot()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                public int? f;
                void M(C c, C other)
                {
                    int? x = !(c != other) ? null : c.f;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49517")]
    public async Task TestParenthesizedExpression()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|(o == null) ? null : (o.ToString())|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = (o?.ToString());
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49517")]
    public async Task TestReversedParenthesizedExpression()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|(o != null) ? (o.ToString()) : null|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = (o?.ToString());
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74273")]
    public async Task TestParenthesizedPropertyAccess()
    {
        await TestInRegularAndScript1Async("""
            using System;
            
            class C
            {
                int? Length(Array array) => [|array == null ? null : (array.Length)|];
            }
            """, """
            using System;
            
            class C
            {
                int? Length(Array array) => (array?.Length);
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74273")]
    public async Task TestReversedParenthesizedPropertyAccess()
    {
        await TestInRegularAndScript1Async("""
            using System;
            
            class C
            {
                int? Length(Array array) => [|array != null ? (array.Length) : null|];
            }
            """, """
            using System;
            
            class C
            {
                int? Length(Array array) => (array?.Length);
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49517")]
    public async Task TestParenthesizedNull()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o == null ? (null) : o.ToString()|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49517")]
    public async Task TestReversedParenthesizedNull()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = [|o != null ? o.ToString() : (null)|];
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    var v = o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_Trivia1()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before
                    [|if|] (o != null)
                        o.ToString();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before
                    o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_Trivia2()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    [|if|] (o != null)
                        // Before2
                        o.ToString();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    // Before2
                    o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_Trivia3()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    [|if|] (o != null)
                    {
                        // Before2
                        o.ToString();
                    }
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    // Before2
                    o?.ToString();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_Trivia4()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    [|if|] (o != null)
                    {
                        // Before2
                        o.ToString(); // After
                    }
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    // Before2
                    o?.ToString(); // After
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestIfStatement_Trivia5()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    [|if|] (o != null)
                    {
                        // Before2
                        o.ToString();
                    } // After
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M(object o)
                {
                    // Before1
                    // Before2
                    o?.ToString(); // After
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestNotOnPointer_IfStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                unsafe void M(int* i)
                {
                    if (i != null)
                        i->ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63557")]
    public async Task TestNotWithColorColorStaticCase()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class D
            {
                public static void StaticMethod(D d) { }
                public void InstanceMethod(D d) { }
            }
 
            public class C
            {
                D D { get; }
 
                public void Test()
                {
                    if (D != null)
                    {
                        D.StaticMethod(D);
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63557")]
    public async Task TestWithColorColorInstanceCase()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class D
            {
                public static void Method(D d) { }
                public void InstanceMethod(D d) { }
            }
 
            public class C
            {
                D D { get; }
 
                public void Test()
                {
                    [|if|] (D != null)
                    {
                        D.InstanceMethod(D);
                    }
                }
            }
            """,
            """
            using System;
 
            class D
            {
                public static void Method(D d) { }
                public void InstanceMethod(D d) { }
            }
 
            public class C
            {
                D D { get; }
 
                public void Test()
                {
                    D?.InstanceMethod(D);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53860")]
    public async Task TestWithMethodGroupReference()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            using System.Collections.Generic;
 
            class C
            {
                Action<int> M(List<int> p) => p is null ? null : p.Add;
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66036")]
    public async Task TestElseIfStatement1()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else [|if|] (s != null)
                    {
                        s.ToString();
                    }
                }
            }
            """, """
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else
                    {
                        s?.ToString();
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66036")]
    public async Task TestElseIfStatement2()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else [|if|] (s != null)
                        s.ToString();
                }
            }
            """, """
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else
                        s?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66036")]
    public async Task TestElseIfStatement_Trivia()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else [|if|] (s != null)
                    {
                        // comment
                        s.ToString();
                    }
                }
            }
            """, """
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else
                    {
                        // comment
                        s?.ToString();
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66036")]
    public async Task TestElseIfStatement_KeepBracePlacementStyle()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else [|if|] (s != null) {
                        s.ToString();
                    }
                }
            }
            """, """
            class C
            {
                void M(string s)
                {
                    if (true)
                    {
                    }
                    else {
                        s?.ToString();
                    }
                }
            }
            """);
    }
}