File: src\Analyzers\CSharp\Tests\RemoveUnnecessaryLambdaExpression\RemoveUnnecessaryLambdaExpressionTests.cs
Web Access
Project: src\src\CodeStyle\CSharp\Tests\Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle.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.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryLambdaExpression;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RemoveUnnecessaryLambdaExpression;
 
using VerifyCS = CSharpCodeFixVerifier<
   CSharpRemoveUnnecessaryLambdaExpressionDiagnosticAnalyzer,
   CSharpRemoveUnnecessaryLambdaExpressionCodeFixProvider>;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)]
public sealed class RemoveUnnecessaryLambdaExpressionTests
{
    private static async Task TestInRegularAndScriptAsync(
        [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string testCode,
        [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string fixedCode,
        LanguageVersion version = LanguageVersion.CSharp12,
        OutputKind? outputKind = null)
    {
        await new VerifyCS.Test
        {
            TestCode = testCode,
            FixedCode = fixedCode,
            LanguageVersion = version,
            TestState =
            {
                OutputKind = outputKind,
            }
        }.RunAsync();
    }
 
    private static Task TestMissingInRegularAndScriptAsync(
        [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string testCode,
        LanguageVersion version = LanguageVersion.CSharp12,
        OutputKind? outputKind = null)
        => TestInRegularAndScriptAsync(testCode, testCode, version, outputKind);
 
    [Fact]
    public async Task TestMissingInCSharp10()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux(s));
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """, LanguageVersion.CSharp10);
    }
 
    [Fact]
    public async Task TestBasicCase()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|s => |]Quux(s));
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestWithOptionOff()
    {
        var code = """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux(s));
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = code,
            LanguageVersion = LanguageVersion.CSharp12,
            Options = { { CSharpCodeStyleOptions.PreferMethodGroupConversion, new CodeStyleOption2<bool>(false, NotificationOption2.None) } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotOnStaticLambda()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(static s => Quux(s));
                }
 
                void Bar(Func<int, string> f) { }
                static string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestNotWithOptionalParameter()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux(s));
                }
 
                void Bar(Func<int, string> f) { }
                static string Quux(int i, int j = 0) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestNotWithParams1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux(s));
                }
 
                void Bar(Func<int, string> f) { }
                static string Quux(int i, params int[] j) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestNotWithParams2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux(s));
                }
 
                void Bar(Func<object, string> f) { }
                static string Quux(params object[] j) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestWithParams1()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|s => |]Quux(s));
                }
 
                void Bar(Func<object[], string> f) { }
                string Quux(params object[] o) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<object[], string> f) { }
                string Quux(params object[] o) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestNotWithRefChange1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux(ref s));
                }
 
                void Bar(Func<int, string> f) { }
                static string Quux(ref int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestNotWithRefChange2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            delegate string X(ref int i);
 
            class C
            {
                void Goo()
                {
                    Bar((ref int s) => Quux(s));
                }
 
                void Bar(X x) { }
                static string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestWithSameRef()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            delegate string X(ref int i);
 
            class C
            {
                void Goo()
                {
                    Bar([|(ref int s) => |]Quux(ref s));
                }
 
                void Bar(X x) { }
                static string Quux(ref int i) => default;
            }
            """,
 
            """
            using System;
 
            delegate string X(ref int i);
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(X x) { }
                static string Quux(ref int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestNotOnConversionToObject()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    object o = (int s) => Quux(s);
                }
 
                void Bar(Func<int, string> f) { }
                static string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestWithParenthesizedLambda()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|(int s) => |]Quux(s));
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestWithAnonymousMethod()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|delegate (int s) { return |]Quux(s); });
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestWithAnonymousMethodNoParameterList()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|delegate { return |]Quux(); });
                }
 
                void Bar(Func<string> f) { }
                string Quux() => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<string> f) { }
                string Quux() => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestFixCoContravariance1()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|s => |]Quux(s));
                }
 
                void Bar(Func<object, string> f) { }
                string Quux(object o) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<object, string> f) { }
                string Quux(object o) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestFixCoContravariance2()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|s => |]Quux(s));
                }
 
                void Bar(Func<string, object> f) { }
                string Quux(object o) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<string, object> f) { }
                string Quux(object o) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestFixCoContravariance3()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => {|CS1662:{|CS0266:Quux(s)|}|});
                }
 
                void Bar(Func<string, string> f) { }
                object Quux(object o) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestFixCoContravariance4()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux({|CS1503:s|}));
                }
 
                void Bar(Func<object, object> f) { }
                string Quux(string o) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestFixCoContravariance5()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(s => Quux({|CS1503:s|}));
                }
 
                void Bar(Func<object, string> f) { }
                object Quux(string o) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestTwoArgs()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|(s1, s2) => |]Quux(s1, s2));
                }
 
                void Bar(Func<int, bool, string> f) { }
                string Quux(int i, bool b) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, bool, string> f) { }
                string Quux(int i, bool b) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestMultipleArgIncorrectPassing1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar((s1, s2) => Quux(s2, s1));
                }
 
                void Bar(Func<int, int, string> f) { }
                string Quux(int i, int b) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestMultipleArgIncorrectPassing2()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar((s1, s2) => Quux(s1, s1));
                }
 
                void Bar(Func<int, int, string> f) { }
                string Quux(int i, int b) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestMultipleArgIncorrectPassing3()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar((s1, s2) => Quux(s1, true));
                }
 
                void Bar(Func<int, bool, string> f) { }
                string Quux(int i, bool b) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestReturnStatement()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|(s1, s2) => {
                        return |]Quux(s1, s2);
                    });
                }
 
                void Bar(Func<int, bool, string> f) { }
                string Quux(int i, bool b) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, bool, string> f) { }
                string Quux(int i, bool b) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestReturnStatement2()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar([|(s1, s2) => {
                        return |]this.Quux(s1, s2);
                    });
                }
 
                void Bar(Func<int, bool, string> f) { }
                string Quux(int i, bool b) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(this.Quux);
                }
 
                void Bar(Func<int, bool, string> f) { }
                string Quux(int i, bool b) => default;
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")]
    public async Task TestMissingOnAmbiguity1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class A
            {
                static void Goo<T>(T x)
                {
                }
 
                static void Bar(Action<int> x)
                {
                }
 
                static void Bar(Action<string> x)
                {
                }
 
                static void Main()
                {
                    {|CS0121:Bar|}(x => Goo(x));
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")]
    public async Task TestWithConstraint1()
    {
        var code = """
            using System;
            class A
            {
                static void Goo<T>(T x) where T : class
                {
                }
 
                static void Bar(Action<int> x)
                {
                }
 
                static void Bar(Action<string> x)
                {
                }
 
                static void Main()
                {
                    Bar([|x => |]Goo<string>(x));
                }
            }
            """;
 
        var expected = """
            using System;
            class A
            {
                static void Goo<T>(T x) where T : class
                {
                }
 
                static void Bar(Action<int> x)
                {
                }
 
                static void Bar(Action<string> x)
                {
                }
 
                static void Main()
                {
                    Bar(Goo<string>);
                }
            }
            """;
        await TestInRegularAndScriptAsync(code, expected);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")]
    public async Task TestWithConstraint2()
    {
        var code = """
            using System;
            class A
            {
                static void Goo<T>(T x) where T : class
                {
                }
 
                static void Bar(Action<int> x)
                {
                }
 
                static void Bar(Action<string> x)
                {
                }
 
                static void Main()
                {
                    Bar(x => Goo(x));
                }
            }
            """;
        await TestMissingInRegularAndScriptAsync(code);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/627092")]
    public async Task TestMissingOnLambdaWithDynamic_1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    C<string>.InvokeGoo();
                }
            }
 
            class C<T>
            {
                public static void InvokeGoo()
                {
                    Action<dynamic, string> goo = (x, y) => C<T>.Goo(x, y); // Simplify lambda expression
                    goo(1, "");
                }
 
                static void Goo(object x, object y)
                {
                    Console.WriteLine("Goo(object x, object y)");
                }
 
                static void Goo(object x, T y)
                {
                    Console.WriteLine("Goo(object x, T y)");
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/627092")]
    public async Task TestWithLambdaWithDynamic()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    C<string>.InvokeGoo();
                }
            }
 
            class C<T>
            {
                public static void InvokeGoo()
                {
                    Action<dynamic> goo = [|x => |]C<T>.Goo(x); // Simplify lambda expression
                    goo(1);
                }
 
                private static void Goo(dynamic x)
                {
                    throw new NotImplementedException();
                }
 
                static void Goo(object x, object y)
                {
                    Console.WriteLine("Goo(object x, object y)");
                }
 
                static void Goo(object x, T y)
                {
                    Console.WriteLine("Goo(object x, T y)");
                }
            }
            """,
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    C<string>.InvokeGoo();
                }
            }
 
            class C<T>
            {
                public static void InvokeGoo()
                {
                    Action<dynamic> goo = C<T>.Goo; // Simplify lambda expression
                    goo(1);
                }
 
                private static void Goo(dynamic x)
                {
                    throw new NotImplementedException();
                }
 
                static void Goo(object x, object y)
                {
                    Console.WriteLine("Goo(object x, object y)");
                }
 
                static void Goo(object x, T y)
                {
                    Console.WriteLine("Goo(object x, T y)");
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544625")]
    public async Task ParenthesizeIfParseChanges()
    {
        var code = """
            using System;
            class C
            {
                static void M()
                {
                    C x = new C();
                    int y = 1;
                    Bar([|() => { return |]Console.ReadLine(); } < x, y > (1 + 2));
                }
 
                static void Bar(object a, object b) { }
                public static bool operator <(Func<string> y, C x) { return true; }
                public static bool operator >(Func<string> y, C x) { return true; }
            }
            """;
 
        var expected = """
            using System;
            class C
            {
                static void M()
                {
                    C x = new C();
                    int y = 1;
                    Bar((Console.ReadLine) < x, y > (1 + 2));
                }
 
                static void Bar(object a, object b) { }
                public static bool operator <(Func<string> y, C x) { return true; }
                public static bool operator >(Func<string> y, C x) { return true; }
            }
            """;
 
        await TestInRegularAndScriptAsync(code, expected);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545856")]
    public async Task TestNotWithSideEffects()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Main()
                {
                    Func<string> a = () => new C().ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545994")]
    public async Task TestExpressionStatement()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    Action a = [|() => {
                        |]Console.WriteLine();
                    };
                }
            }
            """,
            """
            using System;
 
            class Program
            {
                static void Main()
                {
                    Action a = Console.WriteLine;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestTaskOfT1()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|s => |]Quux(s));
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTaskOfT1()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => await |]Quux(s));
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTaskOfT2()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => await |]Quux(s).ConfigureAwait(false));
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncNoAwait1()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(async s => Quux(s));
                }
 
                void Bar(Func<int, Task<string>> f) { }
                string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestTaskOfT1_Return()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|s => { return |]Quux(s); });
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTaskOfT1_Return()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => { return await |]Quux(s); });
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTaskOfT2_Return()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => { return await |]Quux(s).ConfigureAwait(false); });
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task<string>> f) { }
                Task<string> Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncNoAwait1_Return()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(async s => { return Quux(s); });
                }
 
                void Bar(Func<int, Task<string>> f) { }
                string Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestTask1()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|s => |]Quux(s));
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTask1()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => await |]Quux(s));
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTask2()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => await |]Quux(s).ConfigureAwait(false));
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestTask1_ExpressionStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(s {|CS1643:=>|} { Quux(s); });
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTask1_ExpressionStatement()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => { await |]Quux(s); });
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncTask2_ExpressionStatement()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar([|async s => { await |]Quux(s).ConfigureAwait(false); });
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """,
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(Quux);
                }
 
                void Bar(Func<int, Task> f) { }
                Task Quux(int i) => default;
            }
            """);
    }
 
    [Fact]
    public async Task TestAsyncNoAwait1_ExpressionStatement()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void Goo()
                {
                    Bar(async s => { Quux(s); });
                }
 
                void Bar(Func<int, Task> f) { }
                void Quux(int i) { }
            }
            """);
    }
 
    [Fact]
    public async Task TestExplicitGenericCall()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Action a = [|() => |]Quux<int>();
                }
 
                void Quux<T>() { }
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Action a = Quux<int>;
                }
 
                void Quux<T>() { }
            }
            """);
    }
 
    [Fact]
    public async Task TestImplicitGenericCall()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Action<int> a = b => Quux(b);
                }
 
                void Quux<T>(T t) { }
            }
            """);
    }
 
    [Fact]
    public async Task TestNullabilityChanges()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            #nullable enable
 
            using System;
            using System.Collections.Generic;
            using System.Diagnostics.CodeAnalysis;
 
            class C
            {
                void Goo(List<string> assemblies, HashSet<string> usedProjectFileNames)
                {
                    var projectAssemblyFileNames = Select(assemblies, a => GetFileName(a));
                    var v = Any(projectAssemblyFileNames, usedProjectFileNames.Contains);
                }
 
                static List<TResult> Select<TItem, TResult>(List<TItem> items, Func<TItem, TResult> map) => new();
 
                [return: NotNullIfNotNull("path")]
                static string? GetFileName(string? path) => path;
 
                static bool Any<T>(List<T> immutableArray, Func<T, bool> predicate) => true;
            }
 
            namespace System.Diagnostics.CodeAnalysis
            {
                [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
                public sealed class NotNullIfNotNullAttribute : Attribute
                {
                    public string ParameterName => "";
 
                    public NotNullIfNotNullAttribute(string parameterName)
                    {
                    }
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestTrivia1()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(/*before*/[|s => |]Quux(s)/*after*/);
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """,
            """
            using System;
 
            class C
            {
                void Goo()
                {
                    Bar(/*before*/Quux/*after*/);
                }
 
                void Bar(Func<int, string> f) { }
                string Quux(int i) => default;
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63465")]
    public async Task TestNotWithPartialDefinition()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            using System;
            using System.Diagnostics;
 
            public partial class C
            {
                internal void M1()
                {
                    M2(x => M3(x));
                }
 
                partial void M3(string s);
 
                private static void M2(Action<string> a) { }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63465")]
    public async Task TestWithPartialDefinitionAndImplementation()
    {
        await TestInRegularAndScriptAsync(
            """
            using System;
            using System.Diagnostics;
 
            public partial class C
            {
                internal void M1()
                {
                    M2([|x => |]M3(x));
                }
 
                partial void M3(string s);
                partial void M3(string s) { }
 
                private static void M2(Action<string> a) { }
            }
            """,
            """
            using System;
            using System.Diagnostics;
 
            public partial class C
            {
                internal void M1()
                {
                    M2(M3);
                }
 
                partial void M3(string s);
                partial void M3(string s) { }
 
                private static void M2(Action<string> a) { }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63464")]
    public async Task TestNotWithConditionalAttribute()
    {
        await TestMissingInRegularAndScriptAsync("""
            using System;
            using System.Diagnostics;
 
            public class C
            {
                internal void M1()
                {
                    M2(x => M3(x));
                }
 
                [Conditional("DEBUG")]
                internal void M3(string s) { }
 
                private static void M2(Action<string> a) { }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69094")]
    public async Task TestNotWithAssignmentOfInvokedExpression1()
    {
        await TestMissingInRegularAndScriptAsync("""
            using System;
            using System.Threading.Tasks;
 
            TaskCompletionSource<bool> valueSet = new();
            Helper helper = new(v => valueSet.SetResult(v));
            helper.Set(true);
            valueSet = new();
            helper.Set(false);
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """, outputKind: OutputKind.ConsoleApplication);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69094")]
    public async Task TestWithoutAssignmentOfInvokedExpression1()
    {
        await TestInRegularAndScriptAsync("""
            using System;
            using System.Threading.Tasks;
 
            TaskCompletionSource<bool> valueSet = new();
            Helper helper = new([|v => |]valueSet.SetResult(v));
            helper.Set(true);
            helper.Set(false);
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """, """
            using System;
            using System.Threading.Tasks;
 
            TaskCompletionSource<bool> valueSet = new();
            Helper helper = new(valueSet.SetResult);
            helper.Set(true);
            helper.Set(false);
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """,
            outputKind: OutputKind.ConsoleApplication);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69094")]
    public async Task TestNotWithAssignmentOfInvokedExpression2()
    {
        await TestMissingInRegularAndScriptAsync("""
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void M()
                {
                    TaskCompletionSource<bool> valueSet = new();
                    Helper helper = new(v => valueSet.SetResult(v));
                    helper.Set(true);
                    valueSet = new();
                    helper.Set(false);
                }
            }
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69094")]
    public async Task TestWithoutAssignmentOfInvokedExpression2()
    {
        await TestInRegularAndScriptAsync("""
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void M()
                {
                    TaskCompletionSource<bool> valueSet = new();
                    Helper helper = new([|v => |]valueSet.SetResult(v));
                    helper.Set(true);
                    helper.Set(false);
                }
            }
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """, """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void M()
                {
                    TaskCompletionSource<bool> valueSet = new();
                    Helper helper = new(valueSet.SetResult);
                    helper.Set(true);
                    helper.Set(false);
                }
            }
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69094")]
    public async Task TestWithoutAssignmentOfInvokedExpression3()
    {
        await TestInRegularAndScriptAsync("""
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void M()
                {
                    TaskCompletionSource<bool> valueSet = new();
                    Helper helper = new([|v => |]valueSet.SetResult(v));
                    helper.Set(true);
                    helper.Set(false);
 
                    var v = () =>
                    {
                        // this is a different local.  it should not impact the outer simplification
                        TaskCompletionSource<bool> valueSet = new();
                        valueSet = new();
                    };
                }
            }
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """, """
            using System;
            using System.Threading.Tasks;
 
            class C
            {
                void M()
                {
                    TaskCompletionSource<bool> valueSet = new();
                    Helper helper = new(valueSet.SetResult);
                    helper.Set(true);
                    helper.Set(false);
            
                    var v = () =>
                    {
                        // this is a different local.  it should not impact the outer simplification
                        TaskCompletionSource<bool> valueSet = new();
                        valueSet = new();
                    };
                }
            }
 
            class Helper
            {
               private readonly Action<bool> action;
               internal Helper(Action<bool> action)
               {
                 this.action = action;
               }
 
               internal void Set(bool value) => action(value);
            }
            
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71300")]
    public async Task TestWithWriteInOtherMethod()
    {
        await TestInRegularAndScriptAsync("""
            using System;
            using System.Linq;
 
            public class Repro
            {
                private readonly MethodProvider _methodProvider;
 
                public Repro(MethodProvider methodProvider)
                {
                    // Assignment that should not block feature.
                    _methodProvider = methodProvider;
                }
 
                public void Main()
                {
                    int[] numbers = { 1, 2, 3, 4, 5 };
                    string[] asStrings = numbers.Select([|x => |]_methodProvider.ToStr(x)).ToArray();
                    Console.WriteLine(asStrings.Length);
                }
            }
 
            public class MethodProvider
            {
                public string ToStr(int x)
                {
                    return x.ToString();
                }
            }
            """,
            """
            using System;
            using System.Linq;
 
            public class Repro
            {
                private readonly MethodProvider _methodProvider;
 
                public Repro(MethodProvider methodProvider)
                {
                    // Assignment that should not block feature.
                    _methodProvider = methodProvider;
                }
 
                public void Main()
                {
                    int[] numbers = { 1, 2, 3, 4, 5 };
                    string[] asStrings = numbers.Select(_methodProvider.ToStr).ToArray();
                    Console.WriteLine(asStrings.Length);
                }
            }
 
            public class MethodProvider
            {
                public string ToStr(int x)
                {
                    return x.ToString();
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71300")]
    public async Task PreserveComment()
    {
        await TestInRegularAndScriptAsync("""
            using System;
 
            class C
            {
                void M1()
                {
                    M2([|() =>
                    {
                        // I hope M2 doesn't call M1!
                        |]M1();
                    });
                }
 
                void M2(Action a)
                {
                }
            }
            """,
            """
            using System;
 
            class C
            {
                void M1()
                {
                    // I hope M2 doesn't call M1!
                    M2(M1);
                }
            
                void M2(Action a)
                {
                }
            }
            """);
    }
}