File: ExtractMethod\ExtractMethodTests2.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.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeRefactoringVerifier<
    Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod.ExtractMethodCodeRefactoringProvider>;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.ExtractMethod;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod)]
public class ExtractMethodTests : AbstractCSharpCodeActionTest_NoEditor
{
    protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters)
        => new ExtractMethodCodeRefactoringProvider();
 
    private const string EditorConfigNaming_LocalFunctions_CamelCase = """
        [*]
        # Naming rules
 
        dotnet_naming_rule.local_functions_should_be_camel_case.severity = suggestion
        dotnet_naming_rule.local_functions_should_be_camel_case.symbols = local_functions
        dotnet_naming_rule.local_functions_should_be_camel_case.style = camel_case
 
        # Symbol specifications
 
        dotnet_naming_symbols.local_functions.applicable_kinds = local_function
        dotnet_naming_symbols.local_functions.applicable_accessibilities = *
        dotnet_naming_symbols.local_functions.required_modifiers = 
 
        # Naming styles
 
        dotnet_naming_style.camel_case.capitalization = camel_case
        """;
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39946")]
    public async Task LocalFuncExtract()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                int Testing;
 
                void M()
                {
                    local();
 
                    [|NewMethod();|]
 
                    Testing = 5;
 
                    void local()
                    { }
                }
 
                void NewMethod()
                {
                }
            }
            """, """
            class C
            {
                int Testing;
 
                void M()
                {
                    local();
                    {|Rename:NewMethod1|}();
 
                    Testing = 5;
 
                    void local()
                    { }
                }
 
                private void NewMethod1()
                {
                    NewMethod();
                }
 
                void NewMethod()
                {
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540799")]
    public async Task TestPartialSelection()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine([|b != true|] ? b = true : b = false);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine({|Rename:NewMethod|}(b) ? b = true : b = false);
                }
 
                private static bool NewMethod(bool b)
                {
                    return b != true;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestSelectionOfSwitchExpressionArm()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                int Foo(int x) => x switch
                {
                    1 => 1,
                    _ => [|1 + x|]
                };
            }
            """,
            """
            class Program
            {
                int Foo(int x) => x switch
                {
                    1 => 1,
                    _ => {|Rename:NewMethod|}(x)
                };
                private static int NewMethod(int x) => 1 + x;
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestSelectionOfSwitchExpressionArmContainingVariables()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
            using System.Collections.Generic;
 
            class TestClass
            {
                public static T RecursiveExample<T>(IEnumerable<T> sequence) =>
                sequence switch
                {
                    Array { Length: 0 } => default(T),
                    Array { Length: 1 } array => [|(T)array.GetValue(0)|],
                    Array { Length: 2 } array => (T)array.GetValue(1),
                    Array array => (T)array.GetValue(2),
                    _ => throw new NotImplementedException(),
                };
            }
            """,
            """
            using System;
            using System.Collections.Generic;
 
            class TestClass
            {
                public static T RecursiveExample<T>(IEnumerable<T> sequence) =>
                sequence switch
                {
                    Array { Length: 0 } => default(T),
                    Array { Length: 1 } array => {|Rename:NewMethod|}<T>(array),
                    Array { Length: 2 } array => (T)array.GetValue(1),
                    Array array => (T)array.GetValue(2),
                    _ => throw new NotImplementedException(),
                };
                private static T NewMethod<T>(Array array) => (T)array.GetValue(0);
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestUseExpressionBodyWhenPossible()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine([|b != true|] ? b = true : b = false);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine({|Rename:NewMethod|}(b) ? b = true : b = false);
                }
 
                private static bool NewMethod(bool b) => b != true;
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestUseExpressionWhenOnSingleLine_AndIsOnSingleLine()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine([|b != true|] ? b = true : b = false);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine({|Rename:NewMethod|}(b) ? b = true : b = false);
                }
 
                private static bool NewMethod(bool b) => b != true;
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestUseExpressionWhenOnSingleLine_AndIsOnSingleLine2()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine(
 
                        [|b != true|]
                            ? b = true : b = false);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine(
 
                        {|Rename:NewMethod|}(b)
                            ? b = true : b = false);
                }
 
                private static bool NewMethod(bool b) => b != true;
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestUseExpressionWhenOnSingleLine_AndNotIsOnSingleLine()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine([|b != 
                        true|] ? b = true : b = false);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine({|Rename:NewMethod|}(b) ? b = true : b = false);
                }
 
                private static bool NewMethod(bool b)
                {
                    return b !=
                                true;
                }
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestUseExpressionWhenOnSingleLine_AndNotIsOnSingleLine2()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine([|b !=/*
            */true|] ? b = true : b = false);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine({|Rename:NewMethod|}(b) ? b = true : b = false);
                }
 
                private static bool NewMethod(bool b)
                {
                    return b !=/*
            */true;
                }
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestExtractMethodInCtorInit()
    {
        await TestInRegularAndScript1Async(
            """
            class Foo
            {
                public Foo(int a, int b){}
                public Foo(int i) : this([|i * 10 + 2|], 2)
                {}
            }
            """,
            """
            class Foo
            {
                public Foo(int a, int b){}
                public Foo(int i) : this({|Rename:NewMethod|}(i), 2)
                { }
 
                private static int NewMethod(int i) => i * 10 + 2;
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestExtractMethodInCtorInitWithOutVar()
    {
        await TestInRegularAndScript1Async(
            """
            class Foo
            {
                public Foo(int a, int b){}
                public Foo(int i, out int q) : this([|i * 10 + (q = 2)|], 2)
                {}
            }
            """,
            """
            class Foo
            {
                public Foo(int a, int b){}
                public Foo(int i, out int q) : this({|Rename:NewMethod|}(i, out q), 2)
                { }
 
                private static int NewMethod(int i, out int q) => i * 10 + (q = 2);
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestExtractMethodInCtorInitWithByRefVar()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System;
 
            namespace Test
            {
                public class BaseX
                {
                    public BaseX(out int s, int sx, ref int r, in int inRef)
                    {
                        Console.WriteLine("begin base ctor");
 
                        s = 42;
                        Console.WriteLine(sx);
                        Console.WriteLine(r);
                        Console.WriteLine(inRef);
 
                        r = 777;
                        Console.WriteLine(inRef);
                        Console.WriteLine(r);
 
                        Console.WriteLine("end base ctor");
                    }
                }
 
                public class X : BaseX
                {
                    static int PrintX(int i)
                    {
                        Console.WriteLine(i);
                        return i;
                    }
 
 
                    public X(out int x, ref int r) :
                        base(out x, x = PrintX(x = 12), ref r, [|r++|])
                    {
                        Console.WriteLine($"in ctor {x}");
                    }
 
                    static void Main()
                    {
                        int val = 33;
                        var x = new X(out var f, ref val);
                        Console.WriteLine(val);
                    }
                }
            }
            """,
            """
            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System;
 
            namespace Test
            {
                public class BaseX
                {
                    public BaseX(out int s, int sx, ref int r, in int inRef)
                    {
                        Console.WriteLine("begin base ctor");
 
                        s = 42;
                        Console.WriteLine(sx);
                        Console.WriteLine(r);
                        Console.WriteLine(inRef);
 
                        r = 777;
                        Console.WriteLine(inRef);
                        Console.WriteLine(r);
 
                        Console.WriteLine("end base ctor");
                    }
                }
 
                public class X : BaseX
                {
                    static int PrintX(int i)
                    {
                        Console.WriteLine(i);
                        return i;
                    }
 
 
                    public X(out int x, ref int r) :
                        base(out x, x = PrintX(x = 12), ref r, {|Rename:NewMethod|}(ref r))
                    {
                        Console.WriteLine($"in ctor {x}");
                    }
 
                    private static int NewMethod(ref int r) => r++;
 
                    static void Main()
                    {
                        int val = 33;
                        var x = new X(out var f, ref val);
                        Console.WriteLine(val);
                    }
                }
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact]
    public async Task TestUseExpressionWhenOnSingleLine_AndNotIsOnSingleLine3()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine([|"" != @"
            "|] ? b = true : b = false);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    bool b = true;
                    System.Console.WriteLine({|Rename:NewMethod|}() ? b = true : b = false);
                }
 
                private static bool NewMethod()
                {
                    return "" != @"
            ";
                }
            }
            """,
new TestParameters(options: Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenOnSingleLineWithSilentEnforcement)));
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540796")]
    public async Task TestReadOfDataThatDoesNotFlowIn()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    int x = 1;
                    object y = 0;
                    [|int s = true ? fun(x) : fun(y);|]
                }
 
                private static T fun<T>(T t)
                {
                    return t;
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    int x = 1;
                    object y = 0;
                    {|Rename:NewMethod|}(x, y);
                }
 
                private static void NewMethod(int x, object y)
                {
                    int s = true ? fun(x) : fun(y);
                }
 
                private static T fun<T>(T t)
                {
                    return t;
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540819")]
    public async Task TestOnGoto()
    {
        await TestInRegularAndScriptAsync(
            """
            delegate int del(int i);
 
            class C
            {
                static void Main(string[] args)
                {
                    del q = x => {
                        [|goto label2;
                        return x * x;|]
                    };
                label2:
                    return;
                }
            }
            """,
            """
            delegate int del(int i);
 
            class C
            {
                static void Main(string[] args)
                {
                    del q = x =>
                    {
                        return {|Rename:NewMethod|}(x);
                    };
                label2:
                    return;
                }
 
                private static int NewMethod(int x)
                {
                    goto label2;
                    return x * x;
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540819")]
    public async Task TestOnStatementAfterUnconditionalGoto()
    {
        await TestInRegularAndScript1Async(
            """
            delegate int del(int i);
 
            class C
            {
                static void Main(string[] args)
                {
                    del q = x => {
                        goto label2;
                        [|return x * x;|]
                    };
                label2:
                    return;
                }
            }
            """,
            """
            delegate int del(int i);
 
            class C
            {
                static void Main(string[] args)
                {
                    del q = x =>
                    {
                        goto label2;
                        return {|Rename:NewMethod|}(x);
                    };
                label2:
                    return;
                }
 
                private static int NewMethod(int x)
                {
                    return x * x;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnNamespace()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                void Main()
                {
                    [|System|].Console.WriteLine(4);
                }
            }
            """,
            """
            class Program
            {
                void Main()
                {
                    {|Rename:NewMethod|}();
                }
 
                private static void NewMethod()
                {
                    System.Console.WriteLine(4);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnType()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                void Main()
                {
                    [|System.Console|].WriteLine(4);
                }
            }
            """,
            """
            class Program
            {
                void Main()
                {
                    {|Rename:NewMethod|}();
                }
 
                private static void NewMethod()
                {
                    System.Console.WriteLine(4);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingOnBase()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                void Main()
                {
                    [|base|].ToString();
                }
            }
            """,
            """
            class Program
            {
                void Main()
                {
                    {|Rename:NewMethod|}();
                }
 
                private void NewMethod()
                {
                    base.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545623")]
    public async Task TestOnActionInvocation()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                public static Action X { get; set; }
            }
 
            class Program
            {
                void Main()
                {
                    [|C.X|]();
                }
            }
            """,
            """
            using System;
 
            class C
            {
                public static Action X { get; set; }
            }
 
            class Program
            {
                void Main()
                {
                    {|Rename:GetX|}()();
                }
 
                private static Action GetX()
                {
                    return C.X;
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529841"), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/714632")]
    public async Task DisambiguateCallSiteIfNecessary1()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    byte z = 0;
                    Goo([|x => 0|], y => 0, z, z);
                }
 
                static void Goo<T, S>(Func<S, T> p, Func<T, S> q, T r, S s) { Console.WriteLine(1); }
                static void Goo(Func<byte, byte> p, Func<byte, byte> q, int r, int s) { Console.WriteLine(2); }
            }
            """,
 
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    byte z = 0;
                    Goo({|Rename:NewMethod|}(), y => (byte)0, z, z);
                }
 
                private static Func<byte, byte> NewMethod()
                {
                    return x => 0;
                }
 
                static void Goo<T, S>(Func<S, T> p, Func<T, S> q, T r, S s) { Console.WriteLine(1); }
                static void Goo(Func<byte, byte> p, Func<byte, byte> q, int r, int s) { Console.WriteLine(2); }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529841"), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/714632")]
    public async Task DisambiguateCallSiteIfNecessary2()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    byte z = 0;
                    Goo([|x => 0|], y => { return 0; }, z, z);
                }
 
                static void Goo<T, S>(Func<S, T> p, Func<T, S> q, T r, S s) { Console.WriteLine(1); }
                static void Goo(Func<byte, byte> p, Func<byte, byte> q, int r, int s) { Console.WriteLine(2); }
            }
            """,
 
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    byte z = 0;
                    Goo({|Rename:NewMethod|}(), y => { return (byte)0; }, z, z);
                }
 
                private static Func<byte, byte> NewMethod()
                {
                    return x => 0;
                }
 
                static void Goo<T, S>(Func<S, T> p, Func<T, S> q, T r, S s) { Console.WriteLine(1); }
                static void Goo(Func<byte, byte> p, Func<byte, byte> q, int r, int s) { Console.WriteLine(2); }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530709")]
    [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/632182")]
    public async Task DoNotOverparenthesize()
    {
        await TestAsync(
            """
            using System;
 
            static class C
            {
                static void Ex(this string x)
                {
                }
 
                static void Inner(Action<string> x, string y)
                {
                }
 
                static void Inner(Action<string> x, int y)
                {
                }
 
                static void Inner(Action<int> x, int y)
                {
                }
 
                static void Outer(Action<string> x, object y)
                {
                    Console.WriteLine(1);
                }
 
                static void Outer(Action<int> x, int y)
                {
                    Console.WriteLine(2);
                }
 
                static void Main()
                {
                    Outer(y => Inner(x => [|x|].Ex(), y), - -1);
                }
            }
 
            static class E
            {
                public static void Ex(this int x)
                {
                }
            }
            """,
 
            """
            using System;
 
            static class C
            {
                static void Ex(this string x)
                {
                }
 
                static void Inner(Action<string> x, string y)
                {
                }
 
                static void Inner(Action<string> x, int y)
                {
                }
 
                static void Inner(Action<int> x, int y)
                {
                }
 
                static void Outer(Action<string> x, object y)
                {
                    Console.WriteLine(1);
                }
 
                static void Outer(Action<int> x, int y)
                {
                    Console.WriteLine(2);
                }
 
                static void Main()
                {
                    Outer(y => Inner(x => {|Rename:GetX|}(x).Ex(), y), (object)- -1);
                }
 
                private static string GetX(string x)
                {
                    return x;
                }
            }
 
            static class E
            {
                public static void Ex(this int x)
                {
                }
            }
            """,
 
parseOptions: TestOptions.Regular);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/632182")]
    public async Task DoNotOverparenthesizeGenerics()
    {
        await TestAsync(
            """
            using System;
 
            static class C
            {
                static void Ex<T>(this string x)
                {
                }
 
                static void Inner(Action<string> x, string y)
                {
                }
 
                static void Inner(Action<string> x, int y)
                {
                }
 
                static void Inner(Action<int> x, int y)
                {
                }
 
                static void Outer(Action<string> x, object y)
                {
                    Console.WriteLine(1);
                }
 
                static void Outer(Action<int> x, int y)
                {
                    Console.WriteLine(2);
                }
 
                static void Main()
                {
                    Outer(y => Inner(x => [|x|].Ex<int>(), y), - -1);
                }
            }
 
            static class E
            {
                public static void Ex<T>(this int x)
                {
                }
            }
            """,
 
            """
            using System;
 
            static class C
            {
                static void Ex<T>(this string x)
                {
                }
 
                static void Inner(Action<string> x, string y)
                {
                }
 
                static void Inner(Action<string> x, int y)
                {
                }
 
                static void Inner(Action<int> x, int y)
                {
                }
 
                static void Outer(Action<string> x, object y)
                {
                    Console.WriteLine(1);
                }
 
                static void Outer(Action<int> x, int y)
                {
                    Console.WriteLine(2);
                }
 
                static void Main()
                {
                    Outer(y => Inner(x => {|Rename:GetX|}(x).Ex<int>(), y), (object)- -1);
                }
 
                private static string GetX(string x)
                {
                    return x;
                }
            }
 
            static class E
            {
                public static void Ex<T>(this int x)
                {
                }
            }
            """,
 
parseOptions: TestOptions.Regular);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/984831")]
    public async Task PreserveCommentsBeforeDeclaration_1()
    {
        await TestInRegularAndScript1Async(
            """
            class Construct
            {
                public void Do() { }
                static void Main(string[] args)
                {
                    [|Construct obj1 = new Construct();
                    obj1.Do();
                    /* Interesting comment. */
                    Construct obj2 = new Construct();
                    obj2.Do();|]
                    obj1.Do();
                    obj2.Do();
                }
            }
            """,
 
            """
            class Construct
            {
                public void Do() { }
                static void Main(string[] args)
                {
                    Construct obj1, obj2;
                    {|Rename:NewMethod|}(out obj1, out obj2);
                    obj1.Do();
                    obj2.Do();
                }
 
                private static void NewMethod(out Construct obj1, out Construct obj2)
                {
                    obj1 = new Construct();
                    obj1.Do();
                    /* Interesting comment. */
                    obj2 = new Construct();
                    obj2.Do();
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/984831")]
    public async Task PreserveCommentsBeforeDeclaration_2()
    {
        await TestInRegularAndScript1Async(
            """
            class Construct
            {
                public void Do() { }
                static void Main(string[] args)
                {
                    [|Construct obj1 = new Construct();
                    obj1.Do();
                    /* Interesting comment. */
                    Construct obj2 = new Construct();
                    obj2.Do();
                    /* Second Interesting comment. */
                    Construct obj3 = new Construct();
                    obj3.Do();|]
                    obj1.Do();
                    obj2.Do();
                    obj3.Do();
                }
            }
            """,
 
            """
            class Construct
            {
                public void Do() { }
                static void Main(string[] args)
                {
                    Construct obj1, obj2, obj3;
                    {|Rename:NewMethod|}(out obj1, out obj2, out obj3);
                    obj1.Do();
                    obj2.Do();
                    obj3.Do();
                }
 
                private static void NewMethod(out Construct obj1, out Construct obj2, out Construct obj3)
                {
                    obj1 = new Construct();
                    obj1.Do();
                    /* Interesting comment. */
                    obj2 = new Construct();
                    obj2.Do();
                    /* Second Interesting comment. */
                    obj3 = new Construct();
                    obj3.Do();
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/984831")]
    public async Task PreserveCommentsBeforeDeclaration_3()
    {
        await TestInRegularAndScript1Async(
            """
            class Construct
            {
                public void Do() { }
                static void Main(string[] args)
                {
                    [|Construct obj1 = new Construct();
                    obj1.Do();
                    /* Interesting comment. */
                    Construct obj2 = new Construct(), obj3 = new Construct();
                    obj2.Do();
                    obj3.Do();|]
                    obj1.Do();
                    obj2.Do();
                    obj3.Do();
                }
            }
            """,
 
            """
            class Construct
            {
                public void Do() { }
                static void Main(string[] args)
                {
                    Construct obj1, obj2, obj3;
                    {|Rename:NewMethod|}(out obj1, out obj2, out obj3);
                    obj1.Do();
                    obj2.Do();
                    obj3.Do();
                }
 
                private static void NewMethod(out Construct obj1, out Construct obj2, out Construct obj3)
                {
                    obj1 = new Construct();
                    obj1.Do();
                    /* Interesting comment. */
                    obj2 = new Construct();
                    obj3 = new Construct();
                    obj2.Do();
                    obj3.Do();
                }
            }
            """);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task TestTuple()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|(int, int) x = (1, 2);|]
                    System.Console.WriteLine(x.Item1);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int, int) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.Item1);
                }
 
                private static (int, int) NewMethod()
                {
                    return (1, 2);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task TestTupleDeclarationWithNames()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|(int a, int b) x = (1, 2);|]
                    System.Console.WriteLine(x.a);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int a, int b) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.a);
                }
 
                private static (int a, int b) NewMethod()
                {
                    return (1, 2);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task TestTupleDeclarationWithSomeNames()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|(int a, int) x = (1, 2);|]
                    System.Console.WriteLine(x.a);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int a, int) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.a);
                }
 
                private static (int a, int) NewMethod()
                {
                    return (1, 2);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/18311")]
    public async Task TestTupleWith1Arity()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
            class Program
            {
                static void Main(string[] args)
                {
                    ValueTuple<int> y = ValueTuple.Create(1);
                    [|y.Item1.ToString();|]
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            using System;
            class Program
            {
                static void Main(string[] args)
                {
                    ValueTuple<int> y = ValueTuple.Create(1);
                    {|Rename:NewMethod|}(y);
                }
 
                private static void NewMethod(ValueTuple<int> y)
                {
                    y.Item1.ToString();
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task TestTupleLiteralWithNames()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|(int, int) x = (a: 1, b: 2);|]
                    System.Console.WriteLine(x.Item1);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int, int) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.Item1);
                }
 
                private static (int, int) NewMethod()
                {
                    return (a: 1, b: 2);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task TestTupleDeclarationAndLiteralWithNames()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|(int a, int b) x = (c: 1, d: 2);|]
                    System.Console.WriteLine(x.a);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int a, int b) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.a);
                }
 
                private static (int a, int b) NewMethod()
                {
                    return (c: 1, d: 2);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task TestTupleIntoVar()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|var x = (c: 1, d: 2);|]
                    System.Console.WriteLine(x.c);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int c, int d) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.c);
                }
 
                private static (int c, int d) NewMethod()
                {
                    return (c: 1, d: 2);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task RefactorWithoutSystemValueTuple()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|var x = (c: 1, d: 2);|]
                    System.Console.WriteLine(x.c);
                }
            }
            """,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int c, int d) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.c);
                }
 
                private static (int c, int d) NewMethod()
                {
                    return (c: 1, d: 2);
                }
            }
            """);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/11196")]
    public async Task TestTupleWithNestedNamedTuple()
    {
        // This is not the best refactoring, but this is an edge case
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|var x = new System.ValueTuple<int, int, int, int, int, int, int, (string a, string b)>(1, 2, 3, 4, 5, 6, 7, (a: "hello", b: "world"));|]
                    System.Console.WriteLine(x.c);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    (int, int, int, int, int, int, int, string, string) x = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x.c);
                }
 
                private static (int, int, int, int, int, int, int, string, string) NewMethod()
                {
                    return new System.ValueTuple<int, int, int, int, int, int, int, (string a, string b)>(1, 2, 3, 4, 5, 6, 7, (a: "hello", b: "world"));
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    public async Task TestDeconstruction()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    var (x, y) = [|(1, 2)|];
                    System.Console.WriteLine(x);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    var (x, y) = {|Rename:NewMethod|}();
                    System.Console.WriteLine(x);
                }
 
                private static (int, int) NewMethod()
                {
                    return (1, 2);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact, CompilerTrait(CompilerFeature.Tuples)]
    public async Task TestDeconstruction2()
    {
        await TestInRegularAndScript1Async(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    var (x, y) = (1, 2);
                    var z = [|3;|]
                    System.Console.WriteLine(z);
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs,
            """
            class Program
            {
                static void Main(string[] args)
                {
                    var (x, y) = (1, 2);
                    int z = {|Rename:NewMethod|}();
                    System.Console.WriteLine(z);
                }
 
                private static int NewMethod()
                {
                    return 3;
                }
            }
            """ + TestResources.NetFX.ValueTuple.tuplelib_cs);
    }
 
    [Fact]
    [CompilerTrait(CompilerFeature.OutVar)]
    public async Task TestOutVar()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                static void M(int i)
                {
                    int r;
                    [|r = M1(out int y, i);|]
                    System.Console.WriteLine(r + y);
                }
            }
            """,
            """
            class C
            {
                static void M(int i)
                {
                    int r;
                    int y;
                    {|Rename:NewMethod|}(i, out r, out y);
                    System.Console.WriteLine(r + y);
                }
 
                private static void NewMethod(int i, out int r, out int y)
                {
                    r = M1(out y, i);
                }
            }
            """);
    }
 
    [Fact]
    [CompilerTrait(CompilerFeature.Patterns)]
    public async Task TestIsPattern()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                static void M(int i)
                {
                    int r;
                    [|r = M1(3 is int y, i);|]
                    System.Console.WriteLine(r + y);
                }
            }
            """,
            """
            class C
            {
                static void M(int i)
                {
                    int r;
                    int y;
                    {|Rename:NewMethod|}(i, out r, out y);
                    System.Console.WriteLine(r + y);
                }
 
                private static void NewMethod(int i, out int r, out int y)
                {
                    r = M1(3 is int {|Conflict:y|}, i);
                }
            }
            """);
    }
 
    [Fact]
    [CompilerTrait(CompilerFeature.Patterns)]
    public async Task TestOutVarAndIsPattern()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                static void M()
                {
                    int r;
                    [|r = M1(out /*out*/ int /*int*/ y /*y*/) + M2(3 is int z);|]
                    System.Console.WriteLine(r + y + z);
                }
            }
            """,
            """
            class C
            {
                static void M()
                {
                    int r;
                    int y, z;
                    {|Rename:NewMethod|}(out r, out y, out z);
                    System.Console.WriteLine(r + y + z);
                }
 
                private static void NewMethod(out int r, out int y, out int z)
                {
                    r = M1(out /*out*/  /*int*/ y /*y*/) + M2(3 is int {|Conflict:z|});
                }
            }
            """);
    }
 
    [Fact]
    [CompilerTrait(CompilerFeature.Patterns)]
    public async Task ConflictingOutVarLocals()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                static void M()
                {
                    int r;
                    [|r = M1(out int y);
                    {
                        M2(out int y);
                        System.Console.Write(y);
                    }|]
 
                    System.Console.WriteLine(r + y);
                }
            }
            """,
            """
            class C
            {
                static void M()
                {
                    int r;
                    int y;
                    {|Rename:NewMethod|}(out r, out y);
 
                    System.Console.WriteLine(r + y);
                }
 
                private static void NewMethod(out int r, out int y)
                {
                    r = M1(out y);
                    {
                        M2(out int y);
                        System.Console.Write(y);
                    }
                }
            }
            """);
    }
 
    [Fact]
    [CompilerTrait(CompilerFeature.Patterns)]
    public async Task ConflictingPatternLocals()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                static void M()
                {
                    int r;
                    [|r = M1(1 is int y);
                    {
                        M2(2 is int y);
                        System.Console.Write(y);
                    }|]
 
                    System.Console.WriteLine(r + y);
                }
            }
            """,
            """
            class C
            {
                static void M()
                {
                    int r;
                    int y;
                    {|Rename:NewMethod|}(out r, out y);
 
                    System.Console.WriteLine(r + y);
                }
 
                private static void NewMethod(out int r, out int y)
                {
                    r = M1(1 is int {|Conflict:y|});
                    {
                        M2(2 is int y);
                        System.Console.Write(y);
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15218")]
    public async Task TestCancellationTokenGoesLast()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
            using System.Threading;
 
            class C
            {
                void M(CancellationToken ct)
                {
                    var v = 0;
 
                    [|if (true)
                    {
                        ct.ThrowIfCancellationRequested();
                        Console.WriteLine(v);
                    }|]
                }
            }
            """,
            """
            using System;
            using System.Threading;
 
            class C
            {
                void M(CancellationToken ct)
                {
                    var v = 0;
                    {|Rename:NewMethod|}(v, ct);
                }
 
                private static void NewMethod(int v, CancellationToken ct)
                {
                    if (true)
                    {
                        ct.ThrowIfCancellationRequested();
                        Console.WriteLine(v);
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15219")]
    public async Task TestUseVar1()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void Goo(int i)
                {
                    [|var v = (string)null;
 
                    switch (i)
                    {
                        case 0: v = "0"; break;
                        case 1: v = "1"; break;
                    }|]
 
                    Console.WriteLine(v);
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo(int i)
                {
                    var v = {|Rename:NewMethod|}(i);
 
                    Console.WriteLine(v);
                }
 
                private static string NewMethod(int i)
                {
                    var v = (string)null;
 
                    switch (i)
                    {
                        case 0: v = "0"; break;
                        case 1: v = "1"; break;
                    }
 
                    return v;
                }
            }
            """, new TestParameters(options: Option(CSharpCodeStyleOptions.VarForBuiltInTypes, CodeStyleOption2.TrueWithSuggestionEnforcement)));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15219")]
    public async Task TestUseVar2()
    {
        await TestInRegularAndScript1Async(
            """
            using System;
 
            class C
            {
                void Goo(int i)
                {
                    [|var v = (string)null;
 
                    switch (i)
                    {
                        case 0: v = "0"; break;
                        case 1: v = "1"; break;
                    }|]
 
                    Console.WriteLine(v);
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo(int i)
                {
                    string v = {|Rename:NewMethod|}(i);
 
                    Console.WriteLine(v);
                }
 
                private static string NewMethod(int i)
                {
                    var v = (string)null;
 
                    switch (i)
                    {
                        case 0: v = "0"; break;
                        case 1: v = "1"; break;
                    }
 
                    return v;
                }
            }
            """, new TestParameters(options: Option(CSharpCodeStyleOptions.VarWhenTypeIsApparent, CodeStyleOption2.TrueWithSuggestionEnforcement)));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15532")]
    public async Task ExtractLocalFunctionCall()
    {
        var code = """
            class C
            {
                public static void Main()
                {
                    void Local() { }
                    [|Local();|]
                }
            }
            """;
        await TestExactActionSetOfferedAsync(code, [FeaturesResources.Extract_local_function]);
    }
 
    [Fact]
    public async Task ExtractLocalFunctionCall_2()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                public static void Main()
                {
                    [|void Local() { }
                    Local();|]
                }
            }
            """, """
            class C
            {
                public static void Main()
                {
                    {|Rename:NewMethod|}();
                }
 
                private static void NewMethod()
                {
                    void Local() { }
                    Local();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15532")]
    public async Task ExtractLocalFunctionCallWithCapture()
    {
        var code = """
            class C
            {
                public static void Main(string[] args)
                {
                    bool Local() => args == null;
                    [|Local();|]
                }
            }
            """;
        await TestExactActionSetOfferedAsync(code, [FeaturesResources.Extract_local_function]);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15532")]
    public async Task ExtractLocalFunctionDeclaration()
    {
        await TestMissingInRegularAndScriptAsync("""
            class C
            {
                public static void Main()
                {
                    [|bool Local() => args == null;|]
                    Local();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15532")]
    public async Task ExtractLocalFunctionInterior()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                public static void Main()
                {
                    void Local()
                    {
                        [|int x = 0;
                        x++;|]
                    }
                    Local();
                }
            }
            """, """
            class C
            {
                public static void Main()
                {
                    void Local()
                    {
                        {|Rename:NewMethod|}();
                    }
                    Local();
                }
 
                private static void NewMethod()
                {
                    int x = 0;
                    x++;
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538229")]
    public async Task Bug3790()
    {
        await TestInRegularAndScript1Async("""
            class Test
            {
                void method()
                {
                    static void Main(string[] args)
                    {
                        int v = 0;
                        for(int i=0 ; i<5; i++)
                        {
                            [|v = v + i;|]
                        }
                    }
                }
            }
            """, """
            class Test
            {
                void method()
                {
                    static void Main(string[] args)
                    {
                        int v = 0;
                        for(int i=0 ; i<5; i++)
                        {
                            v = {|Rename:NewMethod|}(v, i);
                        }
                    }
                }
 
                private static int NewMethod(int v, int i)
                {
                    v = v + i;
                    return v;
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538229")]
    public async Task Bug3790_1()
    {
        await TestInRegularAndScript1Async("""
            class Test
            {
                void method()
                {
                    static void Main(string[] args)
                    {
                        int v = 0;
                        for(int i=0 ; i<5; i++)
                        {
                            [|v = v + i|];
                        }
                    }
                }
            }
            """, """
            class Test
            {
                void method()
                {
                    static void Main(string[] args)
                    {
                        int v = 0;
                        for(int i=0 ; i<5; i++)
                        {
                            v = {|Rename:NewMethod|}(v, i);
                        }
                    }
                }
 
                private static int NewMethod(int v, int i)
                {
                    return v + i;
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538229")]
    public async Task Bug3790_2()
    {
        await TestInRegularAndScript1Async("""
            class Test
            {
                void method()
                {
                    static void Main(string[] args)
                    {
                        int v = 0;
                        for(int i=0 ; i<5; i++)
                        {
                            [|i = v = v + i|];
                        }
                    }
                }
            }
            """, """
            class Test
            {
                void method()
                {
                    static void Main(string[] args)
                    {
                        int v = 0;
                        for(int i=0 ; i<5; i++)
                        {
                            i = {|Rename:NewMethod|}(ref v, i);
                        }
                    }
                }
 
                private static int NewMethod(ref int v, int i)
                {
                    return v = v + i;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=392560")]
    public async Task TestExpressionBodyProperty()
    {
        await TestInRegularAndScript1Async("""
            class Program
            {
                int field;
 
                public int Blah => [|this.field|];
            }
            """,
            """
            class Program
            {
                int field;
 
                public int Blah => {|Rename:GetField|}();
 
                private int GetField()
                {
                    return this.field;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=392560")]
    public async Task TestExpressionBodyIndexer()
    {
        await TestInRegularAndScript1Async("""
            class Program
            {
                int field;
 
                public int this[int i] => [|this.field|];
            }
            """,
            """
            class Program
            {
                int field;
 
                public int this[int i] => {|Rename:GetField|}();
 
                private int GetField()
                {
                    return this.field;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=392560")]
    public async Task TestExpressionBodyPropertyGetAccessor()
    {
        await TestInRegularAndScript1Async("""
            class Program
            {
                int field;
 
                public int Blah
                {
                    get => [|this.field|];
                    set => field = value;
                }
            }
            """,
            """
            class Program
            {
                int field;
 
                public int Blah
                {
                    get => {|Rename:GetField|}();
                    set => field = value;
                }
 
                private int GetField()
                {
                    return this.field;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=392560")]
    public async Task TestExpressionBodyPropertySetAccessor()
    {
        await TestInRegularAndScript1Async("""
            class Program
            {
                int field;
 
                public int Blah
                {
                    get => this.field;
                    set => field = [|value|];
                }
            }
            """,
            """
            class Program
            {
                int field;
 
                public int Blah
                {
                    get => this.field;
                    set => field = {|Rename:GetValue|}(value);
                }
 
                private static int GetValue(int value)
                {
                    return value;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=392560")]
    public async Task TestExpressionBodyIndexerGetAccessor()
    {
        await TestInRegularAndScript1Async("""
            class Program
            {
                int field;
 
                public int this[int i]
                {
                    get => [|this.field|];
                    set => field = value;
                }
            }
            """,
            """
            class Program
            {
                int field;
 
                public int this[int i]
                {
                    get => {|Rename:GetField|}();
                    set => field = value;
                }
 
                private int GetField()
                {
                    return this.field;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=392560")]
    public async Task TestExpressionBodyIndexerSetAccessor()
    {
        await TestInRegularAndScript1Async("""
            class Program
            {
                int field;
 
                public int this[int i]
                {
                    get => this.field;
                    set => field = [|value|];
                }
            }
            """,
            """
            class Program
            {
                int field;
 
                public int this[int i]
                {
                    get => this.field;
                    set => field = {|Rename:GetValue|}(value);
                }
 
                private static int GetValue(int value)
                {
                    return value;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestTupleWithInferredNames()
    {
        await TestAsync("""
            class Program
            {
                void M()
                {
                    int a = 1;
                    var t = [|(a, b: 2)|];
                    System.Console.Write(t.a);
                }
            }
            """,
            """
            class Program
            {
                void M()
                {
                    int a = 1;
                    var t = {|Rename:GetT|}(a);
                    System.Console.Write(t.a);
                }
 
                private static (int a, int b) GetT(int a)
                {
                    return (a, b: 2);
                }
            }
            """, TestOptions.Regular7_1);
    }
 
    [Fact]
    public async Task TestDeconstruction4()
    {
        await TestAsync("""
            class Program
            {
                void M()
                {
                    [|var (x, y) = (1, 2);|]
                    System.Console.Write(x + y);
                }
            }
            """,
            """
            class Program
            {
                void M()
                {
                    int x, y;
                    {|Rename:NewMethod|}(out x, out y);
                    System.Console.Write(x + y);
                }
 
                private static void NewMethod(out int x, out int y)
                {
                    var (x, y) = (1, 2);
                }
            }
            """, TestOptions.Regular7_1);
    }
 
    [Fact]
    public async Task TestDeconstruction5()
    {
        await TestAsync("""
            class Program
            {
                void M()
                {
                    [|(var x, var y) = (1, 2);|]
                    System.Console.Write(x + y);
                }
            }
            """,
            """
            class Program
            {
                void M()
                {
                    int x, y;
                    {|Rename:NewMethod|}(out x, out y);
                    System.Console.Write(x + y);
                }
 
                private static void NewMethod(out int x, out int y)
                {
                    (x, y) = (1, 2);
                }
            }
            """, TestOptions.Regular7_1);
    }
 
    [Fact]
    public async Task TestIndexExpression()
    {
        await TestInRegularAndScript1Async(TestSources.Index + """
            class Program
            {
                static void Main(string[] args)
                {
                    System.Console.WriteLine([|^1|]);
                }
            }
            """,
TestSources.Index +
"""
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine({|Rename:NewMethod|}());
    }
 
    private static System.Index NewMethod()
    {
        return ^1;
    }
}
""");
    }
 
    [Fact]
    public async Task TestRangeExpression_Empty()
    {
        await TestInRegularAndScript1Async(TestSources.Index + TestSources.Range + """
            class Program
            {
                static void Main(string[] args)
                {
                    System.Console.WriteLine([|..|]);
                }
            }
            """,
TestSources.Index +
TestSources.Range + """
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine({|Rename:NewMethod|}());
    }
 
    private static System.Range NewMethod()
    {
        return ..;
    }
}
""");
    }
 
    [Fact]
    public async Task TestRangeExpression_Left()
    {
        await TestInRegularAndScript1Async(TestSources.Index + TestSources.Range + """
            class Program
            {
                static void Main(string[] args)
                {
                    System.Console.WriteLine([|..1|]);
                }
            }
            """,
TestSources.Index +
TestSources.Range + """
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine({|Rename:NewMethod|}());
    }
 
    private static System.Range NewMethod()
    {
        return ..1;
    }
}
""");
    }
 
    [Fact]
    public async Task TestRangeExpression_Right()
    {
        await TestInRegularAndScript1Async(TestSources.Index + TestSources.Range + """
            class Program
            {
                static void Main(string[] args)
                {
                    System.Console.WriteLine([|1..|]);
                }
            }
            """,
TestSources.Index +
TestSources.Range + """
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine({|Rename:NewMethod|}());
    }
 
    private static System.Range NewMethod()
    {
        return 1..;
    }
}
""");
    }
 
    [Fact]
    public async Task TestRangeExpression_Both()
    {
        await TestInRegularAndScript1Async(TestSources.Index + TestSources.Range + """
            class Program
            {
                static void Main(string[] args)
                {
                    System.Console.WriteLine([|1..2|]);
                }
            }
            """,
TestSources.Index +
TestSources.Range + """
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine({|Rename:NewMethod|}());
    }
 
    private static System.Range NewMethod()
    {
        return 1..2;
    }
}
""");
    }
 
    [Fact]
    public Task TestAnnotatedNullableReturn()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    [|string? x = null;
                    x?.ToString();|]
 
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? x = {|Rename:NewMethod|}();
 
                    return x;
                }
 
                private static string? NewMethod()
                {
                    string? x = null;
                    x?.ToString();
                    return x;
                }
            }
            """);
 
    [Fact]
    public Task TestAnnotatedNullableParameters1()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? a = null;
                    string? b = null;
                    [|string? x = a?.Contains(b).ToString();|]
 
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? a = null;
                    string? b = null;
                    string? x = {|Rename:NewMethod|}(a, b);
 
                    return x;
                }
 
                private static string? NewMethod(string? a, string? b)
                {
                    return a?.Contains(b).ToString();
                }
            }
            """);
 
    [Fact]
    public Task TestAnnotatedNullableParameters2()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = null;
                    string? b = null;
                    int c = 0;
                    [|string x = (a + b + c).ToString();|]
 
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = null;
                    string? b = null;
                    int c = 0;
                    string x = {|Rename:NewMethod|}(a, b, c);
 
                    return x;
                }
 
                private static string NewMethod(string? a, string? b, int c)
                {
                    return (a + b + c).ToString();
                }
            }
            """);
 
    [Fact]
    public Task TestAnnotatedNullableParameters3()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = null;
                    string? b = null;
                    int c = 0;
                    return [|(a + b + c).ToString()|];
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = null;
                    string? b = null;
                    int c = 0;
                    return {|Rename:NewMethod|}(a, b, c);
                }
 
                private static string NewMethod(string? a, string? b, int c)
                {
                    return (a + b + c).ToString();
                }
            }
            """);
 
    [Fact]
    public Task TestAnnotatedNullableParameters4()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? a = null;
                    string? b = null;
                    return [|a?.Contains(b).ToString()|];
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? a = null;
                    string? b = null;
                    return {|Rename:NewMethod|}(a, b);
                }
 
                private static string? NewMethod(string? a, string? b)
                {
                    return a?.Contains(b).ToString();
                }
            }
            """);
 
    [Fact]
    public Task TestFlowStateNullableParameters1()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    return [|(a + b + a).ToString()|];
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    return {|Rename:NewMethod|}(a, b);
                }
 
                private static string NewMethod(string a, string b)
                {
                    return (a + b + a).ToString();
                }
            }
            """);
 
    [Fact]
    public Task TestFlowStateNullableParameters2()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    return [|(a + b + a).ToString()|];
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    return {|Rename:NewMethod|}(a, b);
                }
 
                private static string NewMethod(string a, string b)
                {
                    return (a + b + a).ToString();
                }
            }
            """);
 
    [Fact]
    public Task TestFlowStateNullableParameters3()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = null;
                    string? b = null;
                    return [|(a + b + a)?.ToString()|] ?? string.Empty;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = null;
                    string? b = null;
                    return {|Rename:NewMethod|}(a, b) ?? string.Empty;
                }
 
                private static string? NewMethod(string? a, string? b)
                {
                    return (a + b + a)?.ToString();
                }
            }
            """);
 
    [Fact]
    public Task TestFlowStateNullableParameters_MultipleStates()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    [|string? c = a + b;
                    a = string.Empty;
                    c += a;
                    a = null;
                    b = null;
                    b = "test";
                    c = a?.ToString();|]
                    return c ?? string.Empty;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    string? c = {|Rename:NewMethod|}(ref a, ref b);
                    return c ?? string.Empty;
                }
 
                private static string? NewMethod(ref string? a, ref string? b)
                {
                    string? c = a + b;
                    a = string.Empty;
                    c += a;
                    a = null;
                    b = null;
                    b = "test";
                    c = a?.ToString();
                    return c;
                }
            }
            """);
 
    [Fact]
    public Task TestFlowStateNullableParameters_MultipleStatesNonNullReturn()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    [|string? c = a + b;
                    a = string.Empty;
                    b = string.Empty;
                    a = null;
                    b = null;
                    c = null;
                    c = a + b;|]
                    return c ?? string.Empty;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    string? c = {|Rename:NewMethod|}(ref a, ref b);
                    return c ?? string.Empty;
                }
 
                private static string NewMethod(ref string? a, ref string? b)
                {
                    string? c = a + b;
                    a = string.Empty;
                    b = string.Empty;
                    a = null;
                    b = null;
                    c = null;
                    c = a + b;
                    return c;
                }
            }
            """);
 
    [Fact]
    public Task TestFlowStateNullableParameters_MultipleStatesNullReturn()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    [|string? c = a + b;
                    a = string.Empty;
                    b = string.Empty;
                    a = null;
                    b = null;
                    c = a?.ToString();|]
                    return c ?? string.Empty;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    string? c = {|Rename:NewMethod|}(ref a, ref b);
                    return c ?? string.Empty;
                }
 
                private static string? NewMethod(ref string? a, ref string? b)
                {
                    string? c = a + b;
                    a = string.Empty;
                    b = string.Empty;
                    a = null;
                    b = null;
                    c = a?.ToString();
                    return c;
                }
            }
            """);
 
    [Fact]
    public Task TestFlowStateNullableParameters_RefNotNull()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    [|var c = a + b;
                    a = string.Empty;
                    c += a;
                    b = "test";
                    c = a + b +c;|]
                    return c;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string M()
                {
                    string? a = string.Empty;
                    string? b = string.Empty;
                    string c = {|Rename:NewMethod|}(ref a, ref b);
                    return c;
                }
 
                private static string NewMethod(ref string a, ref string b)
                {
                    var c = a + b;
                    a = string.Empty;
                    c += a;
                    b = "test";
                    c = a + b + c;
                    return c;
                }
            }
            """);
 
    // There's a case below where flow state correctly asseses that the variable
    // 'x' is non-null when returned. It's wasn't obvious when writing, but that's 
    // due to the fact the line above it being executed as 'x.ToString()' would throw
    // an exception and the return statement would never be hit. The only way the return
    // statement gets executed is if the `x.ToString()` call succeeds, thus suggesting 
    // that the value is indeed not null.
    [Fact]
    public Task TestFlowNullableReturn_NotNull1()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    [|string? x = null;
                    x.ToString();|]
 
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? x = {|Rename:NewMethod|}();
 
                    return x;
                }
 
                private static string NewMethod()
                {
                    string? x = null;
                    x.ToString();
                    return x;
                }
            }
            """);
 
    [Fact]
    public Task TestFlowNullableReturn_NotNull2()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    [|string? x = null;
                    x?.ToString();
                    x = string.Empty;|]
 
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            class C
            {
                public string? M()
                {
                    string? x = {|Rename:NewMethod|}();
 
                    return x;
                }
 
                private static string NewMethod()
                {
                    string? x = null;
                    x?.ToString();
                    x = string.Empty;
                    return x;
                }
            }
            """);
    [Fact]
    public Task TestFlowNullable_Lambda()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            using System;
 
            class C
            {
                public string? M()
                {
                    [|string? x = null;
                    Action modifyXToNonNull = () =>
                    {
                        x += x;
                    };
 
                    modifyXToNonNull();|]
 
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            using System;
 
            class C
            {
                public string? M()
                {
                    string? x = {|Rename:NewMethod|}();
 
                    return x;
                }
 
                private static string? NewMethod()
                {
                    string? x = null;
                    Action modifyXToNonNull = () =>
                    {
                        x += x;
                    };
 
                    modifyXToNonNull();
                    return x;
                }
            }
            """);
 
    [Fact]
    public Task TestFlowNullable_LambdaWithReturn()
        => TestInRegularAndScript1Async(
            """
            #nullable enable
 
            using System;
 
            class C
            {
                public string? M()
                {
                    [|string? x = null;
                    Func<string?> returnNull = () =>
                    {
                        return null;
                    };
 
                    x = returnNull() ?? string.Empty;|]
 
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            using System;
 
            class C
            {
                public string? M()
                {
                    string? x = {|Rename:NewMethod|}();
 
                    return x;
                }
 
                private static string NewMethod()
                {
                    string? x = null;
                    Func<string?> returnNull = () =>
                    {
                        return null;
                    };
 
                    x = returnNull() ?? string.Empty;
                    return x;
                }
            }
            """);
 
    [Fact]
    public async Task TestExtractReadOnlyMethod()
    {
        await TestInRegularAndScript1Async(
            """
            struct S1
            {
                readonly int M1() => 42;
                void Main()
                {
                    [|int i = M1() + M1()|];
                }
            }
            """,
            """
            struct S1
            {
                readonly int M1() => 42;
                void Main()
                {
                    {|Rename:NewMethod|}();
                }
 
                private readonly void NewMethod()
                {
                    int i = M1() + M1();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestExtractReadOnlyMethodInReadOnlyStruct()
    {
        await TestInRegularAndScript1Async(
            """
            readonly struct S1
            {
                int M1() => 42;
                void Main()
                {
                    [|int i = M1() + M1()|];
                }
            }
            """,
            """
            readonly struct S1
            {
                int M1() => 42;
                void Main()
                {
                    {|Rename:NewMethod|}();
                }
 
                private void NewMethod()
                {
                    int i = M1() + M1();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestExtractNonReadOnlyMethodInReadOnlyMethod()
    {
        await TestInRegularAndScript1Async(
            """
            struct S1
            {
                int M1() => 42;
                readonly void Main()
                {
                    [|int i = M1() + M1()|];
                }
            }
            """,
            """
            struct S1
            {
                int M1() => 42;
                readonly void Main()
                {
                    {|Rename:NewMethod|}();
                }
 
                private void NewMethod()
                {
                    int i = M1() + M1();
                }
            }
            """);
    }
 
    [Fact]
    public Task TestExtractNullableObjectWithExplicitCast()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = null;
                var s = (string?)[|o|];
                Console.WriteLine(s);
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = null;
                var s = (string?){|Rename:GetO|}(o);
                Console.WriteLine(s);
            }
 
            private static object? GetO(object? o)
            {
                return o;
            }
        }
        """);
 
    [Fact]
    public Task TestExtractNotNullableObjectWithExplicitCast()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = new object();
                var s = (string)[|o|];
                Console.WriteLine(s);
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = new object();
                var s = (string){|Rename:GetO|}(o);
                Console.WriteLine(s);
            }
 
            private static object GetO(object o)
            {
                return o;
            }
        }
        """);
 
    [Fact]
    public Task TestExtractNotNullableWithExplicitCast()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class A
        {
        }
 
        class B : A 
        {
        }
 
        class C
        {
            void M()
            {
                B? b = new B();
                var s = (A)[|b|];
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class A
        {
        }
 
        class B : A 
        {
        }
 
        class C
        {
            void M()
            {
                B? b = new B();
                var s = (A){|Rename:GetB|}(b);
            }
 
            private static B GetB(B b)
            {
                return b;
            }
        }
        """);
 
    [Fact]
    public Task TestExtractNullableWithExplicitCast()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class A
        {
        }
 
        class B : A 
        {
        }
 
        class C
        {
            void M()
            {
                B? b = null;
                var s = (A)[|b|];
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class A
        {
        }
 
        class B : A 
        {
        }
 
        class C
        {
            void M()
            {
                B? b = null;
                var s = (A){|Rename:GetB|}(b);
            }
 
            private static B? GetB(B? b)
            {
                return b;
            }
        }
        """);
 
    [Fact]
    public Task TestExtractNotNullableWithExplicitCastSelected()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = new object();
                var s = [|(string)o|];
                Console.WriteLine(s);
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = new object();
                var s = {|Rename:GetS|}(o);
                Console.WriteLine(s);
            }
 
            private static string GetS(object o)
            {
                return (string)o;
            }
        }
        """);
 
    [Fact]
    public Task TestExtractNullableWithExplicitCastSelected()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = null;
                var s = [|(string?)o|];
                Console.WriteLine(s);
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = null;
                var s = {|Rename:GetS|}(o);
                Console.WriteLine(s);
            }
 
            private static string? GetS(object? o)
            {
                return (string?)o;
            }
        }
        """);
    [Fact]
    public Task TestExtractNullableNonNullFlowWithExplicitCastSelected()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = new object();
                var s = [|(string?)o|];
                Console.WriteLine(s);
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = new object();
                var s = {|Rename:GetS|}(o);
                Console.WriteLine(s);
            }
 
            private static string? GetS(object o)
            {
                return (string?)o;
            }
        }
        """);
 
    [Fact]
    public Task TestExtractNullableToNonNullableWithExplicitCastSelected()
    => TestInRegularAndScript1Async(
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = null;
                var s = [|(string)o|];
                Console.WriteLine(s);
            }
        }
        """,
        """
        #nullable enable
 
        using System;
 
        class C
        {
            void M()
            {
                object? o = null;
                var s = {|Rename:GetS|}(o);
                Console.WriteLine(s);
            }
 
            private static string? GetS(object? o)
            {
                return (string)o;
            }
        }
        """);
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38127")]
    public Task TestNestedNullability_Async()
        => TestInRegularAndScriptAsync(
            """
            #nullable enable
 
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                private Task<string> DoSomethingAsync() => Task.FromResult("");
 
                public Task<string?> async M()
                {
                    [|string? x = await DoSomethingAsync();|]
                    x = null;
                    return x;
                }
            }
            """,
            """
            #nullable enable
 
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                private Task<string> DoSomethingAsync() => Task.FromResult("");
 
                public Task<string?> async M()
                {
                    string? x = await {|Rename:NewMethod|}();
                    x = null;
                    return x;
                }
 
                private async Task<string?> NewMethod()
                {
                    return await DoSomethingAsync();
                }
            }
            """);
 
    [Fact]
    public async Task EnsureStaticLocalFunctionOptionHasNoEffect()
    {
        await TestInRegularAndScript1Async(
"""
class Program
{
    static void Main(string[] args)
    {
        bool b = true;
        System.Console.WriteLine([|b != true|] ? b = true : b = false);
    }
}
""",
"""
class Program
{
    static void Main(string[] args)
    {
        bool b = true;
        System.Console.WriteLine({|Rename:NewMethod|}(b) ? b = true : b = false);
    }
 
    private static bool NewMethod(bool b)
    {
        return b != true;
    }
}
""", new TestParameters(options: Option(CSharpCodeStyleOptions.PreferStaticLocalFunction, CodeStyleOption2.FalseWithSuggestionEnforcement)));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39946")]
    public async Task ExtractLocalFunctionCallAndDeclaration()
    {
        await TestInRegularAndScript1Async("""
            class C
            {
                public static void Main()
                {
                    static void LocalParent()
                    {
                        [|void Local() { }
                        Local();|]
                    }
                }
            }
            """, """
            class C
            {
                public static void Main()
                {
                    static void LocalParent()
                    {
                        {|Rename:NewMethod|}();
                    }
                }
 
                private static void NewMethod()
                {
                    void Local() { }
                    Local();
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestMissingWhenOnlyLocalFunctionCallSelected()
    {
        var code = """
            class Program
            {
                static void Main(string[] args)
                {
                    [|Local();|]
                    static void Local()
                    {
                    }
                }
            }
            """;
        await TestExactActionSetOfferedAsync(code, [FeaturesResources.Extract_local_function]);
    }
 
    [Fact]
    public async Task TestOfferedWhenBothLocalFunctionCallAndDeclarationSelected()
    {
        await TestInRegularAndScript1Async("""
            class Program
            {
                static void Main(string[] args)
                {
                    [|Local();
                    var test = 5;
                    static void Local()
                    {
                    }|]
                }
            }
            """, """
            class Program
            {
                static void Main(string[] args)
                {
                    {|Rename:NewMethod|}();
                }
 
                private static void NewMethod()
                {
                    Local();
                    var test = 5;
                    static void Local()
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractNonAsyncMethodWithAsyncLocalFunction()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                void M() 
                {
                    [|F();
                    async void F() => await Task.Delay(0);|]
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    {|Rename:NewMethod|}();
                }
 
                private static void NewMethod()
                {
                    F();
                    async void F() => await Task.Delay(0);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitFalse()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration).ConfigureAwait(false)|];
                }
            }
            """,
            """
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration).ConfigureAwait(false);
                }
 
                private static async System.Threading.Tasks.Task<object> NewMethod(TimeSpan duration)
                {
                    return await Task.Delay(duration).ConfigureAwait(false);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitFalseNamedParameter()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration).ConfigureAwait(continueOnCapturedContext: false)|];
                }
            }
            """,
            """
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration).ConfigureAwait(false);
                }
 
                private static async System.Threading.Tasks.Task<object> NewMethod(TimeSpan duration)
                {
                    return await Task.Delay(duration).ConfigureAwait(continueOnCapturedContext: false);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitFalseOnNonTask()
    {
        await TestInRegularAndScript1Async(
            """
            using System.Threading.Tasks
 
            class C
            {
                async Task MyDelay() 
                {
                    [|await new ValueTask<int>(0).ConfigureAwait(false)|];
                }
            }
            """,
            """
            using System.Threading.Tasks
 
            class C
            {
                async Task MyDelay()
                {
                    await {|Rename:NewMethod|}().ConfigureAwait(false);
                }
 
                private static async Task<object> NewMethod()
                {
                    return await new ValueTask<int>(0).ConfigureAwait(false);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitTrue()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration).ConfigureAwait(true)|];
                }
            }
            """,
            """
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration);
                }
 
                private static async System.Threading.Tasks.Task<object> NewMethod(TimeSpan duration)
                {
                    return await Task.Delay(duration).ConfigureAwait(true);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitNonLiteral()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration).ConfigureAwait(M())|];
                }
            }
            """,
            """
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration);
                }
 
                private static async System.Threading.Tasks.Task<object> NewMethod(TimeSpan duration)
                {
                    return await Task.Delay(duration).ConfigureAwait(M());
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithNoConfigureAwait()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration)|];
                }
            }
            """,
            """
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration);
                }
 
                private static async System.Threading.Tasks.Task<object> NewMethod(TimeSpan duration)
                {
                    return await Task.Delay(duration);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitFalseInLambda()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Run(async () => await Task.Delay(duration).ConfigureAwait(false))|];
                }
            }
            """,
            """
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration);
                }
 
                private static async System.Threading.Tasks.Task<object> NewMethod(TimeSpan duration)
                {
                    return await Task.Run(async () => await Task.Delay(duration).ConfigureAwait(false));
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitFalseInLocalMethod()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Run(F());
                    async Task F() => await Task.Delay(duration).ConfigureAwait(false);|]
                }
            }
            """,
            """
            using System.Threading.Tasks;
 
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration);
                }
 
                private static async Task NewMethod(TimeSpan duration)
                {
                    await Task.Run(F());
                    async Task F() => await Task.Delay(duration).ConfigureAwait(false);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitMixture1()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration).ConfigureAwait(false);
                    await Task.Delay(duration).ConfigureAwait(true);|]
                }
            }
            """,
            """
            using System.Threading.Tasks;
 
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration).ConfigureAwait(false);
                }
 
                private static async Task NewMethod(TimeSpan duration)
                {
                    await Task.Delay(duration).ConfigureAwait(false);
                    await Task.Delay(duration).ConfigureAwait(true);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitMixture2()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration).ConfigureAwait(true);
                    await Task.Delay(duration).ConfigureAwait(false);|]
                }
            }
            """,
            """
            using System.Threading.Tasks;
 
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration).ConfigureAwait(false);
                }
 
                private static async Task NewMethod(TimeSpan duration)
                {
                    await Task.Delay(duration).ConfigureAwait(true);
                    await Task.Delay(duration).ConfigureAwait(false);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitMixture3()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    [|await Task.Delay(duration).ConfigureAwait(M());
                    await Task.Delay(duration).ConfigureAwait(false);|]
                }
            }
            """,
            """
            using System.Threading.Tasks;
 
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await {|Rename:NewMethod|}(duration).ConfigureAwait(false);
                }
 
                private static async Task NewMethod(TimeSpan duration)
                {
                    await Task.Delay(duration).ConfigureAwait(M());
                    await Task.Delay(duration).ConfigureAwait(false);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38529")]
    public async Task TestExtractAsyncMethodWithConfigureAwaitFalseOutsideSelection()
    {
        await TestInRegularAndScript1Async(
            """
            class C
            {
                async Task MyDelay(TimeSpan duration) 
                {
                    await Task.Delay(duration).ConfigureAwait(false);
                    [|await Task.Delay(duration).ConfigureAwait(true);|]
                }
            }
            """,
            """
            using System.Threading.Tasks;
 
            class C
            {
                async Task MyDelay(TimeSpan duration)
                {
                    await Task.Delay(duration).ConfigureAwait(false);
                    await {|Rename:NewMethod|}(duration);
                }
 
                private static async Task NewMethod(TimeSpan duration)
                {
                    await Task.Delay(duration).ConfigureAwait(true);
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40188")]
    public async Task TestEditorconfigSetting_ExpressionBodiedLocalFunction_True()
    {
        var input = """
            <Workspace>
                <Project Language = "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document FilePath = "z:\\file.cs">
            class Program1
            {
                static void Main()
                {
                    [|bool b = true;|]
                    System.Console.WriteLine(b != true ? b = true : b = false);
                }
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">[*.cs]
            csharp_style_expression_bodied_methods = true:silent
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                     <Document FilePath="z:\\file.cs">
            class Program1
            {
                static void Main()
                {
                    bool b = {|Rename:NewMethod|}();
                    System.Console.WriteLine(b != true ? b = true : b = false);
                }
 
                private static bool NewMethod() => true;
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">[*.cs]
            csharp_style_expression_bodied_methods = true:silent
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        await TestInRegularAndScript1Async(input, expected);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40188")]
    public async Task TestEditorconfigSetting_ExpressionBodiedLocalFunction_False()
    {
        var input = """
            <Workspace>
                <Project Language = "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document FilePath = "z:\\file.cs">
            class Program1
            {
                static void Main()
                {
                    [|bool b = true;|]
                    System.Console.WriteLine(b != true ? b = true : b = false);
                }
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">[*.cs]
            csharp_style_expression_bodied_methods = false:silent
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                     <Document FilePath="z:\\file.cs">
            class Program1
            {
                static void Main()
                {
                    bool b = {|Rename:NewMethod|}();
                    System.Console.WriteLine(b != true ? b = true : b = false);
                }
 
                private static bool NewMethod()
                {
                    return true;
                }
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">[*.cs]
            csharp_style_expression_bodied_methods = false:silent
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        await TestInRegularAndScript1Async(input, expected);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40209")]
    public async Task TestNaming_CamelCase_VerifyLocalFunctionSettingsDoNotApply()
    {
        var input = """
            <Workspace>
                <Project Language = "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document FilePath = "z:\\file.cs">
            class Program1
            {
                static void Main()
                {
                    [|bool b = true;|]
                    System.Console.WriteLine(b != true ? b = true : b = false);
                }
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">
            """ + EditorConfigNaming_LocalFunctions_CamelCase + """
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                     <Document FilePath="z:\\file.cs">
            class Program1
            {
                static void Main()
                {
                    bool b = {|Rename:NewMethod|}();
                    System.Console.WriteLine(b != true ? b = true : b = false);
                }
 
                private static bool NewMethod()
                {
                    return true;
                }
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">
            """ + EditorConfigNaming_LocalFunctions_CamelCase + """
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        await TestInRegularAndScript1Async(input, expected);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40209")]
    public async Task TestNaming_CamelCase_VerifyLocalFunctionSettingsDoNotApply_GetName()
    {
        var input = """
            <Workspace>
                <Project Language = "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document FilePath = "z:\\file.cs">
            class MethodExtraction
            {
                void TestMethod()
                {
                    int a = [|1 + 1|];
                }
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">
            """ + EditorConfigNaming_LocalFunctions_CamelCase + """
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                     <Document FilePath="z:\\file.cs">
            class MethodExtraction
            {
                void TestMethod()
                {
                    int a = {|Rename:GetA|}();
                }
 
                private static int GetA()
                {
                    return 1 + 1;
                }
            }
                    </Document>
                    <AnalyzerConfigDocument FilePath = "z:\\.editorconfig">
            """ + EditorConfigNaming_LocalFunctions_CamelCase + """
            </AnalyzerConfigDocument>
                </Project>
            </Workspace>
            """;
 
        await TestInRegularAndScript1Async(input, expected);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40654")]
    public async Task TestOnInvalidUsingStatement_MultipleStatements()
    {
        var input = """
            class C
            {
                void M()
                {
                    [|var v = 0;
                    using System;|]
                }
            }
            """;
        var expected = """
            class C
            {
                void M()
                {
                    {|Rename:NewMethod|}();
                }
 
                private static void NewMethod()
                {
                    var v = 0;
                    using System;
                }
            }
            """;
        await TestInRegularAndScript1Async(input, expected);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40654")]
    public async Task TestMissingOnInvalidUsingStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|using System;|]
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19461")]
    public async Task TestLocalFunction()
    {
        await TestInRegularAndScript1Async("""
            using System;
 
            class Program
            {
                void M()
                {
                    int y = 0;
                    [|var x = local();
 
                    int local()
                    {
                        return y;
                    }|]
                }
            }
            """, """
            using System;
 
            class Program
            {
                void M()
                {
                    int y = 0;
                    {|Rename:NewMethod|}(y);
                }
 
                private static void NewMethod(int y)
                {
                    var x = local();
 
                    int local()
                    {
                        return y;
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43834")]
    public async Task TestRecursivePatternRewrite()
    {
        await TestInRegularAndScript1Async("""
            using System;
            namespace N
            {
                class Context
                {
                }
                class C
                {
                    public void DoAction(Action<Context> action)
                    {
                    }
                    private void Recursive(object context)
                    {
                        DoAction(context =>
                        {
                            if (context is Context { })
                            {
                                DoAction(
                                    [|context =>|] context.ToString());
                            }
                        });
                    }
                }
            }
            """, """
            using System;
            namespace N
            {
                class Context
                {
                }
                class C
                {
                    public void DoAction(Action<Context> action)
                    {
                    }
                    private void Recursive(object context)
                    {
                        DoAction(context =>
                        {
                            if (context is Context { })
                            {
                                DoAction(
                                    {|Rename:NewMethod|}());
                            }
                        });
                    }
 
                    private static Action<Context> NewMethod()
                    {
                        return context => context.ToString();
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41895")]
    public async Task TestConditionalAccess1()
    {
        await TestInRegularAndScript1Async("""
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = b?.[|ToString|]();
                }
            }
            """, """
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = {|Rename:NewMethod|}(b);
                }
 
                private static string NewMethod(List<int> b)
                {
                    return b?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41895")]
    public async Task TestConditionalAccess2()
    {
        await TestInRegularAndScript1Async("""
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = b?.[|ToString|]().Length;
                }
            }
            """, """
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = {|Rename:NewMethod|}(b);
                }
 
                private static int? NewMethod(List<int> b)
                {
                    return b?.ToString().Length;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41895")]
    public async Task TestConditionalAccess3()
    {
        await TestInRegularAndScript1Async("""
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = b?.Count.[|ToString|]();
                }
            }
            """, """
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = {|Rename:NewMethod|}(b);
                }
 
                private static string NewMethod(List<int> b)
                {
                    return b?.Count.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41895")]
    public async Task TestConditionalAccess4()
    {
        await TestInRegularAndScript1Async("""
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = b?.[|Count|].ToString();
                }
            }
            """, """
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = {|Rename:NewMethod|}(b);
                }
 
                private static string NewMethod(List<int> b)
                {
                    return b?.Count.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41895")]
    public async Task TestConditionalAccess5()
    {
        await TestInRegularAndScript1Async("""
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = b?.[|ToString|]()?.ToString();
                }
            }
            """, """
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = {|Rename:NewMethod|}(b);
                }
 
                private static string NewMethod(List<int> b)
                {
                    return b?.ToString()?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41895")]
    public async Task TestConditionalAccess6()
    {
        await TestInRegularAndScript1Async("""
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = b?.ToString()?.[|ToString|]();
                }
            }
            """, """
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = {|Rename:NewMethod|}(b);
                }
 
                private static string NewMethod(List<int> b)
                {
                    return b?.ToString()?.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41895")]
    public async Task TestConditionalAccess7()
    {
        await TestInRegularAndScript1Async("""
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = b?[|[0]|];
                }
            }
            """, """
            using System;
            using System.Collections.Generic;
            class C
            {
                void Test()
                {
                    List<int> b = null;
                    b?.Clear();
                    _ = {|Rename:NewMethod|}(b);
                }
 
                private static int? NewMethod(List<int> b)
                {
                    return b?[0];
                }
            }
            """);
    }
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/48453")]
    [InlineData("record")]
    [InlineData("record class")]
    public async Task TestInRecord(string record)
    {
        await TestInRegularAndScript1Async($@"
{record} Program
{{
    int field;
 
    public int this[int i] => [|this.field|];
}}",
$@"
{record} Program
{{
    int field;
 
    public int this[int i] => {{|Rename:GetField|}}();
 
    private int GetField()
    {{
        return this.field;
    }}
}}");
    }
 
    [Fact]
    public async Task TestInRecordStruct()
    {
        await TestInRegularAndScript1Async("""
            record struct Program
            {
                int field;
 
                public int this[int i] => [|this.field|];
            }
            """,
            """
            record struct Program
            {
                int field;
 
                public int this[int i] => {|Rename:GetField|}();
 
                private readonly int GetField()
                {
                    return this.field;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53031")]
    public async Task TestMethodInNamespace()
    {
        await TestMissingInRegularAndScriptAsync("""
            namespace TestNamespace
            {
                private bool TestMethod() => [|false|];
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53031")]
    public async Task TestMethodInInterface()
    {
        await TestInRegularAndScript1Async("""
            interface TestInterface
            {
                bool TestMethod() => [|false|];
            }
            """,
            """
            interface TestInterface
            {
                bool TestMethod() => {|Rename:NewMethod|}();
 
                bool NewMethod()
                {
                    return false;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53031")]
    public async Task TestStaticMethodInInterface()
    {
        await TestInRegularAndScript1Async("""
            interface TestInterface
            {
                static bool TestMethod() => [|false|];
            }
            """,
            """
            interface TestInterface
            {
                static bool TestMethod() => {|Rename:NewMethod|}();
 
                static bool NewMethod()
                {
                    return false;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractLocalFunction)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/56969")]
    public async Task TopLevelStatement_FullStatement()
    {
        var code = """
            [|System.Console.WriteLine("string");|]
            """;
 
        await new VerifyCS.Test
        {
            TestState =
            {
                Sources = { code },
                OutputKind = OutputKind.ConsoleApplication,
            },
            FixedCode = code,
            LanguageVersion = LanguageVersion.CSharp9,
            CodeActionEquivalenceKey = nameof(FeaturesResources.Extract_method),
        }.RunAsync();
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractLocalFunction)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/56969")]
    public async Task TopLevelStatement_MultipleStatements()
    {
        var code = """
            System.Console.WriteLine("string");
 
            [|int x = int.Parse("0");
            System.Console.WriteLine(x);|]
 
            System.Console.WriteLine(x);
            """;
 
        await new VerifyCS.Test
        {
            TestState =
            {
                Sources = { code },
                OutputKind = OutputKind.ConsoleApplication,
            },
            FixedCode = code,
            LanguageVersion = LanguageVersion.CSharp9,
            CodeActionEquivalenceKey = nameof(FeaturesResources.Extract_method),
        }.RunAsync();
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractLocalFunction)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/56969")]
    public async Task TopLevelStatement_MultipleStatementsWithUsingAndClass()
    {
        var code = """
            using System;
 
            Console.WriteLine("string");
 
            [|int x = int.Parse("0");
            Console.WriteLine(x);|]
 
            Console.WriteLine(x);
 
            class Ignored { }
            """;
 
        await new VerifyCS.Test
        {
            TestState =
            {
                Sources = { code },
                OutputKind = OutputKind.ConsoleApplication,
            },
            FixedCode = code,
            LanguageVersion = LanguageVersion.CSharp9,
            CodeActionEquivalenceKey = nameof(FeaturesResources.Extract_method),
        }.RunAsync();
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractLocalFunction)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/56969")]
    public async Task TopLevelStatement_MultipleStatementsWithInvalidOrdering()
    {
        var code = """
            using System;
 
            Console.WriteLine("string");
 
            class Ignored { }
 
            [|{|CS8803:int x = int.Parse("0");|}
            Console.WriteLine(x);|]
 
            Console.WriteLine(x);
 
            class Ignored2 { }
            """;
 
        await new VerifyCS.Test
        {
            TestState =
            {
                Sources = { code },
                OutputKind = OutputKind.ConsoleApplication,
            },
            FixedCode = code,
            LanguageVersion = LanguageVersion.CSharp9,
            CodeActionEquivalenceKey = nameof(FeaturesResources.Extract_method),
        }.RunAsync();
    }
 
    [Fact, WorkItem(56969, "https://github.com/dotnet/roslyn/issues/58013")]
    public async Task TopLevelMethod_StaticMethod()
    {
        await TestInRegularAndScript1Async("""
            static void X(string s)
            {
                [|s = s.Trim();|]
            }
            """,
            """
            static void X(string s)
            {
                s = {|Rename:NewMethod|}(s);
            }
 
            static string NewMethod(string s)
            {
                s = s.Trim();
                return s;
            }
            """, parameters: new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9)));
    }
 
    [Fact, WorkItem(56969, "https://github.com/dotnet/roslyn/issues/58013")]
    public async Task StaticMethod_ExtractStatementContainingParameter()
    {
        await TestInRegularAndScript1Async("""
            public class Class
            {
                static void X(string s)
                {
                    [|s = s.Trim();|]
                }
            }
            """,
            """
            public class Class
            {
                static void X(string s)
                {
                    s = {|Rename:NewMethod|}(s);
                }
 
                private static string NewMethod(string s)
                {
                    s = s.Trim();
                    return s;
                }
            }
            """, parameters: new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9)));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/57428")]
    public async Task AttributeArgumentWithLambdaBody()
    {
        await TestInRegularAndScript1Async(
            """
            using System.Runtime.InteropServices;
            class Program
            {
                static void F([DefaultParameterValue(() => { return [|null|]; })] object obj)
                {
                }
            }
            """,
            """
            using System.Runtime.InteropServices;
            class Program
            {
                static void F([DefaultParameterValue(() => { return {|Rename:NewMethod|}(); })] object obj)
                {
                }
 
                private static object NewMethod()
                {
                    return null;
                }
            }
            """);
    }
 
    [Fact]
    public Task ExtractMethod_InsideBaseInitializer()
        => TestInRegularAndScript1Async(
            """
            class Base
            {
                private readonly int _x;
                public Base(int x)
                {
                    _x = x;
                }
            }
 
            class C : Base
            {
                public C(int y)
                    : base([|y + 1|])
                {
                }
            }
            """,
            """
            class Base
            {
                private readonly int _x;
                public Base(int x)
                {
                    _x = x;
                }
            }
 
            class C : Base
            {
                public C(int y)
                    : base({|Rename:NewMethod|}(y))
                {
                }
 
                private static int NewMethod(int y)
                {
                    return y + 1;
                }
            }
            """);
 
    [Fact]
    public Task ExtractMethod_InsideThisInitializer()
        => TestInRegularAndScript1Async(
            """
            class C
            {
                public C(int y)
                    : this(y, [|y + 1|])
                {
                }
 
                public C(int x, int y)
                {
                }
            }
            """,
            """
            class C
            {
                public C(int y)
                    : this(y, {|Rename:NewMethod|}(y))
                {
                }
 
                private static int NewMethod(int y)
                {
                    return y + 1;
                }
        
                public C(int x, int y)
                {
                }
            }
            """);
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/8439")]
    public Task TestRefReturn1()
        => TestInRegularAndScript1Async(
            """
            class Program
            {
                public ref int M()
                {
                    return [|ref M()|];
                }
            }
            """,
            """
            class Program
            {
                public ref int M()
                {
                    return ref {|Rename:NewMethod|}();
                }
 
                private ref int NewMethod()
                {
                    return ref M();
                }
            }
            """);
}