// 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; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Editor.CSharp.ChangeSignature; using Microsoft.CodeAnalysis.Editor.Implementation.Interactive; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ChangeSignature { public partial class ChangeSignatureTests : AbstractChangeSignatureTests { [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] public async Task RemoveParameters1() { var markup = @" static class Ext { /// /// This is a summary of /// /// /// /// /// /// /// /// static void $$M(this object o, int a, string b, bool c, int x = 0, string y = ""Zero"", params int[] p) { object t = new object(); M(t, 1, ""two"", true, 3, ""four"", new[] { 5, 6 }); M(t, 1, ""two"", true, 3, ""four"", 5, 6); t.M(1, ""two"", true, 3, ""four"", new[] { 5, 6 }); t.M(1, ""two"", true, 3, ""four"", 5, 6); M(t, 1, ""two"", true, 3, ""four""); M(t, 1, ""two"", true, 3); M(t, 1, ""two"", true); M(t, 1, ""two"", c: true); M(t, 1, ""two"", true, 3, y: ""four""); M(t, 1, ""two"", true, 3, p: new[] { 5 }); M(t, 1, ""two"", true, p: new[] { 5 }); M(t, 1, ""two"", true, y: ""four""); M(t, 1, ""two"", true, x: 3); M(t, 1, ""two"", true, y: ""four"", x: 3); M(t, 1, y: ""four"", x: 3, b: ""two"", c: true); M(t, y: ""four"", x: 3, c: true, b: ""two"", a: 1); M(t, p: new[] { 5 }, y: ""four"", x: 3, c: true, b: ""two"", a: 1); M(p: new[] { 5 }, y: ""four"", x: 3, c: true, b: ""two"", a: 1, o: t); } }"; var updatedSignature = new[] { 0, 2, 5 }; var updatedCode = @" static class Ext { /// /// This is a summary of /// /// /// /// /// /// /// /// static void M(this object o, string b, string y = ""Zero"") { object t = new object(); M(t, ""two"", ""four""); M(t, ""two"", ""four""); t.M(""two"", ""four""); t.M(""two"", ""four""); M(t, ""two"", ""four""); M(t, ""two""); M(t, ""two""); M(t, ""two""); M(t, ""two"", y: ""four""); M(t, ""two""); M(t, ""two""); M(t, ""two"", y: ""four""); M(t, ""two""); M(t, ""two"", y: ""four""); M(t, y: ""four"", b: ""two""); M(t, y: ""four"", b: ""two""); M(t, y: ""four"", b: ""two""); M(y: ""four"", b: ""two"", o: t); } }"; await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode); } [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] public async Task RemoveParameters_GenericParameterType() { var markup = @" class DA { void M(params int[] i) { } void B() { DP20.D d = new DP20.D(M); /*DA19*/$$d(0); d(); d(0, 1); } } public class DP20 { public delegate void /*DP20*/D(params T[] t); public event D E1; public event D E2; public void M1(params T[] t) { } public void M2(params T[] t) { } public void M3(params T[] t) { } void B() { D d = new D(M1); E1 += new D(M2); E2 -= new D(M3); } }"; var updatedSignature = Array.Empty(); var updatedCode = @" class DA { void M() { } void B() { DP20.D d = new DP20.D(M); /*DA19*/d(); d(); d(); } } public class DP20 { public delegate void /*DP20*/D(); public event D E1; public event D E2; public void M1() { } public void M2() { } public void M3() { } void B() { D d = new D(M1); E1 += new D(M2); E2 -= new D(M3); } }"; await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode); } [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] [WorkItem(1102830, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1102830")] [WorkItem(784, "https://github.com/dotnet/roslyn/issues/784")] public async Task RemoveParameters_ExtensionMethodInAnotherFile() { var workspaceXml = @" "; for (var i = 0; i <= 4; i++) { workspaceXml += $@" class C{i} {{ void M() {{ C5 c = new C5(); c.Ext(1, ""two""); }} }} "; } workspaceXml += @" public class C5 { } public static class C5Ext { public void $$Ext(this C5 c, int i, string s) { } } "; for (var i = 6; i <= 9; i++) { workspaceXml += $@" class C{i} {{ void M() {{ C5 c = new C5(); c.Ext(1, ""two""); }} }} "; } workspaceXml += @" "; var updatedSignature = new[] { new AddedParameterOrExistingIndex(0), new AddedParameterOrExistingIndex(2) }; using var testState = ChangeSignatureTestState.Create(XElement.Parse(workspaceXml)); testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature; var result = testState.ChangeSignature(); Assert.True(result.Succeeded); Assert.Null(testState.ErrorMessage); foreach (var updatedDocument in testState.Workspace.Documents.Select(d => result.UpdatedSolution.GetDocument(d.Id))) { if (updatedDocument.Name == "C5.cs") { Assert.Contains("void Ext(this C5 c, string s)", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); } else { Assert.Contains(@"c.Ext(""two"");", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); } } } [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] [WorkItem(1102830, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1102830")] [WorkItem(784, "https://github.com/dotnet/roslyn/issues/784")] public async Task AddRemoveParameters_ExtensionMethodInAnotherFile() { var workspaceXml = @" "; for (var i = 0; i <= 4; i++) { workspaceXml += $@" class C{i} {{ void M() {{ C5 c = new C5(); c.Ext(1, ""two""); }} }} "; } workspaceXml += @" public class C5 { } public static class C5Ext { public void $$Ext(this C5 c, int i, string s) { } } "; for (var i = 6; i <= 9; i++) { workspaceXml += $@" class C{i} {{ void M() {{ C5 c = new C5(); c.Ext(1, ""two""); }} }} "; } workspaceXml += @" "; var updatedSignature = new[] { new AddedParameterOrExistingIndex(0), new AddedParameterOrExistingIndex(2), new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", CallSiteKind.Value, callSiteValue:"123"), "int") }; using var testState = ChangeSignatureTestState.Create(XElement.Parse(workspaceXml)); testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature; var result = testState.ChangeSignature(); Assert.True(result.Succeeded); Assert.Null(testState.ErrorMessage); foreach (var updatedDocument in testState.Workspace.Documents.Select(d => result.UpdatedSolution.GetDocument(d.Id))) { if (updatedDocument.Name == "C5.cs") { Assert.Contains("void Ext(this C5 c, string s, int newIntegerParameter)", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); } else { Assert.Contains(@"c.Ext(""two"", 123);", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); } } } [WpfFact] [Trait(Traits.Feature, Traits.Features.ChangeSignature)] [Trait(Traits.Feature, Traits.Features.Interactive)] public void ChangeSignatureCommandDisabledInSubmission() { using var workspace = TestWorkspace.Create(XElement.Parse(@" class C { void M$$(int x) { } } "), workspaceKind: WorkspaceKind.Interactive, composition: EditorTestCompositions.EditorFeaturesWpf); // Force initialization. workspace.GetOpenDocumentIds().Select(id => workspace.GetTestDocument(id).GetTextView()).ToList(); var textView = workspace.Documents.Single().GetTextView(); var handler = new CSharpChangeSignatureCommandHandler(workspace.GetService()); var state = handler.GetCommandState(new RemoveParametersCommandArgs(textView, textView.TextBuffer)); Assert.True(state.IsUnspecified); state = handler.GetCommandState(new ReorderParametersCommandArgs(textView, textView.TextBuffer)); Assert.True(state.IsUnspecified); } } }