diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.AddImports.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.AddImports.cs new file mode 100644 index 0000000000000..1e68fce1753fe --- /dev/null +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.AddImports.cs @@ -0,0 +1,150 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeSignature; +using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; +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 AddParameterAddsAllImports() + { + var markup = @" +class C +{ + void $$M() { } +}"; + + var updatedSignature = new[] { + new AddedParameterOrExistingIndex( + new AddedParameter( + null, + "Dictionary>", + "test", + "TODO"), + "System.Collections.Generic.Dictionary>")}; + + var updatedCode = @" +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading.Tasks; + +class C +{ + void M(Dictionary> test) { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameterAddsOnlyMissingImports() + { + var markup = @" +using System.ComponentModel; + +class C +{ + void $$M() { } +}"; + + var updatedSignature = new[] { + new AddedParameterOrExistingIndex( + new AddedParameter( + null, + "Dictionary>", + "test", + "TODO"), + "System.Collections.Generic.Dictionary>")}; + + var updatedCode = @" +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading.Tasks; + +class C +{ + void M(Dictionary> test) { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameterAddsImportsOnCascading() + { + var markup = @" +using NS1; + +namespace NS1 +{ + class B + { + public virtual void M() { } + } +} + +namespace NS2 +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Threading.Tasks; + + class D : B + { + public override void $$M() { } + } +}"; + + var updatedSignature = new[] { + new AddedParameterOrExistingIndex( + new AddedParameter( + null, + "Dictionary>", + "test", + "TODO"), + "System.Collections.Generic.Dictionary>")}; + + var updatedCode = @" +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading.Tasks; +using NS1; + +namespace NS1 +{ + class B + { + public virtual void M(Dictionary> test) { } + } +} + +namespace NS2 +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Threading.Tasks; + + class D : B + { + public override void M(Dictionary> test) { } + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Cascading.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Cascading.cs new file mode 100644 index 0000000000000..f444ce281792e --- /dev/null +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Cascading.cs @@ -0,0 +1,414 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeSignature; +using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; +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 AddParameter_Cascade_ToImplementedMethod() + { + var markup = @" +interface I +{ + void M(int x, string y); +} + +class C : I +{ + $$public void M(int x, string y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +interface I +{ + void M(string y, int newIntegerParameter, int x); +} + +class C : I +{ + public void M(string y, int newIntegerParameter, int x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToImplementedMethod_WithTuples() + { + var markup = @" +interface I +{ + void M((int, int) x, (string a, string b) y); +} + +class C : I +{ + $$public void M((int, int) x, (string a, string b) y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +interface I +{ + void M((string a, string b) y, int newIntegerParameter, (int, int) x); +} + +class C : I +{ + public void M((string a, string b) y, int newIntegerParameter, (int, int) x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToImplementingMethod() + { + var markup = @" +interface I +{ + $$void M(int x, string y); +} + +class C : I +{ + public void M(int x, string y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +interface I +{ + void M(string y, int newIntegerParameter, int x); +} + +class C : I +{ + public void M(string y, int newIntegerParameter, int x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToOverriddenMethod() + { + var markup = @" +class B +{ + public virtual void M(int x, string y) + { } +} + +class D : B +{ + $$public override void M(int x, string y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +class B +{ + public virtual void M(string y, int newIntegerParameter, int x) + { } +} + +class D : B +{ + public override void M(string y, int newIntegerParameter, int x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToOverridingMethod() + { + var markup = @" +class B +{ + $$public virtual void M(int x, string y) + { } +} + +class D : B +{ + public override void M(int x, string y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +class B +{ + public virtual void M(string y, int newIntegerParameter, int x) + { } +} + +class D : B +{ + public override void M(string y, int newIntegerParameter, int x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToOverriddenMethod_Transitive() + { + var markup = @" +class B +{ + public virtual void M(int x, string y) + { } +} + +class D : B +{ + public override void M(int x, string y) + { } +} + +class D2 : D +{ + $$public override void M(int x, string y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +class B +{ + public virtual void M(string y, int newIntegerParameter, int x) + { } +} + +class D : B +{ + public override void M(string y, int newIntegerParameter, int x) + { } +} + +class D2 : D +{ + public override void M(string y, int newIntegerParameter, int x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToOverridingMethod_Transitive() + { + var markup = @" +class B +{ + $$public virtual void M(int x, string y) + { } +} + +class D : B +{ + public override void M(int x, string y) + { } +} + +class D2 : D +{ + public override void M(int x, string y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +class B +{ + public virtual void M(string y, int newIntegerParameter, int x) + { } +} + +class D : B +{ + public override void M(string y, int newIntegerParameter, int x) + { } +} + +class D2 : D +{ + public override void M(string y, int newIntegerParameter, int x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToMethods_Complex() + { + //// B I I2 + //// \ / \ / + //// D (I3) + //// / \ \ + //// $$D2 D3 C + + var markup = @" +class B { public virtual void M(int x, string y) { } } +class D : B, I { public override void M(int x, string y) { } } +class D2 : D { public override void $$M(int x, string y) { } } +class D3 : D { public override void M(int x, string y) { } } +interface I { void M(int x, string y); } +interface I2 { void M(int x, string y); } +interface I3 : I, I2 { } +class C : I3 { public void M(int x, string y) { } }"; + + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +class B { public virtual void M(string y, int newIntegerParameter, int x) { } } +class D : B, I { public override void M(string y, int newIntegerParameter, int x) { } } +class D2 : D { public override void M(string y, int newIntegerParameter, int x) { } } +class D3 : D { public override void M(string y, int newIntegerParameter, int x) { } } +interface I { void M(string y, int newIntegerParameter, int x); } +interface I2 { void M(string y, int newIntegerParameter, int x); } +interface I3 : I, I2 { } +class C : I3 { public void M(string y, int newIntegerParameter, int x) { } }"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Cascade_ToMethods_WithDifferentParameterNames() + { + var markup = @" +public class B +{ + /// + /// + public virtual int M(int x, string y) + { + return 1; + } +} + +public class D : B +{ + /// + /// + public override int M(int a, string b) + { + return 1; + } +} + +public class D2 : D +{ + /// + /// + public override int $$M(int y, string x) + { + M(1, ""Two""); + ((D)this).M(1, ""Two""); + ((B)this).M(1, ""Two""); + + M(1, x: ""Two""); + ((D)this).M(1, b: ""Two""); + ((B)this).M(1, y: ""Two""); + + return 1; + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(0) + }; + var updatedCode = @" +public class B +{ + /// + /// + /// + public virtual int M(string y, int newIntegerParameter, int x) + { + return 1; + } +} + +public class D : B +{ + /// + /// + /// + public override int M(string b, int newIntegerParameter, int a) + { + return 1; + } +} + +public class D2 : D +{ + /// + /// + /// + public override int M(string x, int newIntegerParameter, int y) + { + M(""Two"", 12345, 1); + ((D)this).M(""Two"", 12345, 1); + ((B)this).M(""Two"", 12345, 1); + + M(x: ""Two"", newIntegerParameter: 12345, y: 1); + ((D)this).M(b: ""Two"", newIntegerParameter: 12345, a: 1); + ((B)this).M(y: ""Two"", newIntegerParameter: 12345, x: 1); + + return 1; + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Delegates.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Delegates.cs new file mode 100644 index 0000000000000..5d43587fbd32a --- /dev/null +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Delegates.cs @@ -0,0 +1,901 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeSignature; +using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; +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 AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = null; + d1(true, 12345, ""Two""); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, + expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 0); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = null; + d1.Invoke(true, 12345, ""Two""); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, + expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 1); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = null; + d1.BeginInvoke(true, 12345, ""Two"", null, null); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, + expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 2); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = null; + d1 = delegate (bool g, int newIntegerParameter, string f) { var x = f.Length + (g ? 0 : 1); }; + d1 = delegate { }; + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = null; + d1 = (t, newIntegerParameter, s) => { var x = s.Length + (t ? 0 : 1); }; + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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 = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(int newIntegerParameter); + +class C +{ + void M() + { + MyDelegate d1 = null; + d1 = (newIntegerParameter) => { System.Console.WriteLine(""Test""); }; + d1 = (int newIntegerParameter) => { System.Console.WriteLine(""Test""); }; + d1 = (int newIntegerParameter) => { System.Console.WriteLine(""Test""); }; + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = null; + d1 = Goo; + Goo(true, 12345, ""Two""); + Goo(1, false, false); + } + + void Goo(bool c, int newIntegerParameter, string b) { } + void Goo(int a, object b, bool c) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = new MyDelegate(Goo); + Goo(true, 12345, ""Two""); + Goo(1, false, false); + } + + void Goo(bool c, int newIntegerParameter, string b) { } + void Goo(int a, object b, bool c) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + Target(Goo); + Goo(true, 12345, ""Two""); + Goo(1, false, false); + } + + void Target(MyDelegate d) { } + + void Goo(bool c, int newIntegerParameter, string b) { } + void Goo(int a, object b, bool c) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = Result(); + Goo(true, 12345, ""Two""); + } + + private MyDelegate Result() + { + return Goo; + } + + void Goo(bool c, int newIntegerParameter, string b) { } + void Goo(int a, object b, bool c) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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 Result() + { + yield return Goo; + } + + void Goo(int a, string b, bool c) { } + void Goo(int a, object b, bool c) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +using System.Collections.Generic; + +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + Goo(true, 12345, ""Two""); + } + + private IEnumerable Result() + { + yield return Goo; + } + + void Goo(bool c, int newIntegerParameter, string b) { } + void Goo(int a, object b, bool c) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M6() + { + Target((o, newIntegerParameter, n) => { var x = n.Length + (o ? 0 : 1); }); + } + + void Target(MyDelegate d) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Delegates_ReferencingLambdas_YieldReturn() + { + var markup = @" +using System.Collections.Generic; + +delegate void $$MyDelegate(int x, string y, bool z); +class C +{ + private IEnumerable Result3() + { + yield return (g, h, i) => { var x = h.Length + (i ? 0 : 1); }; + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +using System.Collections.Generic; + +delegate void MyDelegate(bool z, int newIntegerParameter, string y); +class C +{ + private IEnumerable Result3() + { + yield return (i, newIntegerParameter, h) => { var x = h.Length + (i ? 0 : 1); }; + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate RecursiveDelegate RecursiveDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + RecursiveDelegate rd = null; + rd(true, 12345, ""Two"")(true, 12345, ""Two"")(true, 12345, ""Two"")(true, 12345, ""Two"")(true, 12345, ""Two""); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Delegates_DocComments() + { + var markup = @" +/// +/// This is , which has these methods: +/// +/// +/// +/// +/// +/// x! +/// y! +/// z! +delegate void $$MyDelegate(int x, string y, bool z); + +class C +{ + void M() + { + MyDelegate d1 = Goo; + Goo(1, ""Two"", true); + } + + /// + /// + /// + void Goo(int a, string b, bool c) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +/// +/// This is , which has these methods: +/// +/// +/// +/// +/// +/// z! +/// +/// y! +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class C +{ + void M() + { + MyDelegate d1 = Goo; + Goo(true, 12345, ""Two""); + } + + /// + /// + /// + void Goo(bool c, int newIntegerParameter, string b) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_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[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +delegate void MyDelegate(bool z, int newIntegerParameter, string y); + +class Program +{ + void M() + { + MyEvent += Program_MyEvent; + } + + event MyDelegate MyEvent; + void Program_MyEvent(bool c, int newIntegerParameter, string b) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Delegates_Generics1() + { + var markup = @" +public class DP16a +{ + public delegate void D($$T t); + public event D E1; + public event D E2; + + public void M1(int i) { } + public void M2(int i) { } + public void M3(int i) { } + + void B() + { + D d = new D(M1); + E1 += new D(M2); + E2 -= new D(M3); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + }; + var expectedUpdatedCode = @" +public class DP16a +{ + public delegate void D(int newIntegerParameter); + public event D E1; + public event D E2; + + public void M1(int newIntegerParameter) { } + public void M2(int newIntegerParameter) { } + public void M3(int newIntegerParameter) { } + + void B() + { + D d = new D(M1); + E1 += new D(M2); + E2 -= new D(M3); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Delegates_Generics2() + { + var markup = @" +public class D17 +{ + public delegate void $$D(T t); +} +public class D17Test +{ + void Test() { var x = new D17.D(M17); } + internal void M17(string s) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + }; + var expectedUpdatedCode = @" +public class D17 +{ + public delegate void D(int newIntegerParameter); +} +public class D17Test +{ + void Test() { var x = new D17.D(M17); } + internal void M17(int newIntegerParameter) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Delegates_GenericParams() + { + var markup = @" +class DA +{ + void M(params int[] i) { } + void B() + { + DP20.D d = new DP20.D(M); + d(); + d(0); + d(0, 1); + } +} +public class DP20 +{ + public delegate void $$D(params T[] t); + public void M1(params T[] t) { } + + void B() + { + D d = new D(M1); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + }; + var expectedUpdatedCode = @" +class DA +{ + void M(int newIntegerParameter) { } + void B() + { + DP20.D d = new DP20.D(M); + d(12345); + d(12345); + d(12345); + } +} +public class DP20 +{ + public delegate void D(int newIntegerParameter); + public void M1(int newIntegerParameter) { } + + void B() + { + D d = new D(M1); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Delegates_Generic_RemoveArgumentAtReference() + { + var markup = @"public class CD +{ + public delegate void D(T t); +} +class Test +{ + public void M() + { + var dele = new CD.$$D((int x) => { }); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int") + }; + var expectedUpdatedCode = @"public class CD +{ + public delegate void D(int newIntegerParameter); +} +class Test +{ + public void M() + { + var dele = new CD.D((int newIntegerParameter) => { }); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, + expectedUpdatedInvocationDocumentCode: expectedUpdatedCode, expectedSelectedIndex: 0); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Delegate_Generics_RemoveStaticArgument() + { + var markup = @" +public class C2 +{ + public delegate void D(T t); +} + +public class D2 +{ + public static D2 Instance = null; + void M(D2 m) { } + + void B() + { + C2.D d = new C2.D(M); + $$d(D2.Instance); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int") + }; + var expectedUpdatedCode = @" +public class C2 +{ + public delegate void D(int newIntegerParameter); +} + +public class D2 +{ + public static D2 Instance = null; + void M(int newIntegerParameter) { } + + void B() + { + C2.D d = new C2.D(M); + d(12345); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task TestAddParameter_Delegates_Relaxation_ParameterlessFunctionToFunction() + { + var markup = @" +class C0 +{ + delegate int $$MyFunc(int x, string y, bool z); + + class C + { + public void M() + { + MyFunc f = Test(); + } + + private MyFunc Test() + { + return null; + } + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "int"), + new AddedParameterOrExistingIndex(1) + }; + var expectedUpdatedCode = @" +class C0 +{ + delegate int MyFunc(bool z, int newIntegerParameter, string y); + + class C + { + public void M() + { + MyFunc f = Test(); + } + + private MyFunc Test() + { + return null; + } + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Formatting.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Formatting.cs new file mode 100644 index 0000000000000..e61757d48c0d6 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Formatting.cs @@ -0,0 +1,492 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeSignature; +using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; +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 AddParameter_Formatting_KeepCountsPerLine() + { + var markup = @" +class C +{ + void $$Method(int a, int b, int c, + int d, int e, + int f) + { + Method(1, + 2, 3, + 4, 5, 6); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(5), + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(3), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +class C +{ + void Method(int f, int e, int d, + byte bb, int c, + int b, int a) + { + Method(6, + 5, 4, + 34, 3, 2, 1); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")] + public async Task AddParameter_Formatting_KeepTrivia() + { + var markup = @" +class C +{ + void $$Method( + int a, int b, int c, + int d, int e, + int f) + { + Method( + 1, 2, 3, + 4, 5, 6); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(3), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(5)}; + var expectedUpdatedCode = @" +class C +{ + void Method( + int b, int c, int d, + byte bb, int e, + int f) + { + Method( + 2, 3, 4, + 34, 5, 6); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")] + public async Task AddParameter_Formatting_KeepTrivia_WithArgumentNames() + { + var markup = @" +class C +{ + void $$Method( + int a, int b, int c, + int d, int e, + int f) + { + Method( + a: 1, b: 2, c: 3, + d: 4, e: 5, f: 6); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(3), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(5)}; + var expectedUpdatedCode = @" +class C +{ + void Method( + int b, int c, int d, + byte bb, int e, + int f) + { + Method( + b: 2, c: 3, d: 4, + bb: 34, e: 5, f: 6); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_Method() + { + var markup = @" +class C +{ + void $$Method(int a, + int b) + { + Method(1, + 2); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +class C +{ + void Method(int b, + byte bb, int a) + { + Method(2, + 34, 1); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_Constructor() + { + var markup = @" +class SomeClass +{ + $$SomeClass(int a, + int b) + { + new SomeClass(1, + 2); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +class SomeClass +{ + SomeClass(int b, + byte bb, int a) + { + new SomeClass(2, + 34, 1); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_Indexer() + { + var markup = @" +class SomeClass +{ + public int $$this[int a, + int b] + { + get + { + return new SomeClass()[1, + 2]; + } + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +class SomeClass +{ + public int this[int b, + byte bb, int a] + { + get + { + return new SomeClass()[2, + a: 1, bb: 34]; + } + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_Delegate() + { + var markup = @" +class SomeClass +{ + delegate void $$MyDelegate(int a, + int b); + + void M(int a, + int b) + { + var myDel = new MyDelegate(M); + myDel(1, + 2); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +class SomeClass +{ + delegate void MyDelegate(int b, + byte bb, int a); + + void M(int b, + byte bb, int a) + { + var myDel = new MyDelegate(M); + myDel(2, + 34, 1); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_AnonymousMethod() + { + var markup = @" +class SomeClass +{ + delegate void $$MyDelegate(int a, + int b); + + void M() + { + MyDelegate myDel = delegate (int x, + int y) + { + // Nothing + }; + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +class SomeClass +{ + delegate void MyDelegate(int b, + byte bb, int a); + + void M() + { + MyDelegate myDel = delegate (int y, + byte bb, int x) + { + // Nothing + }; + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_ConstructorInitializers() + { + var markup = @" +class B +{ + public $$B(int x, int y) { } + public B() : this(1, + 2) + { } +} + +class D : B +{ + public D() : base(1, + 2) + { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +class B +{ + public B(int y, byte bb, int x) { } + public B() : this(2, + x: 1, bb: 34) + { } +} + +class D : B +{ + public D() : base(2, + x: 1, bb: 34) + { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_Attribute() + { + var markup = @" +[Custom(1, + 2)] +class CustomAttribute : System.Attribute +{ + public $$CustomAttribute(int x, int y) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var expectedUpdatedCode = @" +[Custom(2, + x: 1, bb: 34)] +class CustomAttribute : System.Attribute +{ + public CustomAttribute(int y, byte bb, int x) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")] + public async Task AddParameter_Formatting_Attribute_KeepTrivia() + { + var markup = @" +[Custom( + 1, 2)] +class CustomAttribute : System.Attribute +{ + public $$CustomAttribute(int x, int y) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte") }; + var expectedUpdatedCode = @" +[Custom( + 2, bb: 34)] +class CustomAttribute : System.Attribute +{ + public CustomAttribute(int y, byte bb) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")] + public async Task AddParameter_Formatting_Attribute_KeepTrivia_RemovingSecond() + { + var markup = @" +[Custom( + 1, 2)] +class CustomAttribute : System.Attribute +{ + public $$CustomAttribute(int x, int y) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte")}; + var expectedUpdatedCode = @" +[Custom( + 1, bb: 34)] +class CustomAttribute : System.Attribute +{ + public CustomAttribute(int x, byte bb) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")] + public async Task AddParameter_Formatting_Attribute_KeepTrivia_RemovingBothAddingNew() + { + var markup = @" +[Custom( + 1, 2)] +class CustomAttribute : System.Attribute +{ + public $$CustomAttribute(int x, int y) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte")}; + var expectedUpdatedCode = @" +[Custom( + bb: 34)] +class CustomAttribute : System.Attribute +{ + public CustomAttribute(byte bb) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")] + public async Task AddParameter_Formatting_Attribute_KeepTrivia_RemovingBeforeNewlineComma() + { + var markup = @" +[Custom(1 + , 2, 3)] +class CustomAttribute : System.Attribute +{ + public $$CustomAttribute(int x, int y, int z) { } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(2)}; + var expectedUpdatedCode = @" +[Custom(2, z: 3, bb: 34)] +class CustomAttribute : System.Attribute +{ + public CustomAttribute(int y, byte bb, int z) { } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + + [WorkItem(946220, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/946220")] + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameter_Formatting_LambdaAsArgument() + { + var markup = @"class C +{ + void M(System.Action f, int z$$) + { + M((x, y) => System.Console.WriteLine(x + y), 5); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte")}; + var expectedUpdatedCode = @"class C +{ + void M(System.Action f, byte bb) + { + M((x, y) => System.Console.WriteLine(x + y), 34); + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.cs new file mode 100644 index 0000000000000..fd9fca99f2fd3 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.cs @@ -0,0 +1,1150 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.ChangeSignature; +using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; +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 AddParameters() + { + 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[] { + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "System.Int32"), + new AddedParameterOrExistingIndex(new AddedParameter(null, "string", "newString", ""), "System.String"), + new AddedParameterOrExistingIndex(5)}; + var updatedCode = @" +static class Ext +{ + /// + /// This is a summary of + /// + /// + /// + /// + /// + /// + /// + /// + static void M(this object o, string b, int newIntegerParameter, string newString, string y = ""Zero"") + { + object t = new object(); + + M(t, ""two"", 12345, , ""four""); + M(t, ""two"", 12345, , ""four""); + t.M(""two"", 12345, , ""four""); + t.M(""two"", 12345, , ""four""); + + M(t, ""two"", 12345, , ""four""); + M(t, ""two"", 12345, ); + M(t, ""two"", 12345, ); + + M(t, ""two"", 12345, ); + M(t, ""two"", 12345, , y: ""four""); + + M(t, ""two"", 12345, ); + M(t, ""two"", 12345, ); + M(t, ""two"", 12345, , y: ""four""); + M(t, ""two"", 12345, ); + + M(t, ""two"", 12345, , y: ""four""); + M(t, y: ""four"", newIntegerParameter: 12345, newString:, b: ""two""); + M(t, y: ""four"", newIntegerParameter: 12345, newString:, b: ""two""); + M(t, y: ""four"", newIntegerParameter: 12345, newString:, b: ""two""); + M(y: ""four"", b: ""two"", newIntegerParameter: 12345, newString:, o: t); + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddParameterToParameterlessMethod() + { + var markup = @" +static class Ext +{ + static void $$M() + { + M(); + } +}"; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "12345"), "System.Int32")}; + var updatedCode = @" +static class Ext +{ + static void M(int newIntegerParameter) + { + M(12345); + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderLocalFunctionParametersAndArguments_OnDeclaration() + { + var markup = @" +using System; +class MyClass +{ + public void M() + { + Goo(1, 2); + void $$Goo(int x, string y) + { + } + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +using System; +class MyClass +{ + public void M() + { + Goo(2, 34, 1); + void Goo(string y, byte b, int x) + { + } + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderLocalFunctionParametersAndArguments_OnInvocation() + { + var markup = @" +using System; +class MyClass +{ + public void M() + { + $$Goo(1, null); + void Goo(int x, string y) + { + } + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +using System; +class MyClass +{ + public void M() + { + Goo(null, 34, 1); + void Goo(string y, byte b, int x) + { + } + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderMethodParameters() + { + var markup = @" +using System; +class MyClass +{ + public void $$Goo(int x, string y) + { + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +using System; +class MyClass +{ + public void Goo(string y, byte b, int x) + { + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderMethodParametersAndArguments() + { + var markup = @" +using System; +class MyClass +{ + public void $$Goo(int x, string y) + { + Goo(3, ""hello""); + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +using System; +class MyClass +{ + public void Goo(string y, byte b, int x) + { + Goo(""hello"", 34, 3); + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderMethodParametersAndArgumentsOfNestedCalls() + { + var markup = @" +using System; +class MyClass +{ + public int $$Goo(int x, string y) + { + return Goo(Goo(4, ""inner""), ""outer""); + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +using System; +class MyClass +{ + public int Goo(string y, byte b, int x) + { + return Goo(""outer"", 34, Goo(""inner"", 34, 4)); + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderConstructorParametersAndArguments() + { + var markup = @" +using System; + +class MyClass2 : MyClass +{ + public MyClass2() : base(5, ""test2"") + { + } +} + +class MyClass +{ + public MyClass() : this(2, ""test"") + { + } + + public $$MyClass(int x, string y) + { + var t = new MyClass(x, y); + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +using System; + +class MyClass2 : MyClass +{ + public MyClass2() : base(""test2"", x: 5, b: 34) + { + } +} + +class MyClass +{ + public MyClass() : this(""test"", x: 2, b: 34) + { + } + + public MyClass(string y, byte b, int x) + { + var t = new MyClass(y, 34, x); + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderAttributeConstructorParametersAndArguments() + { + var markup = @" +[My(""test"", 8)] +class MyClass +{ +} + +class MyAttribute : System.Attribute +{ + public MyAttribute(string x, int y)$$ + { + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +[My(8, x: ""test"", b: 34)] +class MyClass +{ +} + +class MyAttribute : System.Attribute +{ + public MyAttribute(int y, byte b, string x) + { + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderExtensionMethodParametersAndArguments_StaticCall() + { + var markup = @" +public class C +{ + static void Main(string[] args) + { + CExt.M(new C(), 1, 2, ""three"", ""four"", ""five""); + } +} + +public static class CExt +{ + public static void M(this $$C goo, int x, int y, string a = ""test_a"", string b = ""test_b"", string c = ""test_c"") + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(5), + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(3)}; + + var updatedCode = @" +public class C +{ + static void Main(string[] args) + { + CExt.M(new C(), 2, 1, 34, ""five"", ""four"", ""three""); + } +} + +public static class CExt +{ + public static void M(this C goo, int y, int x, byte b, string c = ""test_c"", string b = ""test_b"", string a = ""test_a"") + { } +}"; + + // Although the `ParameterConfig` has 0 for the `SelectedIndex`, the UI dialog will make an adjustment + // and select parameter `y` instead because the `this` parameter cannot be moved or removed. + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, + expectedUpdatedInvocationDocumentCode: updatedCode, expectedSelectedIndex: 0); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderExtensionMethodParametersAndArguments_ExtensionCall() + { + var markup = @" +public class C +{ + static void Main(string[] args) + { + new C().M(1, 2, ""three"", ""four"", ""five""); + } +} + +public static class CExt +{ + public static void M(this C goo, int x$$, int y, string a = ""test_a"", string b = ""test_b"", string c = ""test_c"") + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(5), + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(3)}; + var updatedCode = @" +public class C +{ + static void Main(string[] args) + { + new C().M(2, 1, 34, ""five"", ""four"", ""three""); + } +} + +public static class CExt +{ + public static void M(this C goo, int y, int x, byte b, string c = ""test_c"", string b = ""test_b"", string a = ""test_a"") + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, + expectedUpdatedInvocationDocumentCode: updatedCode, expectedSelectedIndex: 1); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamsMethodParametersAndArguments_ParamsAsArray() + { + var markup = @" +public class C +{ + void $$M(int x, int y, params int[] p) + { + M(x, y, new[] { 1, 2, 3 }); + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(2)}; + var updatedCode = @" +public class C +{ + void M(int y, int x, byte b, params int[] p) + { + M(y, x, 34, new[] { 1, 2, 3 }); + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamsMethodParametersAndArguments_ParamsExpanded() + { + var markup = @" +public class C +{ + void $$M(int x, int y, params int[] p) + { + M(x, y, 1, 2, 3); + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(2)}; + + var updatedCode = @" +public class C +{ + void M(int y, int x, byte b, params int[] p) + { + M(y, x, 34, 1, 2, 3); + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderExtensionAndParamsMethodParametersAndArguments_VariedCallsites() + { + var markup = @" +public class C +{ + static void Main(string[] args) + { + CExt.M(new C(), 1, 2, ""three"", ""four"", ""five"", new[] { 6, 7, 8 }); + CExt.M(new C(), 1, 2, ""three"", ""four"", ""five"", 6, 7, 8); + new C().M(1, 2, ""three"", ""four"", ""five"", new[] { 6, 7, 8 }); + new C().M(1, 2, ""three"", ""four"", ""five"", 6, 7, 8); + } +} + +public static class CExt +{ + public static void $$M(this C goo, int x, int y, string a = ""test_a"", string b = ""test_b"", string c = ""test_c"", params int[] p) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(5), + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(3), + new AddedParameterOrExistingIndex(6)}; + var updatedCode = @" +public class C +{ + static void Main(string[] args) + { + CExt.M(new C(), 2, 1, 34, ""five"", ""four"", ""three"", new[] { 6, 7, 8 }); + CExt.M(new C(), 2, 1, 34, ""five"", ""four"", ""three"", 6, 7, 8); + new C().M(2, 1, 34, ""five"", ""four"", ""three"", new[] { 6, 7, 8 }); + new C().M(2, 1, 34, ""five"", ""four"", ""three"", 6, 7, 8); + } +} + +public static class CExt +{ + public static void M(this C goo, int y, int x, byte b, string c = ""test_c"", string b = ""test_b"", string a = ""test_a"", params int[] p) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, + expectedUpdatedInvocationDocumentCode: updatedCode, expectedSelectedIndex: 0); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderIndexerParametersAndArguments() + { + var markup = @" +class Program +{ + void M() + { + var x = new Program()[1, 2]; + new Program()[1, 2] = x; + } + + public int this[int x, int y]$$ + { + get { return 5; } + set { } + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +class Program +{ + void M() + { + var x = new Program()[2, x: 1, b: 34]; + new Program()[2, x: 1, b: 34] = x; + } + + public int this[int y, byte b, int x] + { + get { return 5; } + set { } + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_SingleLineDocComments_OnIndividualLines() + { + var markup = @" +public class C +{ + /// + /// + /// + void $$Goo(int a, int b, int c) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + /// + /// + /// + void Goo(int c, int b, byte bb, int a) + { + + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_SingleLineDocComments_OnSameLine() + { + var markup = @" +public class C +{ + /// a is funb is func is fun + void $$Goo(int a, int b, int c) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// c is funb is fun + /// a is fun + void Goo(int c, int b, byte bb, int a) + { + + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_SingleLineDocComments_MixedLineDistribution() + { + var markup = @" +public class C +{ + /// + /// + /// + /// Comments spread + /// over several + /// lines + void $$Goo(int a, int b, int c, int d, int e, int f) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(5), + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(3), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// Comments spread + /// over several + /// lines + /// + /// + /// + /// + void Goo(int f, int e, int d, int c, byte bb, int b, int a) + { + + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_SingleLineDocComments_MixedWithRegularComments() + { + var markup = @" +public class C +{ + /// + // Why is there a regular comment here? + /// + void $$Goo(int a, int b, int c, int d, int e) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(4), + new AddedParameterOrExistingIndex(3), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + // Why is there a regular comment here? + /// + /// + void Goo(int e, int d, int c, byte b, int b, int a) + { + + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_MultiLineDocComments_OnSeparateLines1() + { + var markup = @" +class Program +{ + /** + * x! + * y! + * z! + */ + static void $$M(int x, int y, int z) + { + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +class Program +{ + /** + * z! + * + * y! + */ + /// x! + static void M(int z, byte b, int y, int x) + { + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_MultiLineDocComments_OnSingleLine() + { + var markup = @" +class Program +{ + /** x!y!z! */ + static void $$M(int x, int y, int z) + { + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +class Program +{ + /** z!y! */ + /// x! + static void M(int z, byte b, int y, int x) + { + } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_IncorrectOrder_MaintainsOrder() + { + var markup = @" +public class C +{ + /// + /// + /// + void $$Goo(int a, int b, int c) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + /// + /// + void Goo(int c, byte bb, int b, int a) + { + + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_WrongNames_MaintainsOrder() + { + var markup = @" +public class C +{ + /// + /// + /// + void $$Goo(int a, int b, int c) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + /// + /// + void Goo(int c, byte b, int b, int a) + { + + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_InsufficientTags_MaintainsOrder() + { + var markup = @" +public class C +{ + /// + /// + void $$Goo(int a, int b, int c) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + /// + void Goo(int c, byte b, int b, int a) + { + + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_ExcessiveTags_MaintainsOrder() + { + var markup = @" +public class C +{ + /// + /// + /// + /// + void $$Goo(int a, int b, int c) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + /// + /// + /// + void Goo(int c, byte bb, int b, int a) + { + + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_OnConstructors() + { + var markup = @" +public class C +{ + /// + /// + /// + public $$C(int a, int b, int c) + { + + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + /// + /// + /// + public C(int c, byte bb, int b, int a) + { + + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParamTagsInDocComments_OnIndexers() + { + var markup = @" +public class C +{ + /// + /// + /// + public int $$this[int a, int b, int c] + { + get { return 5; } + set { } + } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "bb", "34"), "byte"), + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +public class C +{ + /// + /// + /// + /// + public int this[int c, byte bb, int b, int a] + { + get { return 5; } + set { } + } +}"; + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParametersInCrefs() + { + var markup = @" +class C +{ + /// + /// See and + /// + $$void M(int x, string y) + { } +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +class C +{ + /// + /// See and + /// + void M(string y, byte b, int x) + { } +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParametersInMethodThatImplementsInterfaceMethodOnlyThroughADerivedType1() + { + var markup = @" +interface I +{ + $$void M(int x, string y); +} + +class C +{ + public void M(int x, string y) + { + } +} + +class D : C, I +{ +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +interface I +{ + void M(string y, byte b, int x); +} + +class C +{ + public void M(string y, byte b, int x) + { + } +} + +class D : C, I +{ +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public async Task AddAndReorderParametersInMethodThatImplementsInterfaceMethodOnlyThroughADerivedType2() + { + var markup = @" +interface I +{ + void M(int x, string y); +} + +class C +{ + $$public void M(int x, string y) + { + } +} + +class D : C, I +{ +}"; + var permutation = new[] { + new AddedParameterOrExistingIndex(1), + new AddedParameterOrExistingIndex(new AddedParameter(null, "byte", "b", "34"), "byte"), + new AddedParameterOrExistingIndex(0)}; + var updatedCode = @" +interface I +{ + void M(string y, byte b, int x); +} + +class C +{ + public void M(string y, byte b, int x) + { + } +} + +class D : C, I +{ +}"; + + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs index 12578c966ce4c..47b4e09425412 100644 --- a/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs @@ -2,9 +2,13 @@ // 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.Linq; +using System.Threading; using System.Threading.Tasks; +using System.Xml.Linq; using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; using Roslyn.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignature_Delegates.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignature_Delegates.cs index ce33ab40c0dac..c483df4339692 100644 --- a/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignature_Delegates.cs +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignature_Delegates.cs @@ -188,7 +188,7 @@ void M() MyDelegate d1 = null; d1 = (r) => { System.Console.WriteLine(""Test""); }; d1 = r => { System.Console.WriteLine(""Test""); }; - d1 =r=>{ System.Console.WriteLine(""Test""); }; + d1 = r => { System.Console.WriteLine(""Test""); }; } }"; var updatedSignature = Array.Empty(); @@ -202,7 +202,7 @@ void M() MyDelegate d1 = null; d1 = () => { System.Console.WriteLine(""Test""); }; d1 = () => { System.Console.WriteLine(""Test""); }; - d1 =()=>{ System.Console.WriteLine(""Test""); }; + d1 = () => { System.Console.WriteLine(""Test""); }; } }"; await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode); diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs index b00e0df21d35b..96ff6d6be5f36 100644 --- a/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs @@ -7,14 +7,15 @@ 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.Utilities; 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; @@ -186,7 +187,7 @@ void B() [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() + public async Task AddRemoveParameters_ExtensionMethodInAnotherFile() { var workspaceXml = @" @@ -244,10 +245,12 @@ void M() // If a reference does not bind correctly, it will believe Ext is not an extension // method and remove the string argument instead of the int argument. - var updatedSignature = new[] { 0, 2 }; + var updatedSignature = new[] { + new AddedParameterOrExistingIndex(0), + new AddedParameterOrExistingIndex(2), + new AddedParameterOrExistingIndex(new AddedParameter(null, "int", "newIntegerParameter", "123"), "int") }; using var testState = ChangeSignatureTestState.Create(XElement.Parse(workspaceXml)); - testState.TestChangeSignatureOptionsService.IsCancelled = false; testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature; var result = testState.ChangeSignature(); @@ -258,11 +261,11 @@ void M() { if (updatedDocument.Name == "C5.cs") { - Assert.Contains("void Ext(this C5 c, string s)", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); + Assert.Contains("void Ext(this C5 c, string s, int newIntegerParameter)", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); } else { - Assert.Contains(@"c.Ext(""two"");", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); + Assert.Contains(@"c.Ext(""two"", 123);", (await updatedDocument.GetTextAsync(CancellationToken.None)).ToString()); } } } diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.InvocationErrors.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.InvocationErrors.cs index ca3628d2e9f30..74d9a5089dff8 100644 --- a/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.InvocationErrors.cs +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.InvocationErrors.cs @@ -45,10 +45,10 @@ public void Goo(int x, string y) } [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] - public async Task ReorderMethodParameters_InsufficientParameters_None() + public async Task ReorderMethodParameters_CanBeStartedEvenWithNoParameters() { var markup = @"class C { void $$M() { } }"; - await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, expectedSuccess: false, expectedErrorText: FeaturesResources.This_signature_does_not_contain_parameters_that_can_be_changed); + await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, expectedSuccess: true); } [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] diff --git a/src/EditorFeatures/Core.Wpf/DependencyObjectExtensions.cs b/src/EditorFeatures/Core.Wpf/DependencyObjectExtensions.cs index 62ec36d3b0777..ac7f14a3b18e0 100644 --- a/src/EditorFeatures/Core.Wpf/DependencyObjectExtensions.cs +++ b/src/EditorFeatures/Core.Wpf/DependencyObjectExtensions.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + using System.Windows; using System.Windows.Documents; using Microsoft.VisualStudio.Text.Classification; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs index c7c86ad58599c..397da007b66d6 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/AbstractChangeSignatureTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using Xunit; @@ -23,13 +24,22 @@ protected override ParseOptions GetScriptOptions() throw new NotSupportedException(); } - public async Task TestChangeSignatureViaCodeActionAsync( + internal async Task TestChangeSignatureViaCodeActionAsync( string markup, bool expectedCodeAction = true, - bool isCancelled = false, int[] updatedSignature = null, string expectedCode = null, int index = 0) + => await TestChangeSignatureViaCodeActionAsync( + markup, updatedSignature?.Select(i => new AddedParameterOrExistingIndex(i)).ToArray(), + expectedCodeAction, expectedCode, index).ConfigureAwait(false); + + internal async Task TestChangeSignatureViaCodeActionAsync( + string markup, + AddedParameterOrExistingIndex[] updatedSignature, + bool expectedCodeAction = true, + string expectedCode = null, + int index = 0) { if (expectedCodeAction) { @@ -37,7 +47,6 @@ public async Task TestChangeSignatureViaCodeActionAsync( using (var workspace = CreateWorkspaceFromOptions(markup, testOptions)) { var optionsService = workspace.Services.GetService() as TestChangeSignatureOptionsService; - optionsService.IsCancelled = isCancelled; optionsService.UpdatedSignature = updatedSignature; var refactoring = await GetCodeRefactoringAsync(workspace, testOptions); @@ -55,7 +64,7 @@ await TestActionAsync(workspace, expectedCode, refactoring.CodeActions[index].ac } } - public async Task TestChangeSignatureViaCommandAsync( + internal async Task TestChangeSignatureViaCommandAsync( string languageName, string markup, bool expectedSuccess = true, @@ -66,10 +75,29 @@ public async Task TestChangeSignatureViaCommandAsync( bool verifyNoDiagnostics = false, ParseOptions parseOptions = null, int expectedSelectedIndex = -1) + => await TestChangeSignatureViaCommandAsync(languageName, markup, + updatedSignature?.Select(i => new AddedParameterOrExistingIndex(i)).ToArray(), + expectedSuccess, expectedUpdatedInvocationDocumentCode, + expectedErrorText, + totalParameters, + verifyNoDiagnostics, + parseOptions, + expectedSelectedIndex); + + internal async Task TestChangeSignatureViaCommandAsync( + string languageName, + string markup, + AddedParameterOrExistingIndex[] updatedSignature, + bool expectedSuccess = true, + string expectedUpdatedInvocationDocumentCode = null, + string expectedErrorText = null, + int? totalParameters = null, + bool verifyNoDiagnostics = false, + ParseOptions parseOptions = null, + int expectedSelectedIndex = -1) { using (var testState = ChangeSignatureTestState.Create(markup, languageName, parseOptions)) { - testState.TestChangeSignatureOptionsService.IsCancelled = false; testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature; var result = testState.ChangeSignature(); @@ -103,7 +131,7 @@ public async Task TestChangeSignatureViaCommandAsync( if (diagnostics.Length > 0) { - Assert.True(false, CreateDiagnosticsString(diagnostics, updatedSignature, totalParameters, (await testState.InvocationDocument.GetTextAsync()).ToString())); + Assert.True(false, CreateDiagnosticsString(diagnostics, updatedSignature, testState.InvocationDocument, totalParameters, (await testState.InvocationDocument.GetTextAsync()).ToString())); } } @@ -115,7 +143,7 @@ public async Task TestChangeSignatureViaCommandAsync( } } - private string CreateDiagnosticsString(ImmutableArray diagnostics, int[] permutation, int? totalParameters, string fileContents) + private string CreateDiagnosticsString(ImmutableArray diagnostics, AddedParameterOrExistingIndex[] permutation, Document document, int? totalParameters, string fileContents) { if (diagnostics.Length == 0) { @@ -124,20 +152,21 @@ private string CreateDiagnosticsString(ImmutableArray diagnostics, i return string.Format("{0} diagnostic(s) introduced in signature configuration \"{1}\":\r\n{2}\r\n{3}", diagnostics.Length, - GetSignatureDescriptionString(permutation, totalParameters), + GetSignatureDescriptionString(document, permutation, totalParameters), string.Join("\r\n", diagnostics.Select(d => d.GetMessage())), fileContents); } - private string GetSignatureDescriptionString(int[] signature, int? totalParameters) + private string GetSignatureDescriptionString(Document document, AddedParameterOrExistingIndex[] signature, int? totalParameters) { + var existingParametersKept = signature.Where(p => p.IsExisting).Select(p => p.OldIndex).ToArray(); var removeDescription = string.Empty; if (totalParameters.HasValue) { var removed = new List(); for (var i = 0; i < totalParameters; i++) { - if (!signature.Contains(i)) + if (!existingParametersKept.Contains(i)) { removed.Add(i); } @@ -146,7 +175,10 @@ private string GetSignatureDescriptionString(int[] signature, int? totalParamete removeDescription = removed.Any() ? string.Format(", Removed: {{{0}}}", string.Join(", ", removed)) : string.Empty; } - return string.Format("Parameters: <{0}>{1}", string.Join(", ", signature), removeDescription); + var newParametersString = string.Join(",", signature.Where(p => !p.IsExisting).Select(p => p.GetAddedParameter(document))); + var addDescription = !newParametersString.IsEmpty() ? string.Format(", Added {{{0}}}", newParametersString) : string.Empty; + + return string.Format("Parameters: <{0}>{1}{2}", string.Join(", ", signature.Select(item => item.ToString())), removeDescription, addDescription); } /// diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs index 9fbfb87d7d189..0b54bdb4729bb 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.VisualBasic.ChangeSignature; using Microsoft.VisualStudio.Composition; using Roslyn.Test.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature { @@ -34,6 +33,7 @@ internal sealed class ChangeSignatureTestState : IDisposable public static ChangeSignatureTestState Create(string markup, string languageName, ParseOptions parseOptions = null) { var exportProvider = s_exportProviderFactory.CreateExportProvider(); + var workspace = languageName == LanguageNames.CSharp ? TestWorkspace.CreateCSharp(markup, exportProvider: exportProvider, parseOptions: (CSharpParseOptions)parseOptions) : TestWorkspace.CreateVisualBasic(markup, exportProvider: exportProvider, parseOptions: parseOptions, compilationOptions: new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); @@ -89,7 +89,12 @@ public async Task GetParameterConfigurationAsync() WpfTestRunner.RequireWpfFact($"{nameof(AbstractChangeSignatureService.ChangeSignature)} currently needs to run on a WPF Fact because it's factored in a way that tries popping up UI in some cases."); var context = await ChangeSignatureService.GetContextAsync(InvocationDocument, _testDocument.CursorPosition.Value, restrictToDeclarations: false, CancellationToken.None); - return context.ParameterConfiguration; + if (context is ChangeSignatureAnalyzedSucceedContext changeSignatureAnalyzedSucceedContext) + { + return changeSignatureAnalyzedSucceedContext.ParameterConfiguration; + } + + throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(((CannotChangeSignatureAnalyzedContext)context).CannotChangeSignatureReason.ToString()); } private static readonly IExportProviderFactory s_exportProviderFactory = @@ -97,7 +102,11 @@ public async Task GetParameterConfigurationAsync() TestExportProvider.MinimumCatalogWithCSharpAndVisualBasic .WithPart(typeof(TestChangeSignatureOptionsService)) .WithPart(typeof(CSharpChangeSignatureService)) - .WithPart(typeof(VisualBasicChangeSignatureService))); + .WithPart(typeof(VisualBasicChangeSignatureService)) + .WithPart(typeof(CodeAnalysis.CSharp.Editing.CSharpImportAdder)) + .WithPart(typeof(CodeAnalysis.VisualBasic.Editing.VisualBasicImportAdder)) + .WithPart(typeof(CodeAnalysis.CSharp.AddImports.CSharpAddImportsService)) + .WithPart(typeof(CodeAnalysis.VisualBasic.AddImports.VisualBasicAddImportsService))); public void Dispose() { diff --git a/src/EditorFeatures/TestUtilities/ChangeSignature/AddedParameterOrExistingIndex.cs b/src/EditorFeatures/TestUtilities/ChangeSignature/AddedParameterOrExistingIndex.cs new file mode 100644 index 0000000000000..25c3956a5ebd8 --- /dev/null +++ b/src/EditorFeatures/TestUtilities/ChangeSignature/AddedParameterOrExistingIndex.cs @@ -0,0 +1,56 @@ +// 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 enable + +using System; +using System.Threading; +using Microsoft.CodeAnalysis.ChangeSignature; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature +{ + internal sealed class AddedParameterOrExistingIndex + { + public bool IsExisting { get; } + + public int? OldIndex { get; } + + private readonly AddedParameter? _addedParameterWithoutTypeSymbol; + private readonly string? _addedParameterFullyQualifiedTypeName; + + public AddedParameterOrExistingIndex(int index) + { + OldIndex = index; + IsExisting = true; + _addedParameterWithoutTypeSymbol = null; + _addedParameterFullyQualifiedTypeName = null; + } + + public AddedParameterOrExistingIndex(AddedParameter addedParameterWithoutTypeSymbol, string addedParameterFullyQualifiedTypeName) + { + OldIndex = null; + IsExisting = false; + _addedParameterWithoutTypeSymbol = addedParameterWithoutTypeSymbol; + _addedParameterFullyQualifiedTypeName = addedParameterFullyQualifiedTypeName; + } + + public override string ToString() + => IsExisting ? OldIndex.ToString() : (_addedParameterWithoutTypeSymbol?.ToString() ?? string.Empty); + + internal AddedParameter GetAddedParameter(Document document) + { + var semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).Result; + + var type = document.Project.Language switch + { + LanguageNames.CSharp => semanticModel.GetSpeculativeTypeInfo(0, CSharp.SyntaxFactory.ParseTypeName(_addedParameterFullyQualifiedTypeName!), SpeculativeBindingOption.BindAsTypeOrNamespace).Type, + LanguageNames.VisualBasic => semanticModel.GetSpeculativeTypeInfo(0, VisualBasic.SyntaxFactory.ParseTypeName(_addedParameterFullyQualifiedTypeName!), SpeculativeBindingOption.BindAsTypeOrNamespace).Type, + _ => throw new ArgumentException("Unsupported language") + }; + + return new AddedParameter(type!, _addedParameterWithoutTypeSymbol!.TypeNameDisplayWithErrorIndicator, _addedParameterWithoutTypeSymbol.ParameterName, _addedParameterWithoutTypeSymbol.CallSiteValue); + } + } +} diff --git a/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs b/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs index aa3875c5858dc..2dbc501ff1086 100644 --- a/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs +++ b/src/EditorFeatures/TestUtilities/ChangeSignature/TestChangeSignatureOptionsService.cs @@ -2,35 +2,42 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + +using System.Collections.Generic; using System.Composition; using System.Linq; using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature; namespace Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature { [ExportWorkspaceService(typeof(IChangeSignatureOptionsService), ServiceLayer.Default), Shared] internal class TestChangeSignatureOptionsService : IChangeSignatureOptionsService { - public bool IsCancelled = true; - public int[] UpdatedSignature = null; + public AddedParameterOrExistingIndex[]? UpdatedSignature = null; [ImportingConstructor] public TestChangeSignatureOptionsService() { } - public ChangeSignatureOptionsResult GetChangeSignatureOptions(ISymbol symbol, ParameterConfiguration parameters) + ChangeSignatureOptionsResult IChangeSignatureOptionsService.GetChangeSignatureOptions( + Document document, + int insertPosition, + ISymbol symbol, + ParameterConfiguration parameters) { var list = parameters.ToListOfParameters(); - - return new ChangeSignatureOptionsResult - { - IsCancelled = IsCancelled, - UpdatedSignature = new SignatureChange( + IEnumerable updateParameters = UpdatedSignature != null + ? UpdatedSignature.Select(item => item.IsExisting ? list[item.OldIndex ?? -1] : item.GetAddedParameter(document)) + : new Parameter?[0]!; + return new ChangeSignatureOptionsResult(new SignatureChange( parameters, - UpdatedSignature == null ? parameters : ParameterConfiguration.Create(UpdatedSignature.Select(i => list[i]).ToList(), parameters.ThisParameter != null, selectedIndex: 0)) - }; + UpdatedSignature == null + ? parameters + : ParameterConfiguration.Create(updateParameters, parameters.ThisParameter != null, selectedIndex: 0)), previewChanges: false); } } } diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.AddImports.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.AddImports.vb new file mode 100644 index 0000000000000..a224c8162b85f --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.AddImports.vb @@ -0,0 +1,41 @@ +' 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. + +Imports Microsoft.CodeAnalysis.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions +Imports Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ChangeSignature + Partial Public Class ChangeSignatureTests + Inherits AbstractChangeSignatureTests + + + Public Async Function AddParameterAddsAllImports() As Task + + Dim markup = .NormalizedValue() + + Dim permutation = {New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Dictionary>", "test", "TODO"), "System.Collections.Generic.Dictionary(Of System.ConsoleColor, System.Threading.Tasks.Task(Of System.ComponentModel.AsyncOperation))")} + + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Cascading.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Cascading.vb new file mode 100644 index 0000000000000..6b5b1a8769427 --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Cascading.vb @@ -0,0 +1,425 @@ +' 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. + +Imports Microsoft.CodeAnalysis.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions +Imports Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ChangeSignature + Partial Public Class ChangeSignatureTests + + Public Async Function TestAddParameter_Cascade_ToImplementedMethod() As Task + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_Cascade_ToImplementedMethod_WithTuples() As Task + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_Cascade_ToImplementingMethod() As Task + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_Cascade_ToOverriddenMethod() As Task + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_Cascade_ToOverridingMethod() As Task + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_Cascade_ToOverriddenMethod_Transitive() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_Cascade_ToOverridingMethod_Transitive() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + + End Function + + + Public Async Function TestAddParameter_Cascade_ToMethods_Complex() As Task + + ' B I I2 + ' \ / \ / + ' D (I3) + ' / \ \ + ' $$D2 D3 C + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + Public Async Function TestAddParameter_Cascade_ToOverridingMethod_IncludeParamTags() As Task + + Dim markup = + ''' + Overridable Sub Goo(a As Integer, b As Integer) + End Sub +End Class + +Class D + Inherits B + + ''' + ''' + Public Overrides Sub $$Goo(x As Integer, y As Integer) + MyBase.Goo(x, y) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = + ''' + ''' + Overridable Sub Goo(b As Integer, newIntegerParameter As Integer, a As Integer) + End Sub +End Class + +Class D + Inherits B + + ''' + ''' + ''' + Public Overrides Sub Goo(y As Integer, newIntegerParameter As Integer, x As Integer) + MyBase.Goo(y, 12345, x) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Delegates.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Delegates.vb new file mode 100644 index 0000000000000..92d8930b61bec --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Delegates.vb @@ -0,0 +1,806 @@ +' 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. + +Imports Microsoft.CodeAnalysis.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions +Imports Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ChangeSignature + Partial Public Class ChangeSignatureTests + Inherits AbstractChangeSignatureTests + + + Public Async Function TestAddParameter_Delegates_ImplicitInvokeCalls() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, + expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode, expectedSelectedIndex:=0) + End Function + + + Public Async Function TestAddParameter_Delegates_ExplicitInvokeCalls() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, + expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode, expectedSelectedIndex:=0) + End Function + + + Public Async Function TestAddParameter_Delegates_BeginInvokeCalls() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, + expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode, expectedSelectedIndex:=0) + End Function + + + Public Async Function TestAddParameter_Delegates_SubLambdas() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, + expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode, expectedSelectedIndex:=1) + End Function + + + Public Async Function TestAddParameter_Delegates_FunctionLambdas() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, + expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode, expectedSelectedIndex:=2) + End Function + + + Public Async Function TestAddParameter_Delegates_ReferencingLambdas_MethodArgument() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Delegates_ReferencingLambdas_ReturnValue() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Delegates_Recursive() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Delegates_DocComments() As Task + Dim markup = +''' This is , which has these methods: +''' +''' +''' +''' +''' +''' x! +''' y! +''' z! +Delegate Sub $$MyFunc(x As Integer, y As String, z As Boolean) + +Class C + Sub M() + Dim f As MyFunc = AddressOf Test + End Sub + + ''' + ''' + ''' + Private Sub Test(a As Integer, b As String, c As Boolean) + End Sub +End Class +]]>.NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = +''' This is , which has these methods: +''' +''' +''' +''' +''' +''' z! +''' +''' y! +Delegate Sub MyFunc(z As Boolean, newIntegerParameter As Integer, y As String) + +Class C + Sub M() + Dim f As MyFunc = AddressOf Test + End Sub + + ''' + ''' + ''' + Private Sub Test(c As Boolean, newIntegerParameter As Integer, b As String) + End Sub +End Class +]]>.NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Delegates_Relaxation_FunctionToSub() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Delegates_Relaxation_ParameterlessFunctionToFunction() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Delegates_CascadeToEvents() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Events_ReferencedBy_RaiseEvent() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Events_ReferencedBy_AddHandler() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Events_ReferencedBy_GeneratedDelegateTypeInvocations() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Events_ReferencedBy_HandlesClause() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_CustomEvents_ReferencedBy_RaiseEvent() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_CustomEvents_ReferencedBy_AddHandler() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_CustomEvents_ReferencedBy_Invocations() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_CustomEvents_ReferencedBy_HandlesClause() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Delegates_Generics() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer")} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Formatting.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Formatting.vb new file mode 100644 index 0000000000000..2353eae9fd9dc --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.Formatting.vb @@ -0,0 +1,409 @@ +' 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. + +Imports Microsoft.CodeAnalysis.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions +Imports Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ChangeSignature + Partial Public Class ChangeSignatureTests + Inherits AbstractChangeSignatureTests + + + Public Async Function TestAddParameter_Formatting_KeepCountsPerLine() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(5), + New AddedParameterOrExistingIndex(4), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(3), + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_SubMethods() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_FunctionMethods() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_Events() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_CustomEvents() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_Constructors() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_Properties() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_Attribute() As Task + Dim markup = +Class CustomAttribute + Inherits Attribute + Sub $$New(x As Integer, y As Integer) + End Sub +End Class +]]>.NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = +Class CustomAttribute + Inherits Attribute + Sub New(y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class +]]>.NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_DelegateFunction() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_MultilineSubLambda() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_MultilineFunctionLambda() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_SingleLineSubLambda() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + + + Public Async Function TestAddParameter_Formatting_SingleLineFunctionLambda() As Task + Dim markup = .NormalizedValue() + Dim updatedSignature = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim expectedUpdatedCode = .NormalizedValue() + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=updatedSignature, expectedUpdatedInvocationDocumentCode:=expectedUpdatedCode) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.vb new file mode 100644 index 0000000000000..cd6728a79a330 --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.vb @@ -0,0 +1,779 @@ +' 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. + +Imports Microsoft.CodeAnalysis.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions +Imports Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ChangeSignature + Partial Public Class ChangeSignatureTests + Inherits AbstractChangeSignatureTests + + + Public Async Function TestAddRemoveParameters() As Task + + Dim markup = + ''' See + ''' + ''' o! + ''' a! + ''' b! + ''' c! + ''' x! + ''' y! + + Sub $$M(ByVal o As String, a As Integer, b As String, c As Boolean, Optional x As Integer = 0, Optional y As String = "Zero") + Dim t = "Test" + + M(t, 1, "Two", True, 3, "Four") + t.M(1, "Two", True, 3, "Four") + + M(t, 1, "Two", True, 3) + M(t, 1, "Two", True) + + M(t, 1, "Two", True, 3, y:="Four") + M(t, 1, "Two", c:=True) + + 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(y:="Four", x:=3, c:=True, b:="Two", a:=1, o:=t) + End Sub +End Module + +]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(0), + New AddedParameterOrExistingIndex(3), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(5)} + Dim updatedCode = + ''' See + ''' + ''' o! + ''' c! + ''' + ''' a! + ''' y! + ''' + + Sub M(ByVal o As String, c As Boolean, newIntegerParameter As Integer, a As Integer, Optional y As String = "Zero") + Dim t = "Test" + + M(t, True, 12345, 1, "Four") + t.M(True, 12345, 1, "Four") + + M(t, True, 12345, 1) + M(t, True, 12345, 1) + + M(t, True, 12345, 1, y:="Four") + M(t, c:=True, newIntegerParameter:=12345, a:=1) + + M(t, True, 12345, 1, y:="Four") + M(t, True, 12345, 1) + + M(t, True, 12345, 1, y:="Four") + M(t, a:=1, newIntegerParameter:=12345, y:="Four", c:=True) + M(t, y:="Four", newIntegerParameter:=12345, c:=True, a:=1) + M(y:="Four", c:=True, newIntegerParameter:=12345, a:=1, o:=t) + End Sub +End Module + +]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameterToParameterlessMethod() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer")} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_Parameters() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + + End Function + + + Public Async Function TestAddParameter_ParametersAndArguments() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ParametersAndArgumentsOfNestedCalls() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderConstructorParametersAndArguments() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderAttributeConstructorParametersAndArguments() As Task + + Dim markup = +Class C + Inherits Attribute + + $$Sub New(x As Integer, y As String) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = +Class C + Inherits Attribute + + Sub New(y As String, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ExtensionMethodParametersAndArguments_StaticCall() As Task + + Dim markup = + Public Sub M($$ByVal this As C, x As Integer, y As Integer, Optional a As String = "test_a", Optional b As String = "test_b", Optional c As String = "test_c") + End Sub +End Module]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(0), + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(5), + New AddedParameterOrExistingIndex(4), + New AddedParameterOrExistingIndex(3)} + Dim updatedCode = + Public Sub M(ByVal this As C, y As Integer, newIntegerParameter As Integer, x As Integer, Optional c As String = "test_c", Optional b As String = "test_b", Optional a As String = "test_a") + End Sub +End Module]]>.NormalizedValue() + + ' Although the `ParameterConfig` has 0 for the `SelectedIndex`, the UI dialog will make an adjustment + ' and select parameter `y` instead because the `this` parameter cannot be moved or removed. + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, + expectedUpdatedInvocationDocumentCode:=updatedCode, expectedSelectedIndex:=0) + End Function + + + Public Async Function TestAddParameter_ReorderExtensionMethodParametersAndArguments_ExtensionCall() As Task + + Dim markup = + $$Public Sub M(ByVal this As C, x As Integer, y As Integer, Optional a As String = "test_a", Optional b As String = "test_b", Optional c As String = "test_c") + End Sub +End Module]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(0), + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(5), + New AddedParameterOrExistingIndex(4), + New AddedParameterOrExistingIndex(3)} + Dim updatedCode = + Public Sub M(ByVal this As C, y As Integer, newIntegerParameter As Integer, x As Integer, Optional c As String = "test_c", Optional b As String = "test_b", Optional a As String = "test_a") + End Sub +End Module]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamsMethodParametersAndArguments_ParamsAsArray() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(0), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(2)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamsMethodParametersAndArguments_ParamsExpanded() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(0), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(2)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderExtensionAndParamsMethodParametersAndArguments_VariedCallsites() As Task + + Dim markup = + $$Public Sub M(ByVal this As C, x As Integer, y As Integer, ParamArray p As Integer()) + End Sub +End Module]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(0), + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(3)} + Dim updatedCode = + Public Sub M(ByVal this As C, y As Integer, newIntegerParameter As Integer, x As Integer, ParamArray p As Integer()) + End Sub +End Module]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderIndexerParametersAndArguments() As Task + + Dim markup = .NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = .NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_OnIndividualLines() As Task + + Dim markup = x! + ''' y! + ''' z! + $$Sub Goo(x As Integer, y As Integer, z As Integer) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = z! + ''' y! + ''' + ''' x! + Sub Goo(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_OnSameLine() As Task + + Dim markup = x!y!z! + $$Sub Goo(x As Integer, y As Integer, z As Integer) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = z!y! + ''' x! + Sub Goo(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_OutOfOrder_MaintainsOrder() As Task + + Dim markup = x! + ''' z! + ''' y! + $$Sub Goo(x As Integer, y As Integer, z As Integer) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = x! + ''' z! + ''' y! + Sub Goo(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_InsufficientTags_MaintainsOrder() As Task + + Dim markup = x! + ''' z! + $$Sub Goo(x As Integer, y As Integer, z As Integer) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = x! + ''' z! + Sub Goo(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_ExcessiveTags_MaintainsOrder() As Task + + Dim markup = w! + ''' x! + ''' y! + ''' z! + $$Sub Goo(x As Integer, y As Integer, z As Integer) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = w! + ''' x! + ''' y! + ''' z! + Sub Goo(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_IncorrectlyNamedTags_MaintainsOrder() As Task + + Dim markup = x2! + ''' y! + ''' z! + $$Sub Goo(x As Integer, y As Integer, z As Integer) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = x2! + ''' y! + ''' z! + Sub Goo(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_OnFunctions() As Task + + Dim markup = x! + ''' y! + ''' z! + $$Function Goo(x As Integer, y As Integer, z As Integer) As Integer + Return 1 + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = z! + ''' y! + ''' + ''' x! + Function Goo(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) As Integer + Return 1 + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_OnConstructors() As Task + + Dim markup = x! + ''' y! + ''' z! + $$Sub New(x As Integer, y As Integer, z As Integer) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = z! + ''' y! + ''' + ''' x! + Sub New(z As Integer, y As Integer, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParamTagsInDocComments_OnProperties() As Task + + Dim markup = x! + ''' y! + ''' z! + $$Default Public Property Item(ByVal x As Integer, ByVal y As Integer, ByVal z As Integer) As Integer + Get + Return 5 + End Get + Set(value As Integer) + End Set + End Property +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(2), + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = z! + ''' y! + ''' + ''' x! + Default Public Property Item(ByVal z As Integer, ByVal y As Integer, newIntegerParameter As Integer, ByVal x As Integer) As Integer + Get + Return 5 + End Get + Set(value As Integer) + End Set + End Property +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + + + Public Async Function TestAddParameter_ReorderParametersInCrefs() As Task + + Dim markup = + ''' See and + ''' + $$Sub M(x As Integer, y As String) + End Sub +End Class]]>.NormalizedValue() + Dim permutation = { + New AddedParameterOrExistingIndex(1), + New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "newIntegerParameter", "12345"), "Integer"), + New AddedParameterOrExistingIndex(0)} + Dim updatedCode = + ''' See and + ''' + Sub M(y As String, newIntegerParameter As Integer, x As Integer) + End Sub +End Class]]>.NormalizedValue() + + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationErrors.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationErrors.vb index 6bf4a4e09f579..8d177ffd02e5c 100644 --- a/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationErrors.vb +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.InvocationErrors.vb @@ -32,26 +32,26 @@ End Class]]>.NormalizedValue() End Function - Public Async Function TestReorderMethodParameters_InsufficientParameters_None() As Task + Public Async Function TestReorderMethodParameters_NoChangeableParameters() As Task Dim markup = .NormalizedValue() - Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, expectedSuccess:=False, expectedErrorText:=FeaturesResources.This_signature_does_not_contain_parameters_that_can_be_changed) + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, expectedSuccess:=False, expectedErrorText:=FeaturesResources.You_can_only_change_the_signature_of_a_constructor_indexer_method_or_delegate) End Function - Public Async Function TestReorderMethodParameters_InvokeOnOperator_ShouldFail() As Task + Public Async Function TestChangeSignature_AllowedWithNoParameters() As Task Dim markup = .NormalizedValue() - Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, expectedSuccess:=False, expectedErrorText:=FeaturesResources.You_can_only_change_the_signature_of_a_constructor_indexer_method_or_delegate) + Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, expectedSuccess:=True) End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.MultiFile.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.MultiFile.vb index df7fd11890573..9510a0c39f73c 100644 --- a/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.MultiFile.vb +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/ReorderParameters.MultiFile.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions +Imports Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature Imports Microsoft.VisualStudio.Text.Operations Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ChangeSignature @@ -33,7 +34,7 @@ class C - Dim permutation = {1, 0} + Dim permutation = {New AddedParameterOrExistingIndex(1), New AddedParameterOrExistingIndex(0)} Dim expectedVBCode = - Dim permutation = {1, 0} + Dim permutation = {New AddedParameterOrExistingIndex(1), New AddedParameterOrExistingIndex(0)} Dim expectedVBCode = CSharpSyntaxGenerator.Instance; + private static readonly ImmutableArray _declarationKinds = ImmutableArray.Create( SyntaxKind.MethodDeclaration, SyntaxKind.ConstructorDeclaration, @@ -142,6 +147,30 @@ private static int TryGetSelectedIndexFromDeclaration(int position, SyntaxNode m return parameters != null ? GetParameterIndex(parameters.Parameters, position) : 0; } + // Find the position to insert the new parameter. + // We will insert a new comma and a parameter. + protected override int? TryGetInsertPositionFromDeclaration(SyntaxNode matchingNode) + { + var parameters = matchingNode.ChildNodes().OfType().SingleOrDefault(); + + if (parameters == null) + { + return null; + } + + switch (parameters) + { + case ParameterListSyntax parameterListSyntax: + return parameterListSyntax.CloseParenToken.SpanStart; + case BracketedParameterListSyntax bracketedParameterListSyntax: + return bracketedParameterListSyntax.CloseBracketToken.SpanStart; + } + + return null; + } + + protected override string LanguageName => LanguageNames.CSharp; + private SyntaxNode GetMatchingNode(SyntaxNode node, bool restrictToDeclarations) { var matchKinds = restrictToDeclarations @@ -238,7 +267,7 @@ private SyntaxNode GetNodeContainingTargetNode(SyntaxNode matchingNode) } } - public override SyntaxNode ChangeSignature( + public override async Task ChangeSignatureAsync( Document document, ISymbol declarationSymbol, SyntaxNode potentiallyUpdatedNode, @@ -249,13 +278,12 @@ public override SyntaxNode ChangeSignature( var updatedNode = potentiallyUpdatedNode as CSharpSyntaxNode; // Update tags. - if (updatedNode.IsKind(SyntaxKind.MethodDeclaration) || updatedNode.IsKind(SyntaxKind.ConstructorDeclaration) || updatedNode.IsKind(SyntaxKind.IndexerDeclaration) || updatedNode.IsKind(SyntaxKind.DelegateDeclaration)) { - var updatedLeadingTrivia = UpdateParamTagsInLeadingTrivia(updatedNode, declarationSymbol, signaturePermutation); + var updatedLeadingTrivia = UpdateParamTagsInLeadingTrivia(document, updatedNode, declarationSymbol, signaturePermutation); if (updatedLeadingTrivia != null) { updatedNode = updatedNode.WithLeadingTrivia(updatedLeadingTrivia); @@ -263,34 +291,33 @@ public override SyntaxNode ChangeSignature( } // Update declarations parameter lists - if (updatedNode.IsKind(SyntaxKind.MethodDeclaration, out MethodDeclarationSyntax method)) { - var updatedParameters = PermuteDeclaration(method.ParameterList.Parameters, signaturePermutation); + var updatedParameters = UpdateDeclaration(method.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax); return method.WithParameterList(method.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.LocalFunctionStatement, out LocalFunctionStatementSyntax localFunction)) { - var updatedParameters = PermuteDeclaration(localFunction.ParameterList.Parameters, signaturePermutation); + var updatedParameters = UpdateDeclaration(localFunction.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax); return localFunction.WithParameterList(localFunction.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.ConstructorDeclaration, out ConstructorDeclarationSyntax constructor)) { - var updatedParameters = PermuteDeclaration(constructor.ParameterList.Parameters, signaturePermutation); + var updatedParameters = UpdateDeclaration(constructor.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax); return constructor.WithParameterList(constructor.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.IndexerDeclaration, out IndexerDeclarationSyntax indexer)) { - var updatedParameters = PermuteDeclaration(indexer.ParameterList.Parameters, signaturePermutation); + var updatedParameters = UpdateDeclaration(indexer.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax); return indexer.WithParameterList(indexer.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.DelegateDeclaration, out DelegateDeclarationSyntax delegateDeclaration)) { - var updatedParameters = PermuteDeclaration(delegateDeclaration.ParameterList.Parameters, signaturePermutation); + var updatedParameters = UpdateDeclaration(delegateDeclaration.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax); return delegateDeclaration.WithParameterList(delegateDeclaration.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } @@ -302,7 +329,7 @@ public override SyntaxNode ChangeSignature( return anonymousMethod; } - var updatedParameters = PermuteDeclaration(anonymousMethod.ParameterList.Parameters, signaturePermutation); + var updatedParameters = UpdateDeclaration(anonymousMethod.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax); return anonymousMethod.WithParameterList(anonymousMethod.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } @@ -310,12 +337,16 @@ public override SyntaxNode ChangeSignature( { if (signaturePermutation.UpdatedConfiguration.ToListOfParameters().Any()) { - Debug.Assert(false, "Updating a simple lambda expression without removing its parameter"); + var updatedParameters = UpdateDeclaration(SyntaxFactory.SeparatedList(new[] { lambda.Parameter }), signaturePermutation, CreateNewParameterSyntax); + return SyntaxFactory.ParenthesizedLambdaExpression( + lambda.AsyncKeyword, + SyntaxFactory.ParameterList(updatedParameters), + lambda.ArrowToken, + lambda.Body); } else { // No parameters. Change to a parenthesized lambda expression - var emptyParameterList = SyntaxFactory.ParameterList() .WithLeadingTrivia(lambda.Parameter.GetLeadingTrivia()) .WithTrailingTrivia(lambda.Parameter.GetTrailingTrivia()); @@ -326,15 +357,21 @@ public override SyntaxNode ChangeSignature( if (updatedNode.IsKind(SyntaxKind.ParenthesizedLambdaExpression, out ParenthesizedLambdaExpressionSyntax parenLambda)) { - var updatedParameters = PermuteDeclaration(parenLambda.ParameterList.Parameters, signaturePermutation); + bool doNotSkipParameterType = parenLambda.ParameterList.Parameters.Any() && parenLambda.ParameterList.Parameters.First().Type != null; + Func createNewParameterDelegate = + p => CreateNewParameterSyntax(p, !doNotSkipParameterType); + + var updatedParameters = UpdateDeclaration( + parenLambda.ParameterList.Parameters, + signaturePermutation, + createNewParameterDelegate); return parenLambda.WithParameterList(parenLambda.ParameterList.WithParameters(updatedParameters)); } // Update reference site argument lists - if (updatedNode.IsKind(SyntaxKind.InvocationExpression, out InvocationExpressionSyntax invocation)) { - var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var symbolInfo = semanticModel.GetSymbolInfo((InvocationExpressionSyntax)originalNode, cancellationToken); var isReducedExtensionMethod = false; @@ -344,37 +381,48 @@ public override SyntaxNode ChangeSignature( isReducedExtensionMethod = true; } - var newArguments = PermuteArgumentList(document, declarationSymbol, invocation.ArgumentList.Arguments, signaturePermutation, isReducedExtensionMethod); + var newArguments = PermuteArgumentList(declarationSymbol, invocation.ArgumentList.Arguments, signaturePermutation.WithoutAddedParameters(), isReducedExtensionMethod); + newArguments = AddNewArgumentsToList(newArguments, signaturePermutation, isReducedExtensionMethod); return invocation.WithArgumentList(invocation.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.ObjectCreationExpression, out ObjectCreationExpressionSyntax objCreation)) { - var newArguments = PermuteArgumentList(document, declarationSymbol, objCreation.ArgumentList.Arguments, signaturePermutation); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + var symbolInfo = semanticModel.GetSymbolInfo((ObjectCreationExpressionSyntax)originalNode, cancellationToken); + var isReducedExtensionMethod = false; + + if (symbolInfo.Symbol is IMethodSymbol methodSymbol && methodSymbol.MethodKind == MethodKind.ReducedExtension) + { + isReducedExtensionMethod = true; + } + + var newArguments = PermuteArgumentList(declarationSymbol, objCreation.ArgumentList.Arguments, signaturePermutation.WithoutAddedParameters()); + newArguments = AddNewArgumentsToList(newArguments, signaturePermutation, isReducedExtensionMethod); return objCreation.WithArgumentList(objCreation.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.ThisConstructorInitializer, out ConstructorInitializerSyntax constructorInit) || updatedNode.IsKind(SyntaxKind.BaseConstructorInitializer, out constructorInit)) { - var newArguments = PermuteArgumentList(document, declarationSymbol, constructorInit.ArgumentList.Arguments, signaturePermutation); + var newArguments = PermuteArgumentList(declarationSymbol, constructorInit.ArgumentList.Arguments, signaturePermutation); return constructorInit.WithArgumentList(constructorInit.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.ElementAccessExpression, out ElementAccessExpressionSyntax elementAccess)) { - var newArguments = PermuteArgumentList(document, declarationSymbol, elementAccess.ArgumentList.Arguments, signaturePermutation); + var newArguments = PermuteArgumentList(declarationSymbol, elementAccess.ArgumentList.Arguments, signaturePermutation); return elementAccess.WithArgumentList(elementAccess.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } if (updatedNode.IsKind(SyntaxKind.Attribute, out AttributeSyntax attribute)) { - var newArguments = PermuteAttributeArgumentList(document, declarationSymbol, attribute.ArgumentList.Arguments, signaturePermutation); + var newArguments = PermuteAttributeArgumentList(declarationSymbol, attribute.ArgumentList.Arguments, signaturePermutation); return attribute.WithArgumentList(attribute.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)); } // Handle references in crefs - if (updatedNode.IsKind(SyntaxKind.NameMemberCref, out NameMemberCrefSyntax nameMemberCref)) { if (nameMemberCref.Parameters == null || @@ -383,7 +431,7 @@ public override SyntaxNode ChangeSignature( return nameMemberCref; } - var newParameters = PermuteDeclaration(nameMemberCref.Parameters.Parameters, signaturePermutation); + var newParameters = UpdateDeclaration(nameMemberCref.Parameters.Parameters, signaturePermutation, CreateNewCrefParameterSyntax); var newCrefParameterList = nameMemberCref.Parameters.WithParameters(newParameters); return nameMemberCref.WithParameters(newCrefParameterList); @@ -393,29 +441,34 @@ public override SyntaxNode ChangeSignature( return null; } - private SeparatedSyntaxList PermuteDeclaration(SeparatedSyntaxList list, SignatureChange updatedSignature) where T : SyntaxNode + private static ParameterSyntax CreateNewParameterSyntax(AddedParameter addedParameter) + => CreateNewParameterSyntax(addedParameter, skipParameterType: false); + + private static ParameterSyntax CreateNewParameterSyntax(AddedParameter addedParameter, bool skipParameterType) + => SyntaxFactory.Parameter( + attributeLists: SyntaxFactory.List(), + modifiers: SyntaxFactory.TokenList(), + type: skipParameterType + ? null + : addedParameter.Type.GenerateTypeSyntax(allowVar: false) + .WithTrailingTrivia(SyntaxFactory.ElasticSpace), + SyntaxFactory.Identifier(addedParameter.ParameterName), + @default: null); + + private static CrefParameterSyntax CreateNewCrefParameterSyntax(AddedParameter addedParameter) + => SyntaxFactory.CrefParameter(type: addedParameter.Type.GenerateTypeSyntax(allowVar: false)) + .WithLeadingTrivia(SyntaxFactory.ElasticSpace); + + private SeparatedSyntaxList UpdateDeclaration( + SeparatedSyntaxList list, + SignatureChange updatedSignature, + Func createNewParameterMethod) where T : SyntaxNode { - var originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters(); - var reorderedParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters(); - - var newParameters = new List(); - for (var index = 0; index < reorderedParameters.Count; index++) - { - var newParam = reorderedParameters[index]; - var pos = originalParameters.IndexOf(newParam); - var param = list[pos]; - - // copy whitespace trivia from original position - param = TransferLeadingWhitespaceTrivia(param, list[index]); - - newParameters.Add(param); - } - - var numSeparatorsToSkip = originalParameters.Count - reorderedParameters.Count; - return SyntaxFactory.SeparatedList(newParameters, GetSeparators(list, numSeparatorsToSkip)); + var updatedDeclaration = base.UpdateDeclarationBase(list, updatedSignature, createNewParameterMethod); + return SyntaxFactory.SeparatedList(updatedDeclaration.parameters, updatedDeclaration.separators); } - private static T TransferLeadingWhitespaceTrivia(T newArgument, SyntaxNode oldArgument) where T : SyntaxNode + protected override T TransferLeadingWhitespaceTrivia(T newArgument, SyntaxNode oldArgument) { var oldTrivia = oldArgument.GetLeadingTrivia(); var oldOnlyHasWhitespaceTrivia = oldTrivia.All(t => t.IsKind(SyntaxKind.WhitespaceTrivia)); @@ -431,13 +484,14 @@ private static T TransferLeadingWhitespaceTrivia(T newArgument, SyntaxNode ol return newArgument; } - private static SeparatedSyntaxList PermuteAttributeArgumentList( - Document document, + private SeparatedSyntaxList PermuteAttributeArgumentList( ISymbol declarationSymbol, SeparatedSyntaxList arguments, SignatureChange updatedSignature) { - var newArguments = PermuteArguments(document, declarationSymbol, arguments.Select(a => UnifiedArgumentSyntax.Create(a)).ToList(), updatedSignature); + var newArguments = PermuteArguments(declarationSymbol, arguments.Select(a => UnifiedArgumentSyntax.Create(a)).ToList(), + updatedSignature, + callSiteValue => UnifiedArgumentSyntax.Create(SyntaxFactory.AttributeArgument(SyntaxFactory.ParseExpression(callSiteValue)))); var numSeparatorsToSkip = arguments.Count - newArguments.Count; // copy whitespace trivia from original position @@ -447,14 +501,18 @@ private static SeparatedSyntaxList PermuteAttributeArgu return SyntaxFactory.SeparatedList(newArgumentsWithTrivia, GetSeparators(arguments, numSeparatorsToSkip)); } - private static SeparatedSyntaxList PermuteArgumentList( - Document document, + private SeparatedSyntaxList PermuteArgumentList( ISymbol declarationSymbol, SeparatedSyntaxList arguments, SignatureChange updatedSignature, bool isReducedExtensionMethod = false) { - var newArguments = PermuteArguments(document, declarationSymbol, arguments.Select(a => UnifiedArgumentSyntax.Create(a)).ToList(), updatedSignature, isReducedExtensionMethod); + var newArguments = PermuteArguments( + declarationSymbol, + arguments.Select(a => UnifiedArgumentSyntax.Create(a)).ToList(), + updatedSignature, + callSiteValue => UnifiedArgumentSyntax.Create(SyntaxFactory.Argument(SyntaxFactory.ParseExpression(callSiteValue))), + isReducedExtensionMethod); // copy whitespace trivia from original position var newArgumentsWithTrivia = TransferLeadingWhitespaceTrivia( @@ -464,7 +522,7 @@ private static SeparatedSyntaxList PermuteArgumentList( return SyntaxFactory.SeparatedList(newArgumentsWithTrivia, GetSeparators(arguments, numSeparatorsToSkip)); } - private static List TransferLeadingWhitespaceTrivia(IEnumerable newArguments, SeparatedSyntaxList oldArguments) + private List TransferLeadingWhitespaceTrivia(IEnumerable newArguments, SeparatedSyntaxList oldArguments) where T : SyntaxNode where U : SyntaxNode { @@ -472,14 +530,22 @@ private static List TransferLeadingWhitespaceTrivia(IEnumerable newA var index = 0; foreach (var newArgument in newArguments) { - result.Add(TransferLeadingWhitespaceTrivia(newArgument, oldArguments[index])); + if (index < oldArguments.Count) + { + result.Add(TransferLeadingWhitespaceTrivia(newArgument, oldArguments[index])); + } + else + { + result.Add(newArgument); + } + index++; } return result; } - private List UpdateParamTagsInLeadingTrivia(CSharpSyntaxNode node, ISymbol declarationSymbol, SignatureChange updatedSignature) + private List UpdateParamTagsInLeadingTrivia(Document document, CSharpSyntaxNode node, ISymbol declarationSymbol, SignatureChange updatedSignature) { if (!node.HasLeadingTrivia) { @@ -497,13 +563,12 @@ private List UpdateParamTagsInLeadingTrivia(CSharpSyntaxNode node, return null; } - return GetPermutedTrivia(node, permutedParamNodes); + return GetPermutedTrivia(document, node, permutedParamNodes); } - private List VerifyAndPermuteParamNodes(IEnumerable paramNodes, ISymbol declarationSymbol, SignatureChange updatedSignature) + private List VerifyAndPermuteParamNodes(IEnumerable paramNodes, ISymbol declarationSymbol, SignatureChange updatedSignature) { // Only reorder if count and order match originally. - var originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters(); var reorderedParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters(); @@ -513,6 +578,11 @@ private List VerifyAndPermuteParamNodes(IEnumerable(); var i = 0; foreach (var paramNode in paramNodes) @@ -534,84 +604,24 @@ private List VerifyAndPermuteParamNodes(IEnumerable(); + var permutedParams = new List(); foreach (var parameter in reorderedParameters) { - permutedParams.Add(dictionary[parameter.Name]); - } - - return permutedParams; - } - - private List GetPermutedTrivia(CSharpSyntaxNode node, List permutedParamNodes) - { - var updatedLeadingTrivia = new List(); - var index = 0; - - foreach (var trivia in node.GetLeadingTrivia()) - { - if (!trivia.HasStructure) + if (dictionary.TryGetValue(parameter.Name, out var permutedParam)) { - updatedLeadingTrivia.Add(trivia); - continue; + permutedParams.Add(permutedParam); } - - if (!(trivia.GetStructure() is DocumentationCommentTriviaSyntax structuredTrivia)) + else { - updatedLeadingTrivia.Add(trivia); - continue; + permutedParams.Add(SyntaxFactory.XmlElement( + SyntaxFactory.XmlElementStartTag( + SyntaxFactory.XmlName("param"), + SyntaxFactory.List(new[] { SyntaxFactory.XmlNameAttribute(parameter.Name) })), + SyntaxFactory.XmlElementEndTag(SyntaxFactory.XmlName("param")))); } - - var updatedNodeList = new List(); - var structuredContent = structuredTrivia.Content.ToList(); - for (var i = 0; i < structuredContent.Count; i++) - { - var content = structuredContent[i]; - if (!content.IsKind(SyntaxKind.XmlElement, out XmlElementSyntax xmlElement)) - { - updatedNodeList.Add(content); - continue; - } - - if (xmlElement.StartTag.Name.ToString() != DocumentationCommentXmlNames.ParameterElementName) - { - updatedNodeList.Add(content); - continue; - } - - // Found a param tag, so insert the next one from the reordered list - if (index < permutedParamNodes.Count) - { - updatedNodeList.Add(permutedParamNodes[index].WithLeadingTrivia(content.GetLeadingTrivia()).WithTrailingTrivia(content.GetTrailingTrivia())); - index++; - } - else - { - // Inspecting a param element that we are deleting but not replacing. - } - } - - var newDocComments = SyntaxFactory.DocumentationCommentTrivia(structuredTrivia.Kind(), SyntaxFactory.List(updatedNodeList.AsEnumerable())); - newDocComments = newDocComments.WithEndOfComment(structuredTrivia.EndOfComment); - newDocComments = newDocComments.WithLeadingTrivia(structuredTrivia.GetLeadingTrivia()).WithTrailingTrivia(structuredTrivia.GetTrailingTrivia()); - var newTrivia = SyntaxFactory.Trivia(newDocComments); - - updatedLeadingTrivia.Add(newTrivia); - } - - return updatedLeadingTrivia; - } - - private static List GetSeparators(SeparatedSyntaxList arguments, int numSeparatorsToSkip = 0) where T : SyntaxNode - { - var separators = new List(); - for (var i = 0; i < arguments.SeparatorCount - numSeparatorsToSkip; i++) - { - separators.Add(arguments.GetSeparator(i)); } - return separators; + return permutedParams; } public override async Task> DetermineCascadedSymbolsFromDelegateInvokeAsync( @@ -627,35 +637,33 @@ public override async Task> DetermineCascaded var convertedMethodGroups = nodes .WhereAsArray( n => + { + if (!n.IsKind(SyntaxKind.IdentifierName) || + !semanticModel.GetMemberGroup(n, cancellationToken).Any()) + { + return false; + } + + ISymbol convertedType = semanticModel.GetTypeInfo(n, cancellationToken).ConvertedType; + + if (convertedType != null) { - if (!n.IsKind(SyntaxKind.IdentifierName) || - !semanticModel.GetMemberGroup(n, cancellationToken).Any()) - { - return false; - } - - ISymbol convertedType = semanticModel.GetTypeInfo(n, cancellationToken).ConvertedType; - - if (convertedType != null) - { - convertedType = convertedType.OriginalDefinition; - } - - if (convertedType != null) - { - convertedType = SymbolFinder.FindSourceDefinitionAsync(convertedType, document.Project.Solution, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken) ?? convertedType; - } - - return Equals(convertedType, symbol.ContainingType); - }) + convertedType = convertedType.OriginalDefinition; + } + + if (convertedType != null) + { + convertedType = SymbolFinder.FindSourceDefinitionAsync(convertedType, document.Project.Solution, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken) ?? convertedType; + } + + return Equals(convertedType, symbol.ContainingType); + }) .SelectAsArray(n => semanticModel.GetSymbolInfo(n, cancellationToken).Symbol); return convertedMethodGroups.SelectAsArray(symbolAndProjectId.WithSymbol); } protected override IEnumerable GetFormattingRules(Document document) - { - return SpecializedCollections.SingletonEnumerable(new ChangeSignatureFormattingRule()).Concat(Formatter.GetDefaultFormattingRules(document)); - } + => SpecializedCollections.SingletonEnumerable(new ChangeSignatureFormattingRule()).Concat(Formatter.GetDefaultFormattingRules(document)); } } diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs index aed2052d682d0..7989b9009f338 100644 --- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs +++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -10,6 +12,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols.Finders; using Microsoft.CodeAnalysis.Formatting; @@ -18,6 +21,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -41,7 +45,7 @@ internal abstract class AbstractChangeSignatureService : ILanguageService public abstract Task> DetermineCascadedSymbolsFromDelegateInvokeAsync( SymbolAndProjectId symbolAndProjectId, Document document, CancellationToken cancellationToken); - public abstract SyntaxNode ChangeSignature( + public abstract Task ChangeSignatureAsync( Document document, ISymbol declarationSymbol, SyntaxNode potentiallyUpdatedNode, @@ -51,40 +55,43 @@ public abstract SyntaxNode ChangeSignature( protected abstract IEnumerable GetFormattingRules(Document document); + protected abstract string LanguageName { get; } + + protected abstract T TransferLeadingWhitespaceTrivia(T newArgument, SyntaxNode oldArgument) where T : SyntaxNode; + public async Task> GetChangeSignatureCodeActionAsync(Document document, TextSpan span, CancellationToken cancellationToken) { var context = await GetContextAsync(document, span.Start, restrictToDeclarations: true, cancellationToken: cancellationToken).ConfigureAwait(false); - return context.CanChangeSignature - ? ImmutableArray.Create(new ChangeSignatureCodeAction(this, context)) + return context is ChangeSignatureAnalyzedSucceedContext changeSignatureAnalyzedSucceedContext + ? ImmutableArray.Create(new ChangeSignatureCodeAction(this, changeSignatureAnalyzedSucceedContext)) : ImmutableArray.Empty; } internal ChangeSignatureResult ChangeSignature(Document document, int position, Action errorHandler, CancellationToken cancellationToken) { - var context = GetContextAsync(document, position, restrictToDeclarations: false, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); + var context = GetContextAsync(document, position, restrictToDeclarations: false, cancellationToken: cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); - if (context.CanChangeSignature) + switch (context) { - return ChangeSignatureWithContext(context, cancellationToken); - } - else - { - switch (context.CannotChangeSignatureReason) - { - case CannotChangeSignatureReason.DefinedInMetadata: - errorHandler(FeaturesResources.The_member_is_defined_in_metadata, NotificationSeverity.Error); - break; - case CannotChangeSignatureReason.IncorrectKind: - errorHandler(FeaturesResources.You_can_only_change_the_signature_of_a_constructor_indexer_method_or_delegate, NotificationSeverity.Error); - break; - case CannotChangeSignatureReason.InsufficientParameters: - errorHandler(FeaturesResources.This_signature_does_not_contain_parameters_that_can_be_changed, NotificationSeverity.Error); - break; - } + case ChangeSignatureAnalyzedSucceedContext changeSignatureAnalyzedSucceedContext: + return ChangeSignatureWithContext(changeSignatureAnalyzedSucceedContext, cancellationToken); + case CannotChangeSignatureAnalyzedContext cannotChangeSignatureAnalyzedContext: + switch (cannotChangeSignatureAnalyzedContext.CannotChangeSignatureReason) + { + case CannotChangeSignatureReason.DefinedInMetadata: + errorHandler(FeaturesResources.The_member_is_defined_in_metadata, NotificationSeverity.Error); + break; + case CannotChangeSignatureReason.IncorrectKind: + errorHandler(FeaturesResources.You_can_only_change_the_signature_of_a_constructor_indexer_method_or_delegate, NotificationSeverity.Error); + break; + } - return new ChangeSignatureResult(succeeded: false); + break; } + + return new ChangeSignatureResult(succeeded: false); + } internal async Task GetContextAsync( @@ -98,7 +105,7 @@ internal async Task GetContextAsync( if (symbol == null) { - return new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind); + return new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind); } if (symbol is IMethodSymbol method) @@ -129,28 +136,49 @@ internal async Task GetContextAsync( if (symbol.Locations.Any(loc => loc.IsInMetadata)) { - return new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata); + return new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata); } - if (!symbol.MatchesKind(SymbolKind.Method, SymbolKind.Property, SymbolKind.NamedType)) + // This should be called after the metadata check above to avoid looking for nodes in metadata. + var declarationLocation = symbol.Locations.FirstOrDefault(); + if (declarationLocation == null) { - return new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind); + return new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata); } - var parameterConfiguration = ParameterConfiguration.Create(symbol.GetParameters().ToList(), symbol is IMethodSymbol && (symbol as IMethodSymbol).IsExtensionMethod, selectedIndex); - if (!parameterConfiguration.IsChangeable()) + var solution = document.Project.Solution; + var documentId = solution.GetDocumentId(declarationLocation.SourceTree); + var declarationDocument = solution.GetDocument(documentId); + var declarationChangeSignatureService = declarationDocument?.GetRequiredLanguageService(); + + if (declarationChangeSignatureService == null) { - return new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.InsufficientParameters); + return new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DeclarationLanguageServiceNotFound); } - return new ChangeSignatureAnalyzedContext( - document.Project, symbol, parameterConfiguration); + int? insertPositionOpt = declarationChangeSignatureService.TryGetInsertPositionFromDeclaration(symbol.Locations.FirstOrDefault().FindNode(cancellationToken)); + if (insertPositionOpt == null) + { + return new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DeclarationMethodPositionNotFound); + } + + if (!symbol.MatchesKind(SymbolKind.Method, SymbolKind.Property, SymbolKind.NamedType)) + { + return new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind); + } + + var parameterConfiguration = ParameterConfiguration.Create( + symbol.GetParameters().Select(p => new ExistingParameter(p)), + symbol.IsExtensionMethod(), selectedIndex); + + return new ChangeSignatureAnalyzedSucceedContext( + declarationDocument ?? document, insertPositionOpt.Value, symbol, parameterConfiguration); } - private ChangeSignatureResult ChangeSignatureWithContext(ChangeSignatureAnalyzedContext context, CancellationToken cancellationToken) + private ChangeSignatureResult ChangeSignatureWithContext(ChangeSignatureAnalyzedSucceedContext context, CancellationToken cancellationToken) { var options = GetChangeSignatureOptions(context); - if (options.IsCancelled) + if (options == null) { return new ChangeSignatureResult(succeeded: false); } @@ -158,16 +186,20 @@ private ChangeSignatureResult ChangeSignatureWithContext(ChangeSignatureAnalyzed return ChangeSignatureWithContext(context, options, cancellationToken); } - internal ChangeSignatureResult ChangeSignatureWithContext(ChangeSignatureAnalyzedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken) + protected abstract int? TryGetInsertPositionFromDeclaration(SyntaxNode matchingNode); + + internal ChangeSignatureResult ChangeSignatureWithContext(ChangeSignatureAnalyzedSucceedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken) { var succeeded = TryCreateUpdatedSolution(context, options, cancellationToken, out var updatedSolution); return new ChangeSignatureResult(succeeded, updatedSolution, context.Symbol.ToDisplayString(), context.Symbol.GetGlyph(), options.PreviewChanges); } - internal ChangeSignatureOptionsResult GetChangeSignatureOptions(ChangeSignatureAnalyzedContext context) + internal ChangeSignatureOptionsResult? GetChangeSignatureOptions(ChangeSignatureAnalyzedSucceedContext context) { var changeSignatureOptionsService = context.Solution.Workspace.Services.GetService(); - return changeSignatureOptionsService.GetChangeSignatureOptions(context.Symbol, context.ParameterConfiguration); + + return changeSignatureOptionsService?.GetChangeSignatureOptions( + context.Document, context.InsertPosition, context.Symbol, context.ParameterConfiguration); } private static async Task> FindChangeSignatureReferencesAsync( @@ -180,10 +212,9 @@ private static async Task> FindChangeSignatureR var streamingProgress = new StreamingProgressCollector( StreamingFindReferencesProgress.Instance); - IImmutableSet documents = null; var engine = new FindReferencesSearchEngine( solution, - documents, + documents: null, ReferenceFinders.DefaultReferenceFinders.Add(DelegateInvokeMethodReferenceFinder.DelegateInvokeMethod), streamingProgress, FindReferencesSearchOptions.Default, @@ -197,7 +228,7 @@ private static async Task> FindChangeSignatureR #nullable enable private bool TryCreateUpdatedSolution( - ChangeSignatureAnalyzedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken, [NotNullWhen(true)] out Solution? updatedSolution) + ChangeSignatureAnalyzedSucceedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken, [NotNullWhen(true)] out Solution? updatedSolution) { updatedSolution = null; @@ -210,9 +241,11 @@ private bool TryCreateUpdatedSolution( var hasLocationsInMetadata = false; var symbols = FindChangeSignatureReferencesAsync( - SymbolAndProjectId.Create(declaredSymbol, context.Project.Id), + SymbolAndProjectId.Create(declaredSymbol, context.Document.Project.Id), context.Solution, cancellationToken).WaitAndGetResult(cancellationToken); + var declaredSymbolParametersCount = declaredSymbol.GetParameters().Length; + foreach (var symbol in symbols) { var methodSymbol = symbol.Definition as IMethodSymbol; @@ -269,10 +302,16 @@ private bool TryCreateUpdatedSolution( { includeDefinitionLocations = false; } + + // We update delegates which may have different signature. + // It seems it is enough for now to compare delegates by parameter count only. + if (methodSymbol.Parameters.Length != declaredSymbolParametersCount) + { + includeDefinitionLocations = false; + } } // Find and annotate all the relevant definitions - if (includeDefinitionLocations) { foreach (var def in symbolWithSyntacticParameters.Locations) @@ -292,7 +331,6 @@ private bool TryCreateUpdatedSolution( } // Find and annotate all the relevant references - foreach (var location in symbol.Locations) { if (location.Location.IsInMetadata) @@ -325,7 +363,6 @@ private bool TryCreateUpdatedSolution( } // Construct all the relevant syntax trees from the base solution - var updatedRoots = new Dictionary(); foreach (var docId in nodesToUpdate.Keys) { @@ -340,9 +377,15 @@ private bool TryCreateUpdatedSolution( var nodes = nodesToUpdate[docId]; var newRoot = root.ReplaceNodes(nodes, (originalNode, potentiallyUpdatedNode) => - { - return updater.ChangeSignature(doc, definitionToUse[originalNode], potentiallyUpdatedNode, originalNode, CreateCompensatingSignatureChange(definitionToUse[originalNode], options.UpdatedSignature), cancellationToken); - }); + { + return updater.ChangeSignatureAsync( + doc, + definitionToUse[originalNode], + potentiallyUpdatedNode, + originalNode, + CreateCompensatingSignatureChange(definitionToUse[originalNode], options.UpdatedSignature), + cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); + }); var annotatedNodes = newRoot.GetAnnotatedNodes(syntaxAnnotation: changeSignatureFormattingAnnotation); @@ -358,10 +401,14 @@ private bool TryCreateUpdatedSolution( } // Update the documents using the updated syntax trees - foreach (var docId in nodesToUpdate.Keys) { - currentSolution = currentSolution.WithDocumentSyntaxRoot(docId, updatedRoots[docId]); + var updatedDoc = currentSolution.GetDocument(docId)!.WithSyntaxRoot(updatedRoots[docId]); + var docWithImports = ImportAdder.AddImportsFromSymbolAnnotationAsync(updatedDoc, safe: true, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); + var reducedDoc = Simplifier.ReduceAsync(docWithImports, Simplifier.Annotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); + var formattedDoc = Formatter.FormatAsync(reducedDoc, SyntaxAnnotation.ElasticAnnotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); + + currentSolution = currentSolution.WithDocumentSyntaxRoot(docId, formattedDoc.GetSyntaxRootSynchronously(cancellationToken)!); } updatedSolution = currentSolution; @@ -395,15 +442,14 @@ private bool TryGetNodeWithEditableSignatureOrAttributes(Location location, Solu return nodeToUpdate != null; } - protected static List PermuteArguments( - Document document, + protected List PermuteArguments( ISymbol declarationSymbol, List arguments, SignatureChange updatedSignature, + Func createIUnifiedArgument, bool isReducedExtensionMethod = false) { // 1. Determine which parameters are permutable - var declarationParameters = declarationSymbol.GetParameters().ToList(); var declarationParametersToPermute = GetParametersToPermute(arguments, declarationParameters, isReducedExtensionMethod); var argumentsToPermute = arguments.Take(declarationParametersToPermute.Count).ToList(); @@ -427,14 +473,13 @@ protected static List PermuteArguments( } // 3. Sort the arguments that need to be reordered - argumentsToPermute.Sort((a1, a2) => { return parameterToIndexMap[argumentToParameterMap[a1]].CompareTo(parameterToIndexMap[argumentToParameterMap[a2]]); }); // 4. Add names to arguments where necessary. - var newArguments = new List(); var expectedIndex = 0 + (isReducedExtensionMethod ? 1 : 0); var seenNamedArgument = false; + IUnifiedArgumentSyntax paramsArrayArgument = null; foreach (var argument in argumentsToPermute) { @@ -446,24 +491,55 @@ protected static List PermuteArguments( continue; } - if ((seenNamedArgument || actualIndex != expectedIndex) && !argument.IsNamed) + if (!param.IsParams) { - newArguments.Add(argument.WithName(param.Name).WithAdditionalAnnotations(Formatter.Annotation)); - seenNamedArgument = true; + // If seen a named argument before, add names for subsequent ones. + if ((seenNamedArgument || actualIndex != expectedIndex) && !argument.IsNamed) + { + + newArguments.Add(argument.WithName(param.Name).WithAdditionalAnnotations(Formatter.Annotation)); + seenNamedArgument = true; + } + else + { + newArguments.Add(argument); + } } else { - newArguments.Add(argument); + paramsArrayArgument = argument; } seenNamedArgument |= argument.IsNamed; expectedIndex++; } - // 5. Add the remaining arguments. These will already have names or be params arguments, but may have been removed. + // 5. Add added arguments (only at end for the moment) + var brandNewParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters().OfType(); - var removedParams = updatedSignature.OriginalConfiguration.ParamsParameter != null && updatedSignature.UpdatedConfiguration.ParamsParameter == null; + foreach (var brandNewParameter in brandNewParameters) + { + newArguments.Add(createIUnifiedArgument(brandNewParameter.CallSiteValue).WithName(brandNewParameter.ParameterName)); + } + // 6. Add the params argument with the first value: + if (paramsArrayArgument != null) + { + var param = argumentToParameterMap[paramsArrayArgument]; + var actualIndex = updatedSignature.GetUpdatedIndex(declarationParameters.IndexOf(param)); + if (seenNamedArgument && !paramsArrayArgument.IsNamed) + { + newArguments.Add(paramsArrayArgument.WithName(param.Name).WithAdditionalAnnotations(Formatter.Annotation)); + seenNamedArgument = true; + } + else + { + newArguments.Add(paramsArrayArgument); + } + } + + // 7. Add the remaining arguments. These will already have names or be params arguments, but may have been removed. + var removedParams = updatedSignature.OriginalConfiguration.ParamsParameter != null && updatedSignature.UpdatedConfiguration.ParamsParameter == null; for (var i = declarationParametersToPermute.Count; i < arguments.Count; i++) { if (!arguments[i].IsNamed && removedParams && i >= updatedSignature.UpdatedConfiguration.ToListOfParameters().Count) @@ -484,19 +560,19 @@ private static SignatureChange CreateCompensatingSignatureChange(ISymbol declara { if (declarationSymbol.GetParameters().Length > updatedSignature.OriginalConfiguration.ToListOfParameters().Count) { - var origStuff = updatedSignature.OriginalConfiguration.ToListOfParameters(); - var newStuff = updatedSignature.UpdatedConfiguration.ToListOfParameters(); + var originalConfigurationParameters = updatedSignature.OriginalConfiguration.ToListOfParameters(); + var updatedConfigurationParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters(); - var realStuff = declarationSymbol.GetParameters(); + var realParameters = declarationSymbol.GetParameters(); - var bonusParameters = realStuff.Skip(origStuff.Count); + var bonusParameters = realParameters.Skip(originalConfigurationParameters.Count); - origStuff.AddRange(bonusParameters); - newStuff.AddRange(bonusParameters); + originalConfigurationParameters.AddRange(bonusParameters.Select(p => new ExistingParameter(p))); + updatedConfigurationParameters.AddRange(bonusParameters.Select(p => new ExistingParameter(p))); - var newOrigParams = ParameterConfiguration.Create(origStuff, updatedSignature.OriginalConfiguration.ThisParameter != null, selectedIndex: 0); - var newUpdatedParams = ParameterConfiguration.Create(newStuff, updatedSignature.OriginalConfiguration.ThisParameter != null, selectedIndex: 0); - updatedSignature = new SignatureChange(newOrigParams, newUpdatedParams); + var newOriginalParameters = ParameterConfiguration.Create(originalConfigurationParameters, updatedSignature.OriginalConfiguration.ThisParameter != null, selectedIndex: 0); + var newUpdatedParams = ParameterConfiguration.Create(updatedConfigurationParameters, updatedSignature.OriginalConfiguration.ThisParameter != null, selectedIndex: 0); + updatedSignature = new SignatureChange(newOriginalParameters, newUpdatedParams); } return updatedSignature; @@ -579,5 +655,227 @@ protected static int GetParameterIndex(SeparatedSyntaxList paramet return parameters.Count - 1; } + + protected (IEnumerable parameters, IEnumerable separators) UpdateDeclarationBase( + SeparatedSyntaxList list, + SignatureChange updatedSignature, + Func createNewParameterMethod) where T : SyntaxNode + { + var originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters(); + var reorderedParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters(); + + int numAddedParameters = 0; + + var newParameters = new List(); + for (var index = 0; index < reorderedParameters.Count; index++) + { + var newParam = reorderedParameters[index]; + if (newParam is ExistingParameter existingParameter) + { + var pos = originalParameters.IndexOf(p => p is ExistingParameter ep && ep.Symbol == existingParameter.Symbol); + if (pos >= 0) + { + var param = list[pos]; + + // copy whitespace trivia from original position + param = TransferLeadingWhitespaceTrivia(param, list[index - numAddedParameters]); + newParameters.Add(param); + } + } + else + { + // Added parameter + numAddedParameters++; + var newParameter = createNewParameterMethod(newParam as AddedParameter); + newParameters.Add(newParameter); + } + } + + int numSeparatorsToSkip; + if (originalParameters.Count == 0) + { + // () + // Adding X parameters, need to add X-1 separators. + numSeparatorsToSkip = originalParameters.Count - reorderedParameters.Count + 1; + } + else + { + // (a,b,c) + // Adding X parameters, need to add X separators. + numSeparatorsToSkip = originalParameters.Count - reorderedParameters.Count; + } + + return (newParameters, GetSeparators(list, numSeparatorsToSkip)); + } + + protected List GetSeparators(SeparatedSyntaxList arguments, int numSeparatorsToSkip = 0) where T : SyntaxNode + { + var separators = new List(); + + for (int i = 0; i < arguments.SeparatorCount - numSeparatorsToSkip; i++) + { + if (i >= arguments.SeparatorCount) + { + separators.Add(Generator.CommaTokenWithElasticSpace()); + } + else + { + separators.Add(arguments.GetSeparator(i)); + } + } + + return separators; + } + + protected abstract SyntaxGenerator Generator { get; } + + protected SeparatedSyntaxList AddNewArgumentsToList( + SeparatedSyntaxList newArguments, + SignatureChange signaturePermutation, + bool isReducedExtensionMethod) + { + List fullList = new List(); + List separators = new List(); + + var updatedParameters = signaturePermutation.UpdatedConfiguration.ToListOfParameters(); + + int indexInExistingList = 0; + + bool seenNameEquals = false; + + for (int i = 0; i < updatedParameters.Count; i++) + { + // Skip this parameter in list of arguments for extension method calls but not for reduced ones. + if (updatedParameters[i] != signaturePermutation.UpdatedConfiguration.ThisParameter + || !isReducedExtensionMethod) + { + if (updatedParameters[i] is AddedParameter addedParameter) + { + fullList.Add( + Generator.Argument( + name: seenNameEquals ? addedParameter.Name : null, + refKind: RefKind.None, + expression: Generator.ParseExpression(addedParameter.CallSiteValue))); + separators.Add(Generator.CommaTokenWithElasticSpace()); + } + else + { + if (indexInExistingList < newArguments.Count) + { + if (Generator.IsNamedArgument(newArguments[indexInExistingList])) + { + seenNameEquals = true; + } + + if (indexInExistingList < newArguments.SeparatorCount) + { + separators.Add(newArguments.GetSeparator(indexInExistingList)); + } + + fullList.Add(newArguments[indexInExistingList++]); + } + } + } + } + + // Add the rest of existing parameters, e.g. from the params argument. + while (indexInExistingList < newArguments.Count) + { + if (indexInExistingList < newArguments.SeparatorCount) + { + separators.Add(newArguments.GetSeparator(indexInExistingList)); + } + + fullList.Add(newArguments[indexInExistingList++]); + } + + if (fullList.Count == separators.Count && separators.Count != 0) + { + separators.Remove(separators.Last()); + } + + return Generator.SeparatedList(fullList, separators); + } + + protected List GetPermutedTrivia(Document document, SyntaxNode node, List permutedParamNodes) + { + var updatedLeadingTrivia = new List(); + var index = 0; + SyntaxTrivia lastWhiteSpaceTrivia = default; + + var lastDocumentationCommentTriviaSyntax = node.GetLeadingTrivia() + .LastOrDefault(t => t.HasStructure && Generator.IsDocumentationCommentTriviaSyntax(t.GetStructure())); + + foreach (var trivia in node.GetLeadingTrivia()) + { + if (!trivia.HasStructure) + { + if (Generator.IsWhitespaceTrivia(trivia)) + { + lastWhiteSpaceTrivia = trivia; + } + + updatedLeadingTrivia.Add(trivia); + continue; + } + + var structuredTrivia = trivia.GetStructure(); + if (!(Generator.IsDocumentationCommentTriviaSyntax(structuredTrivia))) + { + updatedLeadingTrivia.Add(trivia); + continue; + } + + var updatedNodeList = new List(); + var structuredContent = Generator.GetContentFromDocumentationCommentTriviaSyntax(trivia); + for (var i = 0; i < structuredContent.Length; i++) + { + var content = structuredContent[i]; + if (!Generator.IsParameterNameXmlElementSyntax(content)) + { + updatedNodeList.Add(content); + continue; + } + + // Found a param tag, so insert the next one from the reordered list + if (index < permutedParamNodes.Count) + { + updatedNodeList.Add(permutedParamNodes[index].WithLeadingTrivia(content.GetLeadingTrivia()).WithTrailingTrivia(content.GetTrailingTrivia())); + index++; + } + else + { + // Inspecting a param element that we are deleting but not replacing. + } + } + + var newDocComments = Generator.DocumentationCommentTriviaWithUpdatedContent(trivia, updatedNodeList.AsEnumerable()); + newDocComments = newDocComments.WithLeadingTrivia(structuredTrivia.GetLeadingTrivia()).WithTrailingTrivia(structuredTrivia.GetTrailingTrivia()); + var newTrivia = Generator.Trivia(newDocComments); + updatedLeadingTrivia.Add(newTrivia); + } + + var extraNodeList = new List(); + while (index < permutedParamNodes.Count) + { + extraNodeList.Add(permutedParamNodes[index]); + index++; + } + + if (extraNodeList.Any()) + { + var extraDocComments = Generator.DocumentationCommentTrivia( + extraNodeList.AsEnumerable(), + node.GetTrailingTrivia(), + lastWhiteSpaceTrivia, + document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageName)); + + var newTrivia = Generator.Trivia(extraDocComments); + + updatedLeadingTrivia.Add(newTrivia); + } + + return updatedLeadingTrivia; + } } } diff --git a/src/Features/Core/Portable/ChangeSignature/CannotChangeSignatureReason.cs b/src/Features/Core/Portable/ChangeSignature/CannotChangeSignatureReason.cs index 6799c18bf6a3e..3c0f62535cb40 100644 --- a/src/Features/Core/Portable/ChangeSignature/CannotChangeSignatureReason.cs +++ b/src/Features/Core/Portable/ChangeSignature/CannotChangeSignatureReason.cs @@ -9,6 +9,7 @@ internal enum CannotChangeSignatureReason None, DefinedInMetadata, IncorrectKind, - InsufficientParameters + DeclarationLanguageServiceNotFound, + DeclarationMethodPositionNotFound, } } diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureAnalyzedContext.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureAnalyzedContext.cs index 99992c3438a11..8948dc1f86605 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureAnalyzedContext.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureAnalyzedContext.cs @@ -2,31 +2,39 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + namespace Microsoft.CodeAnalysis.ChangeSignature { - internal sealed class ChangeSignatureAnalyzedContext + internal abstract class ChangeSignatureAnalyzedContext { - public readonly bool CanChangeSignature; - public readonly Project Project; + } + + internal sealed class ChangeSignatureAnalyzedSucceedContext : ChangeSignatureAnalyzedContext + { + public readonly Document Document; public readonly ISymbol Symbol; - public readonly CannotChangeSignatureReason CannotChangeSignatureReason; public readonly ParameterConfiguration ParameterConfiguration; + public readonly int InsertPosition; - public Solution Solution => Project.Solution; + public Solution Solution => Document.Project.Solution; - public ChangeSignatureAnalyzedContext( - Project project, ISymbol symbol, ParameterConfiguration parameterConfiguration) + public ChangeSignatureAnalyzedSucceedContext( + Document document, int insertPosition, ISymbol symbol, ParameterConfiguration parameterConfiguration) { - CanChangeSignature = true; - Project = project; + Document = document; Symbol = symbol; ParameterConfiguration = parameterConfiguration; - CannotChangeSignatureReason = CannotChangeSignatureReason.None; + InsertPosition = insertPosition; } + } + + internal sealed class CannotChangeSignatureAnalyzedContext : ChangeSignatureAnalyzedContext + { + public readonly CannotChangeSignatureReason CannotChangeSignatureReason; - public ChangeSignatureAnalyzedContext(CannotChangeSignatureReason reason) + public CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason reason) { - CanChangeSignature = false; CannotChangeSignatureReason = reason; } } diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs index bdf6064073fb5..ce4c15f173f24 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs @@ -15,9 +15,9 @@ namespace Microsoft.CodeAnalysis.ChangeSignature internal class ChangeSignatureCodeAction : CodeActionWithOptions { private readonly AbstractChangeSignatureService _changeSignatureService; - private readonly ChangeSignatureAnalyzedContext _context; + private readonly ChangeSignatureAnalyzedSucceedContext _context; - public ChangeSignatureCodeAction(AbstractChangeSignatureService changeSignatureService, ChangeSignatureAnalyzedContext context) + public ChangeSignatureCodeAction(AbstractChangeSignatureService changeSignatureService, ChangeSignatureAnalyzedSucceedContext context) { _changeSignatureService = changeSignatureService; _context = context; @@ -27,18 +27,19 @@ public ChangeSignatureCodeAction(AbstractChangeSignatureService changeSignatureS public override object GetOptions(CancellationToken cancellationToken) { - return _changeSignatureService.GetChangeSignatureOptions(_context); + return _changeSignatureService.GetChangeSignatureOptions(_context) + ?? new ChangeSignatureOptionsResult(null!, false); } protected override Task> ComputeOperationsAsync(object options, CancellationToken cancellationToken) { - if (options is ChangeSignatureOptionsResult changeSignatureOptions && !changeSignatureOptions.IsCancelled) + if (options is ChangeSignatureOptionsResult changeSignatureOptions && changeSignatureOptions != null) { var changeSignatureResult = _changeSignatureService.ChangeSignatureWithContext(_context, changeSignatureOptions, cancellationToken); if (changeSignatureResult.Succeeded) { - return Task.FromResult(SpecializedCollections.SingletonEnumerable(new ApplyChangesOperation(changeSignatureResult.UpdatedSolution))); + return Task.FromResult(SpecializedCollections.SingletonEnumerable(new ApplyChangesOperation(changeSignatureResult.UpdatedSolution!))); } } diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureOptionsResult.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureOptionsResult.cs index 1a40277732621..7cd8110df05e8 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureOptionsResult.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureOptionsResult.cs @@ -2,12 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + namespace Microsoft.CodeAnalysis.ChangeSignature { internal sealed class ChangeSignatureOptionsResult { - public bool IsCancelled { get; set; } - public bool PreviewChanges { get; internal set; } - public SignatureChange UpdatedSignature { get; set; } + public readonly bool PreviewChanges; + public readonly SignatureChange UpdatedSignature; + + public ChangeSignatureOptionsResult(SignatureChange updatedSignature, bool previewChanges) + { + UpdatedSignature = updatedSignature; + PreviewChanges = previewChanges; + } } } diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureResult.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureResult.cs index 12429ccfa502e..2d180f2810218 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureResult.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureResult.cs @@ -2,17 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + namespace Microsoft.CodeAnalysis.ChangeSignature { internal sealed class ChangeSignatureResult { public bool Succeeded { get; } - public Solution UpdatedSolution { get; } - public string Name { get; } + public Solution? UpdatedSolution { get; } + public string? Name { get; } public Glyph? Glyph { get; } public bool PreviewChanges { get; } - public ChangeSignatureResult(bool succeeded, Solution updatedSolution = null, string name = null, Glyph? glyph = null, bool previewChanges = false) + public ChangeSignatureResult(bool succeeded, Solution? updatedSolution = null, string? name = null, Glyph? glyph = null, bool previewChanges = false) { Succeeded = succeeded; UpdatedSolution = updatedSolution; diff --git a/src/Features/Core/Portable/ChangeSignature/IChangeSignatureOptionsService.cs b/src/Features/Core/Portable/ChangeSignature/IChangeSignatureOptionsService.cs index 315e6950388a4..123aa6bdebfb5 100644 --- a/src/Features/Core/Portable/ChangeSignature/IChangeSignatureOptionsService.cs +++ b/src/Features/Core/Portable/ChangeSignature/IChangeSignatureOptionsService.cs @@ -2,12 +2,26 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.ChangeSignature { internal interface IChangeSignatureOptionsService : IWorkspaceService { - ChangeSignatureOptionsResult GetChangeSignatureOptions(ISymbol symbol, ParameterConfiguration parameters); + /// + /// Changes signature of the symbol (currently a method symbol or an event symbol) + /// + /// the context document + /// the position in the document with the signature of the method + /// the symbol for changing the signature + /// existing parameters of the symbol + /// + ChangeSignatureOptionsResult? GetChangeSignatureOptions( + Document document, + int insertPosition, + ISymbol symbol, + ParameterConfiguration parameters); } } diff --git a/src/Features/Core/Portable/ChangeSignature/Parameter.cs b/src/Features/Core/Portable/ChangeSignature/Parameter.cs new file mode 100644 index 0000000000000..9a8899d29f95c --- /dev/null +++ b/src/Features/Core/Portable/ChangeSignature/Parameter.cs @@ -0,0 +1,50 @@ +// 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 enable + +namespace Microsoft.CodeAnalysis.ChangeSignature +{ + internal abstract class Parameter + { + public abstract bool HasExplicitDefaultValue { get; } + public abstract string Name { get; } + } + + internal sealed class ExistingParameter : Parameter + { + public IParameterSymbol Symbol { get; } + + public ExistingParameter(IParameterSymbol param) + { + Symbol = param; + } + + public override bool HasExplicitDefaultValue => Symbol.HasExplicitDefaultValue; + public override string Name => Symbol.Name; + } + + internal sealed class AddedParameter : Parameter + { + public AddedParameter(ITypeSymbol type, string typeNameDisplayWithErrorIndicator, string parameter, string callSiteValue) + { + Type = type; + TypeNameDisplayWithErrorIndicator = typeNameDisplayWithErrorIndicator; + ParameterName = parameter; + CallSiteValue = callSiteValue; + } + + public ITypeSymbol Type { get; set; } + public string ParameterName { get; set; } + public string CallSiteValue { get; set; } + + public override bool HasExplicitDefaultValue => false; + public override string Name => ParameterName; + + public string TypeNameDisplayWithErrorIndicator { get; set; } + + // For test purposes: to display assert failure details in tests. + public override string ToString() => $"{Type.ToDisplayString(new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters))} {Name} ({CallSiteValue})"; + } +} diff --git a/src/Features/Core/Portable/ChangeSignature/ParameterConfiguration.cs b/src/Features/Core/Portable/ChangeSignature/ParameterConfiguration.cs index 8d8439625ad6f..d7bcf060f4dda 100644 --- a/src/Features/Core/Portable/ChangeSignature/ParameterConfiguration.cs +++ b/src/Features/Core/Portable/ChangeSignature/ParameterConfiguration.cs @@ -2,19 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; namespace Microsoft.CodeAnalysis.ChangeSignature { internal sealed class ParameterConfiguration { - public readonly IParameterSymbol ThisParameter; - public readonly List ParametersWithoutDefaultValues; - public readonly List RemainingEditableParameters; - public readonly IParameterSymbol ParamsParameter; + public readonly ExistingParameter? ThisParameter; + public readonly ImmutableArray ParametersWithoutDefaultValues; + public readonly ImmutableArray RemainingEditableParameters; + public readonly ExistingParameter? ParamsParameter; public readonly int SelectedIndex; - public ParameterConfiguration(IParameterSymbol thisParameter, List parametersWithoutDefaultValues, List remainingEditableParameters, IParameterSymbol paramsParameter, int selectedIndex) + public ParameterConfiguration( + ExistingParameter? thisParameter, + ImmutableArray parametersWithoutDefaultValues, + ImmutableArray remainingEditableParameters, + ExistingParameter? paramsParameter, + int selectedIndex) { ThisParameter = thisParameter; ParametersWithoutDefaultValues = parametersWithoutDefaultValues; @@ -23,42 +32,49 @@ public ParameterConfiguration(IParameterSymbol thisParameter, List parameters, bool isExtensionMethod, int selectedIndex) + public static ParameterConfiguration Create(IEnumerable parameters, bool isExtensionMethod, int selectedIndex) { - IParameterSymbol thisParameter = null; - var parametersWithoutDefaultValues = new List(); - var remainingReorderableParameters = new List(); - IParameterSymbol paramsParameter = null; + var parametersList = parameters.ToList(); + ExistingParameter? thisParameter = null; + var parametersWithoutDefaultValues = ImmutableArray.CreateBuilder(); + var remainingReorderableParameters = ImmutableArray.CreateBuilder(); + ExistingParameter? paramsParameter = null; - if (parameters.Count > 0 && isExtensionMethod) + if (parametersList.Count > 0 && isExtensionMethod) { - thisParameter = parameters[0]; - parameters.RemoveAt(0); + thisParameter = parametersList[0] as ExistingParameter; + parametersList.RemoveAt(0); } - if (parameters.Count > 0 && parameters[parameters.Count - 1].IsParams) + if (parametersList.Count > 0 && (parametersList[parametersList.Count - 1] as ExistingParameter)?.Symbol.IsParams == true) { - paramsParameter = parameters[parameters.Count - 1]; - parameters.RemoveAt(parameters.Count - 1); + paramsParameter = parametersList[parametersList.Count - 1] as ExistingParameter; + parametersList.RemoveAt(parametersList.Count - 1); } var seenDefaultValues = false; - foreach (var param in parameters) + foreach (var param in parametersList) { - if (param.HasExplicitDefaultValue) + if (param != null) { - seenDefaultValues = true; - } + if (param.HasExplicitDefaultValue) + { + seenDefaultValues = true; + } - (seenDefaultValues ? remainingReorderableParameters : parametersWithoutDefaultValues).Add(param); + (seenDefaultValues ? remainingReorderableParameters : parametersWithoutDefaultValues).Add(param); + } } - return new ParameterConfiguration(thisParameter, parametersWithoutDefaultValues, remainingReorderableParameters, paramsParameter, selectedIndex); + return new ParameterConfiguration(thisParameter, parametersWithoutDefaultValues.ToImmutable(), remainingReorderableParameters.ToImmutable(), paramsParameter, selectedIndex); } - public List ToListOfParameters() + internal ParameterConfiguration WithoutAddedParameters() + => Create(ToListOfParameters().OfType(), ThisParameter != null, selectedIndex: 0); + + public List ToListOfParameters() { - var list = new List(); + var list = new List(); if (ThisParameter != null) { @@ -75,10 +91,6 @@ public List ToListOfParameters() return list; } - - public bool IsChangeable() - { - return ParametersWithoutDefaultValues.Count > 0 || RemainingEditableParameters.Count > 0 || ParamsParameter != null; - } } } + diff --git a/src/Features/Core/Portable/ChangeSignature/SignatureChange.cs b/src/Features/Core/Portable/ChangeSignature/SignatureChange.cs index c78d3bb4402eb..e30053b4b3153 100644 --- a/src/Features/Core/Portable/ChangeSignature/SignatureChange.cs +++ b/src/Features/Core/Portable/ChangeSignature/SignatureChange.cs @@ -2,7 +2,9 @@ // 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.Collections.Generic; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.ChangeSignature { @@ -24,9 +26,18 @@ public SignatureChange(ParameterConfiguration originalConfiguration, ParameterCo for (var i = 0; i < originalParameterList.Count; i++) { + int? index = null; var parameter = originalParameterList[i]; - var updatedIndex = updatedParameterList.IndexOf(parameter); - _originalIndexToUpdatedIndexMap.Add(i, updatedIndex != -1 ? updatedIndex : (int?)null); + if (parameter is ExistingParameter existingParameter) + { + var updatedIndex = updatedParameterList.IndexOf(p => p is ExistingParameter ep && ep.Symbol == existingParameter.Symbol); + if (updatedIndex >= 0) + { + index = updatedIndex; + } + } + + _originalIndexToUpdatedIndexMap.Add(i, index); } } @@ -39,5 +50,8 @@ public SignatureChange(ParameterConfiguration originalConfiguration, ParameterCo return _originalIndexToUpdatedIndexMap[parameterIndex]; } + + internal SignatureChange WithoutAddedParameters() + => new SignatureChange(OriginalConfiguration, UpdatedConfiguration.WithoutAddedParameters()); } } diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index 9b30d5242c544..f1714fff75711 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -649,9 +649,6 @@ Do you want to continue? Remove qualification - - This signature does not contain parameters that can be changed. - Unknown error occurred diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index e8ffa2b5093af..9d68c3727ecde 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -1553,11 +1553,6 @@ Chcete pokračovat? Odebrat kvalifikaci - - This signature does not contain parameters that can be changed. - Tento podpis neobsahuje parametry, které by se daly změnit. - - Unknown error occurred Došlo k neznámé chybě. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index e78d4107bf0d9..9bd65975a4ee3 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -1553,11 +1553,6 @@ Möchten Sie fortfahren? Qualifizierung entfernen - - This signature does not contain parameters that can be changed. - Diese Signatur enthält keine Parameter, die geändert werden können. - - Unknown error occurred Unbekannter Fehler aufgetreten diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index f3bdec99b1952..c62c5f14a6676 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -1553,11 +1553,6 @@ Do you want to continue? Quitar cualificación - - This signature does not contain parameters that can be changed. - Esta firma no contiene parámetros que se puedan cambiar. - - Unknown error occurred Se ha producido un error desconocido diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 0b8745b56bbd8..c040df0908194 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -1553,11 +1553,6 @@ Voulez-vous continuer ? Supprimer une qualification - - This signature does not contain parameters that can be changed. - Cette signature ne contient pas de paramètres susceptibles d'être modifiés. - - Unknown error occurred Une erreur inconnue s'est produite diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index f6539db2b3074..b825e30e4d209 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -1553,11 +1553,6 @@ Continuare? Rimuovi qualificazione - - This signature does not contain parameters that can be changed. - Questa firma non contiene parametri modificabili. - - Unknown error occurred Si è verificato un errore sconosciuto diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index e6ab893266499..c02e718b78b01 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -1553,11 +1553,6 @@ Do you want to continue? 修飾子を削除 - - This signature does not contain parameters that can be changed. - この署名には、変更できるパラメーターが含まれていません。 - - Unknown error occurred 不明なエラーが発生しました diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index f684aab71c0ea..3c2fdec6135f8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -1553,11 +1553,6 @@ Do you want to continue? 한정자 제거 - - This signature does not contain parameters that can be changed. - 이 시그니처에는 변경할 수 있는 매개 변수가 포함되어 있지 않습니다. - - Unknown error occurred 알 수 없는 오류 발생 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 980e299847af1..d91dd7a0fe715 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -1553,11 +1553,6 @@ Czy chcesz kontynuować? Usuń kwalifikacje - - This signature does not contain parameters that can be changed. - Ta sygnatura nie zawiera parametrów, które można zmienić. - - Unknown error occurred Wystąpił nieznany błąd diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 1c637f5dc27b2..d9af9fa92e761 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -1553,11 +1553,6 @@ Deseja continuar? Remover qualificação - - This signature does not contain parameters that can be changed. - Esta assinatura não contêm parâmetros que podem ser alterados. - - Unknown error occurred Erro desconhecido diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 53e8c2fd75ff4..d902e515c9ab8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -1553,11 +1553,6 @@ Do you want to continue? Удалить квалификацию - - This signature does not contain parameters that can be changed. - Эта подпись не содержит параметры, которые можно изменить. - - Unknown error occurred Возникла неизвестная ошибка diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 8baf9644a0229..d20ea08ecc8bc 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -1553,11 +1553,6 @@ Devam etmek istiyor musunuz? Nitelemeyi kaldır - - This signature does not contain parameters that can be changed. - Bu imza değiştirilebilen parametreleri içermiyor. - - Unknown error occurred Bilinmeyen hata oluştu diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index 76f261f2424a0..f5d7deb631b26 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -1553,11 +1553,6 @@ Do you want to continue? 删除限定 - - This signature does not contain parameters that can be changed. - 此签名不含可更改的参数。 - - Unknown error occurred 发生未知错误 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 6b5a655accbff..401511764c0c2 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -1553,11 +1553,6 @@ Do you want to continue? 移除限定性條件 - - This signature does not contain parameters that can be changed. - 此簽章不包含可以變更的參數。 - - Unknown error occurred 發生不明錯誤 diff --git a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb index 793d07f94f95e..240759801625e 100644 --- a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb +++ b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb @@ -2,16 +2,20 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Immutable +Imports System.Composition Imports System.Threading +Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.ChangeSignature -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.FindSymbols -Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.Formatting +Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.PooledObjects -Imports System.Composition +Imports Microsoft.CodeAnalysis.Simplification +Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature @@ -78,6 +82,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature SyntaxKind.SubNewStatement, SyntaxKind.ConstructorBlock) + Dim s_createNewParameterSyntaxDelegate As Func(Of AddedParameter, ParameterSyntax) = AddressOf CreateNewParameterSyntax + Dim s_createNewCrefParameterSyntaxDelegate As Func(Of AddedParameter, CrefSignaturePartSyntax) = AddressOf CreateNewCrefParameterSyntax + Public Sub New() End Sub @@ -128,6 +135,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return (If(symbolInfo.Symbol, symbolInfo.CandidateSymbols.FirstOrDefault()), 0) End Function + Protected Overrides Function TryGetInsertPositionFromDeclaration(matchingNode As SyntaxNode) As Integer? + Dim parameters = matchingNode.ChildNodes().OfType(Of ParameterListSyntax)().SingleOrDefault() + + If parameters Is Nothing Then + Return Nothing + End If + + Return parameters.CloseParenToken.SpanStart + End Function + Private Function TryGetSelectedIndexFromDeclaration(position As Integer, matchingNode As SyntaxNode) As Integer Dim parameters = matchingNode.ChildNodes().OfType(Of ParameterListSyntax)().SingleOrDefault() Return If(parameters Is Nothing, 0, GetParameterIndex(parameters.Parameters, position)) @@ -251,13 +268,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return matchingNode End Function - Public Overrides Function ChangeSignature(document As Document, declarationSymbol As ISymbol, potentiallyUpdatedNode As SyntaxNode, originalNode As SyntaxNode, updatedSignature As SignatureChange, cancellationToken As CancellationToken) As SyntaxNode + Public Overrides Async Function ChangeSignatureAsync(document As Document, declarationSymbol As ISymbol, potentiallyUpdatedNode As SyntaxNode, originalNode As SyntaxNode, updatedSignature As SignatureChange, cancellationToken As CancellationToken) As Task(Of SyntaxNode) Dim vbnode = DirectCast(potentiallyUpdatedNode, VisualBasicSyntaxNode) - - If Not declarationSymbol.GetParameters().Any() Then - Return vbnode - End If - If vbnode.IsKind(SyntaxKind.SubStatement) OrElse vbnode.IsKind(SyntaxKind.FunctionStatement) OrElse vbnode.IsKind(SyntaxKind.SubNewStatement) OrElse @@ -268,7 +280,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature vbnode.IsKind(SyntaxKind.EventBlock) OrElse vbnode.IsKind(SyntaxKind.EventStatement) Then - Dim updatedLeadingTrivia = UpdateParamNodesInLeadingTrivia(vbnode, declarationSymbol, updatedSignature) + Dim updatedLeadingTrivia = UpdateParamNodesInLeadingTrivia(document, vbnode, declarationSymbol, updatedSignature) If updatedLeadingTrivia IsNot Nothing Then vbnode = vbnode.WithLeadingTrivia(updatedLeadingTrivia) End If @@ -276,7 +288,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If vbnode.IsKind(SyntaxKind.SubStatement) OrElse vbnode.IsKind(SyntaxKind.FunctionStatement) Then Dim method = DirectCast(vbnode, MethodStatementSyntax) - Dim updatedParameters = PermuteDeclaration(method.ParameterList.Parameters, updatedSignature) + Dim updatedParameters = UpdateDeclaration(method.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Return method.WithParameterList(method.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If @@ -284,7 +296,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Dim eventStatement = DirectCast(vbnode, EventStatementSyntax) If eventStatement.ParameterList IsNot Nothing Then - Dim updatedParameters = PermuteDeclaration(eventStatement.ParameterList.Parameters, updatedSignature) + Dim updatedParameters = UpdateDeclaration(eventStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) eventStatement = eventStatement.WithParameterList(eventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If @@ -295,14 +307,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Dim eventBlock = DirectCast(vbnode, EventBlockSyntax) If eventBlock.EventStatement.ParameterList IsNot Nothing Then - Dim updatedParameters = PermuteDeclaration(eventBlock.EventStatement.ParameterList.Parameters, updatedSignature) + Dim updatedParameters = UpdateDeclaration(eventBlock.EventStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Return eventBlock.WithEventStatement(eventBlock.EventStatement.WithParameterList(eventBlock.EventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))) End If Dim raiseEventAccessor = eventBlock.Accessors.FirstOrDefault(Function(a) a.IsKind(SyntaxKind.RaiseEventAccessorBlock)) If raiseEventAccessor IsNot Nothing Then If raiseEventAccessor.BlockStatement.ParameterList IsNot Nothing Then - Dim updatedParameters = PermuteDeclaration(raiseEventAccessor.BlockStatement.ParameterList.Parameters, updatedSignature) + Dim updatedParameters = UpdateDeclaration(raiseEventAccessor.BlockStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Dim updatedRaiseEventAccessor = raiseEventAccessor.WithAccessorStatement(raiseEventAccessor.AccessorStatement.WithParameterList(raiseEventAccessor.AccessorStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))) eventBlock = eventBlock.WithAccessors(eventBlock.Accessors.Remove(raiseEventAccessor).Add(updatedRaiseEventAccessor)) End If @@ -313,13 +325,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If vbnode.IsKind(SyntaxKind.RaiseEventStatement) Then Dim raiseEventStatement = DirectCast(vbnode, RaiseEventStatementSyntax) - Dim updatedArguments = PermuteArgumentList(raiseEventStatement.ArgumentList.Arguments, updatedSignature, document, declarationSymbol) + Dim updatedArguments = PermuteArgumentList(raiseEventStatement.ArgumentList.Arguments, updatedSignature, declarationSymbol) Return raiseEventStatement.WithArgumentList(raiseEventStatement.ArgumentList.WithArguments(updatedArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.InvocationExpression) Then Dim invocation = DirectCast(vbnode, InvocationExpressionSyntax) - Dim semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken) + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) Dim isReducedExtensionMethod = False Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, InvocationExpressionSyntax)) @@ -328,31 +340,42 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature isReducedExtensionMethod = True End If - Dim newArguments = PermuteArgumentList(invocation.ArgumentList.Arguments, updatedSignature, document, declarationSymbol, isReducedExtensionMethod) + Dim newArguments = PermuteArgumentList(invocation.ArgumentList.Arguments, updatedSignature.WithoutAddedParameters(), declarationSymbol, isReducedExtensionMethod) + newArguments = AddNewArgumentsToList(newArguments, updatedSignature, isReducedExtensionMethod) Return invocation.WithArgumentList(invocation.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.SubNewStatement) Then Dim constructor = DirectCast(vbnode, SubNewStatementSyntax) - Dim newParameters = PermuteDeclaration(constructor.ParameterList.Parameters, updatedSignature) + Dim newParameters = UpdateDeclaration(constructor.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Return constructor.WithParameterList(constructor.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.Attribute) Then Dim attribute = DirectCast(vbnode, AttributeSyntax) - Dim newArguments = PermuteArgumentList(attribute.ArgumentList.Arguments, updatedSignature, document, declarationSymbol) + Dim newArguments = PermuteArgumentList(attribute.ArgumentList.Arguments, updatedSignature, declarationSymbol) Return attribute.WithArgumentList(attribute.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.ObjectCreationExpression) Then Dim objectCreation = DirectCast(vbnode, ObjectCreationExpressionSyntax) - Dim newArguments = PermuteArgumentList(objectCreation.ArgumentList.Arguments, updatedSignature, document, declarationSymbol) + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) + + Dim isReducedExtensionMethod = False + Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, ObjectCreationExpressionSyntax)) + Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol) + If methodSymbol IsNot Nothing AndAlso methodSymbol.MethodKind = MethodKind.ReducedExtension Then + isReducedExtensionMethod = True + End If + + Dim newArguments = PermuteArgumentList(objectCreation.ArgumentList.Arguments, updatedSignature.WithoutAddedParameters(), declarationSymbol, isReducedExtensionMethod) + newArguments = AddNewArgumentsToList(newArguments, updatedSignature, isReducedExtensionMethod) Return objectCreation.WithArgumentList(objectCreation.ArgumentList.WithArguments(newArguments).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If If vbnode.IsKind(SyntaxKind.PropertyStatement) Then Dim propertyStatement = DirectCast(vbnode, PropertyStatementSyntax) - Dim newParameters = PermuteDeclaration(propertyStatement.ParameterList.Parameters, updatedSignature) + Dim newParameters = UpdateDeclaration(propertyStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Return propertyStatement.WithParameterList(propertyStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If @@ -364,7 +387,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return crefReference End If - Dim newParameters = PermuteDeclaration(crefReference.Signature.ArgumentTypes, updatedSignature) + Dim newParameters = UpdateDeclaration(crefReference.Signature.ArgumentTypes, updatedSignature, s_createNewCrefParameterSyntaxDelegate) Return crefReference.WithSignature(crefReference.Signature.WithArgumentTypes(newParameters)) End If @@ -377,7 +400,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return vbnode End If - Dim newParameters = PermuteDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature) + Dim newParameters = UpdateDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) Return lambda.WithSubOrFunctionHeader(newBegin) End If @@ -391,7 +414,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return vbnode End If - Dim newParameters = PermuteDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature) + Dim newParameters = UpdateDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) Return lambda.WithSubOrFunctionHeader(newBegin) End If @@ -399,7 +422,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If vbnode.IsKind(SyntaxKind.DelegateSubStatement) OrElse vbnode.IsKind(SyntaxKind.DelegateFunctionStatement) Then Dim delegateStatement = DirectCast(vbnode, DelegateStatementSyntax) - Dim newParameters = PermuteDeclaration(delegateStatement.ParameterList.Parameters, updatedSignature) + Dim newParameters = UpdateDeclaration(delegateStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate) Return delegateStatement.WithParameterList(delegateStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)) End If @@ -409,32 +432,55 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Private Function PermuteArgumentList( arguments As SeparatedSyntaxList(Of ArgumentSyntax), permutedSignature As SignatureChange, - document As Document, declarationSymbol As ISymbol, Optional isReducedExtensionMethod As Boolean = False) As SeparatedSyntaxList(Of ArgumentSyntax) - Dim newArguments As List(Of IUnifiedArgumentSyntax) = MyBase.PermuteArguments(document, declarationSymbol, arguments.Select(Function(a) UnifiedArgumentSyntax.Create(a)).ToList(), permutedSignature, isReducedExtensionMethod) + Dim newArguments As List(Of IUnifiedArgumentSyntax) = MyBase.PermuteArguments( + declarationSymbol, arguments.Select(Function(a) UnifiedArgumentSyntax.Create(a)).ToList(), permutedSignature, + Function(callSiteValue) UnifiedArgumentSyntax.Create(SyntaxFactory.SimpleArgument(SyntaxFactory.ParseExpression(callSiteValue))), + isReducedExtensionMethod) + + Dim numSeparatorsToSkip As Integer + If arguments.Count = 0 Then + ' () + ' Adding X parameters, need to add X-1 separators. + numSeparatorsToSkip = arguments.Count - newArguments.Count + 1 + Else + ' (a,b,c) + ' Adding X parameters, need to add X separators. + numSeparatorsToSkip = arguments.Count - newArguments.Count + End If - Dim numSeparatorsToSkip = arguments.Count - newArguments.Count Return SyntaxFactory.SeparatedList(newArguments.Select(Function(a) CType(DirectCast(a, UnifiedArgumentSyntax), ArgumentSyntax)), GetSeparators(arguments, numSeparatorsToSkip)) End Function - Private Function PermuteDeclaration(Of T As SyntaxNode)(list As SeparatedSyntaxList(Of T), updatedSignature As SignatureChange) As SeparatedSyntaxList(Of T) - Dim originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters() - Dim reorderedParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters() + Private Function UpdateDeclaration(Of T As SyntaxNode)( + parameterList As SeparatedSyntaxList(Of T), + updatedSignature As SignatureChange, + createNewParameterMethod As Func(Of AddedParameter, T)) As SeparatedSyntaxList(Of T) + Dim updatedDeclaration = UpdateDeclarationBase(parameterList, updatedSignature, createNewParameterMethod) + Return SyntaxFactory.SeparatedList(updatedDeclaration.parameters, updatedDeclaration.separators) + End Function - Dim newParameters = New List(Of T) - For Each newParam In reorderedParameters - Dim pos = originalParameters.IndexOf(newParam) - Dim param = list(pos) - newParameters.Add(param) - Next + Private Shared Function CreateNewParameterSyntax(addedParameter As AddedParameter) As ParameterSyntax + Return SyntaxFactory.Parameter( + attributeLists:=SyntaxFactory.List(Of AttributeListSyntax)(), + modifiers:=SyntaxFactory.TokenList(), + identifier:=SyntaxFactory.ModifiedIdentifier(addedParameter.ParameterName), + asClause:=SyntaxFactory.SimpleAsClause( + addedParameter.Type.GenerateTypeSyntax() _ + .WithPrependedLeadingTrivia(SyntaxFactory.ElasticSpace)) _ + .WithPrependedLeadingTrivia(SyntaxFactory.ElasticSpace), + [default]:=Nothing) + End Function - Dim numSeparatorsToSkip = originalParameters.Count - reorderedParameters.Count - Return SyntaxFactory.SeparatedList(newParameters, GetSeparators(list, numSeparatorsToSkip)) + Private Shared Function CreateNewCrefParameterSyntax(addedParameter As AddedParameter) As CrefSignaturePartSyntax + Return SyntaxFactory.CrefSignaturePart( + modifier:=Nothing, + type:=addedParameter.Type.GenerateTypeSyntax()) End Function - Private Function UpdateParamNodesInLeadingTrivia(node As VisualBasicSyntaxNode, declarationSymbol As ISymbol, updatedSignature As SignatureChange) As List(Of SyntaxTrivia) + Private Function UpdateParamNodesInLeadingTrivia(document As Document, node As VisualBasicSyntaxNode, declarationSymbol As ISymbol, updatedSignature As SignatureChange) As List(Of SyntaxTrivia) If Not node.HasLeadingTrivia Then Return Nothing End If @@ -444,16 +490,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature .OfType(Of XmlElementSyntax)() _ .Where(Function(e) e.StartTag.Name.ToString() = DocumentationCommentXmlNames.ParameterElementName) - Dim permutedParamNodes = VerifyAndPermuteParamNodes(paramNodes, declarationSymbol, updatedSignature) + Dim permutedParamNodes As List(Of SyntaxNode) = VerifyAndPermuteParamNodes(paramNodes, declarationSymbol, updatedSignature) If permutedParamNodes Is Nothing Then ' Something is wrong with the tags, so don't change anything. Return Nothing End If - Return GetPermutedTrivia(node, permutedParamNodes) + Return GetPermutedTrivia(document, node, permutedParamNodes) End Function - Private Function VerifyAndPermuteParamNodes(paramNodes As IEnumerable(Of XmlElementSyntax), declarationSymbol As ISymbol, updatedSignature As SignatureChange) As List(Of XmlElementSyntax) + Private Function VerifyAndPermuteParamNodes(paramNodes As IEnumerable(Of XmlElementSyntax), declarationSymbol As ISymbol, updatedSignature As SignatureChange) As List(Of SyntaxNode) ' Only reorder if count and order match originally. Dim originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters() @@ -464,6 +510,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Return Nothing End If + If declaredParameters.Length = 0 Then + Return Nothing + End If + Dim dictionary = New Dictionary(Of String, XmlElementSyntax)() Dim i = 0 For Each paramNode In paramNodes @@ -482,72 +532,21 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Next ' Everything lines up, so permute them. - - Dim permutedParams = New List(Of XmlElementSyntax)() - + Dim permutedParams = New List(Of SyntaxNode)() For Each parameter In reorderedParameters - permutedParams.Add(dictionary(parameter.Name)) - Next - - Return permutedParams - End Function - - Private Function GetPermutedTrivia(node As VisualBasicSyntaxNode, permutedParamNodes As List(Of XmlElementSyntax)) As List(Of SyntaxTrivia) - Dim updatedLeadingTrivia = New List(Of SyntaxTrivia)() - Dim index = 0 - - For Each trivia In node.GetLeadingTrivia() - If Not trivia.HasStructure Then - - updatedLeadingTrivia.Add(trivia) - Continue For - End If - - Dim structuredTrivia = TryCast(trivia.GetStructure(), DocumentationCommentTriviaSyntax) - If structuredTrivia Is Nothing Then - updatedLeadingTrivia.Add(trivia) - Continue For + Dim permutedParam As XmlElementSyntax = Nothing + If dictionary.TryGetValue(parameter.Name, permutedParam) Then + permutedParams.Add(permutedParam) + Else + permutedParams.Add(SyntaxFactory.XmlElement( + SyntaxFactory.XmlElementStartTag( + SyntaxFactory.XmlName(Nothing, SyntaxFactory.XmlNameToken(DocumentationCommentXmlNames.ParameterElementName, SyntaxKind.XmlNameToken)), + SyntaxFactory.List(Of XmlNodeSyntax)({SyntaxFactory.XmlNameAttribute(parameter.Name)})), + SyntaxFactory.XmlElementEndTag(SyntaxFactory.XmlName(Nothing, SyntaxFactory.XmlNameToken(DocumentationCommentXmlNames.ParameterElementName, SyntaxKind.XmlNameToken))))) End If - - Dim updatedNodeList = New List(Of XmlNodeSyntax)() - For Each content In structuredTrivia.Content - If Not content.IsKind(SyntaxKind.XmlElement) Then - updatedNodeList.Add(content) - Continue For - End If - - Dim xmlElement = DirectCast(content, XmlElementSyntax) - If xmlElement.StartTag.Name.ToString() <> DocumentationCommentXmlNames.ParameterElementName Then - updatedNodeList.Add(content) - Continue For - End If - - ' Found a param tag, so insert the next one from the reordered list. - If index < permutedParamNodes.Count Then - updatedNodeList.Add(permutedParamNodes(index).WithLeadingTrivia(content.GetLeadingTrivia()).WithTrailingTrivia(content.GetTrailingTrivia())) - index += 1 - Else - ' Inspecting a param element that we are deleting but not replacing. - End If - Next - - Dim newDocComments = SyntaxFactory.DocumentationCommentTrivia(SyntaxFactory.List(updatedNodeList.AsEnumerable())) - newDocComments = newDocComments.WithLeadingTrivia(structuredTrivia.GetLeadingTrivia()).WithTrailingTrivia(structuredTrivia.GetTrailingTrivia()) - Dim newTrivia = SyntaxFactory.Trivia(newDocComments) - - updatedLeadingTrivia.Add(newTrivia) - Next - - Return updatedLeadingTrivia - End Function - - Private Shared Function GetSeparators(Of T As SyntaxNode)(arguments As SeparatedSyntaxList(Of T), Optional numSeparatorsToSkip As Integer = 0) As List(Of SyntaxToken) - Dim separators = New List(Of SyntaxToken) - For i = 0 To arguments.SeparatorCount - 1 - numSeparatorsToSkip - separators.Add(arguments.GetSeparator(i)) Next - Return separators + Return permutedParams End Function Public Overrides Async Function DetermineCascadedSymbolsFromDelegateInvokeAsync( @@ -606,8 +605,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature End Function Protected Overrides Function GetFormattingRules(document As Document) As IEnumerable(Of AbstractFormattingRule) - Return SpecializedCollections.SingletonEnumerable(Of AbstractFormattingRule)(New ChangeSignatureFormattingRule()). - Concat(Formatter.GetDefaultFormattingRules(document)) + Return SpecializedCollections.SingletonEnumerable(Of AbstractFormattingRule)(New ChangeSignatureFormattingRule()).Concat(Formatter.GetDefaultFormattingRules(document)) + End Function + + Protected Overrides Function TransferLeadingWhitespaceTrivia(Of T As SyntaxNode)(newArgument As T, oldArgument As SyntaxNode) As T + Return newArgument End Function + + Protected Overrides ReadOnly Property Generator As SyntaxGenerator + Get + Return VisualBasicSyntaxGenerator.Instance + End Get + End Property + + + Protected Overrides ReadOnly Property LanguageName As String + Get + Return LanguageNames.VisualBasic + End Get + End Property + End Class End Namespace diff --git a/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs new file mode 100644 index 0000000000000..1c9f3a0414db2 --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs @@ -0,0 +1,34 @@ +// 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.Composition; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature; +using static Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.ChangeSignatureDialogViewModel; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.ChangeSignature +{ + [ExportLanguageService(typeof(IChangeSignatureViewModelFactoryService), LanguageNames.CSharp), Shared] + internal class CSharpChangeSignatureViewModelFactoryService : ChangeSignatureViewModelFactoryService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpChangeSignatureViewModelFactoryService() + { + } + + public override SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel) + => new[] { + new SymbolDisplayPart(SymbolDisplayPartKind.Keyword, null, addedParameterViewModel.Type), + new SymbolDisplayPart(SymbolDisplayPartKind.Space, null, " "), + new SymbolDisplayPart(SymbolDisplayPartKind.ParameterName, null, addedParameterViewModel.ParameterName)}; + + public override bool IsTypeNameValid(string typeName) => !SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics; + + public override SyntaxNode GetTypeNode(string typeName) => SyntaxFactory.ParseTypeName(typeName); + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialog.xaml b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialog.xaml new file mode 100644 index 0000000000000..73dd173c0e8e2 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialog.xaml @@ -0,0 +1,65 @@ + + + 9,2,9,2 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialog.xaml.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialog.xaml.cs new file mode 100644 index 0000000000000..4f1d594ac44cc --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialog.xaml.cs @@ -0,0 +1,84 @@ +// 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 enable + +using System.Windows; +using Microsoft.VisualStudio.PlatformUI; +using Microsoft.CodeAnalysis; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature +{ + /// + /// Interaction logic for AddParameterDialog.xaml + /// + internal partial class AddParameterDialog : DialogWindow + { + private readonly AddParameterDialogViewModel _viewModel; + private readonly Document _document; + + public string OK { get { return ServicesVSResources.OK; } } + public string Cancel { get { return ServicesVSResources.Cancel; } } + + public string TypeNameLabel { get { return ServicesVSResources.Type_Name; } } + + public string ParameterNameLabel { get { return ServicesVSResources.Parameter_Name; } } + + public string CallSiteValueLabel { get { return ServicesVSResources.Call_site_value; } } + + public string AddParameterDialogTitle { get { return ServicesVSResources.Add_Parameter; } } + + public AddParameterDialog(AddParameterDialogViewModel viewModel) + { + // The current implementation supports Add only. + // The dialog should be initialized the other way if called for Edit. + _viewModel = viewModel; + _document = viewModel.Document; + this.Loaded += AddParameterDialog_Loaded; + DataContext = _viewModel; + + InitializeComponent(); + } + + private void AddParameterDialog_Loaded(object sender, RoutedEventArgs e) + { + MinHeight = Height; + TypeContentControl.Focus(); + } + + private void OK_Click(object sender, RoutedEventArgs e) + { + _viewModel.ParameterName = NameContentControl.Text; + _viewModel.CallSiteValue = CallSiteValueTextBox.Text; + _viewModel.UpdateTypeSymbol(TypeContentControl.Text); + + if (_viewModel.TrySubmit(_document)) + { + DialogResult = true; + } + } + + private void Cancel_Click(object sender, RoutedEventArgs e) + { + DialogResult = false; + } + + internal TestAccessor GetTestAccessor() + => new TestAccessor(this); + + internal readonly struct TestAccessor + { + private readonly AddParameterDialog _dialog; + + public TestAccessor(AddParameterDialog dialog) + { + _dialog = dialog; + } + + public DialogButton OKButton => _dialog.OKButton; + + public DialogButton CancelButton => _dialog.CancelButton; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs new file mode 100644 index 0000000000000..89305db8d9aae --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs @@ -0,0 +1,109 @@ +// 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 enable + +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature +{ + internal class AddParameterDialogViewModel : AbstractNotifyPropertyChanged + { + private readonly INotificationService? _notificationService; + + public readonly Document Document; + public readonly int InsertPosition; + + private readonly SemanticModel _semanticModel; + + public AddParameterDialogViewModel(Document document, int insertPosition) + { + _notificationService = document.Project.Solution.Workspace.Services.GetService(); + _semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); + + Document = document; + InsertPosition = insertPosition; + ParameterName = string.Empty; + CallSiteValue = string.Empty; + } + + public string ParameterName { get; set; } + + public string CallSiteValue { get; set; } + + private string TypeNameWithoutErrorIndicator + { + get + { + return TypeSymbol!.ToDisplayString(); + } + } + + private SymbolDisplayFormat _symbolDisplayFormat = new SymbolDisplayFormat( + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + + public ITypeSymbol? TypeSymbol { get; set; } + + public string TypeName + { + get + { + return (TypeSymbol!.IsErrorType() ? "(x) " : "") + TypeSymbol!.ToDisplayString(_symbolDisplayFormat); + } + } + + internal void UpdateTypeSymbol(string typeName) + { + var languageService = Document.GetRequiredLanguageService(); + TypeSymbol = _semanticModel.GetSpeculativeTypeInfo(InsertPosition, languageService.GetTypeNode(typeName), SpeculativeBindingOption.BindAsTypeOrNamespace).Type; + } + + internal bool TrySubmit(Document document) + { + if (string.IsNullOrEmpty(ParameterName) || string.IsNullOrEmpty(TypeNameWithoutErrorIndicator)) + { + SendFailureNotification(ServicesVSResources.A_type_and_name_must_be_provided); + return false; + } + + if (!IsParameterTypeValid(TypeNameWithoutErrorIndicator, document)) + { + SendFailureNotification(ServicesVSResources.Parameter_type_contains_invalid_characters); + return false; + } + + if (!IsParameterNameValid(ParameterName, document)) + { + SendFailureNotification(ServicesVSResources.Parameter_name_contains_invalid_characters); + return false; + } + + return true; + } + + private void SendFailureNotification(string message) + { + _notificationService?.SendNotification(message, severity: NotificationSeverity.Information); + } + + private bool IsParameterTypeValid(string typeName, Document document) + { + var languageService = document.GetRequiredLanguageService(); + return languageService.IsTypeNameValid(typeName); + } + + private bool IsParameterNameValid(string identifierName, Document document) + { + var languageService = document.GetRequiredLanguageService(); + return languageService.IsValidIdentifier(identifierName); + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialog.xaml b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialog.xaml index d75e3b6cb8220..e0dcae21e7862 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialog.xaml +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialog.xaml @@ -9,8 +9,8 @@ xmlns:imagecatalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog" xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" xmlns:imagingPlatformUI="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Imaging" - Height="420" Width="560" - MinHeight="420" MinWidth="560" + Height="470" Width="560" + MinHeight="470" MinWidth="560" Title="{Binding ElementName=dialog, Path=ChangeSignatureDialogTitle}" HasHelpButton="True" ResizeMode="CanResizeWithGrip" @@ -61,7 +61,7 @@ - + @@ -109,7 +109,7 @@ + + + + + - + + + + + + @@ -263,22 +277,27 @@ Width="16" Moniker="{x:Static imagecatalog:KnownMonikers.MoveDown}" Grayscale="{Binding IsEnabled, ElementName=DownButton, Converter={StaticResource NegateBooleanConverter}}"/> - + - - + Height="Auto" Width="Auto"/> - /// Interaction logic for ExtractInterfaceDialog.xaml + /// Interaction logic for ChangeSignatureDialog.xaml /// internal partial class ChangeSignatureDialog : DialogWindow { @@ -25,6 +26,7 @@ internal partial class ChangeSignatureDialog : DialogWindow public string PreviewReferenceChanges { get { return ServicesVSResources.Preview_reference_changes; } } public string Remove { get { return ServicesVSResources.Re_move; } } public string Restore { get { return ServicesVSResources.Restore; } } + public string Add { get { return ServicesVSResources.Add; } } public string OK { get { return ServicesVSResources.OK; } } public string Cancel { get { return ServicesVSResources.Cancel; } } @@ -48,6 +50,8 @@ internal ChangeSignatureDialog(ChangeSignatureDialogViewModel viewModel) defaultHeader.Header = ServicesVSResources.Default_; typeHeader.Header = ServicesVSResources.Type; parameterHeader.Header = ServicesVSResources.Parameter; + callsiteHeader.Header = ServicesVSResources.Callsite; + indexHeader.Header = ServicesVSResources.Index; ParameterText = SystemParameters.HighContrast ? SystemColors.WindowTextBrush : new SolidColorBrush(Color.FromArgb(0xFF, 0x1E, 0x1E, 0x1E)); RemovedParameterText = SystemParameters.HighContrast ? SystemColors.WindowTextBrush : new SolidColorBrush(Colors.Gray); @@ -127,6 +131,28 @@ private void Restore_Click(object sender, RoutedEventArgs e) SetFocusToSelectedRow(); } + private void Add_Click(object sender, RoutedEventArgs e) + { + var addParameterViewModel = _viewModel.CreateAddParameterDialogViewModel(); + var dialog = new AddParameterDialog(addParameterViewModel); + var result = dialog.ShowModal(); + + if (result.HasValue && result.Value) + { + var addedParameter = new AddedParameter( + addParameterViewModel.TypeSymbol, + addParameterViewModel.TypeName, + addParameterViewModel.ParameterName, + string.IsNullOrWhiteSpace(addParameterViewModel.CallSiteValue) + ? ServicesVSResources.ChangeSignature_NewParameterIntroduceTODOVariable + : addParameterViewModel.CallSiteValue); + + _viewModel.AddParameter(addedParameter); + } + + SetFocusToSelectedRow(); + } + private void SetFocusToSelectedRow() { if (Members.SelectedIndex >= 0) @@ -228,6 +254,8 @@ public TestAccessor(ChangeSignatureDialog dialog) public DialogButton UpButton => _dialog.UpButton; + public DialogButton AddButton => _dialog.AddButton; + public DialogButton RemoveButton => _dialog.RemoveButton; public DialogButton RestoreButton => _dialog.RestoreButton; diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.cs index 2bf2fac4c827d..a81cc4af6ed3d 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.cs @@ -2,6 +2,7 @@ // 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.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -11,6 +12,8 @@ using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.Text.Classification; using Roslyn.Utilities; @@ -21,45 +24,112 @@ internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged { private readonly IClassificationFormatMap _classificationFormatMap; private readonly ClassificationTypeMap _classificationTypeMap; + private readonly INotificationService _notificationService; private readonly ParameterConfiguration _originalParameterConfiguration; - private readonly ParameterViewModel _thisParameter; - private readonly List _parameterGroup1; - private readonly List _parameterGroup2; - private readonly ParameterViewModel _paramsParameter; - private readonly HashSet _disabledParameters = new HashSet(); + // This can be changed to ParameterViewModel if we will allow adding 'this' parameter. + private readonly ExistingParameterViewModel _thisParameter; + private readonly List _parametersWithoutDefaultValues; + private readonly List _parametersWithDefaultValues; + + // This can be changed to ParameterViewModel if we will allow adding 'params' parameter. + private readonly ExistingParameterViewModel _paramsParameter; + private HashSet _disabledParameters = new HashSet(); + private readonly int _insertPosition; + private ImmutableArray _declarationParts; private bool _previewChanges; - internal ChangeSignatureDialogViewModel(ParameterConfiguration parameters, ISymbol symbol, IClassificationFormatMap classificationFormatMap, ClassificationTypeMap classificationTypeMap) + /// + /// The document where the symbol we are changing signature is defined. + /// + private readonly Document _document; + + internal ChangeSignatureDialogViewModel( + ParameterConfiguration parameters, + ISymbol symbol, + Document document, + int insertPosition, + IClassificationFormatMap classificationFormatMap, + ClassificationTypeMap classificationTypeMap) { _originalParameterConfiguration = parameters; + _document = document; + _insertPosition = insertPosition; _classificationFormatMap = classificationFormatMap; _classificationTypeMap = classificationTypeMap; + _notificationService = document.Project.Solution.Workspace.Services.GetService(); + + // This index is displayed to users. That is why we start it from 1. + var initialDisplayIndex = 1; + if (parameters.ThisParameter != null) { - _thisParameter = new ParameterViewModel(this, parameters.ThisParameter); - _disabledParameters.Add(parameters.ThisParameter); + _thisParameter = new ExistingParameterViewModel(this, parameters.ThisParameter, initialDisplayIndex++); + _disabledParameters.Add(_thisParameter); } + _declarationParts = symbol.ToDisplayParts(s_symbolDeclarationDisplayFormat); + + _parametersWithoutDefaultValues = CreateParameterViewModels(parameters.ParametersWithoutDefaultValues, ref initialDisplayIndex); + _parametersWithDefaultValues = CreateParameterViewModels(parameters.RemainingEditableParameters, ref initialDisplayIndex); + if (parameters.ParamsParameter != null) { - _paramsParameter = new ParameterViewModel(this, parameters.ParamsParameter); + _paramsParameter = new ExistingParameterViewModel(this, parameters.ParamsParameter, initialDisplayIndex++); } - _declarationParts = symbol.ToDisplayParts(s_symbolDeclarationDisplayFormat); + var selectedIndex = parameters.SelectedIndex; + // Currently, we do not support editing the ThisParameter. + // Therefore, if there is such parameter, we should move the selectedIndex. + if (parameters.ThisParameter != null && selectedIndex == 0) + { + // If we have at least one paramter after the ThisParameter, select the first one after This. + // Otherwise, do not select anything. + if (parameters.ParametersWithoutDefaultValues.Length + parameters.RemainingEditableParameters.Length > 0) + { + this.SelectedIndex = 1; + } + else + { + this.SelectedIndex = null; + } + } + else + { + this.SelectedIndex = selectedIndex; + } + } - _parameterGroup1 = parameters.ParametersWithoutDefaultValues.Select(p => new ParameterViewModel(this, p)).ToList(); - _parameterGroup2 = parameters.RemainingEditableParameters.Select(p => new ParameterViewModel(this, p)).ToList(); + public AddParameterDialogViewModel CreateAddParameterDialogViewModel() + => new AddParameterDialogViewModel(_document, _insertPosition); - var selectedIndex = parameters.SelectedIndex; - this.SelectedIndex = (parameters.ThisParameter != null && selectedIndex == 0) ? 1 : selectedIndex; + List CreateParameterViewModels(ImmutableArray parameters, ref int initialIndex) + { + var list = new List(); + foreach (ExistingParameter existingParameter in parameters) + { + list.Add(new ExistingParameterViewModel(this, existingParameter, initialIndex)); + initialIndex++; + } + + return list; } public int GetStartingSelectionIndex() { - return _thisParameter == null ? 0 : 1; + if (_thisParameter == null) + { + return 0; + } + + if (_parametersWithDefaultValues.Count + _parametersWithoutDefaultValues.Count > 0) + { + return 1; + } + + return -1; } public bool PreviewChanges @@ -79,6 +149,11 @@ public bool CanRemove { get { + if (!AllParameters.Any()) + { + return false; + } + if (!SelectedIndex.HasValue) { return false; @@ -91,8 +166,6 @@ public bool CanRemove return false; } - // index = thisParameter == null ? index : index - 1; - return !AllParameters[index].IsRemoved; } } @@ -101,6 +174,11 @@ public bool CanRestore { get { + if (!AllParameters.Any()) + { + return false; + } + if (!SelectedIndex.HasValue) { return false; @@ -113,45 +191,83 @@ public bool CanRestore return false; } - // index = thisParameter == null ? index : index - 1; - return AllParameters[index].IsRemoved; } } + public bool CanEdit + { + get + { + if (!SelectedIndex.HasValue) + { + return false; + } + + // Cannot edit `this` parameter + var index = SelectedIndex.Value; + if (index == 0 && _thisParameter != null) + { + return false; + } + + // Cannot edit params parameter + if (index >= (_thisParameter == null ? 0 : 1) + _parametersWithoutDefaultValues.Count + _parametersWithDefaultValues.Count) + { + return false; + } + + return !AllParameters[SelectedIndex.Value].IsRemoved; + } + } + internal void Remove() { - AllParameters[_selectedIndex.Value].IsRemoved = true; - NotifyPropertyChanged(nameof(AllParameters)); - NotifyPropertyChanged(nameof(SignatureDisplay)); - NotifyPropertyChanged(nameof(SignaturePreviewAutomationText)); - NotifyPropertyChanged(nameof(IsOkButtonEnabled)); - NotifyPropertyChanged(nameof(CanRemove)); - NotifyPropertyChanged(nameof(RemoveAutomationText)); - NotifyPropertyChanged(nameof(CanRestore)); - NotifyPropertyChanged(nameof(RestoreAutomationText)); + if (AllParameters[_selectedIndex.Value] is AddedParameterViewModel) + { + ParameterViewModel parameterToRemove = AllParameters[_selectedIndex.Value]; + _parametersWithoutDefaultValues.Remove(parameterToRemove); + } + else + { + AllParameters[_selectedIndex.Value].IsRemoved = true; + } + + RemoveRestoreNotifyPropertyChanged(); } internal void Restore() { AllParameters[_selectedIndex.Value].IsRemoved = false; + RemoveRestoreNotifyPropertyChanged(); + } + + internal void AddParameter(AddedParameter addedParameter) + { + _parametersWithoutDefaultValues.Add(new AddedParameterViewModel(this, addedParameter)); + + RemoveRestoreNotifyPropertyChanged(); + } + + internal void RemoveRestoreNotifyPropertyChanged() + { NotifyPropertyChanged(nameof(AllParameters)); NotifyPropertyChanged(nameof(SignatureDisplay)); NotifyPropertyChanged(nameof(SignaturePreviewAutomationText)); - NotifyPropertyChanged(nameof(IsOkButtonEnabled)); NotifyPropertyChanged(nameof(CanRemove)); NotifyPropertyChanged(nameof(RemoveAutomationText)); NotifyPropertyChanged(nameof(CanRestore)); NotifyPropertyChanged(nameof(RestoreAutomationText)); + NotifyPropertyChanged(nameof(CanEdit)); } internal ParameterConfiguration GetParameterConfiguration() { return new ParameterConfiguration( _originalParameterConfiguration.ThisParameter, - _parameterGroup1.Where(p => !p.IsRemoved).Select(p => p.ParameterSymbol).ToList(), - _parameterGroup2.Where(p => !p.IsRemoved).Select(p => p.ParameterSymbol).ToList(), - (_paramsParameter == null || _paramsParameter.IsRemoved) ? null : _paramsParameter.ParameterSymbol, + _parametersWithoutDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter).ToImmutableArray(), + _parametersWithDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter).ToImmutableArray(), + (_paramsParameter == null || _paramsParameter.IsRemoved) ? null : _paramsParameter.Parameter as ExistingParameter, selectedIndex: -1); } @@ -231,7 +347,21 @@ private List GetSignatureDisplayParts() } first = false; - displayParts.AddRange(parameter.ParameterSymbol.ToDisplayParts(s_parameterDisplayFormat)); + + switch (parameter) + { + case ExistingParameterViewModel existingParameter: + displayParts.AddRange(existingParameter.ParameterSymbol.ToDisplayParts(s_parameterDisplayFormat)); + break; + + case AddedParameterViewModel addedParameterViewModel: + var languageService = _document.GetLanguageService(); + displayParts.AddRange(languageService.GeneratePreviewDisplayParts(addedParameterViewModel)); + break; + + default: + throw ExceptionUtilities.UnexpectedValue(parameter.GetType().ToString()); + } } displayParts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.Punctuation, null, ")")); @@ -248,8 +378,8 @@ public List AllParameters list.Add(_thisParameter); } - list.AddRange(_parameterGroup1); - list.AddRange(_parameterGroup2); + list.AddRange(_parametersWithoutDefaultValues); + list.AddRange(_parametersWithDefaultValues); if (_paramsParameter != null) { @@ -271,7 +401,7 @@ public bool CanMoveUp var index = SelectedIndex.Value; index = _thisParameter == null ? index : index - 1; - if (index <= 0 || index == _parameterGroup1.Count || index >= _parameterGroup1.Count + _parameterGroup2.Count) + if (index <= 0 || index == _parametersWithoutDefaultValues.Count || index >= _parametersWithoutDefaultValues.Count + _parametersWithDefaultValues.Count) { return false; } @@ -291,7 +421,7 @@ public bool CanMoveDown var index = SelectedIndex.Value; index = _thisParameter == null ? index : index - 1; - if (index < 0 || index == _parameterGroup1.Count - 1 || index >= _parameterGroup1.Count + _parameterGroup2.Count - 1) + if (index < 0 || index == _parametersWithoutDefaultValues.Count - 1 || index >= _parametersWithoutDefaultValues.Count + _parametersWithDefaultValues.Count - 1) { return false; } @@ -306,7 +436,7 @@ internal void MoveUp() var index = SelectedIndex.Value; index = _thisParameter == null ? index : index - 1; - Move(index < _parameterGroup1.Count ? _parameterGroup1 : _parameterGroup2, index < _parameterGroup1.Count ? index : index - _parameterGroup1.Count, delta: -1); + Move(index < _parametersWithoutDefaultValues.Count ? _parametersWithoutDefaultValues : _parametersWithDefaultValues, index < _parametersWithoutDefaultValues.Count ? index : index - _parametersWithoutDefaultValues.Count, delta: -1); } internal void MoveDown() @@ -315,7 +445,7 @@ internal void MoveDown() var index = SelectedIndex.Value; index = _thisParameter == null ? index : index - 1; - Move(index < _parameterGroup1.Count ? _parameterGroup1 : _parameterGroup2, index < _parameterGroup1.Count ? index : index - _parameterGroup1.Count, delta: 1); + Move(index < _parametersWithoutDefaultValues.Count ? _parametersWithoutDefaultValues : _parametersWithDefaultValues, index < _parametersWithoutDefaultValues.Count ? index : index - _parametersWithoutDefaultValues.Count, delta: 1); } private void Move(List list, int index, int delta) @@ -329,34 +459,27 @@ private void Move(List list, int index, int delta) NotifyPropertyChanged(nameof(AllParameters)); NotifyPropertyChanged(nameof(SignatureDisplay)); NotifyPropertyChanged(nameof(SignaturePreviewAutomationText)); - NotifyPropertyChanged(nameof(IsOkButtonEnabled)); } internal bool TrySubmit() { - return IsOkButtonEnabled; - } + var canSubmit = AllParameters.Any(p => p.IsRemoved) || + AllParameters.Any(p => p is AddedParameterViewModel) || + !_parametersWithoutDefaultValues.OfType().Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.ParametersWithoutDefaultValues.Cast().Select(p => p.Symbol)) || + !_parametersWithDefaultValues.OfType().Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.RemainingEditableParameters.Cast().Select(p => p.Symbol)); - private bool IsDisabled(ParameterViewModel parameterViewModel) - { - return _disabledParameters.Contains(parameterViewModel.ParameterSymbol); - } + if (!canSubmit) + { + _notificationService.SendNotification(ServicesVSResources.You_must_change_the_signature, severity: NotificationSeverity.Information); + return false; + } - private IList GetSelectedGroup() - { - var index = SelectedIndex; - index = _thisParameter == null ? index : index - 1; - return index < _parameterGroup1.Count ? _parameterGroup1 : index < _parameterGroup1.Count + _parameterGroup2.Count ? _parameterGroup2 : SpecializedCollections.EmptyList(); + return true; } - public bool IsOkButtonEnabled + private bool IsDisabled(ParameterViewModel parameterViewModel) { - get - { - return AllParameters.Any(p => p.IsRemoved) || - !_parameterGroup1.Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.ParametersWithoutDefaultValues) || - !_parameterGroup2.Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.RemainingEditableParameters); - } + return _disabledParameters.Contains(parameterViewModel); } private int? _selectedIndex; @@ -385,6 +508,7 @@ public int? SelectedIndex NotifyPropertyChanged(nameof(RemoveAutomationText)); NotifyPropertyChanged(nameof(CanRestore)); NotifyPropertyChanged(nameof(RestoreAutomationText)); + NotifyPropertyChanged(nameof(CanEdit)); } } @@ -397,7 +521,7 @@ public string MoveUpAutomationText return string.Empty; } - return string.Format(ServicesVSResources.Move_0_above_1, AllParameters[SelectedIndex.Value].ParameterAutomationText, AllParameters[SelectedIndex.Value - 1].ParameterAutomationText); + return string.Format(ServicesVSResources.Move_0_above_1, AllParameters[SelectedIndex.Value].ShortAutomationText, AllParameters[SelectedIndex.Value - 1].ShortAutomationText); } } @@ -410,7 +534,7 @@ public string MoveDownAutomationText return string.Empty; } - return string.Format(ServicesVSResources.Move_0_below_1, AllParameters[SelectedIndex.Value].ParameterAutomationText, AllParameters[SelectedIndex.Value + 1].ParameterAutomationText); + return string.Format(ServicesVSResources.Move_0_below_1, AllParameters[SelectedIndex.Value].ShortAutomationText, AllParameters[SelectedIndex.Value + 1].ShortAutomationText); } } @@ -423,7 +547,7 @@ public string RemoveAutomationText return string.Empty; } - return string.Format(ServicesVSResources.Remove_0, AllParameters[SelectedIndex.Value].ParameterAutomationText); + return string.Format(ServicesVSResources.Remove_0, AllParameters[SelectedIndex.Value].ShortAutomationText); } } @@ -436,25 +560,112 @@ public string RestoreAutomationText return string.Empty; } - return string.Format(ServicesVSResources.Restore_0, AllParameters[SelectedIndex.Value].ParameterAutomationText); + return string.Format(ServicesVSResources.Restore_0, AllParameters[SelectedIndex.Value].ShortAutomationText); } } - public class ParameterViewModel + public abstract class ParameterViewModel { - private readonly ChangeSignatureDialogViewModel _changeSignatureDialogViewModel; + protected readonly ChangeSignatureDialogViewModel changeSignatureDialogViewModel; + + public abstract Parameter Parameter { get; } - public IParameterSymbol ParameterSymbol { get; } + public abstract string Type { get; } + public abstract string ParameterName { get; } + public abstract bool IsRemoved { get; set; } + public abstract string ShortAutomationText { get; } + public abstract bool IsDisabled { get; } + public abstract string CallSite { get; } - public ParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel, IParameterSymbol parameter) + public ParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel) { - _changeSignatureDialogViewModel = changeSignatureDialogViewModel; - ParameterSymbol = parameter; + this.changeSignatureDialogViewModel = changeSignatureDialogViewModel; } - public string ParameterAutomationText => $"{Type} {Parameter}"; + public abstract string InitialIndex { get; } + public abstract string Modifier { get; } + public abstract string Default { get; } - public string Modifier + public virtual string FullAutomationText + { + get + { + var text = $"{Modifier} {Type} {Parameter}"; + if (!string.IsNullOrWhiteSpace(Default)) + { + text += $" = {Default}"; + } + + return text; + } + } + } + + public class AddedParameterViewModel : ParameterViewModel + { + public override Parameter Parameter => _addedParameter; + public readonly AddedParameter _addedParameter; + + public AddedParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel, AddedParameter addedParameter) + : base(changeSignatureDialogViewModel) + { + _addedParameter = addedParameter; + } + + public override string Type => _addedParameter.TypeNameDisplayWithErrorIndicator; + + public override string ParameterName => _addedParameter.ParameterName; + + public override bool IsRemoved { get => false; set => throw new InvalidOperationException(); } + + public override string ShortAutomationText => $"{Type} {ParameterName}"; + public override string FullAutomationText + { + get + { + var baseText = base.FullAutomationText; + return ServicesVSResources.Added_Parameter + baseText + string.Format(ServicesVSResources.Inserting_call_site_value_0, CallSite); + } + } + + public override bool IsDisabled => false; + + public override string CallSite => _addedParameter.CallSiteValue; + + public override string InitialIndex => ServicesVSResources.ChangeSignature_NewParameterIndicator; + + // Newly added parameters cannot have modifiers yet + public override string Modifier => string.Empty; + + // Only required parameters are supported currently + public override string Default => string.Empty; + } + +#nullable enable + + public class ExistingParameterViewModel : ParameterViewModel + { + public IParameterSymbol ParameterSymbol => _existingParameter.Symbol; + + private readonly ExistingParameter _existingParameter; + + public override Parameter Parameter => _existingParameter; + + public ExistingParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel, ExistingParameter existingParameter, int initialIndex) + : base(changeSignatureDialogViewModel) + { + _existingParameter = existingParameter; + InitialIndex = initialIndex.ToString(); + } + + public override string ShortAutomationText => $"{Type} {Parameter.Name}"; + + public override string CallSite => string.Empty; + + public override string InitialIndex { get; } + +#nullable disable + public override string Modifier { get { @@ -485,8 +696,8 @@ string ModifierText(string @out = default, string @ref = default, string @in = d return @params ?? string.Empty; } - if (_changeSignatureDialogViewModel._thisParameter != null && - Equals(ParameterSymbol, _changeSignatureDialogViewModel._thisParameter.ParameterSymbol)) + if (changeSignatureDialogViewModel._thisParameter != null && + ParameterSymbol == (changeSignatureDialogViewModel._thisParameter as ExistingParameterViewModel).ParameterSymbol) { return @this ?? string.Empty; } @@ -495,11 +706,13 @@ string ModifierText(string @out = default, string @ref = default, string @in = d } } - public string Type => ParameterSymbol.Type.ToDisplayString(s_parameterDisplayFormat); +#nullable enable + + public override string Type => ParameterSymbol.Type.ToDisplayString(s_parameterDisplayFormat); - public string Parameter => ParameterSymbol.Name; + public override string ParameterName => ParameterSymbol.Name; - public string Default + public override string Default { get { @@ -523,25 +736,25 @@ string NullText(string @null, string @default) } } - public bool IsDisabled => _changeSignatureDialogViewModel.IsDisabled(this); + public override bool IsDisabled => changeSignatureDialogViewModel.IsDisabled(this); public bool NeedsBottomBorder { get { - if (this == _changeSignatureDialogViewModel._thisParameter) + if (this == changeSignatureDialogViewModel._thisParameter) { return true; } - if (this == _changeSignatureDialogViewModel._parameterGroup1.LastOrDefault() && - (_changeSignatureDialogViewModel._parameterGroup2.Any() || _changeSignatureDialogViewModel._paramsParameter != null)) + if (this == changeSignatureDialogViewModel._parametersWithoutDefaultValues.LastOrDefault() && + (changeSignatureDialogViewModel._parametersWithDefaultValues.Any() || changeSignatureDialogViewModel._paramsParameter != null)) { return true; } - if (this == _changeSignatureDialogViewModel._parameterGroup2.LastOrDefault() && - _changeSignatureDialogViewModel._paramsParameter != null) + if (this == changeSignatureDialogViewModel._parametersWithDefaultValues.LastOrDefault() && + changeSignatureDialogViewModel._paramsParameter != null) { return true; } @@ -550,7 +763,7 @@ public bool NeedsBottomBorder } } - public bool IsRemoved { get; set; } + public override bool IsRemoved { get; set; } } } } diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs new file mode 100644 index 0000000000000..bd1c150834783 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs @@ -0,0 +1,24 @@ +// 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 enable + +using Microsoft.CodeAnalysis; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature +{ + internal abstract class ChangeSignatureViewModelFactoryService : IChangeSignatureViewModelFactoryService + { + public ChangeSignatureViewModelFactoryService() + { + } + + public abstract SymbolDisplayPart[] GeneratePreviewDisplayParts( + ChangeSignatureDialogViewModel.AddedParameterViewModel addedParameterViewModel); + + public abstract bool IsTypeNameValid(string typeName); + + public abstract SyntaxNode GetTypeNode(string typeName); + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs new file mode 100644 index 0000000000000..1b7b1c55937d2 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs @@ -0,0 +1,21 @@ +// 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 enable + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host; +using static Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.ChangeSignatureDialogViewModel; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature +{ + internal interface IChangeSignatureViewModelFactoryService : ILanguageService + { + SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel); + + bool IsTypeNameValid(string typeName); + + SyntaxNode GetTypeNode(string typeName); + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs index bba2132ec3880..ed9e078eb9a81 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/VisualStudioChangeSignatureOptionsService.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + +using System; using System.Composition; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ChangeSignature; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Notification; using Microsoft.VisualStudio.Text.Classification; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature @@ -19,27 +21,38 @@ internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptio private readonly ClassificationTypeMap _classificationTypeMap; [ImportingConstructor] - public VisualStudioChangeSignatureOptionsService(IClassificationFormatMapService classificationFormatMapService, ClassificationTypeMap classificationTypeMap) + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VisualStudioChangeSignatureOptionsService( + IClassificationFormatMapService classificationFormatMapService, + ClassificationTypeMap classificationTypeMap) { _classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap("tooltip"); _classificationTypeMap = classificationTypeMap; } - public ChangeSignatureOptionsResult GetChangeSignatureOptions(ISymbol symbol, ParameterConfiguration parameters) + public ChangeSignatureOptionsResult? GetChangeSignatureOptions( + Document document, + int insertPosition, + ISymbol symbol, + ParameterConfiguration parameters) { - var viewModel = new ChangeSignatureDialogViewModel(parameters, symbol, _classificationFormatMap, _classificationTypeMap); + var viewModel = new ChangeSignatureDialogViewModel( + parameters, + symbol, + document, + insertPosition, + _classificationFormatMap, + _classificationTypeMap); var dialog = new ChangeSignatureDialog(viewModel); var result = dialog.ShowModal(); if (result.HasValue && result.Value) { - return new ChangeSignatureOptionsResult { IsCancelled = false, UpdatedSignature = new SignatureChange(parameters, viewModel.GetParameterConfiguration()), PreviewChanges = viewModel.PreviewChanges }; - } - else - { - return new ChangeSignatureOptionsResult { IsCancelled = true }; + return new ChangeSignatureOptionsResult(new SignatureChange(parameters, viewModel.GetParameterConfiguration()), previewChanges: viewModel.PreviewChanges); } + + return null; } } } diff --git a/src/VisualStudio/Core/Def/Implementation/Utilities/DependencyObjectExtensions.cs b/src/VisualStudio/Core/Def/Implementation/Utilities/DependencyObjectExtensions.cs new file mode 100644 index 0000000000000..860a3f6eac2b3 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Utilities/DependencyObjectExtensions.cs @@ -0,0 +1,33 @@ +// 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.Windows; +using System.Windows.Media; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation +{ + internal static class DependencyObjectExtensions + { + public static DependencyObject TryGetParent(this DependencyObject obj) + { + return (obj is Visual) ? VisualTreeHelper.GetParent(obj) : null; + } + + public static T GetParentOfType(this DependencyObject element) where T : Visual + { + var parent = element.TryGetParent(); + if (parent is T) + { + return (T)parent; + } + + if (parent == null) + { + return null; + } + + return parent.GetParentOfType(); + } + } +} diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 78b4495c85ff7..11260d2bd147c 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1064,9 +1064,15 @@ I agree to all of the foregoing: Avoid unused value assignments + + Parameter name contains invalid character(s). + Parameter preferences: + + Parameter type contains invalid character(s). + Non-public methods @@ -1172,6 +1178,9 @@ I agree to all of the foregoing: A new namespace will be created + + A type and name must be provided. + Rename {0} to {1} @@ -1354,6 +1363,56 @@ I agree to all of the foregoing: Live Share C#/Visual Basic Language Server Client 'Live Share' is a product name and does not need to be localized. + + _Edit + + + Edit {0} + {0} is a parameter description + + + Parameter Details + + + _Add + Adding an element to a list + + + Call site + + + Add Parameter + + + Call site value: + + + Parameter name: + + + Type name: + + + You must change the signature + "signature" here means the definition of a method + + + <new> + + + TODO + "TODO" is an indication that there is work to be done still + + + Added parameter. + + + Inserting call site value '{0}' + + + Index + Index of parameter in original signature + Value: diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index d8f5be1c43cf7..1ecfa7f6bafeb 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -12,11 +12,31 @@ Vytvoří se nový obor názvů. + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Přidat do _aktuálního souboru + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Aby bylo možné dokončit refaktoring, je nutné udělat další změny. Zkontrolujte změny níže. @@ -82,6 +102,26 @@ Počítají se závislosti... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. Dokončila se analýza kódu pro {0}. @@ -112,6 +152,16 @@ Aktuální dokument + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ V jiných operátorech + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Nainstalujte Microsoftem doporučené analyzátory Roslyn, které poskytují další diagnostiku a opravy pro běžné problémy s návrhem, zabezpečením, výkonem a spolehlivostí rozhraní API. @@ -382,11 +442,31 @@ Otevřené dokumenty + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Předvolby parametrů: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Předvolby závorek: @@ -552,6 +632,11 @@ Toto je neplatný obor názvů. + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local Nepoužitá hodnota se explicitně přiřadí nepoužité lokální hodnotě. @@ -617,6 +702,11 @@ Tento pracovní prostor nepodporuje aktualizaci možností kompilace jazyka Visual Basic. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. Musíte vybrat aspoň jednoho člena. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 242f47f57c153..50d984a281a05 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -12,11 +12,31 @@ Ein neuer Namespace wird erstellt. + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Zu a_ktueller Datei hinzufügen + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Es sind weitere Änderungen erforderlich, um das Refactoring abzuschließen. Prüfen Sie die unten aufgeführten Änderungen. @@ -82,6 +102,26 @@ Abhängige Objekte werden berechnet... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. Die Codeanalyse für "{0}" wurde abgeschlossen. @@ -112,6 +152,16 @@ Aktuelles Dokument + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ In anderen Operatoren + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Installieren Sie von Microsoft empfohlene Roslyn-Analysetools, die zusätzliche Diagnosen und Fixes für allgemeine Design-, Sicherheits-, Leistungs- und Zuverlässigkeitsprobleme bei APIs bereitstellen. @@ -382,11 +442,31 @@ Geöffnete Dokumente + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Parametereinstellungen: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Voreinstellungen für Klammern: @@ -552,6 +632,11 @@ Dies ist ein ungültiger Namespace. + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local Der nicht verwendete Wert wird explizit einer nicht verwendeten lokalen Variablen zugewiesen. @@ -617,6 +702,11 @@ Das Aktualisieren von Visual Basic-Kompilierungsoptionen wird von diesem Arbeitsbereich nicht unterstützt. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. Sie müssen mindestens einen Member auswählen. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index d007d4cb143a3..c7d0239ca57c1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -12,11 +12,31 @@ Se creará un espacio de nombres + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Agregar al archivo _actual + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Se necesitan cambios adicionales para finalizar la refactorización. Revise los cambios a continuación. @@ -82,6 +102,26 @@ Calculando dependientes... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. El análisis de código se ha completado para "{0}". @@ -112,6 +152,16 @@ Documento actual + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ En otros operadores + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Instale los analizadores de Roslyn recomendados por Microsoft, que proporcionan diagnósticos y correcciones adicionales para problemas comunes de confiabilidad, rendimiento, seguridad y diseño de API. @@ -382,11 +442,31 @@ Abrir documentos + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Preferencias de parámetros: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Preferencias de paréntesis: @@ -552,6 +632,11 @@ Este espacio de nombres no es válido + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local El valor sin usar se asigna explícitamente a una variable local sin usar @@ -617,6 +702,11 @@ Esta área de trabajo no admite la actualización de opciones de compilación de Visual Basic. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. Debe seleccionar al menos un miembro. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 41df2a1973226..db7dcebae5f37 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -12,11 +12,31 @@ Un espace de noms va être créé + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Ajouter au fichier a_ctif + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Des changements supplémentaires sont nécessaires pour effectuer la refactorisation. Passez en revue les changements ci-dessous. @@ -82,6 +102,26 @@ Calcul des dépendants... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. Analyse du code effectuée pour '{0}'. @@ -112,6 +152,16 @@ Document en cours + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ Dans les autres opérateurs + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Installer les analyseurs Roslyn recommandés par Microsoft, qui fournissent des diagnostics et des correctifs supplémentaires pour les problèmes usuels liés à la conception, à la sécurité, au niveau de performance et à la fiabilité des API @@ -382,11 +442,31 @@ Documents ouverts + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Préférences relatives aux paramètres : + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Préférences relatives aux parenthèses : @@ -552,6 +632,11 @@ Ceci est un espace de noms non valide + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local La valeur inutilisée est explicitement affectée à une variable locale inutilisée @@ -617,6 +702,11 @@ Cet espace de travail ne prend pas en charge la mise à jour des options de compilation Visual Basic. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. Vous devez sélectionner au moins un membre. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index bc1cfaf5991b4..ef60a9d9d1526 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -12,11 +12,31 @@ Verrà creato un nuovo spazio dei nomi + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Aggiungi al file _corrente + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Per completare il refactoring, sono necessarie modifiche aggiuntive. Esaminare le modifiche di seguito. @@ -82,6 +102,26 @@ Calcolo dei dipendenti... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. Analisi codice completata per '{0}'. @@ -112,6 +152,16 @@ Documento corrente + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ In altri operatori + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Installare gli analizzatori Roslyn consigliati da Microsoft, che offrono ulteriori funzionalità di diagnostica e correzioni per problemi comuni di sicurezza, prestazioni, affidabilità e progettazione di API @@ -382,11 +442,31 @@ Apri documenti + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Preferenze per parametri: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Preferenze per parentesi: @@ -552,6 +632,11 @@ Questo è uno spazio dei nomi non valido + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local Il valore inutilizzato viene assegnato in modo esplicito a una variabile locale inutilizzata @@ -617,6 +702,11 @@ Quest'area di lavoro non supporta l'aggiornamento delle opzioni di compilazione di Visual Basic. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. È necessario selezionare almeno un membro. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 49d589778cd37..8bb47cd9708aa 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -12,11 +12,31 @@ 新しい名前空間が作成されます + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file 現在のファイルに追加(_C) + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. リファクタリングを完了するには、追加的な変更が必要です。下記の変更内容を確認してください。 @@ -82,6 +102,26 @@ 依存を計算しています... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. '{0}' のコード分析が完了しました。 @@ -112,6 +152,16 @@ 現在のドキュメント + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ その他の演算子内で + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Microsoft で推奨されている Roslyn アナライザーをインストールします。これにより、一般的な API の設計、セキュリティ、パフォーマンス、信頼性の問題に対する追加の診断と修正が提供されます @@ -382,11 +442,31 @@ 開かれているドキュメント + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: パラメーターの優先順位: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: かっこの優先順位: @@ -552,6 +632,11 @@ これは無効な名前空間です + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local 未使用のローカルに未使用の値が明示的に割り当てられます @@ -617,6 +702,11 @@ このワークスペースでは、Visual Basic コンパイル オプションの更新がサポートされていません。 + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. 少なくとも 1 人のメンバーを選択する必要があります。 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index f98ee65a35c87..c23cd0e4b78b3 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -12,11 +12,31 @@ 새 네임스페이스가 만들어집니다. + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file 현재 파일에 추가(_C) + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. 리팩터링을 완료하려면 추가 변경이 필요합니다. 아래 변경 내용을 검토하세요. @@ -82,6 +102,26 @@ 종속 항목을 계산하는 중... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. '{0}'에 대한 코드 분석이 완료되었습니다. @@ -112,6 +152,16 @@ 현재 문서 + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ 기타 연산자 + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues 일반적인 API 디자인, 보안, 성능 및 안정성 문제에 대한 추가 진단 및 수정을 제공하는 Microsoft 권장 Roslyn 분석기를 설치합니다. @@ -382,11 +442,31 @@ 문서 열기 + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: 매개 변수 기본 설정: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: 괄호 기본 설정: @@ -552,6 +632,11 @@ 잘못된 네임스페이스입니다. + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local 사용되지 않는 값이 사용되지 않는 로컬에 명시적으로 할당됩니다. @@ -617,6 +702,11 @@ 이 작업 영역은 Visual Basic 컴파일 옵션 업데이트를 지원하지 않습니다. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. 멤버를 하나 이상 선택해야 합니다. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index cc540a4497d9f..787f5ae4050f6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -12,11 +12,31 @@ Zostanie utworzona nowa przestrzeń nazw + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Dodaj do _bieżącego pliku + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. W celu ukończenia refaktoryzacji wymagane są dodatkowe zmiany. Przejrzyj zmiany poniżej. @@ -82,6 +102,26 @@ Obliczanie elementów zależnych... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. Ukończono analizę kodu dla elementu „{0}”. @@ -112,6 +152,16 @@ Bieżący dokument + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ W innych operatorach + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Zainstaluj analizatory Roslyn rekomendowane przez firmę Microsoft, które oferują dodatkową diagnostykę i poprawki w zakresie typowego projektu interfejsu API, zabezpieczeń, wydajności i niezawodności @@ -382,11 +442,31 @@ Otwórz dokumenty + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Preferencje dotyczące parametrów: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Preferencje dotyczące nawiasów: @@ -552,6 +632,11 @@ To jest nieprawidłowa przestrzeń nazw + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local Nieużywana wartość jest jawnie przypisywana do nieużywanej zmiennej lokalnej @@ -617,6 +702,11 @@ Ten obszar roboczy nie obsługuje aktualizowania opcji kompilacji dla języka Visual Basic. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. Musisz wybrać co najmniej jeden element członkowski. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index 1fd077a2fcd35..0543a3b1598c8 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -12,11 +12,31 @@ Um namespace será criado + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Adicionar ao _arquivo atual + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Alterações adicionais são necessárias para concluir a refatoração. Revise as alterações abaixo. @@ -82,6 +102,26 @@ Calculando dependentes... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. Análise de código concluída para '{0}'. @@ -112,6 +152,16 @@ Documento atual + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ Em outros operadores + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Instale os analisadores Roslyn recomendados pela Microsoft, que fornecem diagnósticos adicionais e correções para problemas comuns de confiabilidade, desempenho, segurança e design de API @@ -382,11 +442,31 @@ Abrir documentos + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Preferências de parâmetro: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Preferências de parênteses: @@ -552,6 +632,11 @@ Este é um namespace inválido + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local O valor não utilizado é explicitamente atribuído a um local não utilizado @@ -617,6 +702,11 @@ Este workspace não é compatível com a atualização das opções de compilação do Visual Basic. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. Você deve selecionar pelo menos um membro. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 9dd29765bfeca..59c24745cdfe5 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -12,11 +12,31 @@ Будет создано пространство имен + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Добавить в _текущий файл + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Для завершения рефакторинга требуется внести дополнительные изменения. Просмотрите их ниже. @@ -82,6 +102,26 @@ Вычисление зависимостей… + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. Анализ кода для "{0}" выполнен. @@ -112,6 +152,16 @@ Текущий документ + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ В других операторах + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Установите рекомендуемые корпорацией Майкрософт анализаторы Roslyn, которые предоставляют дополнительные средства диагностики и исправления для распространенных проблем, связанных с разработкой, безопасностью, производительностью и надежностью API. @@ -382,11 +442,31 @@ Открыть документы + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Предпочтения для параметров: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Параметры круглых скобок: @@ -552,6 +632,11 @@ Это недопустимое пространство имен. + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local Неиспользуемое значение явным образом задано неиспользуемой локальной переменной. @@ -617,6 +702,11 @@ Эта рабочая область не поддерживает обновление параметров компиляции Visual Basic. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. Необходимо выбрать по крайней мере один элемент. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index bf631554df6c1..64b5f835bef26 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -12,11 +12,31 @@ Yeni bir ad alanı oluşturulacak + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file Geçerli _dosyaya ekle + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. Yeniden düzenlemeyi tamamlamak için ek değişiklikler gerekli. Aşağıdaki değişiklikleri gözden geçirin. @@ -82,6 +102,26 @@ Bağımlılar hesaplanıyor... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. '{0}' için kod analizi tamamlandı. @@ -112,6 +152,16 @@ Geçerli belge + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ Diğer işleçlerde + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues Microsoft'un önerdiği, genel API tasarımı, güvenlik, performans ve güvenilirlik sorunları için ek tanılama ve düzeltmeler sağlayan Roslyn çözümleyicilerini yükleyin @@ -382,11 +442,31 @@ Açık belgeler + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: Parametre tercihleri: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: Parantez tercihleri: @@ -552,6 +632,11 @@ Bu geçersiz bir ad alanı + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local Kullanılmayan değer açıkça kullanılmayan bir yerele atandı @@ -617,6 +702,11 @@ Bu çalışma alanı Visual Basic derleme seçeneklerinin güncelleştirilmesini desteklemiyor. + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. En az bir üye seçmelisiniz. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index f3a1d29bf1c23..aeb55b6495076 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -12,11 +12,31 @@ 将创建一个新的命名空间 + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file 添加到当前文件(_C) + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. 需要进行其他更改才可完成重构。请在下方查看所作更改。 @@ -82,6 +102,26 @@ 正在计算依赖项... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. “{0}”的代码分析已完成。 @@ -112,6 +152,16 @@ 当前文档 + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ 在其他运算符中 + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues 安装 Microsoft 推荐的 Roslyn 分析器,它提供了针对常见 API 设计、安全性、性能和可靠性问题的额外诊断和修补程序 @@ -382,11 +442,31 @@ 打开文档 + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: 参数首选项: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: 括号首选项: @@ -552,6 +632,11 @@ 这是一个无效的命名空间 + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local 未使用的值会显式分配给未使用的本地函数 @@ -617,6 +702,11 @@ 此工作区不支持更新 Visual Basic 编译选项。 + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. 必须至少选择一个成员。 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index 35a18b90803a4..32645ead629f6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -12,11 +12,31 @@ 將會建立新的命名空間 + + A type and name must be provided. + A type and name must be provided. + + + + _Add + _Add + Adding an element to a list + + + Add Parameter + Add Parameter + + Add to _current file 新增至 _current 檔案 + + Added parameter. + Added parameter. + + Additional changes are needed to complete the refactoring. Review changes below. 必須進行其他變更,才能完成重構。請檢閱以下變更。 @@ -82,6 +102,26 @@ 正在計算相依項... + + Call site value: + Call site value: + + + + Call site + Call site + + + + <new> + <new> + + + + TODO + TODO + "TODO" is an indication that there is work to be done still + Code analysis completed for '{0}'. '{0}' 的程式碼分析已完成。 @@ -112,6 +152,16 @@ 目前的文件 + + _Edit + _Edit + + + + Edit {0} + Edit {0} + {0} is a parameter description + Editor Color Scheme Editor Color Scheme @@ -157,6 +207,16 @@ 其他運算子中 + + Index + Index + Index of parameter in original signature + + + Inserting call site value '{0}' + Inserting call site value '{0}' + + Install Microsoft-recommended Roslyn analyzers, which provide additional diagnostics and fixes for common API design, security, performance, and reliability issues 安裝 Microsoft 建議的 Roslyn 分析器,其可為一般 API 設計、安全性、效能及可靠性問題提供額外的診斷與修正 @@ -382,11 +442,31 @@ 開啟文件 + + Parameter Details + Parameter Details + + + + Parameter name: + Parameter name: + + + + Parameter name contains invalid character(s). + Parameter name contains invalid character(s). + + Parameter preferences: 參數喜好設定: + + Parameter type contains invalid character(s). + Parameter type contains invalid character(s). + + Parentheses preferences: 括號喜好設定: @@ -552,6 +632,11 @@ 這是無效的命名空間 + + Type name: + Type name: + + Unused value is explicitly assigned to an unused local 未使用的值已明確指派至未使用的區域 @@ -617,6 +702,11 @@ 此工作區不支援更新 Visual Basic 編譯選項。 + + You must change the signature + You must change the signature + "signature" here means the definition of a method + You must select at least one member. 您必須選取至少一個成員。 diff --git a/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb b/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb index db29ac3b344c0..7bd37959e6954 100644 --- a/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb +++ b/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.LanguageServices Imports Microsoft.CodeAnalysis.Shared.Extensions Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature +Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.ChangeSignatureDialogViewModel Imports Microsoft.VisualStudio.Text.Classification Imports Roslyn.Test.Utilities Imports Roslyn.Utilities @@ -43,7 +44,7 @@ class MyClass VerifyAlteredState( viewModelTestState, monitor, - isOkButtonEnabled:=False, + canCommit:=False, canMoveUp:=False, canMoveDown:=False) @@ -51,7 +52,7 @@ class MyClass End Function - Public Async Function ReorderParameters_MethodWithTwoNormalParameters_OkButtonNotOfferedAfterPermutationsResultingInOriginalOrdering() As Tasks.Task + Public Async Function ReorderParameters_MethodWithTwoNormalParameters_CannotCommitAfterPermutationsResultingInOriginalOrdering() As Tasks.Task Dim markup = + Public Async Function ChangeSignature_VerifyParamsArrayFunctionality() As Tasks.Task + Dim markup = + + Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + Dim viewModel = viewModelTestState.ViewModel + VerifyOpeningState(viewModel, "public ref int M(int x, params int[] y)") + + viewModel.SelectedIndex = 1 + + VerifyAlteredState(viewModelTestState, + canMoveUp:=False, + canMoveDown:=False, + canRemove:=True, + canEdit:=False) + End Function + + + Public Async Function TestRefKindsDisplayedCorrectly() As Tasks.Task + Dim includedInTest = {RefKind.None, RefKind.Ref, RefKind.Out, RefKind.In, RefKind.RefReadOnly} + Assert.Equal(includedInTest, EnumUtilities.GetValues(Of RefKind)()) + + Dim markup = + + Dim state = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) + VerifyOpeningState(state.ViewModel, "private void Method(int p1, ref int p2, in int p3, out int p4)") + + Assert.Equal("", state.ViewModel.AllParameters(0).Modifier) + Assert.Equal("ref", state.ViewModel.AllParameters(1).Modifier) + Assert.Equal("in", state.ViewModel.AllParameters(2).Modifier) + Assert.Equal("out", state.ViewModel.AllParameters(3).Modifier) + End Function + Public Async Function ChangeSignature_ParameterDisplay_DefaultStruct() As Tasks.Task @@ -274,7 +332,7 @@ class Goo { } -}"]]> +}]]> Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) Dim viewModel = viewModelTestState.ViewModel @@ -289,9 +347,12 @@ class Goo Private Sub VerifyAlteredState( viewModelTestState As ChangeSignatureViewModelTestState, Optional monitor As PropertyChangedTestMonitor = Nothing, - Optional isOkButtonEnabled As Boolean? = Nothing, + Optional canCommit As Boolean? = Nothing, Optional canMoveUp As Boolean? = Nothing, Optional canMoveDown As Boolean? = Nothing, + Optional canRemove As Boolean? = Nothing, + Optional canRestore As Boolean? = Nothing, + Optional canEdit As Boolean? = Nothing, Optional permutation As Integer() = Nothing, Optional signatureDisplay As String = Nothing) @@ -301,8 +362,8 @@ class Goo monitor.VerifyExpectations() End If - If isOkButtonEnabled IsNot Nothing Then - Assert.Equal(isOkButtonEnabled, viewModel.IsOkButtonEnabled) + If canCommit IsNot Nothing Then + Assert.Equal(canCommit, viewModel.TrySubmit()) End If If canMoveUp IsNot Nothing Then @@ -313,6 +374,18 @@ class Goo Assert.Equal(canMoveDown, viewModel.CanMoveDown) End If + If canRemove IsNot Nothing Then + Assert.Equal(canRemove, viewModel.CanRemove) + End If + + If canRestore IsNot Nothing Then + Assert.Equal(canRestore, viewModel.CanRestore) + End If + + If canEdit IsNot Nothing Then + Assert.Equal(canEdit, viewModel.CanEdit) + End If + If permutation IsNot Nothing Then AssertPermuted(permutation, viewModel.AllParameters, viewModelTestState.OriginalParameterList) End If @@ -327,27 +400,25 @@ class Goo Dim finalParameterList = actualParameterList.Where(Function(p) Not p.IsRemoved) For index = 0 To permutation.Length - 1 Dim expected = originalParameterList(permutation(index)) - Assert.Equal(expected, finalParameterList(index).ParameterSymbol) + Assert.Equal(expected, DirectCast(finalParameterList(index), ExistingParameterViewModel).ParameterSymbol) Next End Sub Private Sub VerifyOpeningState(viewModel As ChangeSignatureDialogViewModel, openingSignatureDisplay As String) Assert.Equal(openingSignatureDisplay, viewModel.TEST_GetSignatureDisplayText()) - Assert.False(viewModel.IsOkButtonEnabled) Assert.False(viewModel.TrySubmit) Assert.False(viewModel.CanMoveUp) End Sub Private Sub VerifyParameterInfo( viewModel As ChangeSignatureDialogViewModel, - parameterIndex As Integer, - Optional modifier As String = Nothing, - Optional type As String = Nothing, - Optional parameterName As String = Nothing, - Optional defaultValue As String = Nothing, - Optional isDisabled As Boolean? = Nothing, - Optional isRemoved As Boolean? = Nothing, - Optional needsBottomBorder As Boolean? = Nothing) + parameterIndex As Integer, + Optional modifier As String = Nothing, + Optional type As String = Nothing, + Optional parameterName As String = Nothing, + Optional defaultValue As String = Nothing, + Optional isDisabled As Boolean? = Nothing, + Optional isRemoved As Boolean? = Nothing) Dim parameter = viewModel.AllParameters(parameterIndex) @@ -360,7 +431,7 @@ class Goo End If If parameterName IsNot Nothing Then - Assert.Equal(parameterName, parameter.Parameter) + Assert.Equal(parameterName, parameter.ParameterName) End If If defaultValue IsNot Nothing Then @@ -374,10 +445,6 @@ class Goo If isRemoved.HasValue Then Assert.Equal(isRemoved.Value, parameter.IsRemoved) End If - - If needsBottomBorder.HasValue Then - Assert.Equal(needsBottomBorder.Value, parameter.NeedsBottomBorder) - End If End Sub Private Async Function GetViewModelTestStateAsync( @@ -403,32 +470,14 @@ class Goo Dim symbol = (Await workspaceDoc.GetSemanticModelAsync()).GetDeclaredSymbol(token.Parent) Dim viewModel = New ChangeSignatureDialogViewModel( - ParameterConfiguration.Create(symbol.GetParameters().ToList(), symbol.IsExtensionMethod(), selectedIndex:=0), + ParameterConfiguration.Create(symbol.GetParameters().Select(Function(p) DirectCast(New ExistingParameter(p), Parameter)), symbol.IsExtensionMethod(), selectedIndex:=0), symbol, + workspaceDoc, + insertPosition:=0, workspace.ExportProvider.GetExportedValue(Of IClassificationFormatMapService)().GetClassificationFormatMap("text"), workspace.ExportProvider.GetExportedValue(Of ClassificationTypeMap)()) Return New ChangeSignatureViewModelTestState(viewModel, symbol.GetParameters()) End Using End Function - - - Public Async Function TestRefKindsDisplayedCorrectly() As Tasks.Task - Dim includedInTest = {RefKind.None, RefKind.Ref, RefKind.Out, RefKind.In, RefKind.RefReadOnly} - Assert.Equal(includedInTest, EnumUtilities.GetValues(Of RefKind)()) - - Dim markup = - - Dim state = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp) - VerifyOpeningState(state.ViewModel, "private void Method(int p1, ref int p2, in int p3, out int p4)") - - Assert.Equal("", state.ViewModel.AllParameters(0).Modifier) - Assert.Equal("ref", state.ViewModel.AllParameters(1).Modifier) - Assert.Equal("in", state.ViewModel.AllParameters(2).Modifier) - Assert.Equal("out", state.ViewModel.AllParameters(3).Modifier) - End Function End Class End Namespace diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpChangeSignatureDialog.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpChangeSignatureDialog.cs index 2abdcc05390c5..ab9e936c09015 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpChangeSignatureDialog.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpChangeSignatureDialog.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.IntegrationTest.Utilities; using Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess; @@ -20,6 +21,8 @@ public class CSharpChangeSignatureDialog : AbstractEditorTest private ChangeSignatureDialog_OutOfProc ChangeSignatureDialog => VisualStudio.ChangeSignatureDialog; + private AddParameterDialog_OutOfProc AddParameterDialog => VisualStudio.AddParameterDialog; + public CSharpChangeSignatureDialog(VisualStudioInstanceFactory instanceFactory, ITestOutputHelper testOutputHelper) : base(instanceFactory, testOutputHelper, nameof(CSharpChangeSignatureDialog)) { @@ -176,5 +179,165 @@ End Sub actualText = VisualStudio.Editor.GetText(); Assert.Contains(@"vb.Method(2, ""world"");", actualText); } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public void VerifyAddParameter() + { + SetUpEditor(@" +class C +{ + public void Method$$(int a, string b) { } + + public void NewMethod() + { + Method(1, ""stringB""); + } + +}"); + + ChangeSignatureDialog.Invoke(); + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + // Add 'c' + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("int"); + AddParameterDialog.FillNameField("c"); + AddParameterDialog.FillCallSiteField("2"); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + // Add 'd' + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("int"); + AddParameterDialog.FillNameField("d"); + AddParameterDialog.FillCallSiteField("3"); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + // Remove 'c' + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.SelectParameter("int c"); + ChangeSignatureDialog.ClickRemoveButton(); + + // Move 'd' between 'a' and 'b' + ChangeSignatureDialog.SelectParameter("int d"); + ChangeSignatureDialog.ClickUpButton(); + ChangeSignatureDialog.ClickUpButton(); + ChangeSignatureDialog.ClickDownButton(); + + ChangeSignatureDialog.ClickAddButton(); + + // Add 'c' (as a String instead of an Integer this time) + // Note that 'c' does not have a callsite value. + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("string"); + AddParameterDialog.FillNameField("c"); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.ClickOK(); + ChangeSignatureDialog.VerifyClosed(); + var actualText = VisualStudio.Editor.GetText(); + Assert.Contains(@" +class C +{ + public void Method(int a, int d, string b, string c) { } + + public void NewMethod() + { + Method(1, 3, ""stringB"", TODO); + } + +}", actualText); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public void VerifyAddParameterRefactoringCancelled() + { + SetUpEditor(@" +class C +{ + public void Method$$(int a, string b) { } +}"); + + ChangeSignatureDialog.Invoke(); + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + AddParameterDialog.VerifyOpen(); + AddParameterDialog.ClickCancel(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickCancel(); + ChangeSignatureDialog.VerifyClosed(); + var actualText = VisualStudio.Editor.GetText(); + Assert.Contains(@" +class C +{ + public void Method(int a, string b) { } +}", actualText); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public void VerifyAddParametersAcrossLanguages() + { + SetUpEditor(@" +using VBProject; + +class CSharpTest +{ + public void TestMethod() + { + VBClass x = new VBClass(); + x.Method$$(0, ""str"", 3.0); + } +}"); + var vbProject = new ProjectUtils.Project("VBProject"); + VisualStudio.SolutionExplorer.AddProject(vbProject, WellKnownProjectTemplates.ClassLibrary, LanguageNames.VisualBasic); + VisualStudio.Editor.SetText(@" +Public Class VBClass + Public Function Method(a As Integer, b As String, c As Double) As Integer + Return 1 + End Function +End Class +"); + VisualStudio.SolutionExplorer.SaveAll(); + var project = new ProjectUtils.Project(ProjectName); + var vbProjectReference = new ProjectUtils.ProjectReference("VBProject"); + VisualStudio.SolutionExplorer.AddProjectReference(project, vbProjectReference); + VisualStudio.SolutionExplorer.OpenFile(project, "Class1.cs"); + + VisualStudio.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.Workspace); + + ChangeSignatureDialog.Invoke(); + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("String"); + AddParameterDialog.FillNameField("d"); + AddParameterDialog.FillCallSiteField(@"""str2"""); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.ClickOK(); + ChangeSignatureDialog.VerifyClosed(); + var actualText = VisualStudio.Editor.GetText(); + Assert.Contains(@"x.Method(0, ""str"", 3.0, ""str2"")", actualText); + VisualStudio.SolutionExplorer.OpenFile(vbProject, "Class1.vb"); + actualText = VisualStudio.Editor.GetText(); + var expectedText = @" +Public Class VBClass + Public Function Method(a As Integer, b As String, c As Double, d As String) As Integer + Return 1 + End Function +End Class"; + Assert.Contains(expectedText, actualText); + } } } diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicChangeSignatureDialog.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicChangeSignatureDialog.cs index 3b829212dfd57..ea216de857af6 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicChangeSignatureDialog.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicChangeSignatureDialog.cs @@ -21,6 +21,8 @@ public class BasicChangeSignatureDialog : AbstractEditorTest private ChangeSignatureDialog_OutOfProc ChangeSignatureDialog => VisualStudio.ChangeSignatureDialog; + private AddParameterDialog_OutOfProc AddParameterDialog => VisualStudio.AddParameterDialog; + public BasicChangeSignatureDialog(VisualStudioInstanceFactory instanceFactory, ITestOutputHelper testOutputHelper) : base(instanceFactory, testOutputHelper, nameof(BasicChangeSignatureDialog)) { @@ -149,6 +151,159 @@ public int Method(string b) { return 1; } +}"; + Assert.Contains(expectedText, actualText); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public void VerifyAddParameter() + { + SetUpEditor(@" +Class C + Sub Method$$(a As Integer, b As String) + End Sub + Sub NewMethod() + Method(1, ""stringB"") + End Sub +End Class"); + + ChangeSignatureDialog.Invoke(); + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + // Add 'c' + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("Integer"); + AddParameterDialog.FillNameField("c"); + AddParameterDialog.FillCallSiteField("2"); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + // Add 'd' + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("Integer"); + AddParameterDialog.FillNameField("d"); + AddParameterDialog.FillCallSiteField("3"); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + // Remove 'c' + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.SelectParameter("Integer c"); + ChangeSignatureDialog.ClickRemoveButton(); + + // Move 'd' between 'a' and 'b' + ChangeSignatureDialog.SelectParameter("Integer d"); + ChangeSignatureDialog.ClickUpButton(); + ChangeSignatureDialog.ClickUpButton(); + ChangeSignatureDialog.ClickDownButton(); + + ChangeSignatureDialog.ClickAddButton(); + + // Add 'c' (as a String instead of an Integer this time) + // Note that 'c' does not have a callsite value. + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("String"); + AddParameterDialog.FillNameField("c"); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.ClickOK(); + ChangeSignatureDialog.VerifyClosed(); + var actualText = VisualStudio.Editor.GetText(); + Assert.Contains(@" +Class C + Sub Method(a As Integer, d As Integer, b As String, c As String) + End Sub + Sub NewMethod() + Method(1, 3, ""stringB"", TODO) + End Sub +End Class", actualText); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public void VerifyAddParameterRefactoringCancelled() + { + SetUpEditor(@" +Class C + Sub Method$$(a As Integer, b As String) + End Sub +End Class"); + + ChangeSignatureDialog.Invoke(); + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + AddParameterDialog.VerifyOpen(); + AddParameterDialog.ClickCancel(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickCancel(); + ChangeSignatureDialog.VerifyClosed(); + var actualText = VisualStudio.Editor.GetText(); + Assert.Contains(@" +Class C + Sub Method(a As Integer, b As String) + End Sub +End Class", actualText); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)] + public void VerifyAddParametersAcrossLanguages() + { + SetUpEditor(@" +Class VBTest + Sub TestMethod() + Dim x As New CSharpClass + x.Method$$(0, ""str"", 3.0) + End Sub +End Class"); + var csharpProject = new ProjectUtils.Project("CSharpProject"); + VisualStudio.SolutionExplorer.AddProject(csharpProject, WellKnownProjectTemplates.ClassLibrary, LanguageNames.CSharp); + VisualStudio.Editor.SetText(@" +public class CSharpClass +{ + public int Method(int a, string b, double c) + { + return 1; + } +}"); + VisualStudio.SolutionExplorer.SaveAll(); + var project = new ProjectUtils.Project(ProjectName); + var csharpProjectReference = new ProjectUtils.ProjectReference("CSharpProject"); + VisualStudio.SolutionExplorer.AddProjectReference(project, csharpProjectReference); + VisualStudio.SolutionExplorer.OpenFile(project, "Class1.vb"); + + VisualStudio.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.Workspace); + + ChangeSignatureDialog.Invoke(); + ChangeSignatureDialog.VerifyOpen(); + ChangeSignatureDialog.ClickAddButton(); + + AddParameterDialog.VerifyOpen(); + AddParameterDialog.FillTypeField("string"); + AddParameterDialog.FillNameField("d"); + AddParameterDialog.FillCallSiteField(@"""str2"""); + AddParameterDialog.ClickOK(); + AddParameterDialog.VerifyClosed(); + + ChangeSignatureDialog.ClickOK(); + ChangeSignatureDialog.VerifyClosed(); + var actualText = VisualStudio.Editor.GetText(); + Assert.Contains(@"x.Method(0, ""str"", 3.0, ""str2"")", actualText); + VisualStudio.SolutionExplorer.OpenFile(csharpProject, "Class1.cs"); + actualText = VisualStudio.Editor.GetText(); + var expectedText = @" +public class CSharpClass +{ + public int Method(int a, string b, double c, string d) + { + return 1; + } }"; Assert.Contains(expectedText, actualText); } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/AddParameterDialog_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/AddParameterDialog_InProc.cs new file mode 100644 index 0000000000000..91c6ea779bbba --- /dev/null +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/AddParameterDialog_InProc.cs @@ -0,0 +1,91 @@ +// 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.Threading; +using Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature; +using Microsoft.VisualStudio.Threading; + +namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess +{ + internal class AddParameterDialog_InProc : AbstractCodeRefactorDialog_InProc + { + private AddParameterDialog_InProc() + { + } + + public static AddParameterDialog_InProc Create() + => new AddParameterDialog_InProc(); + + public void FillCallSiteField(string callSiteValue) + { + using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) + { + JoinableTaskFactory.Run(async () => + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationTokenSource.Token); + var dialog = await GetDialogAsync(cancellationTokenSource.Token); + dialog.CallSiteValueTextBox.Text = callSiteValue; + }); + } + } + + public void FillNameField(string parameterName) + { + using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) + { + JoinableTaskFactory.Run(async () => + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationTokenSource.Token); + var dialog = await GetDialogAsync(cancellationTokenSource.Token); + dialog.NameContentControl.Text = parameterName; + }); + } + } + + public void FillTypeField(string typeName) + { + using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) + { + JoinableTaskFactory.Run(async () => + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationTokenSource.Token); + var dialog = await GetDialogAsync(cancellationTokenSource.Token); + dialog.TypeContentControl.Text = typeName; + }); + } + } + + public void ClickOK() + { + using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) + { + JoinableTaskFactory.Run(() => ClickAsync(testAccessor => testAccessor.OKButton, cancellationTokenSource.Token)); + } + } + + public void ClickCancel() + { + using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) + { + JoinableTaskFactory.Run(() => ClickAsync(testAccessor => testAccessor.CancelButton, cancellationTokenSource.Token)); + } + } + + public bool CloseWindow() + { + using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) + { + if (JoinableTaskFactory.Run(() => TryGetDialogAsync(cancellationTokenSource.Token)) is null) + { + return false; + } + } + + ClickCancel(); + return true; + } + + protected override AddParameterDialog.TestAccessor GetAccessor(AddParameterDialog dialog) => dialog.GetTestAccessor(); + } +} diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ChangeSignatureDialog_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ChangeSignatureDialog_InProc.cs index 126d107b68034..a302d36f1ea61 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ChangeSignatureDialog_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ChangeSignatureDialog_InProc.cs @@ -2,7 +2,6 @@ // 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 Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature; @@ -64,6 +63,14 @@ public void ClickUpButton() } } + public void ClickAddButton() + { + using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) + { + JoinableTaskFactory.Run(() => ClickAsync(testAccessor => testAccessor.AddButton, cancellationTokenSource.Token)); + } + } + public void ClickRemoveButton() { using (var cancellationTokenSource = new CancellationTokenSource(Helper.HangMitigatingTimeout)) @@ -89,7 +96,7 @@ public void SelectParameter(string parameterName) await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationTokenSource.Token); var dialog = await GetDialogAsync(cancellationTokenSource.Token); var members = dialog.GetTestAccessor().Members; - members.SelectedItem = dialog.GetTestAccessor().ViewModel.AllParameters.Single(p => p.ParameterAutomationText == parameterName); + members.SelectedItem = dialog.GetTestAccessor().ViewModel.AllParameters.Single(p => p.ShortAutomationText == parameterName); }); } } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/AddParameterDialog_OutOfProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/AddParameterDialog_OutOfProc.cs new file mode 100644 index 0000000000000..a0377d3b4fbcd --- /dev/null +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/AddParameterDialog_OutOfProc.cs @@ -0,0 +1,44 @@ +// 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 Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess; +using Microsoft.VisualStudio.IntegrationTest.Utilities.Input; + +namespace Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess +{ + public class AddParameterDialog_OutOfProc : OutOfProcComponent + { + private readonly AddParameterDialog_InProc _inProc; + + public AddParameterDialog_OutOfProc(VisualStudioInstance visualStudioInstance) + : base(visualStudioInstance) + { + _inProc = CreateInProcComponent(visualStudioInstance); + } + + public void VerifyOpen() + => _inProc.VerifyOpen(); + + public void VerifyClosed() + => _inProc.VerifyClosed(); + + public bool CloseWindow() + => _inProc.CloseWindow(); + + public void ClickOK() + => _inProc.ClickOK(); + + public void ClickCancel() + => _inProc.ClickCancel(); + + public void FillCallSiteField(string callsiteValue) + => _inProc.FillCallSiteField(callsiteValue); + + public void FillNameField(string parameterName) + => _inProc.FillNameField(parameterName); + + public void FillTypeField(string typeName) + => _inProc.FillTypeField(typeName); + } +} diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/ChangeSignatureDialog_OutOfProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/ChangeSignatureDialog_OutOfProc.cs index 29b58ba349fd6..04e6dba1eb538 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/ChangeSignatureDialog_OutOfProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/ChangeSignatureDialog_OutOfProc.cs @@ -41,6 +41,9 @@ public void ClickDownButton() public void ClickUpButton() => _inProc.ClickUpButton(); + public void ClickAddButton() + => _inProc.ClickAddButton(); + public void ClickRemoveButton() => _inProc.ClickRemoveButton(); diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs index fa24e3d49b749..1b7c78618216f 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs @@ -13,7 +13,7 @@ using Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess; using Microsoft.VisualStudio.IntegrationTest.Utilities.Input; using Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess; - +using Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature; using Process = System.Diagnostics.Process; namespace Microsoft.VisualStudio.IntegrationTest.Utilities @@ -30,6 +30,8 @@ public class VisualStudioInstance private readonly IpcClientChannel _integrationServiceChannel; private readonly VisualStudio_InProc _inProc; + public AddParameterDialog_OutOfProc AddParameterDialog { get; } + public ChangeSignatureDialog_OutOfProc ChangeSignatureDialog { get; } public CSharpInteractiveWindow_OutOfProc InteractiveWindow { get; } @@ -125,6 +127,7 @@ public VisualStudioInstance(Process hostProcess, DTE dte, ImmutableHashSet + Friend Class VisualBasicChangeSignatureViewModelFactoryService + Inherits ChangeSignatureViewModelFactoryService + + + Public Sub New() + End Sub + + Public Overrides Function GeneratePreviewDisplayParts(addedParameterViewModel As ChangeSignatureDialogViewModel.AddedParameterViewModel) As SymbolDisplayPart() + Return { + New SymbolDisplayPart(SymbolDisplayPartKind.ParameterName, Nothing, addedParameterViewModel.ParameterName), + New SymbolDisplayPart(SymbolDisplayPartKind.Keyword, Nothing, " As " + addedParameterViewModel.Type)} + End Function + + Public Overrides Function IsTypeNameValid(typeName As String) As Boolean + Return Not SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics + End Function + + Public Overrides Function GetTypeNode(typeName As String) As SyntaxNode + Return SyntaxFactory.ParseTypeName(typeName) + End Function + End Class +End Namespace diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index ec0273ffc567c..7849f668d965f 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -57,6 +57,67 @@ internal override SyntaxTrivia SingleLineComment(string text) internal override SeparatedSyntaxList SeparatedList(SyntaxNodeOrTokenList list) => SyntaxFactory.SeparatedList(list); + internal override SeparatedSyntaxList SeparatedList(IEnumerable nodes, IEnumerable separators) + => SyntaxFactory.SeparatedList(nodes, separators); + + internal override SyntaxTrivia Trivia(SyntaxNode node) + { + if (node is StructuredTriviaSyntax structuredTriviaSyntax) + { + return SyntaxFactory.Trivia(structuredTriviaSyntax); + } + + return default; + } + + internal override SyntaxNode DocumentationCommentTrivia(IEnumerable nodes, SyntaxTriviaList trailingTrivia, SyntaxTrivia lastWhitespaceTrivia, string endOfLineString) + { + var docTrivia = SyntaxFactory.DocumentationCommentTrivia( + SyntaxKind.MultiLineDocumentationCommentTrivia, + SyntaxFactory.List(nodes), + SyntaxFactory.Token(SyntaxKind.EndOfDocumentationCommentToken)); + + return docTrivia + .WithLeadingTrivia(SyntaxFactory.DocumentationCommentExterior("/// ")) + .WithTrailingTrivia(trailingTrivia) + .WithTrailingTrivia( + SyntaxFactory.EndOfLine(endOfLineString), + lastWhitespaceTrivia); + } + + internal override bool IsNamedArgument(SyntaxNode syntaxNode) + => syntaxNode is ArgumentSyntax argumentSyntax && argumentSyntax.NameColon != null; + + internal override bool IsWhitespaceTrivia(SyntaxTrivia trivia) + => trivia.IsKind(SyntaxKind.WhitespaceTrivia); + + internal override bool IsDocumentationCommentTriviaSyntax(SyntaxNode node) + => node is DocumentationCommentTriviaSyntax; + + internal override bool IsParameterNameXmlElementSyntax(SyntaxNode node) + => node.IsKind(SyntaxKind.XmlElement, out XmlElementSyntax xmlElement) && + xmlElement.StartTag.Name.ToString() == DocumentationCommentXmlNames.ParameterElementName; + + internal override SyntaxNode[] GetContentFromDocumentationCommentTriviaSyntax(SyntaxTrivia trivia) + { + if (trivia.GetStructure() is DocumentationCommentTriviaSyntax documentationCommentTrivia) + { + return documentationCommentTrivia.Content.ToArray(); + } + + return new SyntaxNode[0]; + } + + internal override SyntaxNode DocumentationCommentTriviaWithUpdatedContent(SyntaxTrivia trivia, IEnumerable content) + { + if (trivia.GetStructure() is DocumentationCommentTriviaSyntax documentationCommentTrivia) + { + return SyntaxFactory.DocumentationCommentTrivia(documentationCommentTrivia.Kind(), SyntaxFactory.List(content), documentationCommentTrivia.EndOfComment); + } + + return null; + } + public static readonly SyntaxGenerator Instance = new CSharpSyntaxGenerator(); #region Declarations @@ -3676,6 +3737,13 @@ static IEnumerable> splitIntoLines(SyntaxTriviaList tr return new SyntaxTriviaList(syntaxWithoutComments); } + + internal override SyntaxNode ParseExpression(string stringToParse) + => SyntaxFactory.ParseExpression(stringToParse); + + internal override SyntaxToken CommaTokenWithElasticSpace() + => SyntaxFactory.Token(SyntaxKind.CommaToken).WithTrailingTrivia(SyntaxFactory.ElasticSpace); + #endregion #region Patterns diff --git a/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj b/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj index 7f3bfc19c008f..ad75c19fd682a 100644 --- a/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj +++ b/src/Workspaces/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Workspaces.csproj @@ -45,6 +45,7 @@ + diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index 01b5bb0a71a0d..4b21b7f730df2 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -1294,6 +1294,8 @@ public SyntaxNode RemoveNodes(SyntaxNode root, IEnumerable declarati internal abstract SeparatedSyntaxList SeparatedList(SyntaxNodeOrTokenList list) where TElement : SyntaxNode; + internal abstract SeparatedSyntaxList SeparatedList(IEnumerable nodes, IEnumerable separators) where TElement : SyntaxNode; + internal static SyntaxTokenList Merge(SyntaxTokenList original, SyntaxTokenList newList) { // return tokens from newList, but use original tokens of kind matches @@ -2301,6 +2303,29 @@ public SyntaxNode LambdaParameter(string identifier, ITypeSymbol type) /// public abstract SyntaxNode TupleExpression(IEnumerable arguments); + /// + /// Parses an expression from string + /// + internal abstract SyntaxNode ParseExpression(string stringToParse); + + internal abstract SyntaxToken CommaTokenWithElasticSpace(); + + internal abstract SyntaxTrivia Trivia(SyntaxNode node); + + internal abstract SyntaxNode DocumentationCommentTrivia(IEnumerable nodes, SyntaxTriviaList trailingTrivia, SyntaxTrivia lastWhitespaceTrivia, string endOfLineString); + + internal abstract bool IsNamedArgument(SyntaxNode syntaxNode); + + internal abstract bool IsWhitespaceTrivia(SyntaxTrivia trivia); + + internal abstract bool IsDocumentationCommentTriviaSyntax(SyntaxNode node); + + internal abstract bool IsParameterNameXmlElementSyntax(SyntaxNode node); + + internal abstract SyntaxNode[] GetContentFromDocumentationCommentTriviaSyntax(SyntaxTrivia trivia); + + internal abstract SyntaxNode DocumentationCommentTriviaWithUpdatedContent(SyntaxTrivia trivia, IEnumerable content); + #endregion #region Patterns diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index 03766ededb99f..4e044de7f0ea9 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -49,6 +49,70 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.SeparatedList(Of TElement)(list) End Function + Friend Overrides Function SeparatedList(Of TElement As SyntaxNode)(nodes As IEnumerable(Of TElement), separators As IEnumerable(Of SyntaxToken)) As SeparatedSyntaxList(Of TElement) + Return SyntaxFactory.SeparatedList(nodes, separators) + End Function + + Friend Overrides Function Trivia(node As SyntaxNode) As SyntaxTrivia + Dim structuredTrivia = TryCast(node, StructuredTriviaSyntax) + If structuredTrivia IsNot Nothing Then + Return SyntaxFactory.Trivia(structuredTrivia) + End If + + Return Nothing + End Function + + Friend Overrides Function DocumentationCommentTrivia(nodes As IEnumerable(Of SyntaxNode), trailingTrivia As SyntaxTriviaList, lastWhitespaceTrivia As SyntaxTrivia, endOfLineString As String) As SyntaxNode + Dim node = SyntaxFactory.DocumentationCommentTrivia(SyntaxFactory.List(nodes)) + Return node.WithLeadingTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia("''' ")). + WithTrailingTrivia(node.GetTrailingTrivia()). + WithTrailingTrivia(SyntaxFactory.EndOfLine(endOfLineString), lastWhitespaceTrivia) + End Function + + Friend Overrides Function IsNamedArgument(syntaxNode As SyntaxNode) As Boolean + Dim argument = TryCast(syntaxNode, ArgumentSyntax) + If argument IsNot Nothing Then + Return argument.IsNamed + Else + Return False + End If + End Function + + Friend Overrides Function IsWhitespaceTrivia(trivia As SyntaxTrivia) As Boolean + Return trivia.IsKind(SyntaxKind.WhitespaceTrivia) + End Function + + Friend Overrides Function IsDocumentationCommentTriviaSyntax(node As SyntaxNode) As Boolean + Return node.IsKind(SyntaxKind.DocumentationCommentTrivia) + End Function + + Friend Overrides Function IsParameterNameXmlElementSyntax(node As SyntaxNode) As Boolean + Dim xmlElement = TryCast(node, XmlElementSyntax) + If xmlElement IsNot Nothing Then + Return xmlElement.StartTag.Name.ToString() = DocumentationCommentXmlNames.ParameterElementName + End If + + Return False + End Function + + Friend Overrides Function GetContentFromDocumentationCommentTriviaSyntax(trivia As SyntaxTrivia) As SyntaxNode() + Dim documentationCommentTrivia = TryCast(trivia.GetStructure(), DocumentationCommentTriviaSyntax) + If documentationCommentTrivia IsNot Nothing Then + Return documentationCommentTrivia.Content.ToArray() + End If + + Return Nothing + End Function + + Friend Overrides Function DocumentationCommentTriviaWithUpdatedContent(trivia As SyntaxTrivia, content As IEnumerable(Of SyntaxNode)) As SyntaxNode + Dim documentationCommentTrivia = TryCast(trivia.GetStructure(), DocumentationCommentTriviaSyntax) + If documentationCommentTrivia IsNot Nothing Then + Return SyntaxFactory.DocumentationCommentTrivia(SyntaxFactory.List(content)) + End If + + Return Nothing + End Function + #Region "Expressions and Statements" Public Overrides Function AddEventHandler([event] As SyntaxNode, handler As SyntaxNode) As SyntaxNode @@ -405,37 +469,37 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Public Overrides Function TypeExpression(specialType As SpecialType) As SyntaxNode Select Case specialType - Case specialType.System_Boolean + Case SpecialType.System_Boolean Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BooleanKeyword)) - Case specialType.System_Byte + Case SpecialType.System_Byte Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ByteKeyword)) - Case specialType.System_Char + Case SpecialType.System_Char Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.CharKeyword)) - Case specialType.System_Decimal + Case SpecialType.System_Decimal Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DecimalKeyword)) - Case specialType.System_Double + Case SpecialType.System_Double Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DoubleKeyword)) - Case specialType.System_Int16 + Case SpecialType.System_Int16 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ShortKeyword)) - Case specialType.System_Int32 + Case SpecialType.System_Int32 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntegerKeyword)) - Case specialType.System_Int64 + Case SpecialType.System_Int64 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.LongKeyword)) - Case specialType.System_Object + Case SpecialType.System_Object Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ObjectKeyword)) - Case specialType.System_SByte + Case SpecialType.System_SByte Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.SByteKeyword)) - Case specialType.System_Single + Case SpecialType.System_Single Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.SingleKeyword)) - Case specialType.System_String + Case SpecialType.System_String Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)) - Case specialType.System_UInt16 + Case SpecialType.System_UInt16 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.UShortKeyword)) - Case specialType.System_UInt32 + Case SpecialType.System_UInt32 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.UIntegerKeyword)) - Case specialType.System_UInt64 + Case SpecialType.System_UInt64 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ULongKeyword)) - Case specialType.System_DateTime + Case SpecialType.System_DateTime Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DateKeyword)) Case Else Throw New NotSupportedException("Unsupported SpecialType") @@ -681,6 +745,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return expression End Function + Friend Overrides Function ParseExpression(stringToParse As String) As SyntaxNode + Return SyntaxFactory.ParseExpression(stringToParse) + End Function + + Friend Overrides Function CommaTokenWithElasticSpace() As SyntaxToken + Return SyntaxFactory.Token(SyntaxKind.CommaToken).WithTrailingTrivia(SyntaxFactory.ElasticSpace) + End Function + #End Region #Region "Declarations" @@ -901,7 +973,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration If initializer IsNot Nothing Then tokens = tokens.Add(SyntaxFactory.Token(SyntaxKind.OptionalKeyword)) End If - If refKind <> refKind.None Then + If refKind <> RefKind.None Then tokens = tokens.Add(SyntaxFactory.Token(SyntaxKind.ByRefKeyword)) End If Return tokens @@ -2467,7 +2539,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim newTokens = GetModifierList(accessibility, mods, GetDeclarationKind(declaration), isDefault) 'GetDeclarationKind returns None for Field if the count is > 1 'To handle multiple declarations on a field if the Accessibility is NotApplicable, we need to add the Dim - If declaration.Kind = SyntaxKind.FieldDeclaration AndAlso accessibility = accessibility.NotApplicable AndAlso newTokens.Count = 0 Then + If declaration.Kind = SyntaxKind.FieldDeclaration AndAlso accessibility = Accessibility.NotApplicable AndAlso newTokens.Count = 0 Then ' Add the Dim newTokens = newTokens.Add(SyntaxFactory.Token(SyntaxKind.DimKeyword)) End If @@ -2570,6 +2642,65 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return _list End Function + Private Sub GetAccessibilityAndModifiers(modifierTokens As SyntaxTokenList, ByRef accessibility As Accessibility, ByRef modifiers As DeclarationModifiers, ByRef isDefault As Boolean) + accessibility = Accessibility.NotApplicable + modifiers = DeclarationModifiers.None + isDefault = False + + For Each token In modifierTokens + Select Case token.Kind + Case SyntaxKind.DefaultKeyword + isDefault = True + Case SyntaxKind.PublicKeyword + accessibility = Accessibility.Public + Case SyntaxKind.PrivateKeyword + If accessibility = Accessibility.Protected Then + accessibility = Accessibility.ProtectedAndFriend + Else + accessibility = Accessibility.Private + End If + Case SyntaxKind.FriendKeyword + If accessibility = Accessibility.Protected Then + accessibility = Accessibility.ProtectedOrFriend + Else + accessibility = Accessibility.Friend + End If + Case SyntaxKind.ProtectedKeyword + If accessibility = Accessibility.Friend Then + accessibility = Accessibility.ProtectedOrFriend + ElseIf accessibility = Accessibility.Private Then + accessibility = Accessibility.ProtectedAndFriend + Else + accessibility = Accessibility.Protected + End If + Case SyntaxKind.MustInheritKeyword, SyntaxKind.MustOverrideKeyword + modifiers = modifiers Or DeclarationModifiers.Abstract + Case SyntaxKind.ShadowsKeyword + modifiers = modifiers Or DeclarationModifiers.[New] + Case SyntaxKind.OverridesKeyword + modifiers = modifiers Or DeclarationModifiers.Override + Case SyntaxKind.OverridableKeyword + modifiers = modifiers Or DeclarationModifiers.Virtual + Case SyntaxKind.SharedKeyword + modifiers = modifiers Or DeclarationModifiers.Static + Case SyntaxKind.AsyncKeyword + modifiers = modifiers Or DeclarationModifiers.Async + Case SyntaxKind.ConstKeyword + modifiers = modifiers Or DeclarationModifiers.Const + Case SyntaxKind.ReadOnlyKeyword + modifiers = modifiers Or DeclarationModifiers.ReadOnly + Case SyntaxKind.WriteOnlyKeyword + modifiers = modifiers Or DeclarationModifiers.WriteOnly + Case SyntaxKind.NotInheritableKeyword, SyntaxKind.NotOverridableKeyword + modifiers = modifiers Or DeclarationModifiers.Sealed + Case SyntaxKind.WithEventsKeyword + modifiers = modifiers Or DeclarationModifiers.WithEvents + Case SyntaxKind.PartialKeyword + modifiers = modifiers Or DeclarationModifiers.Partial + End Select + Next + End Sub + Private Function GetTypeParameters(typeParameterNames As IEnumerable(Of String)) As TypeParameterListSyntax If typeParameterNames Is Nothing Then Return Nothing diff --git a/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj b/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj index ce48b7b5c75f1..946169e6d6523 100644 --- a/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj +++ b/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj @@ -39,6 +39,7 @@ +