File: RemoveUnusedVariable\RemoveUnusedVariableTests.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.
 
#nullable disable
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.RemoveUnusedVariable;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RemoveUnusedVariable;
 
public partial class RemoveUnusedVariableTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor
{
    public RemoveUnusedVariableTests(ITestOutputHelper logger)
      : base(logger)
    {
    }
 
    internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
        => (null, new CSharpRemoveUnusedVariableCodeFixProvider());
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariable()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    [|int a = 3;|]
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariable1()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    [|string a;|]
                    string b = ";
                    var c = b;
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                    string b = ";
                    var c = b;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariable3()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    [|string a;|]
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariableMultipleOnLine()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    [|string a|], b;
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                    string b;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariableMultipleOnLine1()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    string a, [|b|];
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                    string a;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariableFixAll()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    {|FixAllInDocument:string a;|}
                    string b;
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariableFixAll1()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    {|FixAllInDocument:string a;|}
                    string b, c;
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedVariableFixAll2()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    string a, {|FixAllInDocument:b|};
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/20466")]
    public async Task RemoveUnusedCatchVariable()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    try
                    {
                    }
                    catch (System.Exception [|e|])
                    {
                    }
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                    try
                    {
                    }
                    catch (System.Exception)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/20987")]
    public async Task LeadingDirectives()
    {
        await TestInRegularAndScriptAsync(
            """
            #define DIRECTIVE1
 
            using System;
 
            namespace ClassLibrary
            {
                public class Class1
                {
                    public static string GetText()
                    {
            #if DIRECTIVE1
                    return "Hello from " + Environment.OSVersion;
            #elif DIRECTIVE2
                    return "Hello from .NET Standard";
            #else
            #error Unknown platform 
            #endif
                        int [|blah|] = 5;
                    }
                }
            }
            """,
            """
            #define DIRECTIVE1
 
            using System;
 
            namespace ClassLibrary
            {
                public class Class1
                {
                    public static string GetText()
                    {
            #if DIRECTIVE1
                    return "Hello from " + Environment.OSVersion;
            #elif DIRECTIVE2
                    return "Hello from .NET Standard";
            #else
            #error Unknown platform 
            #endif
                    }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/20942")]
    public async Task TestWhitespaceBetweenStatements1()
    {
        await TestInRegularAndScriptAsync(
            """
            class Test
            {
                bool TrySomething()
                {
                    bool used = true;
                    int [|unused|];
 
                    return used;
                }
            }
            """,
            """
            class Test
            {
                bool TrySomething()
                {
                    bool used = true;
 
                    return used;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/20942")]
    public async Task TestWhitespaceBetweenStatements2()
    {
        await TestInRegularAndScriptAsync(
            """
            class Test
            {
                bool TrySomething()
                {
                    int [|unused|];
 
                    return used;
                }
            }
            """,
            """
            class Test
            {
                bool TrySomething()
                {
                    return used;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task TestWhitespaceBetweenStatementsInSwitchSection1()
    {
        await TestInRegularAndScriptAsync(
            """
            class Test
            {
                bool TrySomething()
                {
                    switch (true)
                    {
                        case true:
                            bool used = true;
                            int [|unused|];
 
                            return used;
                    }
                }
            }
            """,
            """
            class Test
            {
                bool TrySomething()
                {
                    switch (true)
                    {
                        case true:
                            bool used = true;
 
                            return used;
                    }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task TestWhitespaceBetweenStatementsInSwitchSection2()
    {
        await TestInRegularAndScriptAsync(
            """
            class Test
            {
                bool TrySomething()
                {
                    switch (true)
                    {
                        case true:
                            int [|unused|];
 
                            return used;
                    }
                }
            }
            """,
            """
            class Test
            {
                bool TrySomething()
                {
                    switch (true)
                    {
                        case true:
                            return used;
                    }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveVariableAndComment()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    int [|unused|] = 0; // remove also comment
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveVariableAndAssgnment()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    int [|b|] = 0;
                    b = 0;
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task JointDeclarationRemoveFirst()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int M()
                {
                    int [|unused|] = 0, used = 0;
                    return used;
                }
            }
            """,
            """
            class C
            {
                int M()
                {
                    int used = 0;
                    return used;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task JointDeclarationRemoveSecond()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int M()
                {
                    int used = 0, [|unused|] = 0;
                    return used;
                }
            }
            """,
            """
            class C
            {
                int M()
                {
                    int used = 0;
                    return used;
                }
            }
            """);
    }
 
    [Fact(Skip = "https://github.com/dotnet/roslyn/issues/23322"), Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task JointAssignmentRemoveFirst()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int M()
                {
                    int [|unused|] = 0;
                    int used = 0;
                    unused = used = 0;
                    return used;
                }
            }
            """,
            """
            class C
            {
                int M()
                {
                    int used = 0;
                    used = 0;
                    return used;
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task JointAssignmentRemoveSecond()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int M()
                {
                    int used = 0;
                    int [|unused|] = 0;
                    used = unused = 0;
                    return used;
                }
            }
            """,
            """
            class C
            {
                int M()
                {
                    int used = 0;
                    used = 0;
                    return used;
                }
            }
            """);
    }
 
    [Fact(Skip = "https://github.com/dotnet/roslyn/issues/22921"), Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    public async Task RemoveUnusedLambda()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                int M()
                {
                    Func<int> [|unused|] = () =>
                    {
                        return 0;
                    };
                    return 1;
                }
            }
            """,
            """
            class C
            {
                int M()
                {
                    return 1;
                }
            }
            """);
    }
 
    [Fact]
    [Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)]
    [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
    public async Task JointDeclarationRemoveBoth()
    {
        var input = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            class C
            {
                int M()
                {
                    int {|FixAllInDocument:a|} = 0, b = 0;
                    return 0;
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            class C
            {
                int M()
                {
                    return 0;
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """;
 
        await TestInRegularAndScriptAsync(input, expected);
    }
 
    [Fact]
    [Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)]
    [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
    public async Task JointAssignment()
    {
        var input = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            class C
            {
                int M()
                {
                    int a = 0;
                    int {|FixAllInDocument:b|} = 0;
                    a = b = 0;
                    return 0;
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """;
 
        var expected = """
            <Workspace>
                <Project Language="C#" AssemblyName="Assembly1" CommonReferences="true">
                    <Document>
            class C
            {
                int M()
                {
                    int a = 0;
                    a = 0;
                    return 0;
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """;
 
        await TestInRegularAndScriptAsync(input, expected);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/40336")]
    public async Task RemoveUnusedVariableDeclaredInForStatement()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    for([|int i = 0|]; ; )
                    {
 
                    }
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                    for(; ; )
                    {
 
                    }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/40336")]
    public async Task RemoveUnusedVariableJointDeclaredInForStatement()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    for(int i = 0[|, j = 0|]; i < 1; i++)
                    {
 
                    }
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                    for(int i = 0; i < 1; i++)
                    {
 
                    }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/44273")]
    public async Task TopLevelStatement()
    {
        await TestAsync("""
            [|int i = 0|];
            """,
            """
 
            """, TestOptions.Regular);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/49827")]
    public async Task RemoveUnusedVariableJointDeclaredInForStatementInsideIfStatement()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method()
                {
                    if (true)
                        for(int i = 0[|, j = 0|]; i < 1; i++)
                        {
 
                        }
                }
            }
            """,
            """
            class Class
            {
                void Method()
                {
                    if (true)
                        for(int i = 0; i < 1; i++)
                        {
 
                        }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/49827")]
    public async Task DoNotCrashOnDeclarationInsideIfStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class Class
            {
                void Method(bool test)
                {
                    if (test [|and test|])
                    {
 
                    }
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedVariable)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/56924")]
    public async Task RemoveUnusedVariableInCatchInsideBadLocalDeclaration()
    {
        await TestInRegularAndScriptAsync(
            """
            class Class
            {
                void Method(bool test)
                {
                    if (test) var x = () => {
                        try { }
                        catch (Exception [|ex|]) { }
                    };
                }
            }
            """,
            """
            class Class
            {
                void Method(bool test)
                {
                    if (test) var x = () => {
                        try { }
                        catch (Exception) { }
                    };
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
    [WorkItem("https://github.com/dotnet/roslyn/issues/51737")]
    public async Task RemoveUnusedVariableTopLevel()
    {
        await TestAsync(
            """
            [|int i = 1|];
            i = 2;
            """,
            """
 
            """, CSharpParseOptions.Default);
    }
}