File: src\Analyzers\CSharp\Tests\RemoveUnusedParametersAndValues\RemoveUnusedParametersTests.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.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.RemoveUnusedParametersAndValues;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
using static Roslyn.Test.Utilities.TestHelpers;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RemoveUnusedParametersAndValues;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedParameters)]
public class RemoveUnusedParametersTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor
{
    public RemoveUnusedParametersTests(ITestOutputHelper logger)
      : base(logger)
    {
    }
 
    internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
        => (new CSharpRemoveUnusedParametersAndValuesDiagnosticAnalyzer(), new CSharpRemoveUnusedValuesCodeFixProvider());
 
    private OptionsCollection NonPublicMethodsOnly
        => Option(CodeStyleOptions2.UnusedParameters,
            new CodeStyleOption2<UnusedParametersPreference>(UnusedParametersPreference.NonPublicMethods, NotificationOption2.Suggestion));
 
    // Ensure that we explicitly test missing UnusedParameterDiagnosticId, which has no corresponding code fix (non-fixable diagnostic).
    private Task TestDiagnosticMissingAsync(string initialMarkup, ParseOptions? parseOptions = null)
        => TestDiagnosticMissingAsync(initialMarkup, options: null, parseOptions);
    private Task TestDiagnosticsAsync(string initialMarkup, params DiagnosticDescription[] expectedDiagnostics)
        => TestDiagnosticsAsync(initialMarkup, options: null, parseOptions: null, expectedDiagnostics);
    private Task TestDiagnosticMissingAsync(string initialMarkup, OptionsCollection? options, ParseOptions? parseOptions = null)
        => TestDiagnosticMissingAsync(initialMarkup, new TestParameters(parseOptions, options: options, retainNonFixableDiagnostics: true));
    private Task TestDiagnosticsAsync(string initialMarkup, OptionsCollection options, params DiagnosticDescription[] expectedDiagnostics)
        => TestDiagnosticsAsync(initialMarkup, options, parseOptions: null, expectedDiagnostics);
    private Task TestDiagnosticsAsync(string initialMarkup, OptionsCollection? options, ParseOptions? parseOptions, params DiagnosticDescription[] expectedDiagnostics)
        => TestDiagnosticsAsync(initialMarkup, new TestParameters(parseOptions, options: options, retainNonFixableDiagnostics: true), expectedDiagnostics);
 
