File: IntroduceParameter\IntroduceParameterTests.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.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.IntroduceParameter;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.IntroduceParameter;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceParameter)]
public class IntroduceParameterTests : AbstractCSharpCodeActionTest_NoEditor
{
    protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters)
        => new CSharpIntroduceParameterCodeRefactoringProvider();
 
    protected override ImmutableArray<CodeAction> MassageActions(ImmutableArray<CodeAction> actions)
        => FlattenActions(actions);
 
    private OptionsCollection UseExpressionBody
        => Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenPossibleWithSuggestionEnforcement);
 
    [Fact]
    public async Task TestExpressionWithNoMethodCallsCase()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    int m = [|x * y * z;|]
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z, int m) 
                {
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithLocal()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    int l = 5;
                    int m = [|l * y * z;|]
                }
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestBasicComplexExpressionCase()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(string x, int y, int z) 
                {
                    int m = [|x.Length * y * z|];
                }
 
                void M1(string y)
                {
                    M(y, 5, 2);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(string x, int y, int z, int m) 
                {
                }
 
                void M1(string y)
                {
                    M(y, 5, 2, y.Length * 5 * 2);
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithSingleMethodCall()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|x * z * z|];
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, x, z);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z, int m)
                {
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, x, z, z * z * z);
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestLocalDeclarationMultipleDeclarators()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|x * z * z|], y = 0;
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, x, z);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z, int v)
                {
                    int m = {|Rename:v|}, y = 0;
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, x, z, z * z * z);
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestDeclarationInForLoop()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int a, int b)
                {
                    var v = () =>
                    {
                        for (var y = [|a * b|]; ;) { }
                    };
                }
            }
            """;
 
        await TestMissingAsync(code);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithSingleMethodCallInLocalFunction()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = M2(x, z);
 
                    int M2(int x, int y)
                    {
                        int val = [|x * y|];
                        return val;
                    }
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = M2(x, z, x * z);
 
                    int M2(int x, int y, int val)
                    {
                        return val;
                    }
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithSingleMethodCallInStaticLocalFunction()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = M2(x, z);
 
                    static int M2(int x, int y)
                    {
                        int val = [|x * y|];
                        return val;
                    }
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = M2(x, z, x * z);
 
                    static int M2(int x, int y, int val)
                    {
                        return val;
                    }
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestHighlightIncompleteExpressionCaseWithSingleMethodCall()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = 5 * [|x * y * z|];
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, y, x);
                }
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithMultipleMethodCall()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|x * y * z|];
                }
 
                void M1(int x, int y, int z) 
                {
                    M(a + b, 5, x);
                    M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z, int m)
                {
                }
 
                void M1(int x, int y, int z) 
                {
                    M(a + b, 5, x, (a + b) * 5 * x);
                    M(z, y, x, z * y * x);
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionAllOccurrences()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = x * y * z;
                    int f = [|x * y * z|];
                }
 
                void M1(int x, int y, int z) 
                {
                    M(a + b, 5, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z, int f)
                {
                    int m = f;
                }
 
                void M1(int x, int y, int z) 
                {
                    M(a + b, 5, x, (a + b) * 5 * x);
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 3);
    }
 
    [Fact]
    public async Task TestxpressionWithNoMethodCallTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    int m = [|x * y * z;|]
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y, int z)
                {
                    return x * y * z;
                }
 
                void M(int x, int y, int z, int m) 
                {
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|y * x|];
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y)
                {
                    return y * x;
                }
 
                void M(int x, int y, int z, int m)
                {
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, y, x, GetM(z, y));
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallAndAccessorsTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|y * x|];
                }
 
                void M1(int x, int y, int z) 
                {
                    this.M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y)
                {
                    return y * x;
                }
 
                void M(int x, int y, int z, int m)
                {
                }
 
                void M1(int x, int y, int z) 
                {
                    this.M(z, y, x, GetM(z, y));
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallAndAccessorsConditionalTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|y * x|];
                }
 
                void M1(int x, int y, int z) 
                {
                    this?.M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y)
                {
                    return y * x;
                }
 
                void M(int x, int y, int z, int m)
                {
                }
 
                void M1(int x, int y, int z) 
                {
                    this?.M(z, y, x, this?.GetM(z, y));
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallMultipleAccessorsTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    A a = new A();
                    var age = a.Prop.ComputeAge(x, y);
                }
            }
 
            class A
            {
                public B Prop { get; set; }
            }
            class B
            {
                public int ComputeAge(int x, int y)
                {
                    var age = [|x + y|];
                    return age;
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    A a = new A();
                    var age = a.Prop.ComputeAge(x, y, a.Prop.GetAge(x, y));
                }
            }
 
            class A
            {
                public B Prop { get; set; }
            }
            class B
            {
                public int GetAge(int x, int y)
                {
                    return x + y;
                }
 
                public int ComputeAge(int x, int y, int age)
                {
                    return age;
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallMultipleAccessorsConditionalTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    A a = new A();
                    var age = a?.Prop?.ComputeAge(x, y);
                }
            }
 
            class A
            {
                public B Prop { get; set; }
            }
            class B
            {
                public int ComputeAge(int x, int y)
                {
                    var age = [|x + y|];
                    return age;
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    A a = new A();
                    var age = a?.Prop?.ComputeAge(x, y, a?.Prop?.GetAge(x, y));
                }
            }
 
            class A
            {
                public B Prop { get; set; }
            }
            class B
            {
                public int GetAge(int x, int y)
                {
                    return x + y;
                }
 
                public int ComputeAge(int x, int y, int age)
                {
                    return age;
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallAccessorsMixedConditionalTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    A a = new A();
                    var age = a.Prop?.ComputeAge(x, y);
                }
            }
 
            class A
            {
                public B Prop { get; set; }
            }
            class B
            {
                public int ComputeAge(int x, int y)
                {
                    var age = [|x + y|];
                    return age;
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    A a = new A();
                    var age = a.Prop?.ComputeAge(x, y, a.Prop?.GetAge(x, y));
                }
            }
 
            class A
            {
                public B Prop { get; set; }
            }
            class B
            {
                public int GetAge(int x, int y)
                {
                    return x + y;
                }
 
                public int ComputeAge(int x, int y, int age)
                {
                    return age;
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallTrampolineAllOccurrences()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|x * y * z|];
                    int l = x * y * z;
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y, int z)
                {
                    return x * y * z;
                }
 
                void M(int x, int y, int z, int m)
                {
                    int l = m;
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, y, x, GetM(z, y, x));
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 4, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithNoMethodCallOverload()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z) 
                {
                    int m = [|x * y * z;|]
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private void M(int x, int y, int z)
                {
                    M(x, y, z, x * y * z);
                }
 
                void M(int x, int y, int z, int m) 
                {
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 2, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionWithSingleMethodCallOverload()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(int x, int y, int z)
                {
                    int m = [|x * y * z|];
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private void M(int x, int y, int z)
                {
                    M(x, y, z, x * y * z);
                }
 
                void M(int x, int y, int z, int m)
                {
                }
 
                void M1(int x, int y, int z) 
                {
                    M(z, y, x);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 2, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionBodiedMemberOverload()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z) => [|x * y * z|];
 
                void M1(int x, int y, int z)
                {
                    int prod = M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int M(int x, int y, int z) => M(x, y, z, x * y * z);
                int M(int x, int y, int z, int v) => {|Rename:v|};
 
                void M1(int x, int y, int z)
                {
                    int prod = M(z, y, x);
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 2, options: UseExpressionBody, parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionBodiedMemberTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z) => [|x * y * z|];
 
                void M1(int x, int y, int z)
                {
                    int prod = M(z, y, x);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetV(int x, int y, int z)
                {
                    return x * y * z;
                }
 
                int M(int x, int y, int z, int v) => {|Rename:v|};
 
                void M1(int x, int y, int z)
                {
                    int prod = M(z, y, x, GetV(z, y, x));
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithRecursiveCall()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z)
                {
                    int m = [|x * y * z|];
                    return M(x, x, z);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z, int m)
                {
                    return M(x, x, z, x * x * z);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithNestedRecursiveCall()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z)
                {
                    int m = [|x * y * z|];
                    return M(x, x, M(x, y, z));
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z, int m)
                {
                    return M(x, x, M(x, y, z, x * y * z), x * x * M(x, y, z, x * y * z));
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithParamsArg()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(params int[] args)
                {
                    int m = [|args[0] + args[1]|];
                    return m;
                }
 
                void M1()
                {
                    M(5, 6, 7);
                }
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithOptionalParameters()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y = 5)
                {
                    int m = [|x * y|];
                    return m;
                }
 
                void M1()
                {
                    M(5, 3);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                int M(int x, int m, int y = 5)
                {
                    return m;
                }
 
                void M1()
                {
                    M(5, 5 * 3, 3);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithOptionalParametersUsed()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y = 5)
                {
                    int m = [|x * y|];
                    return m;
                }
 
                void M1()
                {
                    M(7);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                int M(int x, int m, int y = 5)
                {
                    return m;
                }
 
                void M1()
                {
                    M(7, 7 * 5);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithOptionalParametersUsedOverload()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y = 5)
                {
                    int m = [|x * y|];
                    return m;
                }
 
                void M1()
                {
                    M(7);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int M(int x, int y = 5)
                {
                    return M(x, x * y, y);
                }
 
                int M(int x, int m, int y = 5)
                {
                    return m;
                }
 
                void M1()
                {
                    M(7);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 2);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithOptionalParametersUsedTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y = 5)
                {
                    int m = [|x * y|];
                    return m;
                }
 
                void M1()
                {
                    M(7);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y = 5)
                {
                    return x * y;
                }
 
                int M(int x, int m, int y = 5)
                {
                    return m;
                }
 
                void M1()
                {
                    M(7, GetM(7));
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 1);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithOptionalParametersUnusedTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y = 5)
                {
                    int m = [|x * y|];
                    return m;
                }
 
                void M1()
                {
                    M(7, 2);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y = 5)
                {
                    return x * y;
                }
 
                int M(int x, int m, int y = 5)
                {
                    return m;
                }
 
                void M1()
                {
                    M(7, GetM(7, 2), 2);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 1);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithCancellationToken()
    {
        var code =
            """
            using System;
            using System.Threading;
            class TestClass
            {
                int M(int x, CancellationToken cancellationToken)
                {
                    int m = [|x * x|];
                    return m;
                }
 
                void M1(CancellationToken cancellationToken)
                {
                    M(7, cancellationToken);
                }
            }
            """;
 
        var expected =
            """
            using System;
            using System.Threading;
            class TestClass
            {
                int M(int x, int m, CancellationToken cancellationToken)
                {
                    return m;
                }
 
                void M1(CancellationToken cancellationToken)
                {
                    M(7, 7 * 7, cancellationToken);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithRecursiveCallTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z)
                {
                    int m = [|x * y * z|];
                    return M(x, x, z);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y, int z)
                {
                    return x * y * z;
                }
 
                int M(int x, int y, int z, int m)
                {
                    return M(x, x, z, GetM(x, x, z));
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionCaseWithNestedRecursiveCallTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y, int z)
                {
                    int m = [|x * y * z|];
                    return M(x, x, M(x, y, x));
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(int x, int y, int z)
                {
                    return x * y * z;
                }
 
                int M(int x, int y, int z, int m)
                {
                    return M(x, x, M(x, y, x, GetM(x, y, x)), GetM(x, x, M(x, y, x, GetM(x, y, x))));
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 1, options: new OptionsCollection(GetLanguage()), parseOptions: CSharpParseOptions.Default);
    }
 
    [Fact]
    public async Task TestExpressionCaseInConstructor()
    {
        var code =
            """
            using System;
            class TestClass
            {
                public TestClass(int x, int y)
                {
                    Math.Max([|x + y|], x * y);
                }
 
                void TestMethod()
                {
                    var test = new TestClass(5, 6);
                }
            }
            """;
        var expected =
            """
            using System;
            class TestClass
            {
                public TestClass(int x, int y, int val1)
                {
                    Math.Max({|Rename:val1|}, x * y);
                }
 
                void TestMethod()
                {
                    var test = new TestClass(5, 6, 5 + 6);
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, 0);
    }
 
    [Fact]
    public async Task TestLambdaCaseNormal()
    {
        var code =
            """
            using System;
            class TestClass
            {
                Func<int, int, int> mult = (x, y) => [|x * y|];
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestLambdaCaseTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                Func<int, int, int> mult = (x, y) => [|x * y|];
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestLambdaCaseOverload()
    {
        var code =
            """
            using System;
            class TestClass
            {
                Func<int, int, int> mult = (x, y) => [|x * y|];
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestTopLevelStatements()
    {
        var code =
            """
            using System;
            Math.Max(5 + 5, [|6 + 7|]);
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestFieldInitializer()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int a = [|5 + 3|];
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestIndexer()
    {
        var code =
            """
            using System;
            class SampleCollection<T>
            {
                private T[] arr = new T[100];
 
                public T this[int i] => arr[[|i + 5|]];
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestPropertyGetter()
    {
        var code =
            """
            using System;
 
            class TimePeriod
            {
               private double _seconds;
 
               public double Hours
               {
                   get { return [|_seconds / 3600|]; }
               }
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestPropertySetter()
    {
        var code =
            """
            using System;
 
            class TimePeriod
            {
               private double _seconds;
 
               public double Hours
               {
                   set {
                      _seconds = [|value * 3600|];
                    }
                }
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestDestructor()
    {
        var code =
            """
            using System;
            class TestClass
            {
                public ~TestClass()
                {
                    Math.Max([|5 + 5|], 5 * 5);
                }
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestExpressionInParameter()
    {
        var code =
            """
            using System;
            class TestClass
            {
                public void M(int x = [|5 * 5|])
                {
                }
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestCrossLanguageInvocations()
    {
        var code =
            """
            <Workspace>
                <Project Language= "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            public class Program
            {
                public Program() {}
 
                public int M(int x, int y)
                {
                    int m = [|x * y|];
                    return m;
                }
 
                void M1()
                {
                    M(7, 2);
                }
            }
                    </Document>
                </Project>
 
            <Project Language= "Visual Basic" AssemblyName="Assembly2" CommonReferences="true">
                    <ProjectReference>Assembly1</ProjectReference>
                    <Document>
            Class ProgramVB
                Sub M2()
                    Dim programC = New Program()
                    programC.M(7, 2)
                End Sub
            End Class
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected =
            """
            <Workspace>
                <Project Language= "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            public class Program
            {
                public Program() {}
 
                public int M(int x, int y, int m)
                {
                    return m;
                }
 
                void M1()
                {
                    M(7, 2, 7 * 2);
                }
            }
                    </Document>
                </Project>
 
            <Project Language= "Visual Basic" AssemblyName="Assembly2" CommonReferences="true">
                    <ProjectReference>Assembly1</ProjectReference>
                    <Document>
            Class ProgramVB
                Sub M2()
                    Dim programC = New Program()
                    programC.M(7, 2)
                End Sub
            End Class
                    </Document>
                </Project>
            </Workspace>
            """;
        await TestInRegularAndScriptAsync(code, expected, 0);
    }
 
    [Fact]
    public async Task TestConvertedTypeInExpression()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(double x, double y) 
                {
                    int m = [|(int)(x * y);|]
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(double x, double y, int m) 
                {
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestConvertedTypeInExpressionTrampoline()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M(double x, double y) 
                {
                    int m = [|(int)(x * y);|]
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                private int GetM(double x, double y)
                {
                    return (int)(x * y);
                }
 
                void M(double x, double y, int m) 
                {
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 1);
    }
 
    [Fact]
    public async Task TestThisKeywordInExpression()
    {
        var code =
            """
            using System;
            class TestClass
            {
                public int M1()
                {
                    return 5;
                }
 
                public int M(int x, int y)
                {
                    int m = [|x * this.M1();|]
                    return m;
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                public int M1()
                {
                    return 5;
                }
 
                public int GetM(int x)
                {
                    return x * this.M1();
                }
 
                public int M(int x, int y, int m)
                {
                    return m;
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestThisImplicitInExpression()
    {
        var code =
            """
            using System;
            class TestClass
            {
                public int M1()
                {
                    return 5;
                }
 
                public int M(int x, int y)
                {
                    int m = [|x * M1();|]
                    return m;
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                public int M1()
                {
                    return 5;
                }
 
                public int GetM(int x)
                {
                    return x * M1();
                }
 
                public int M(int x, int y, int m)
                {
                    return m;
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestStaticMethodCallInExpression()
    {
        var code =
            """
            using System;
            class TestClass
            {
                public static int M1()
                {
                    return 5;
                }
 
                public int M(int x, int y)
                {
                    int m = [|x * M1();|]
                    return m;
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                public static int M1()
                {
                    return 5;
                }
 
                public int M(int x, int y, int m)
                {
                    return m;
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestBaseKeywordInExpression()
    {
        var code =
            """
            using System;
            class Net
            {
                public int _value = 6;
            }
 
            class Perl : Net
            {
                public new int _value = 7;
 
                public void Write()
                {
                    int x = [|base._value + 1;|]
                }
            }
            """;
 
        var expected =
            """
            using System;
            class Net
            {
                public int _value = 6;
            }
 
            class Perl : Net
            {
                public new int _value = 7;
 
                public int GetX()
                {
                    return base._value + 1;
                }
 
                public void Write(int x)
                {
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestFieldReferenceInOptionalParameter()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y = int.MaxValue)
                {
                    int m = [|x * y|];
                    return m;
                }
 
                void M1()
                {
                    M(7);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                int M(int x, int m, int y = int.MaxValue)
                {
                    return m;
                }
 
                void M1()
                {
                    M(7, 7 * int.MaxValue);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestNamedParameterNecessary()
    {
        var code =
            """
            using System;
            class TestClass
            {
                int M(int x, int y = 5, int z = 3)
                {
                    int m = [|z * y|];
                    return m;
                }
 
                void M1()
                {
                    M(z: 0, y: 2);
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                int M(int x, int m, int y = 5, int z = 3)
                {
                    return m;
                }
 
                void M1()
                {
                    M(z: 0, m: 0 * 2, y: 2);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestHighlightReturnType()
    {
        var code =
            """
            using System;
            class TestClass
            {
                [|int|] M(int x)
                {
                    return x;
                }
 
                void M1()
                {
                    M(5);
                }
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestTypeOfOnString()
    {
        var code =
            """
            using System;
            class TestClass
            {
                void M()
                {
                    var x = [|typeof(string);|]
                }
            }
            """;
 
        var expected =
            """
            using System;
            class TestClass
            {
                void M(Type x)
                {
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, index: 0);
    }
 
    [Fact]
    public async Task TestClassObject()
    {
        var code =
            """
            class F
            {
                public int x;
                public int y;
 
                public F(int x, int y)
                {
                    this.x = x;
                    this.y = y;
                }
            }
 
            class TestClass
            {
                int N(F f)
                {
                    return f.[|x|];
                }
 
                void M()
                {
                    N(new F(1, 2));
                }
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestReferenceInDifferentDocumentWithUsings()
    {
        var code =
            """
            <Workspace>
                <Project Language= "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            using System;
            using System.Linq;
 
            namespace Foo
            {
                public class Bar
                {
                    public Bar()
                    {
                        [|var x = 2|];
                    }
                }
            }
                    </Document>
 
                    <Document>
            namespace Refactorings
            {
                using Foo;
                class Program
                {
                    public Program(int x)
                    {
                        var bar = new Bar();
 
                    }
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected =
            """
            <Workspace>
                <Project Language= "C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            using System;
            using System.Linq;
 
            namespace Foo
            {
                public class Bar
                {
                    public Bar(int x)
                    {
                    }
                }
            }
                    </Document>
 
                    <Document>
            namespace Refactorings
            {
                using Foo;
                class Program
                {
                    public Program(int x)
                    {
                        var bar = new Bar(2);
 
                    }
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """;
        await TestInRegularAndScriptAsync(code, expected, 0);
    }
 
    [Fact]
    public async Task TestIntroduceParameterOnParameter()
    {
        var code =
            """
            using System;
 
            class Program
            {
                public static void Main(string[] args)
                {
                    Console.WriteLine([|args|]);
                }
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact]
    public async Task TestIntroduceParameterOnExpressionContainingParameter()
    {
        var code =
            """
            public class C
            {
                public void M(string s)
                {
                    localFunction();
 
                    void localFunction()
                    {
                        _ = [|s|].ToString();
                    }
                }
            }
            """;
 
        var expected =
            """
            public class C
            {
                public void M(string s)
                {
                    localFunction(s);
 
                    void localFunction(string s)
                    {
                        _ = {|Rename:s|}.ToString();
                    }
                }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected, 0);
    }
 
    [Fact]
    public async Task TestIntroduceParameterOnOverload()
    {
        var code =
            """
            M();
            int M(int _) => M([|1234|]);
            """;
 
        var expected =
            """
            M();
            int M(int _, int v) => M({|Rename:v|}, 1234);
            """;
 
        await TestInRegularAndScriptAsync(code, expected, 0);
    }
 
    [Fact]
    public async Task TestIntroduceParameterOnAttributeArgument()
    {
        var code =
            """
            public class C
            {
                [Theory]
                [InlineData([|"A"|])]
                public void Test(string s)
                {
                }
            }
            """;
 
        await TestMissingInRegularAndScriptAsync(code);
    }
}