File: ChangeSignature\ChangeSignature_Delegates.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ChangeSignature;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ChangeSignature;
 
[Trait(Traits.Feature, Traits.Features.ChangeSignature)]
public partial class ChangeSignatureTests : AbstractChangeSignatureTests
{
    protected override CodeRefactoringProvider CreateCodeRefactoringProvider(EditorTestWorkspace workspace, TestParameters parameters)
        => new ChangeSignatureCodeRefactoringProvider();
 
    protected internal override string GetLanguage()
        => LanguageNames.CSharp;
 
    [Fact]
    public async Task ChangeSignature_Delegates_ImplicitInvokeCalls()
    {
        var markup = """
            delegate void MyDelegate($$int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1(1, "Two", true);
                }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1(true, "Two");
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature,
            expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 0);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_ExplicitInvokeCalls()
    {
        var markup = """
            delegate void MyDelegate(int x, string $$y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1.Invoke(1, "Two", true);
                }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1.Invoke(true, "Two");
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature,
            expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 1);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_BeginInvokeCalls()
    {
        var markup = """
            delegate void MyDelegate(int x, string y, bool z$$);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1.BeginInvoke(1, "Two", true, null, null);
                }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1.BeginInvoke(true, "Two", null, null);
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature,
            expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 2);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_AnonymousMethods()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = delegate (int e, string f, bool g) { var x = f.Length + (g ? 0 : 1); };
                    d1 = delegate { };
                }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = delegate (bool g, string f) { var x = f.Length + (g ? 0 : 1); };
                    d1 = delegate { };
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_Lambdas()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = (r, s, t) => { var x = s.Length + (t ? 0 : 1); };
                }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = (t, s) => { var x = s.Length + (t ? 0 : 1); };
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_Lambdas_RemovingOnlyParameterIntroducesParentheses()
    {
        var markup = """
            delegate void $$MyDelegate(int x);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = (r) => { System.Console.WriteLine("Test"); };
                    d1 = r => { System.Console.WriteLine("Test"); };
                    d1 = r => { System.Console.WriteLine("Test"); };
                }
            }
            """;
        var updatedSignature = Array.Empty<int>();
        var expectedUpdatedCode = """
            delegate void MyDelegate();
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = () => { System.Console.WriteLine("Test"); };
                    d1 = () => { System.Console.WriteLine("Test"); };
                    d1 = () => { System.Console.WriteLine("Test"); };
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_CascadeThroughMethodGroups_AssignedToVariable()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = Goo;
                    Goo(1, "Two", true);
                    Goo(1, false, false);
                }
 
                void Goo(int a, string b, bool c) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = null;
                    d1 = Goo;
                    Goo(true, "Two");
                    Goo(1, false, false);
                }
 
                void Goo(bool c, string b) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_CascadeThroughMethodGroups_DelegateConstructor()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = new MyDelegate(Goo);
                    Goo(1, "Two", true);
                    Goo(1, false, false);
                }
 
                void Goo(int a, string b, bool c) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = new MyDelegate(Goo);
                    Goo(true, "Two");
                    Goo(1, false, false);
                }
 
                void Goo(bool c, string b) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_CascadeThroughMethodGroups_PassedAsArgument()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    Target(Goo);
                    Goo(1, "Two", true);
                    Goo(1, false, false);
                }
 
                void Target(MyDelegate d) { }
 
                void Goo(int a, string b, bool c) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    Target(Goo);
                    Goo(true, "Two");
                    Goo(1, false, false);
                }
 
                void Target(MyDelegate d) { }
 
                void Goo(bool c, string b) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_CascadeThroughMethodGroups_ReturnValue()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = Result();
                    Goo(1, "Two", true);
                }
 
                private MyDelegate Result()
                {
                    return Goo;
                }
 
                void Goo(int a, string b, bool c) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = Result();
                    Goo(true, "Two");
                }
 
                private MyDelegate Result()
                {
                    return Goo;
                }
 
                void Goo(bool c, string b) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_CascadeThroughMethodGroups_YieldReturnValue()
    {
        var markup = """
            using System.Collections.Generic;
 
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    Goo(1, "Two", true);
                }
 
                private IEnumerable<MyDelegate> Result()
                {
                    yield return Goo;
                }
 
                void Goo(int a, string b, bool c) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            using System.Collections.Generic;
 
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    Goo(true, "Two");
                }
 
                private IEnumerable<MyDelegate> Result()
                {
                    yield return Goo;
                }
 
                void Goo(bool c, string b) { }
                void Goo(int a, object b, bool c) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_ReferencingLambdas_MethodArgument()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M6()
                {
                    Target((m, n, o) => { var x = n.Length + (o ? 0 : 1); });
                }
 
                void Target(MyDelegate d) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M6()
                {
                    Target((o, n) => { var x = n.Length + (o ? 0 : 1); });
                }
 
                void Target(MyDelegate d) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_ReferencingLambdas_YieldReturn()
    {
        var markup = """
            using System.Collections.Generic;
 
            delegate void $$MyDelegate(int x, string y, bool z);
            class C
            {
                private IEnumerable<MyDelegate> Result3()
                {
                    yield return (g, h, i) => { var x = h.Length + (i ? 0 : 1); };
                }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            using System.Collections.Generic;
 
            delegate void MyDelegate(bool z, string y);
            class C
            {
                private IEnumerable<MyDelegate> Result3()
                {
                    yield return (i, h) => { var x = h.Length + (i ? 0 : 1); };
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_Recursive()
    {
        var markup = """
            delegate RecursiveDelegate $$RecursiveDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    RecursiveDelegate rd = null;
                    rd(1, "Two", true)(1, "Two", true)(1, "Two", true)(1, "Two", true)(1, "Two", true);
                }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate RecursiveDelegate RecursiveDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    RecursiveDelegate rd = null;
                    rd(true, "Two")(true, "Two")(true, "Two")(true, "Two")(true, "Two");
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_DocComments()
    {
        var markup = """
            /// <summary>
            /// This is <see cref="MyDelegate"/>, which has these methods:
            ///     <see cref="MyDelegate.MyDelegate(object, IntPtr)"/>
            ///     <see cref="MyDelegate.Invoke(int, string, bool)"/>
            ///     <see cref="MyDelegate.EndInvoke(IAsyncResult)"/>
            ///     <see cref="MyDelegate.BeginInvoke(int, string, bool, AsyncCallback, object)"/>
            /// </summary>
            /// <param name="x">x!</param>
            /// <param name="y">y!</param>
            /// <param name="z">z!</param>
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = Goo;
                    Goo(1, "Two", true);
                }
 
                /// <param name="a"></param>
                /// <param name="b"></param>
                /// <param name="c"></param>
                void Goo(int a, string b, bool c) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            /// <summary>
            /// This is <see cref="MyDelegate"/>, which has these methods:
            ///     <see cref="MyDelegate.MyDelegate(object, IntPtr)"/>
            ///     <see cref="MyDelegate.Invoke(bool, string)"/>
            ///     <see cref="MyDelegate.EndInvoke(IAsyncResult)"/>
            ///     <see cref="MyDelegate.BeginInvoke(int, string, bool, AsyncCallback, object)"/>
            /// </summary>
            /// <param name="z">z!</param>
            /// <param name="y">y!</param>
            /// 
            delegate void MyDelegate(bool z, string y);
 
            class C
            {
                void M()
                {
                    MyDelegate d1 = Goo;
                    Goo(true, "Two");
                }
 
                /// <param name="c"></param>
                /// <param name="b"></param>
                /// 
                void Goo(bool c, string b) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_CascadeThroughEventAdd()
    {
        var markup = """
            delegate void $$MyDelegate(int x, string y, bool z);
 
            class Program
            {
                void M()
                {
                    MyEvent += Program_MyEvent;
                }
 
                event MyDelegate MyEvent;
                void Program_MyEvent(int a, string b, bool c) { }
            }
            """;
        var updatedSignature = new[] { 2, 1 };
        var expectedUpdatedCode = """
            delegate void MyDelegate(bool z, string y);
 
            class Program
            {
                void M()
                {
                    MyEvent += Program_MyEvent;
                }
 
                event MyDelegate MyEvent;
                void Program_MyEvent(bool c, string b) { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_Generics1()
    {
        var markup = """
            public class DP16a
            {
                public delegate void D<T>($$T t);
                public event D<int> E1;
                public event D<int> E2;
 
                public void M1(int i) { }
                public void M2(int i) { }
                public void M3(int i) { }
 
                void B()
                {
                    D<int> d = new D<int>(M1);
                    E1 += new D<int>(M2);
                    E2 -= new D<int>(M3);
                }
            }
            """;
        var updatedSignature = Array.Empty<int>();
        var expectedUpdatedCode = """
            public class DP16a
            {
                public delegate void D<T>();
                public event D<int> E1;
                public event D<int> E2;
 
                public void M1() { }
                public void M2() { }
                public void M3() { }
 
                void B()
                {
                    D<int> d = new D<int>(M1);
                    E1 += new D<int>(M2);
                    E2 -= new D<int>(M3);
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_Generics2()
    {
        var markup = """
            public class D17<T>
            {
                public delegate void $$D(T t);
            }
            public class D17Test
            {
                void Test() { var x = new D17<string>.D(M17); }
                internal void M17(string s) { }
            }
            """;
        var updatedSignature = Array.Empty<int>();
        var expectedUpdatedCode = """
            public class D17<T>
            {
                public delegate void D();
            }
            public class D17Test
            {
                void Test() { var x = new D17<string>.D(M17); }
                internal void M17() { }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_GenericParams()
    {
        var markup = """
            class DA
            {
                void M(params int[] i) { }
                void B()
                {
                    DP20<int>.D d = new DP20<int>.D(M);
                    d();
                    d(0);
                    d(0, 1);
                }
            }
            public class DP20<T>
            {
                public delegate void $$D(params T[] t);
                public void M1(params T[] t) { }
 
                void B()
                {
                    D d = new D(M1);
                }
            }
            """;
        var updatedSignature = Array.Empty<int>();
        var expectedUpdatedCode = """
            class DA
            {
                void M() { }
                void B()
                {
                    DP20<int>.D d = new DP20<int>.D(M);
                    d();
                    d();
                    d();
                }
            }
            public class DP20<T>
            {
                public delegate void D();
                public void M1() { }
 
                void B()
                {
                    D d = new D(M1);
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegates_Generic_RemoveArgumentAtReference()
    {
        var markup = """
            public class CD<T>
            {
                public delegate void D(T t);
            }
            class Test
            {
                public void M()
                {
                    var dele = new CD<int>.$$D((int x) => { });
                }
            }
            """;
        var updatedSignature = Array.Empty<int>();
        var expectedUpdatedCode = """
            public class CD<T>
            {
                public delegate void D();
            }
            class Test
            {
                public void M()
                {
                    var dele = new CD<int>.D(() => { });
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature,
            expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 0);
    }
 
    [Fact]
    public async Task ChangeSignature_Delegate_Generics_RemoveStaticArgument()
    {
        var markup = """
            public class C2<T>
            {
                public delegate void D(T t);
            }
 
            public class D2
            {
                public static D2 Instance = null;
                void M(D2 m) { }
 
                void B()
                {
                    C2<D2>.D d = new C2<D2>.D(M);
                    $$d(D2.Instance);
                }
            }
            """;
        var updatedSignature = Array.Empty<int>();
        var expectedUpdatedCode = """
            public class C2<T>
            {
                public delegate void D();
            }
 
            public class D2
            {
                public static D2 Instance = null;
                void M() { }
 
                void B()
                {
                    C2<D2>.D d = new C2<D2>.D(M);
                    d();
                }
            }
            """;
        await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
    }
}