    [Fact]
    public async Task Parameter_Used()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(int [|p|])
                {
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_Unused()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(int [|p|])
                {
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Theory]
    [InlineData("public", "public")]
    [InlineData("public", "protected")]
    public async Task Parameter_Unused_NonPrivate_NotApplicable(string typeAccessibility, string methodAccessibility)
    {
        await TestDiagnosticMissingAsync(
            $$"""
            {{typeAccessibility}} class C
            {
                {{methodAccessibility}} void M(int [|p|])
                {
                }
            }
            """, NonPublicMethodsOnly);
    }
 
    [Theory]
    [InlineData("public", "private")]
    [InlineData("public", "internal")]
    [InlineData("internal", "private")]
    [InlineData("internal", "public")]
    [InlineData("internal", "internal")]
    [InlineData("internal", "protected")]
    public async Task Parameter_Unused_NonPublicMethod(string typeAccessibility, string methodAccessibility)
    {
        await TestDiagnosticsAsync(
            $$"""
            {{typeAccessibility}} class C
            {
                {{methodAccessibility}} void M(int [|p|])
                {
                }
            }
            """, NonPublicMethodsOnly,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task Parameter_Unused_UnusedExpressionAssignment_PreferNone()
    {
        var unusedValueAssignmentOptionSuppressed = Option(CSharpCodeStyleOptions.UnusedValueAssignment,
            new CodeStyleOption2<UnusedValuePreference>(UnusedValuePreference.DiscardVariable, NotificationOption2.None));
 
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(int [|p|])
                {
                    var x = p;
                }
            }
            """, options: unusedValueAssignmentOptionSuppressed);
    }
 
    [Fact]
    public async Task Parameter_WrittenOnly()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(int [|p|])
                {
                    p = 1;
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task Parameter_WrittenThenRead()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(int [|p|])
                {
                    p = 1;
                    var x = p;
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task Parameter_WrittenOnAllControlPaths_BeforeRead()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(int [|p|], bool flag)
                {
                    if (flag)
                    {
                        p = 0;
                    }
                    else
                    {
                        p = 1;
                    }
 
                    var x = p;
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task Parameter_WrittenOnSomeControlPaths_BeforeRead()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(int [|p|], bool flag, bool flag2)
                {
                    if (flag)
                    {
                        if (flag2)
                        {
                            p = 0;
                        }
                    }
                    else
                    {
                        p = 1;
                    }
 
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task OptionalParameter_Unused()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(int [|p|] = 0)
                {
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task Parameter_UsedInConstructorInitializerOnly()
    {
        await TestDiagnosticMissingAsync(
            """
            class B
            {
                protected B(int p) { }
            }
 
            class C: B
            {
                C(int [|p|])
                : base(p)
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_NotUsedInConstructorInitializer_UsedInConstructorBody()
    {
        await TestDiagnosticMissingAsync(
            """
            class B
            {
                protected B(int p) { }
            }
 
            class C: B
            {
                C(int [|p|])
                : base(0)
                {
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_UsedInConstructorInitializerAndConstructorBody()
    {
        await TestDiagnosticMissingAsync(
            """
            class B
            {
                protected B(int p) { }
            }
 
            class C: B
            {
                C(int [|p|])
                : base(p)
                {
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedLocalFunctionParameter()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(int y)
                {
                    LocalFunction(y);
                    void LocalFunction(int [|p|])
                    {
                    }
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task UnusedLocalFunctionParameter_02()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M()
                {
                    LocalFunction(0);
                    void LocalFunction(int [|p|])
                    {
                    }
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task UnusedLocalFunctionParameter_Discard()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M()
                {
                    LocalFunction(0);
                    void LocalFunction(int [|_|])
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedLocalFunctionParameter_PassedAsDelegateArgument()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                void M()
                {
                    M2(LocalFunction);
                    void LocalFunction(int [|p|])
                    {
                    }
                }
 
                void M2(Action<int> a) => a(0);
            }
            """);
    }
 
    [Fact]
    public async Task UsedInLambda_ReturnsDelegate()
    {
        // Currently we bail out from analysis for method returning delegate types.
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private static Action<int> M(object [|p|] = null, Action<object> myDelegate)
                {
                    return d => { myDelegate(p); };
                }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedInLambda_ReturnsDelegate()
    {
        // We bail out from unused value analysis for method returning delegate types.
        // We should still report unused parameters.
        await TestDiagnosticsAsync(
            """
            using System;
 
            class C
            {
                private static Action M(object [|p|])
                {
                    return () => { };
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task UnusedInLambda_LambdaPassedAsArgument()
    {
        // We bail out from unused value analysis when lambda is passed as argument.
        // We should still report unused parameters.
        await TestDiagnosticsAsync(
            """
            using System;
 
            class C
            {
                private static void M(object [|p|])
                {
                    M2(() => { });
                }
 
                private static void M2(Action a) { }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task ReadInLambda_LambdaPassedAsArgument()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private static void M(object [|p|])
                {
                    M2(() => { M3(p); });
                }
 
                private static void M2(Action a) { }
 
                private static void M3(object o) { }
            }
            """);
    }
 
    [Fact]
    public async Task OnlyWrittenInLambda_LambdaPassedAsArgument()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private static void M(object [|p|])
                {
                    M2(() => { M3(out p); });
                }
 
                private static void M2(Action a) { }
 
                private static void M3(out object o) { o = null; }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31744")]
    public async Task UnusedInExpressionTree_PassedAsArgument()
    {
        await TestDiagnosticsAsync(
            """
            using System;
            using System.Linq.Expressions;
 
            class C
            {
                public static void M1(object [|p|])
                {
                    M2(x => x.M3());
                }
 
                private static C M2(Expression<Func<C, int>> a) { return null; }
                private int M3() { return 0; }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31744")]
    public async Task ReadInExpressionTree_PassedAsArgument()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
            using System.Linq.Expressions;
 
            class C
            {
                public static void M1(object [|p|])
                {
                    M2(x => x.M3(p));
                }
 
                private static C M2(Expression<Func<C, int>> a) { return null; }
                private int M3(object o) { return 0; }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31744")]
    public async Task OnlyWrittenInExpressionTree_PassedAsArgument()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
            using System.Linq.Expressions;
 
            class C
            {
                public static void M1(object [|p|])
                {
                    M2(x => x.M3(out p));
                }
 
                private static C M2(Expression<Func<C, int>> a) { return null; }
                private int M3(out object o) { o = null; return 0; }
            }
            """);
    }
 
    [Fact]
    public async Task UsedInLambda_AssignedToField()
    {
        // Currently we bail out from analysis if we have a delegate creation that is not assigned
        // too a local/parameter.
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private Action _field;
                private static void M(object [|p|])
                {
                    _field = () => { Console.WriteLine(p); };
                }
            }
            """);
    }
 
    [Fact]
    public async Task MethodWithLockAndControlFlow()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private static readonly object s_gate = new object();
 
                public static C M(object [|p|], bool flag, C c1, C c2)
                {
                    C c;
                    lock (s_gate)
                    {
                        c = flag > 0 ? c1 : c2;
                    }
 
                    c.M2(p);
                    return c;
                }
 
                private void M2(object p) { }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedLambdaParameter()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                void M(int y)
                {
                    Action<int> myLambda = [|p|] =>
                    {
                    };
 
                    myLambda(y);
                }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedLambdaParameter_Discard()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                void M(int y)
                {
                    Action<int> myLambda = [|_|] =>
                    {
                    };
 
                    myLambda(y);
                }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedLambdaParameter_DiscardTwo()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                void M(int y)
                {
                    Action<int, int> myLambda = ([|_|], _) =>
                    {
                    };
 
                    myLambda(y, y);
                }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedLocalFunctionParameter_DiscardTwo()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                void M(int y)
                {
                    void local([|_|], _)
                    {
                    }
 
                    local(y, y);
                }
            }
            """);
    }
 
    [Fact]
    public async Task UnusedMethodParameter_DiscardTwo()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                void M([|_|], _)
                {
                }
 
                void M2(int y)
                {
                    M(y, y);
                }
            }
            """);
    }
 
    [Fact]
    public async Task UsedLocalFunctionParameter()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(int y)
                {
                    LocalFunction(y);
                    void LocalFunction(int [|p|])
                    {
                        var x = p;
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task UsedLambdaParameter()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                void M(int y)
                {
                    Action<int> myLambda = [|p|] =>
                    {
                        var x = p;
                    }
 
                    myLambda(y);
                }
            }
            """);
    }
 
    [Fact]
    public async Task OptionalParameter_Used()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(int [|p = 0|])
                {
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task InParameter()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(in int [|p|])
                {
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task RefParameter_Unused()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(ref int [|p|])
                {
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task RefParameter_WrittenOnly()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(ref int [|p|])
                {
                    p = 0;
                }
            }
            """);
    }
 
    [Fact]
    public async Task RefParameter_ReadOnly()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(ref int [|p|])
                {
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task RefParameter_ReadThenWritten()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(ref int [|p|])
                {
                    var x = p;
                    p = 1;
                }
            }
            """);
    }
 
    [Fact]
    public async Task RefParameter_WrittenAndThenRead()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(ref int [|p|])
                {
                    p = 1;
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task RefParameter_WrittenTwiceNotRead()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(ref int [|p|])
                {
                    p = 0;
                    p = 1;
                }
            }
            """);
    }
 
    [Fact]
    public async Task OutParameter_Unused()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(out int [|p|])
                {
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact]
    public async Task OutParameter_WrittenOnly()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(out int [|p|])
                {
                    p = 0;
                }
            }
            """);
    }
 
    [Fact]
    public async Task OutParameter_WrittenAndThenRead()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(out int [|p|])
                {
                    p = 0;
                    var x = p;
                }
            }
            """);
    }
 
    [Fact]
    public async Task OutParameter_WrittenTwiceNotRead()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(out int [|p|])
                {
                    p = 0;
                    p = 1;
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_ExternMethod()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                [System.Runtime.InteropServices.DllImport(nameof(M))]
                static extern void M(int [|p|]);
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_AbstractMethod()
    {
        await TestDiagnosticMissingAsync(
            """
            abstract class C
            {
                protected abstract void M(int [|p|]);
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_VirtualMethod()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                protected virtual void M(int [|p|])
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_OverriddenMethod()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                protected virtual void M(int p)
                {
                    var x = p;
                }
            }
 
            class D : C
            {
                protected override void M(int [|p|])
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_ImplicitInterfaceImplementationMethod()
    {
        await TestDiagnosticMissingAsync(
            """
            interface I
            {
                void M(int p);
            }
            class C: I
            {
                public void M(int [|p|])
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_ExplicitInterfaceImplementationMethod()
    {
        await TestDiagnosticMissingAsync(
            """
            interface I
            {
                void M(int p);
            }
            class C: I
            {
                void I.M(int [|p|])
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_IndexerMethod()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                int this[int [|p|]]
                {
                    get { return 0; }
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_ConditionalDirective()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(int [|p|])
                {
            #if DEBUG
                    System.Console.WriteLine(p);
            #endif
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_EventHandler_FirstParameter()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                public void MyHandler(object [|obj|], System.EventArgs args)
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_EventHandler_SecondParameter()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                public void MyHandler(object obj, System.EventArgs [|args|])
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_MethodUsedAsEventHandler()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            public delegate void MyDelegate(int x);
 
            class C
            {
                private event MyDelegate myDel;
 
                void M(C c)
                {
                    c.myDel += Handler;
                }
 
                void Handler(int [|x|])
                {
                }
            }
            """);
    }
 
    [Fact]
    public async Task Parameter_CustomEventArgs()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                public class CustomEventArgs : System.EventArgs
                {
                }
 
                public void MyHandler(object [|obj|], CustomEventArgs args)
                {
                }
            }
            """);
    }
 
    [Theory]
    [InlineData(@"[System.Diagnostics.Conditional(nameof(M))]")]
    [InlineData(@"[System.Obsolete]")]
    [InlineData(@"[System.Runtime.Serialization.OnDeserializingAttribute]")]
    [InlineData(@"[System.Runtime.Serialization.OnDeserializedAttribute]")]
    [InlineData(@"[System.Runtime.Serialization.OnSerializingAttribute]")]
    [InlineData(@"[System.Runtime.Serialization.OnSerializedAttribute]")]
    public async Task Parameter_MethodsWithSpecialAttributes(string attribute)
    {
        await TestDiagnosticMissingAsync(
            $$"""
            class C
            {
                {{attribute}}
                void M(int [|p|])
                {
                }
            }
            """);
    }
 
    [Theory]
    [InlineData("System.Composition", "ImportingConstructorAttribute")]
    [InlineData("System.ComponentModel.Composition", "ImportingConstructorAttribute")]
    public async Task Parameter_ConstructorsWithSpecialAttributes(string attributeNamespace, string attributeName)
    {
        await TestDiagnosticMissingAsync(
            $$"""
            namespace {{attributeNamespace}}
            {
                public class {{attributeName}} : System.Attribute { }
            }
 
            class C
            {
                [{{attributeNamespace}}.{{attributeName}}()]
                public C(int [|p|])
                {
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32133")]
    public async Task Parameter_SerializationConstructor()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
            using System.Runtime.Serialization;
 
            internal sealed class NonSerializable
            {
                public NonSerializable(string value) => Value = value;
 
                public string Value { get; set; }
            }
 
            [Serializable]
            internal sealed class CustomSerializingType : ISerializable
            {
                private readonly NonSerializable _nonSerializable;
 
                public CustomSerializingType(SerializationInfo info, StreamingContext [|context|])
                {
                    _nonSerializable = new NonSerializable(info.GetString("KEY"));
                }
 
                public void GetObjectData(SerializationInfo info, StreamingContext context)
                {
                    info.AddValue("KEY", _nonSerializable.Value);
                }
            }
            """);
    }
 
    [ConditionalFact(typeof(IsEnglishLocal))]
    public async Task Parameter_DiagnosticMessages()
    {
        var source =
            """
            public class C
            {
                // p1 is unused.
                // p2 is written before read.
                [|int M(int p1, int p2)
                {
                    p2 = 0;
                    return p2;
                }
 
                // p3 is unused parameter of a public API.
                // p4 is written before read parameter of a public API.
                public int M2(int p3, int p4)
                {
                    p4 = 0;
                    return p4;
                }
 
                void M3(int p5)
                {
                    _ = nameof(p5);
                }|]
            }
            """;
        var testParameters = new TestParameters(retainNonFixableDiagnostics: true);
        using var workspace = CreateWorkspaceFromOptions(source, testParameters);
        var diagnostics = await GetDiagnosticsAsync(workspace, testParameters).ConfigureAwait(false);
        diagnostics.Verify(
            Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId, "p1").WithLocation(5, 15),
            Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId, "p2").WithLocation(5, 23),
            Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId, "p3").WithLocation(13, 23),
            Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId, "p4").WithLocation(13, 31),
            Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId, "p5").WithLocation(19, 17));
        var sortedDiagnostics = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
 
        Assert.Equal("Remove unused parameter 'p1'", sortedDiagnostics[0].GetMessage());
        Assert.Equal("Parameter 'p2' can be removed; its initial value is never used", sortedDiagnostics[1].GetMessage());
        Assert.Equal("Remove unused parameter 'p3' if it is not part of a shipped public API", sortedDiagnostics[2].GetMessage());
        Assert.Equal("Parameter 'p4' can be removed if it is not part of a shipped public API; its initial value is never used", sortedDiagnostics[3].GetMessage());
        Assert.Equal("Parameter 'p5' can be removed; its initial value is never used", sortedDiagnostics[4].GetMessage());
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32287")]
    public async Task Parameter_DeclarationPatternWithNullDeclaredSymbol()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(object [|o|])
                {
                    if (o is int _)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32851")]
    public async Task Parameter_Unused_SpecialNames()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                [|void M(int _, char _1, C _3)|]
                {
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32851")]
    public async Task Parameter_Used_SemanticError()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                void M(int [|x|])
                {
                    // CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type.
                    Invoke<string>(() => x);
 
                    T Invoke<T>(Func<T> a) { return a(); }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32851")]
    public async Task Parameter_Unused_SemanticError()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M(int [|x|])
                {
                    // CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type.
                    Invoke<string>(() => 0);
 
                    T Invoke<T>(Func<T> a) { return a(); }
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32973")]
    public async Task OutParameter_LocalFunction()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                public static bool M(out int x)
                {
                    return LocalFunction(out x);
 
                    bool LocalFunction(out int [|y|])
                    {
                        y = 0;
                        return true;
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32973")]
    public async Task RefParameter_Unused_LocalFunction()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                public static bool M(ref int x)
                {
                    return LocalFunction(ref x);
 
                    bool LocalFunction(ref int [|y|])
                    {
                        return true;
                    }
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32973")]
    public async Task RefParameter_Used_LocalFunction()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                public static bool M(ref int x)
                {
                    return LocalFunction(ref x);
 
                    bool LocalFunction(ref int [|y|])
                    {
                        y = 0;
                        return true;
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33299")]
    public async Task NullCoalesceAssignment()
    {
        await TestDiagnosticMissingAsync(
            """
            class C
            {
                public static void M(C [|x|])
                {
                    x ??= new C();
                }
            }
            """, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/34301")]
    public async Task GenericLocalFunction()
    {
        await TestDiagnosticsAsync(
            """
            class C
            {
                void M()
                {
                    LocalFunc(0);
 
                    void LocalFunc<T>(T [|value|])
                    {
                    }
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36715")]
    public async Task GenericLocalFunction_02()
    {
        await TestDiagnosticsAsync(
            """
            using System.Collections.Generic;
 
            class C
            {
                void M(object [|value|])
                {
                    try
                    {
                        value = LocalFunc(0);
                    }
                    finally
                    {
                        value = LocalFunc(0);
                    }
 
                    return;
 
                    IEnumerable<T> LocalFunc<T>(T value)
                    {
                        yield return value;
                    }
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36715")]
    public async Task GenericLocalFunction_03()
    {
        await TestDiagnosticsAsync(
            """
            using System;
            using System.Collections.Generic;
 
            class C
            {
                void M(object [|value|])
                {
                    Func<object, IEnumerable<object>> myDel = LocalFunc;
                    try
                    {
                        value = myDel(value);
                    }
                    finally
                    {
                        value = myDel(value);
                    }
 
                    return;
 
                    IEnumerable<T> LocalFunc<T>(T value)
                    {
                        yield return value;
                    }
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/34830")]
    public async Task RegressionTest_ShouldReportUnusedParameter()
    {
        var options = Option(CodeStyleOptions2.UnusedParameters,
            new CodeStyleOption2<UnusedParametersPreference>(default, NotificationOption2.Suggestion));
 
        await TestDiagnosticMissingAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            public interface I { event Action MyAction; }
 
            public sealed class C : IDisposable
            {
                private readonly Task<I> task;
 
                public C(Task<I> [|task|])
                {
                    this.task = task;
                    Task.Run(async () => (await task).MyAction += myAction);
                }
 
                private void myAction() { }
 
                public void Dispose() => task.Result.MyAction -= myAction;
            }
            """, options);
    }
 
#if !CODE_STYLE // Below test is not applicable for CodeStyle layer as attempting to fetch an editorconfig string representation for this invalid option fails.
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37326")]
    public async Task RegressionTest_ShouldReportUnusedParameter_02()
    {
        var options = Option(CodeStyleOptions2.UnusedParameters,
            new CodeStyleOption2<UnusedParametersPreference>((UnusedParametersPreference)2, NotificationOption2.Suggestion));
 
        var parameters = new TestParameters(globalOptions: options, retainNonFixableDiagnostics: true);
 
        await TestDiagnosticMissingAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            public interface I { event Action MyAction; }
 
            public sealed class C : IDisposable
            {
                private readonly Task<I> task;
 
                public C(Task<I> [|task|])
                {
                    this.task = task;
                    Task.Run(async () => (await task).MyAction += myAction);
                }
 
                private void myAction() { }
 
                public void Dispose() => task.Result.MyAction -= myAction;
            }
            """, parameters);
    }
#endif
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37483")]
    public async Task MethodUsedAsDelegateInGeneratedCode_NoDiagnostic()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            public partial class C
            {
                private void M(int [|x|])
                {
                }
            }
 
            public partial class C
            {
                [System.CodeDom.Compiler.GeneratedCodeAttribute("", "")]
                public void M2(out Action<int> a)
                {
                    a = M;
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37483")]
    public async Task UnusedParameterInGeneratedCode_NoDiagnostic()
    {
        await TestDiagnosticMissingAsync(
            """
            public partial class C
            {
                [System.CodeDom.Compiler.GeneratedCodeAttribute("", "")]
                private void M(int [|x|])
                {
                }
            }
            """);
    }
 
    [WorkItem("https://github.com/dotnet/roslyn/issues/57814")]
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedParameters)]
    public async Task UnusedParameterInPartialMethodImplementation_NoDiagnostic()
    {
        await TestDiagnosticMissingAsync(
            """
            public partial class C
            {
                public partial void M(int x);
            }
 
            public partial class C
            {
                public partial void M(int [|x|])
                {
                }
            }
            """);
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedParameters)]
    public async Task ParameterInPartialMethodDefinition_NoDiagnostic()
    {
        await TestDiagnosticMissingAsync(
            """
            public partial class C
            {
                public partial void M(int [|x|]);
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36817")]
    public async Task ParameterWithoutName_NoDiagnostic()
    {
        await TestDiagnosticMissingAsync(
            """
            public class C
            {
                public void M[|(int )|]
                {
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41236")]
    public async Task NotImplementedException_NoDiagnostic1()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private void Goo(int [|i|])
                {
                    throw new NotImplementedException();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41236")]
    public async Task NotImplementedException_NoDiagnostic2()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private void Goo(int [|i|])
                    => throw new NotImplementedException();
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41236")]
    public async Task NotImplementedException_NoDiagnostic3()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                public C(int [|i|])
                    => throw new NotImplementedException();
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56317")]
    public async Task NotImplementedException_NoDiagnostic4()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private int Goo(int [|i|])
                    => throw new NotImplementedException();
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56317")]
    public async Task NotImplementedException_NoDiagnostic5()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C
            {
                private int Goo(int [|i|])
                {
                    throw new NotImplementedException();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41236")]
    public async Task NotImplementedException_MultipleStatements1()
    {
        await TestDiagnosticsAsync(
            """
            using System;
 
            class C
            {
                private void Goo(int [|i|])
                {
                    throw new NotImplementedException();
                    return;
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41236")]
    public async Task NotImplementedException_MultipleStatements2()
    {
        await TestDiagnosticsAsync(
            """
            using System;
 
            class C
            {
                private void Goo(int [|i|])
                {
                    if (true)
                        throw new NotImplementedException();
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47142")]
    public async Task Record_PrimaryConstructorParameter()
    {
        await TestMissingAsync(
            @"record A(int [|X|]);");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47142")]
    public async Task Record_NonPrimaryConstructorParameter()
    {
        await TestDiagnosticsAsync(
            """
            record A
            {
                public A(int [|X|])
                {
                }
            }
            """,
Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47142")]
    public async Task Record_DelegatingPrimaryConstructorParameter()
    {
        await TestDiagnosticMissingAsync(
            """
            record A(int X);
            record B(int X, int [|Y|]) : A(X);
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47174")]
    public async Task RecordPrimaryConstructorParameter_PublicRecord()
    {
        await TestDiagnosticMissingAsync(
            """
            public record Base(int I) { }
            public record Derived(string [|S|]) : Base(42) { }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45743")]
    public async Task RequiredGetInstanceMethodByICustomMarshaler()
    {
        await TestDiagnosticMissingAsync("""
            using System;
            using System.Runtime.InteropServices;
 
 
            public class C : ICustomMarshaler
            {
                public void CleanUpManagedData(object ManagedObj)
                    => throw new NotImplementedException();
 
                public void CleanUpNativeData(IntPtr pNativeData)
                    => throw new NotImplementedException();
 
                public int GetNativeDataSize()
                    => throw new NotImplementedException();
 
                public IntPtr MarshalManagedToNative(object ManagedObj)
                    => throw new NotImplementedException();
 
                public object MarshalNativeToManaged(IntPtr pNativeData)
                    => throw new NotImplementedException();
 
                public static ICustomMarshaler GetInstance(string [|s|])
                    => null;
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65275")]
    public async Task TestMethodWithUnusedParameterThrowsExpressionBody()
    {
        await TestDiagnosticMissingAsync(
            """
            public class Class
            {
                public void Method(int [|x|]) => throw new System.Exception();
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65275")]
    public async Task TestMethodWithUnusedParameterThrowsMethodBody()
    {
        await TestDiagnosticMissingAsync(
            """
            public class Class
            {
                public void Method(int [|x|])
                {
                    throw new System.Exception();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65275")]
    public async Task TestMethodWithUnusedParameterThrowsConstructorBody()
    {
        await TestDiagnosticMissingAsync(
            """
            public class Class
            {
                public Class(int [|x|])
                {
                    throw new System.Exception();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65275")]
    public async Task TestMethodWithUnusedParameterThrowsConstructorExpressionBody()
    {
        await TestDiagnosticMissingAsync(
            """
            public class Class
            {
                public Class(int [|x|]) => throw new System.Exception();
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/65275")]
    public async Task TestMethodWithUnusedParameterThrowsLocalFunctionExpressionBody()
    {
        await TestDiagnosticMissingAsync(
            """
            public class Class
            {
                public void Method()
                {
                    void LocalMethod(int [|x|]) => throw new System.Exception();
                }
            }
            """);
    }
 
    [Fact, WorkItem(67013, "https://github.com/dotnet/roslyn/issues/67013")]
    public async Task Test_PrimaryConstructor1()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C(int [|a100|])
            {
            }
            """);
    }
 
    [Fact, WorkItem(67013, "https://github.com/dotnet/roslyn/issues/67013")]
    public async Task Test_PrimaryConstructor2()
    {
        await TestDiagnosticMissingAsync(
            """
            using System;
 
            class C(int [|a100|]) : Object()
            {
                int M1() => a100;
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70276")]
    public async Task TestMethodWithNameOf()
    {
        await TestDiagnosticsAsync("""
            class C
            {
                void M(int [|x|])
                {
                    const string y = nameof(C);
                }
            }
            """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58168")]
    public async Task TestInterpolatedStringHandler_TwoIntParameters_FirstParameter()
    {
        await TestDiagnosticMissingAsync("""
            <Workspace>
                <Project Language="C#" CommonReferencesNet6="true">
                    <Document>using System.Runtime.CompilerServices;
 
            [InterpolatedStringHandler]
            public struct MyInterpolatedStringHandler
            {
                public MyInterpolatedStringHandler(int [|literalLength|], int formattedCount)
                {
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58168")]
    public async Task TestInterpolatedStringHandler_TwoIntParameters_SecondParameter()
    {
        await TestDiagnosticMissingAsync("""
            <Workspace>
                <Project Language="C#" CommonReferencesNet6="true">
                    <Document>using System.Runtime.CompilerServices;
 
            [InterpolatedStringHandler]
            public struct MyInterpolatedStringHandler
            {
                public MyInterpolatedStringHandler(int literalLength, int [|formattedCount|])
                {
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """);
    }
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/58168")]
    [MemberData(nameof(NonIntTypes))]
    public async Task TestInterpolatedStringHandler_TwoParameters_FirstNonIntParameter(string nonIntType)
    {
        await TestDiagnosticsAsync($$"""
            <Workspace>
                <Project Language="C#" CommonReferencesNet6="true">
                    <Document>using System.Runtime.CompilerServices;
 
            [InterpolatedStringHandler]
            public struct MyInterpolatedStringHandler
            {
                public MyInterpolatedStringHandler({{nonIntType}} [|literalLength|], int formattedCount)
                {
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/58168")]
    [MemberData(nameof(NonIntTypes))]
    public async Task TestInterpolatedStringHandler_TwoParameters_SecondNonIntParameter(string nonIntType)
    {
        await TestDiagnosticsAsync($$"""
            <Workspace>
                <Project Language="C#" CommonReferencesNet6="true">
                    <Document>using System.Runtime.CompilerServices;
 
            [InterpolatedStringHandler]
            public struct MyInterpolatedStringHandler
            {
                public MyInterpolatedStringHandler(int literalLength, {{nonIntType}} [|formattedCount|])
                {
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58168")]
    public async Task TestInterpolatedStringHandler_OneIntParameter()
    {
        await TestDiagnosticMissingAsync("""
            <Workspace>
                <Project Language="C#" CommonReferencesNet6="true">
                    <Document>using System.Runtime.CompilerServices;
 
            [InterpolatedStringHandler]
            public struct MyInterpolatedStringHandler
            {
                public MyInterpolatedStringHandler(int [|literalLength|])
                {
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """);
    }
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/58168")]
    [MemberData(nameof(NonIntTypes))]
    public async Task TestInterpolatedStringHandler_OneNonIntParameter(string nonIntType)
    {
        await TestDiagnosticsAsync($$"""
            <Workspace>
                <Project Language="C#" CommonReferencesNet6="true">
                    <Document>using System.Runtime.CompilerServices;
 
            [InterpolatedStringHandler]
            public struct MyInterpolatedStringHandler
            {
                public MyInterpolatedStringHandler({{nonIntType}} [|p|])
                {
                }
            }
                    </Document>
                </Project>
            </Workspace>
            """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId));
    }
 
    public static IEnumerable<object[]> NonIntTypes()
    {
        yield return ["byte"];
        yield return ["long"];
        yield return ["object"];
        yield return ["string"];
    }
}