File: src\Analyzers\CSharp\Tests\UsePatternMatching\CSharpAsAndNullCheckTests.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.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.UsePatternMatching;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UsePatternMatching;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsInlineTypeCheck)]
public partial class CSharpAsAndNullCheckTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor
{
    public CSharpAsAndNullCheckTests(ITestOutputHelper logger)
      : base(logger)
    {
    }
 
    internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
        => (new CSharpAsAndNullCheckDiagnosticAnalyzer(), new CSharpAsAndNullCheckCodeFixProvider());
 
    [Theory]
    [InlineData("x != null", "o is string x")]
    [InlineData("null != x", "o is string x")]
    [InlineData("(object)x != null", "o is string x")]
    [InlineData("null != (object)x", "o is string x")]
    [InlineData("x is object", "o is string x")]
    [InlineData("x == null", "!(o is string x)")]
    [InlineData("null == x", "!(o is string x)")]
    [InlineData("(object)x == null", "!(o is string x)")]
    [InlineData("null == (object)x", "!(o is string x)")]
    [InlineData("x is null", "!(o is string x)")]
    [InlineData("(x = o as string) != null", "o is string x")]
    [InlineData("null != (x = o as string)", "o is string x")]
    [InlineData("(x = o as string) is object", "o is string x")]
    [InlineData("(x = o as string) == null", "!(o is string x)")]
    [InlineData("null == (x = o as string)", "!(o is string x)")]
    [InlineData("(x = o as string) is null", "!(o is string x)")]
    [InlineData("x == null", "o is not string x", LanguageVersion.CSharp9)]
    public async Task InlineTypeCheck1(string input, string output, LanguageVersion version = LanguageVersion.CSharp8)
    {
        await TestStatement($"if ({input}) {{ }}", $"if ({output}) {{ }}", version);
        await TestStatement($"var y = {input};", $"var y = {output};", version);
        await TestStatement($"return {input};", $"return {output};", version);
    }
 
    [Theory]
    [InlineData("(x = o as string) != null", "o is string x")]
    [InlineData("null != (x = o as string)", "o is string x")]
    [InlineData("(x = o as string) is object", "o is string x")]
    [InlineData("(x = o as string) == null", "!(o is string x)")]
    [InlineData("null == (x = o as string)", "!(o is string x)")]
    public async Task InlineTypeCheck2(string input, string output)
        => await TestStatement($"while ({input}) {{ }}", $"while ({output}) {{ }}");
 
