|
// 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.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.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature;
using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions;
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
{
[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
public async Task RemoveParameters1()
{
var markup = """
static class Ext
{
/// <summary>
/// This is a summary of <see cref="M(object, int, string, bool, int, string, int[])"/>
/// </summary>
/// <param name="o"></param>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="p"></param>
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
{
/// <summary>
/// This is a summary of <see cref="M(object, string, string)"/>
/// </summary>
/// <param name="o"></param>
/// <param name="b"></param>
/// <param name="y"></param>
///
///
///
///
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);
}
[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
public async Task RemoveParameters_GenericParameterType()
{
var markup = """
class DA
{
void M(params int[] i) { }
void B()
{
DP20<int>.D d = new DP20<int>.D(M);
/*DA19*/$$d(0);
d();
d(0, 1);
}
}
public class DP20<T>
{
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<int>();
var updatedCode = """
class DA
{
void M() { }
void B()
{
DP20<int>.D d = new DP20<int>.D(M);
/*DA19*/d();
d();
d();
}
}
public class DP20<T>
{
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);
}
[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1102830")]
[WorkItem("https://github.com/dotnet/roslyn/issues/784")]
public async Task RemoveParameters_ExtensionMethodInAnotherFile()
{
var workspaceXml = """
<Workspace>
<Project Language="C#" AssemblyName="CSharpAssembly" CommonReferences="true">
""";
for (var i = 0; i <= 4; i++)
{
workspaceXml += $@"
<Document FilePath = ""C{i}.cs"">
class C{i}
{{
void M()
{{
C5 c = new C5();
c.Ext(1, ""two"");
}}
}}
</Document>";
}
workspaceXml += """
<Document FilePath = "C5.cs">
public class C5
{
}
public static class C5Ext
{
public void $$Ext(this C5 c, int i, string s)
{
}
}
</Document>
""";
for (var i = 6; i <= 9; i++)
{
workspaceXml += $@"
<Document FilePath = ""C{i}.cs"">
class C{i}
{{
void M()
{{
C5 c = new C5();
c.Ext(1, ""two"");
}}
}}
</Document>";
}
workspaceXml += """
</Project>
</Workspace>
""";
var updatedSignature = new[] {
new AddedParameterOrExistingIndex(0),
new AddedParameterOrExistingIndex(2) };
using var testState = ChangeSignatureTestState.Create(XElement.Parse(workspaceXml));
testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature;
var result = await testState.ChangeSignatureAsync().ConfigureAwait(false);
Assert.True(result.Succeeded);
Assert.Null(result.ChangeSignatureFailureKind);
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());
}
}
}
[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1102830")]
[WorkItem("https://github.com/dotnet/roslyn/issues/784")]
public async Task AddRemoveParameters_ExtensionMethodInAnotherFile()
{
var workspaceXml = """
<Workspace>
<Project Language="C#" AssemblyName="CSharpAssembly" CommonReferences="true">
""";
for (var i = 0; i <= 4; i++)
{
workspaceXml += $@"
<Document FilePath = ""C{i}.cs"">
class C{i}
{{
void M()
{{
C5 c = new C5();
c.Ext(1, ""two"");
}}
}}
</Document>";
}
workspaceXml += """
<Document FilePath = "C5.cs">
public class C5
{
}
public static class C5Ext
{
public void $$Ext(this C5 c, int i, string s)
{
}
}
</Document>
""";
for (var i = 6; i <= 9; i++)
{
workspaceXml += $@"
<Document FilePath = ""C{i}.cs"">
class C{i}
{{
void M()
{{
C5 c = new C5();
c.Ext(1, ""two"");
}}
}}
</Document>";
}
workspaceXml += """
</Project>
</Workspace>
""";
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 = await testState.ChangeSignatureAsync().ConfigureAwait(false);
Assert.True(result.Succeeded);
Assert.Null(result.ChangeSignatureFailureKind);
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 = EditorTestWorkspace.Create(XElement.Parse("""
<Workspace>
<Submission Language="C#" CommonReferences="true">
class C
{
void M$$(int x)
{
}
}
</Submission>
</Workspace>
"""),
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 = workspace.ExportProvider.GetCommandHandler<CSharpChangeSignatureCommandHandler>(PredefinedCommandHandlerNames.ChangeSignature, ContentTypeNames.CSharpContentType);
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);
}
[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[WorkItem("https://github.com/dotnet/roslyn/issues/44126")]
public async Task RemoveParameters_ImplicitObjectCreation()
{
var markup = """
public class C
{
public $$C(int a, string b) { }
void M()
{
C c = new(1, "b");
}
}
""";
var updatedSignature = new[] { 1 };
var updatedCode = """
public class C
{
public C(string b) { }
void M()
{
C c = new("b");
}
}
""";
await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode);
}
[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[WorkItem("https://github.com/dotnet/roslyn/issues/66547")]
public async Task RemoveParameters_SpecialSymbolNamedParameter()
{
var markup = """
void $$m(object? param, bool @new = true)
{
}
m(null, @new: false);
""";
var updatedSignature = new[] { 1 };
var updatedCode = """
void m(bool @new = true)
{
}
m(@new: false);
""";
await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode);
}
}
|