File: MakeLocalFunctionStatic\MakeLocalFunctionStaticRefactoringTests.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.CSharp;
using Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.MakeLocalFunctionStatic;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsMakeLocalFunctionStatic)]
public class MakeLocalFunctionStaticRefactoringTests : AbstractCSharpCodeActionTest_NoEditor
{
    protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters)
        => new MakeLocalFunctionStaticCodeRefactoringProvider();
 
    private static readonly ParseOptions CSharp72ParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_2);
    private static readonly ParseOptions CSharp8ParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8);
 
    [Fact]
    public async Task ShouldNotTriggerForCSharp7()
    {
        await TestMissingAsync(
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal();
 
                    int [||]AddLocal()
                    {
                        return x + 1;
                    }
                }  
            }
            """, parameters: new TestParameters(parseOptions: CSharp72ParseOptions));
    }
 
    [Fact]
    public async Task ShouldNotTriggerIfNoCaptures()
    {
        await TestMissingAsync(
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal(x);
 
                    int [||]AddLocal(int x)
                    {
                        return x + 1;
                    }
                }  
            }
            """, parameters: new TestParameters(parseOptions: CSharp8ParseOptions));
    }
 
    [Fact]
    public async Task ShouldNotTriggerIfAlreadyStatic()
    {
        await TestMissingAsync(
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal(x);
 
                    static int [||]AddLocal(int x)
                    {
                        return x + 1;
                    }
                }  
            }
            """, parameters: new TestParameters(parseOptions: CSharp8ParseOptions));
    }
 
    [Fact]
    public async Task ShouldNotTriggerIfAlreadyStaticWithError()
    {
        await TestMissingAsync(
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal();
 
                    static int [||]AddLocal()
                    {
                        return x + 1;
                    }
                }  
            }
            """, parameters: new TestParameters(parseOptions: CSharp8ParseOptions));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38734")]
    public async Task ShouldTriggerIfCapturesThisParameter1()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal();
 
                    int [||]AddLocal()
                    {
                        return this.x + 1;
                    }
                }  
            }
            """,
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal(this);
 
                    static int AddLocal(C @this)
                    {
                        return @this.x + 1;
                    }
                }  
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38734")]
    public async Task ShouldTriggerIfCapturesThisParameter2()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal();
 
                    int [||]AddLocal()
                    {
                        return x + 1;
                    }
                }  
            }
            """,
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal(this);
 
                    static int [||]AddLocal(C @this)
                    {
                        return @this.x + 1;
                    }
                }  
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38734")]
    public async Task ShouldTriggerIfCapturesThisParameter3()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal(0);
 
                    int [||]AddLocal(int y)
                    {
                        return x + y;
                    }
                }  
            }
            """,
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal(this, 0);
 
                    static int [||]AddLocal(C @this, int y)
                    {
                        return @this.x + y;
                    }
                }  
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38734")]
    public async Task ShouldTriggerIfCapturesThisParameter4()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal(null);
 
                    int [||]AddLocal(C c)
                    {
                        return x + c.x;
                    }
                }  
            }
            """,
            """
            class C
            {
                int x;
 
                int N()
                {
                    return AddLocal(this, null);
 
                    static int AddLocal(C @this, C c)
                    {
                        return @this.x + c.x;
                    }
                }  
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task ShouldTriggerIfExplicitlyPassedInThisParameter()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int x;
 
                int N()
                {
                    int y;
                    return AddLocal(this);
 
                    int [||]AddLocal(C c)
                    {
                        return c.x + y;
                    }
                }  
            }
            """,
            """
            class C
            {
                int x;
 
                int N()
                {
                    int y;
                    return AddLocal(this, y);
 
                    static int [||]AddLocal(C c, int y)
                    {
                        return c.x + y;
                    }
                }  
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task ShouldTriggerForCSharp8()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal();
 
                    int [||]AddLocal()
                    {
                        return x + 1;
                    }
                }  
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal(x);
 
                    static int AddLocal(int x)
                    {
                        return x + 1;
                    }
                }  
            }
            """,
parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestMultipleVariables()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    return AddLocal();
 
                    int[||] AddLocal()
                    {
                        return x + y;
                    }
                }
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    return AddLocal(x, y);
 
                    static int AddLocal(int x, int y)
                    {
                        return x + y;
                    }
                }
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestMultipleCalls()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    return AddLocal() + AddLocal();
 
                    int[||] AddLocal()
                    {
                        return x + y;
                    }
                }
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    return AddLocal(x, y) + AddLocal(x, y);
 
                    static int AddLocal(int x, int y)
                    {
                        return x + y;
                    }
                }
            }
            """
, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestMultipleCallsWithExistingParameters()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    var m = AddLocal(1, 2);
                    return AddLocal(m, m);
 
                    int[||] AddLocal(int a, int b)
                    {
                        return a + b + x + y;
                    }
                }
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    var m = AddLocal(1, 2, x, y);
                    return AddLocal(m, m, x, y);
 
                    static int AddLocal(int a, int b, int x, int y)
                    {
                        return a + b + x + y;
                    }
                }
            }
            """
, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestRecursiveCall()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    var m = AddLocal(1, 2);
                    return AddLocal(m, m);
 
                    int[||] AddLocal(int a, int b)
                    {
                        return AddLocal(a, b) + x + y;
                    }
                }
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    var m = AddLocal(1, 2, x, y);
                    return AddLocal(m, m, x, y);
 
                    static int AddLocal(int a, int b, int x, int y)
                    {
                        return AddLocal(a, b, x, y) + x + y;
                    }
                }
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestCallInArgumentList()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    return AddLocal(AddLocal(1, 2), AddLocal(3, 4));
 
                    int[||] AddLocal(int a, int b)
                    {
                        return AddLocal(a, b) + x + y;
                    }
                }
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    return AddLocal(AddLocal(1, 2, x, y), AddLocal(3, 4, x, y), x, y);
 
                    static int AddLocal(int a, int b, int x, int y)
                    {
                        return AddLocal(a, b, x, y) + x + y;
                    }
                }
            }
            """, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestCallsWithNamedArguments()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    var m = AddLocal(1, b: 2);
                    return AddLocal(b: m, a: m);
 
                    int[||] AddLocal(int a, int b)
                    {
                        return a + b + x + y;
                    }
                }
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    int y = 10;
                    var m = AddLocal(1, b: 2, x: x, y: y);
                    return AddLocal(b: m, a: m, x: x, y: y);
 
                    static int AddLocal(int a, int b, int x, int y)
                    {
                        return a + b + x + y;
                    }
                }
            }
            """
, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestCallsWithDafaultValue()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    string y = ";
                    var m = AddLocal(1);
                    return AddLocal(b: m);
 
                    int[||] AddLocal(int a = 0, int b = 0)
                    {
                        return a + b + x + y.Length;
                    }
                }
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    string y = ";
                    var m = AddLocal(1, x: x, y: y);
                    return AddLocal(b: m, x: x, y: y);
 
                    static int AddLocal(int a = 0, int b = 0, int x = 0, string y = null)
                    {
                        return a + b + x + y.Length;
                    }
                }
            }
            """
, parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestWarningAnnotation()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                void N(int x)
                {
                    Func<int> del = AddLocal;
 
                    int [||]AddLocal()
                    {
                        return x + 1;
                    }
                }  
            }
            """,
            """
            class C
            {
                void N(int x)
                {
                    Func<int> del = AddLocal;
 
                    {|Warning:static int AddLocal(int x)
                    {
                        return x + 1;
                    }|}
                }  
            }
            """,
parseOptions: CSharp8ParseOptions);
    }
 
    [Fact]
    public async Task TestNonCamelCaseCapture()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    int Static = 0;
                    return AddLocal();
 
                    int [||]AddLocal()
                    {
                        return Static + 1;
                    }
                }  
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    int Static = 0;
                    return AddLocal(Static);
 
                    static int AddLocal(int @static)
                    {
                        return @static + 1;
                    }
                }  
            }
            """,
parseOptions: CSharp8ParseOptions);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46858")]
    public async Task ShouldNotTriggerIfCallsOtherLocalFunction()
    {
        await TestMissingAsync(
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal();
 
                    int [||]AddLocal()
                    {
                        B();
                        return x + 1;
                    }
 
                    void B()
                    {
                    }
                }  
            }
            """, parameters: new TestParameters(parseOptions: CSharp8ParseOptions));
    }
 
    [Fact]
    public async Task TestCallingStaticLocationFunction()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal();
 
                    int [||]AddLocal()
                    {
                        B();
                        return x + 1;
                    }
 
                    static void B()
                    {
                    }
                }  
            }
            """,
            """
            class C
            {
                int N(int x)
                {
                    return AddLocal(x);
 
                    static int [||]AddLocal(int x)
                    {
                        B();
                        return x + 1;
                    }
 
                    static void B()
                    {
                    }
                }  
            }
            """,
parseOptions: CSharp8ParseOptions);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53179")]
    public async Task TestLocalFunctionAsTopLevelStatement()
    {
        await TestAsync("""
            int y = 10;
            return AddLocal();
 
            int[||] AddLocal()
            {
                return y;
            }
            """, """
            int y = 10;
            return AddLocal(y);
 
            static int AddLocal(int y)
            {
                return y;
            }
            """, parseOptions: CSharp8ParseOptions);
    }
}