    private async Task TestStatement(string input, string output, LanguageVersion version = LanguageVersion.CSharp8)
    {
        await TestInRegularAndScript1Async(
            $$"""
            class C
            {
                void M(object o)
                {
                    [|var|] x = o as string;
                    {{input}}
                }
            }
            """,
            $$"""
            class C
            {
                void M(object o)
                {
                    {{output}}
                }
            }
            """, new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(version)));
    }
 
    [Fact]
    public async Task TestMissingInCSharp6()
    {
        await TestMissingAsync(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null)
                    {
                    }
                }
            }
            """, new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6)));
    }
 
    [Fact]
    public async Task TestMissingInWrongName()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|var|] y = o as string;
                    if (x != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestInSwitchSection()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    switch (o)
                    {
                        default:
                            [|var|] x = o as string;
                            if (x != null)
                            {
                            }
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    switch (o)
                    {
                        default:
                            if (o is string x)
                            {
                            }
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33345")]
    public async Task TestRemoveNewLinesInSwitchStatement()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    switch (o)
                    {
                        default:
                            [|var|] x = o as string;
 
                            //a comment
                            if (x != null)
                            {
                            }
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    switch (o)
                    {
                        default:
                            //a comment
                            if (o is string x)
                            {
                            }
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnNonDeclaration()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|y|] = o as string;
                    if (x != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25237")]
    public async Task TestMissingOnReturnStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|return;|]
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnIsExpression()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o is string;
                    if (x != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task InlineTypeCheckComplexExpression1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = (o ? z : w) as string;
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    if ((o ? z : w) is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestInlineTypeCheckWithElse()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (null != x)
                    {
                    }
                    else
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    if (o is string x)
                    {
                    }
                    else
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestComments1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    // prefix comment
                    [|var|] x = o as string;
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    // prefix comment
                    if (o is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestComments2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string; // suffix comment
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    // suffix comment
                    if (o is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestComments3()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    // prefix comment
                    [|var|] x = o as string; // suffix comment
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    // prefix comment
                    // suffix comment
                    if (o is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33345")]
    public async Task TestRemoveNewLines()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
 
                    //suffix comment
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    //suffix comment
                    if (o is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33345")]
    public async Task TestRemoveNewLinesWhereBlankLineIsNotEmpty()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
 
                    //suffix comment
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    //suffix comment
                    if (o is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33345")]
    public async Task TestRemoveNewLines2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    int a = 0;
                    [|var|] x = o as string;
 
                    //suffix comment
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    int a = 0;
 
                    //suffix comment
                    if (o is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task InlineTypeCheckComplexCondition1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null ? 0 : 1)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    if (o is string x ? 0 : 1)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task InlineTypeCheckComplexCondition2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if ((x != null))
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    if ((o is string x))
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task InlineTypeCheckComplexCondition3()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null && x.Length > 0)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    if (o is string x && x.Length > 0)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestDefiniteAssignment1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null && x.Length > 0)
                    {
                    }
                    else if (x != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestDefiniteAssignment2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null && x.Length > 0)
                    {
                    }
 
                    Console.WriteLine(x);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestDefiniteAssignment3()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null && x.Length > 0)
                    {
                    }
 
                    x = null;
                    Console.WriteLine(x);
                }
            }
            """,
 
            """
            class C
            {
                void M()
                {
                    if (o is string x && x.Length > 0)
                    {
                    }
 
                    x = null;
                    Console.WriteLine(x);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21097")]
    public async Task TestDefiniteAssignment4()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|var|] s = o as string;
                    if (s != null)
                    {
 
                    }
                    else
                    {
                        if (o is int?)
                            s = null;
                        s.ToString();
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24286")]
    public async Task TestDefiniteAssignment5()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            public class Test
            {
                public void TestIt(object o1, object o2)
                {
                    [|var|] test = o1 as Test;
                    if (test != null || o2 != null)
                    {
                        var o3 = test ?? o2;
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestDefiniteAssignment6()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                string Use(string x) => x;
 
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null && x.Length > 0)
                    {
                    }
 
                    Console.WriteLine(x = Use(x));
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestDefiniteAssignment7()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|var|] x = o as string;
                    if (x != null && x.Length > 0)
                    {
                    }
 
                    Console.WriteLine(x);
                    x = "writeAfter";
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/28821")]
    public async Task TestDefiniteAssignment8()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class Program
            {
                static void Goo(System.Activator bar)
                {
                }
 
                static void Main(string[] args)
                {
                    var a = new object();
                    [|var|] b = a as System.Activator;
                    if ((b == null) && false)
                    {
                    }
                    else
                    {
                        Goo(b);
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/28866")]
    public async Task TestWrittenExpressionBeforeNullCheck()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class Goo
            {
                object Data { get; set; }
 
                void DoGoo()
                {
                    [|var|] oldData = this.Data as string;
 
                    Data = null;
 
                    if (oldData != null)
                    {
                        // Do something
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15957")]
    public async Task TestTrivia1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object y)
                {
                    if (y != null)
                    {
                    }
 
                    [|var|] x = o as string;
                    if (x != null)
                    {
                    }
                }
            }
            """,
            """
            class C
            {
                void M(object y)
                {
                    if (y != null)
                    {
                    }
 
                    if (o is string x)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17129")]
    public async Task TestTrivia2()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
            namespace N
            {
                class Program
                {
                    public static void Main()
                    {
                        object o = null;
                        int i = 0;
                        [|var|] s = o as string;
                        if (s != null && i == 0 && i == 1 &&
                            i == 2 && i == 3 &&
                            i == 4 && i == 5)
                        {
                            Console.WriteLine();
                        }
                    }
                }
            }
            """,
            """
            using System;
            namespace N
            {
                class Program
                {
                    public static void Main()
                    {
                        object o = null;
                        int i = 0;
                        if (o is string s && i == 0 && i == 1 &&
                            i == 2 && i == 3 &&
                            i == 4 && i == 5)
                        {
                            Console.WriteLine();
                        }
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17122")]
    public async Task TestMissingOnNullableType()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            namespace N
            {
                class Program
                {
                    public static void Main()
                    {
                        object o = null;
                        [|var|] i = o as int?;
                        if (i != null)
                            Console.WriteLine(i);
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18053")]
    public async Task TestMissingWhenTypesDoNotMatch()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class SyntaxNode
            {
                public SyntaxNode Parent;
            }
 
            class BaseParameterListSyntax : SyntaxNode
            {
            }
 
            class ParameterSyntax : SyntaxNode
            {
 
            }
 
            public static class C
            {
                static void M(ParameterSyntax parameter)
                {
                    [|SyntaxNode|] parent = parameter.Parent as BaseParameterListSyntax;
 
                    if (parent != null)
                    {
                        parent = parent.Parent;
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnWhileNoInline()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|string|] x = o as string;
                    while (x != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWhileDefiniteAssignment1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|string|] x;
                    while ((x = o as string) != null)
                    {
                    }
 
                    var readAfterWhile = x;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWhileDefiniteAssignment2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|string|] x;
                    while ((x = o as string) != null)
                    {
                    }
 
                    x = "writeAfterWhile";
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWhileDefiniteAssignment3()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|string|] x;
                    x = "writeBeforeWhile";
                    while ((x = o as string) != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestWhileDefiniteAssignment4()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|string|] x = null;
                    var readBeforeWhile = x;
                    while ((x = o as string) != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23504")]
    public async Task DoNotChangeOriginalFormatting1()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    object obj = "test";
 
                    [|var|] str = obj as string;
                    var title = str != null
                        ? str
                        : ";
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    object obj = "test";
 
                    var title = obj is string str
                        ? str
                        : ";
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23504")]
    public async Task DoNotChangeOriginalFormatting2()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    object obj = "test";
 
                    [|var|] str = obj as string;
                    var title = str != null ? str : ";
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    object obj = "test";
 
                    var title = obj is string str ? str : ";
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21172")]
    public async Task TestMissingWithDynamic()
    {
        await TestMissingAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|var|] x = o as dynamic;
                    if (x != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21551")]
    public async Task TestOverloadedUserOperator()
    {
        await TestMissingAsync(
            """
            class C
            {
              public static void Main()
              {
                object o = new C();
                [|var|] c = o as C;
                if (c != null)
                  System.Console.WriteLine();
              }
 
              public static bool operator ==(C c1, C c2) => false;
              public static bool operator !=(C c1, C c2) => false;
            }
            """);
    }
 
    [Fact]
    public async Task TestNegativeDefiniteAssignment1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                string M(object o)
                {
                    [|var|] x = o as string;
                    if (x == null) return null;
                    return x;
                }
            }
            """,
            """
            class C
            {
                string M(object o)
                {
                    if (!(o is string x)) return null;
                    return x;
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact]
    public async Task TestNegativeDefiniteAssignment2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                string M(object o, bool b)
                {
                    [|var|] x = o as string;
                    if (((object)x == null) || b)
                    {
                        return null;
                    }
                    else
                    {
                        return x;
                    }
                }
            }
            """,
            """
            class C
            {
                string M(object o, bool b)
                {
                    if ((!(o is string x)) || b)
                    {
                        return null;
                    }
                    else
                    {
                        return x;
                    }
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25993")]
    public async Task TestEmbeddedStatement1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    var fe = e as C;
                    [|var|] ae = e as C;
                    if (fe != null)
                    {
                        M(fe); // fe is used
                    }
                    else if (ae != null)
                    {
                        M(ae); // ae is used
                    }
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    var fe = e as C;
                    if (fe != null)
                    {
                        M(fe); // fe is used
                    }
                    else if (e is C ae)
                    {
                        M(ae); // ae is used
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25993")]
    public async Task TestEmbeddedStatement2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    var fe = e as C;
                    [|var|] ae = e as C;
                    if (fe != null)
                    {
                        M(ae); // ae is used
                    }
                    else if (ae != null)
                    {
                        M(ae); // ae is used
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestUseBeforeDeclaration()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|var|] c = e as C;
                    {
                        {
                            var x1 = c;
 
                            if (c != null)
                            {
 
                            }
                        }
                    }
                }
 
            }
            """);
    }
 
    [Fact]
    public async Task TestPossiblyUnassigned()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|var|] c = e as C;
                    {
                        {
                            if (c != null)
                            {
 
                            }
 
                            var x2 = c;
                        }
 
                        // out of scope
                        var x3 = c;
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestOutOfScope()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|var|] c = e as C;
                    {
                        {
                            if (c != null)
                            {
 
                            }
                        }
 
                        // out of scope
                        var x3 = c;
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestDeclarationOnOuterBlock()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    [|var|] c = e as C;
                    {
                        {
                            if (c != null)
                            {
 
                            }
                        }
                    }
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    {
                        {
                            if (e is C c)
                            {
 
                            }
                        }
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestConditionalExpression()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    [|var|] c = e as C;
                    M(c != null ? c : null);
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    M(e is C c ? c : null);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestConditionalExpression_OppositeBranch()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|var|] c = e as C;
                    M(c != null ? c : null, c);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestForStatement_NoInlineTypeCheck()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|var|] c = e as C;
                    for (;(c)!=null;) {}
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestForStatement_InlineTypeCheck()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    [|C|] c;
                    for (; !((c = e as C)==null);) { }
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    for (; !(!(e is C c));) { }
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact]
    public async Task TestForStatement_InScope()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    [|C|] c = null;
                    for (; !((c = e as C)==null);)
                    {
                        M(c);
                    }
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    for (; !(!(e is C c));)
                    {
                        M(c);
                    }
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact]
    public async Task TestForStatement_NotAssignedBeforeAccess()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|C|] c = null;
                    for (; ((c = e as C)==null);)
                    {
                        if (b) c = null;
                        M(c);
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestForStatement_AssignedBeforeAccess()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e, bool b)
                {
                    [|C|] c = null;
                    for (; (c = e as C)==null;)
                    {
                        if (b) c = null;
                        else c = null;
                        M(c);
                    }
                }
            }
            """,
            """
            class C
            {
                void M(object e, bool b)
                {
                    for (; !(e is C c);)
                    {
                        if (b) c = null;
                        else c = null;
                        M(c);
                    }
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact]
    public async Task TestForStatement_MultipleDeclarators()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    [|C|] c = null, x = null;
                    for (; !((c = e as C)==null);)
                    {
                        M(c);
                    }
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    C x = null;
                    for (; !(!(e is C c));)
                    {
                        M(c);
                    }
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact]
    public async Task TestForStatement_UseBeforeDeclaration()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|C|] c = null, x = c;
                    for (; !((c = e as C)==null);)
                    {
                        M(c);
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestForStatement_Initializer()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object e)
                {
                    [|C|] c;
                    for (var i = !((c = e as C)==null); i != null; )
                    {
                        M(c);
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestLocalFunction()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    [||]var c = e as C;
                    C F() => c == null ? null : c;
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    C F() => !(e is C c) ? null : c;
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact]
    public async Task TestLocalFunction_UseOutOfScope()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                C M(object e)
                {
                    [||]var c = e as C;
                    C F() => c == null ? null : c;
                    return c;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestExpressionLambda()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M(object e)
                {
                    [||]var c = e as C;
                    System.Func<C> f = () => c == null ? null : c;
                }
            }
            """,
            """
            class C
            {
                void M(object e)
                {
                    System.Func<C> f = () => !(e is C c) ? null : c;
                }
            }
            """, parameters: new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
    }
 
    [Fact]
    public async Task TestExpressionLambda_UseOutOfScope()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                C M(object e)
                {
                    [||]var c = e as C;
                    System.Func<C> f = () => c == null ? null : c;
                    return c;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31388")]
    public async Task TestUseBetweenAssignmentAndIfCondition()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M(object o)
                {
                    [|var|] c = o as C;
                    M2(c != null);
                    if (c == null)
                    {
                        return;
                    }
                }
 
                void M2(bool b) { }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40007")]
    public async Task TestSpaceAfterGenericType()
    {
        await TestInRegularAndScript1Async(
            """
            #nullable enable
 
            using System.Collections.Generic;
 
            class Program
            {
                static void Goo<TKey, TValue>(object items)
                {
                    [|var|] itemsAsDictionary = items as IDictionary<TKey, TValue>;
                    SortedDictionary<TKey, TValue>? dictionary = null;
                    if (itemsAsDictionary != null)
                    {
                        dictionary = new SortedDictionary<TKey, TValue>();
                    }
                    return dictionary;
                }
            }
            """,
            """
            #nullable enable
 
            using System.Collections.Generic;
 
            class Program
            {
                static void Goo<TKey, TValue>(object items)
                {
                    SortedDictionary<TKey, TValue>? dictionary = null;
                    if (items is IDictionary<TKey, TValue> itemsAsDictionary)
                    {
                        dictionary = new SortedDictionary<TKey, TValue>();
                    }
                    return dictionary;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45596")]
    public async Task TestMissingInUsingDeclaration()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    using [|var|] x = o as IDisposable;
                    if (x != null)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45596")]
    public async Task TestMissingInUsingStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    using ([|var|] x = o as IDisposable)
                    {
                        if (x != null)
                        {
                        }
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37398")]
    public async Task TestPrecedingDirectiveTrivia()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                public static void M(object o)
                {
            #if DEBUG
                    Console.WriteLine("in debug");
            #endif
 
                    [|string|] s = o as string;
                    if (s != null)
                    {
 
                    }
                }
            }
            """,
            """
            class C
            {
                public static void M(object o)
                {
            #if DEBUG
                    Console.WriteLine("in debug");
            #endif
 
                    if (o is string s)
                    {
 
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40006")]
    public async Task TestArrayOfNullables()
    {
        await TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class Program
            {
                static void Set(object obj, object? item)
                {
                    [|object?[]?|] arr = obj as object[];
                    if (arr != null)
                    {
                        arr[0] = item;
                    }
                }
            }
            """,
            """
            #nullable enable
 
            class Program
            {
                static void Set(object obj, object? item)
                {
                    if (obj is object?[] arr)
                    {
                        arr[0] = item;
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/55782")]
    public async Task TestLocalReferencedAcrossScopes1()
    {
        var code = """
            using System.Transactions;
 
            class BaseObject { }
            class ObjectFactory
            {
                internal static BaseObject CreateObject(int x)
                {
                    throw new NotImplementedException();
                }
            }
 
            struct Repro
            {
                static int Main(string[] args)
                {
                    int x = 0;
                    [|BaseObject|] obj;
 
                    var tso = new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead };
                    using (var trans = new TransactionScope(TransactionScopeOption.Required, tso))
                    {
                        try
                        {
                            if ((obj = ObjectFactory.CreateObject(x) as BaseObject) == null)
                            {
                                return -1;
                            }
                            // uses of obj in the transaction
                        }
                        catch (TransactionAbortedException)
                        {
                            return -1;
                        }
                    }
 
                    // local used here.
                    Console.WriteLine(obj);
                    return 0;
                }
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/55782")]
    public async Task TestLocalReferencedAcrossScopes2()
    {
        await TestInRegularAndScript1Async("""
            using System.Transactions;
 
            class BaseObject { }
            class ObjectFactory
            {
                internal static BaseObject CreateObject(int x)
                {
                    throw new NotImplementedException();
                }
            }
 
            struct Repro
            {
                static int Main(string[] args)
                {
                    int x = 0;
                    [|BaseObject|] obj;
 
                    var tso = new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead };
                    using (var trans = new TransactionScope(TransactionScopeOption.Required, tso))
                    {
                        try
                        {
                            if ((obj = ObjectFactory.CreateObject(x) as BaseObject) == null)
                            {
                                return -1;
                            }
                            // uses of obj in the transaction
                        }
                        catch (TransactionAbortedException)
                        {
                            return -1;
                        }
                    }
 
                    // not used
                    return 0;
                }
            }
            """,
            """
            using System.Transactions;
 
            class BaseObject { }
            class ObjectFactory
            {
                internal static BaseObject CreateObject(int x)
                {
                    throw new NotImplementedException();
                }
            }
 
            struct Repro
            {
                static int Main(string[] args)
                {
                    int x = 0;
 
                    var tso = new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead };
                    using (var trans = new TransactionScope(TransactionScopeOption.Required, tso))
                    {
                        try
                        {
                            if (ObjectFactory.CreateObject(x) is not BaseObject obj)
                            {
                                return -1;
                            }
                            // uses of obj in the transaction
                        }
                        catch (TransactionAbortedException)
                        {
                            return -1;
                        }
                    }
 
                    // not used
                    return 0;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37875")]
    public async Task TestNullableWhenWrittenTo1()
    {
        await TestInRegularAndScript1Async("""
            #nullable enable
            using System;
 
            class Program
            {
                static void Goo(object o1, object o2)
                {
                    [|string?|] s = o1 as string;
                    if (s == null)
                    {
                    }
                }
            }
            """,
            """
            #nullable enable
            using System;
            
            class Program
            {
                static void Goo(object o1, object o2)
                {
                    if (o1 is not string s)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37875")]
    public async Task TestNullableWhenWrittenTo2()
    {
        await TestInRegularAndScript1Async("""
            #nullable enable
            using System;
 
            class Program
            {
                static void Goo(object o1, object o2)
                {
                    [|string?|] s = o1 as string;
                    if (s == null)
                    {
                        s = "";
                    }
                }
            }
            """,
            """
            #nullable enable
            using System;
            
            class Program
            {
                static void Goo(object o1, object o2)
                {
                    if (o1 is not string s)
                    {
                        s = "";
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37875")]
    public async Task TestNullableWhenWrittenTo3()
    {
        await TestMissingInRegularAndScriptAsync("""
            #nullable enable
            using System;
 
            class Program
            {
                static void Goo(object o1, object o2)
                {
                    [|string?|] s = o1 as string;
                    if (s == null)
                    {
                        s = o2 as string;
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37875")]
    public async Task TestNullableWhenWrittenTo4()
    {
        await TestMissingInRegularAndScriptAsync("""
            #nullable enable
            using System;
 
            class Program
            {
                static void Goo(object o1, object o2)
                {
                    [|string?|] s = o1 as string;
                    if (s == null)
                    {
                        s = null;
                    }
                }
            }
            """);
    }
}