/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs
14 505 строк
381 KB
Tomáš Matoušek
Do not report 'no-effect' warning when active top-level code is updated (#79746)
06 авг 2025, 02:18
Не верифицирован
06 авг 2025, 02:18
66b4fd6
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable #pragma warning disable IDE0055 // Collection expression formatting using System; using Microsoft.CodeAnalysis.Contracts.EditAndContinue; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests; [UseExportProvider] public sealed class ActiveStatementTests : EditingTestBase { #region Update [Fact] public void Update_Inner() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { while (true) { <AS:1>Goo(2);</AS:1> } } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "Goo(2);")); } [Fact] public void Update_Inner_NewCommentAtEndOfActiveStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1>// } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } /// <summary> /// CreateNewOnMetadataUpdate has no effect in presence of active statements (in break mode). /// </summary> [Fact] public void Update_Inner_Reloadable() { var src1 = ReloadableAttributeSrc + """ [CreateNewOnMetadataUpdate] class C { static void F() { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = ReloadableAttributeSrc + """ [CreateNewOnMetadataUpdate] class C { static void F() { while (true) { <AS:1>Goo(2);</AS:1> } } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "Goo(2);")); } [Fact] public void Update_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { while (true) { <AS:1>Goo(1);</AS:1> } } static void Goo(int a) { <AS:0>Console.WriteLine(a + 1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Update_Leaf_NewCommentAtEndOfActiveStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0>// } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } /// <summary> /// CreateNewOnMetadataUpdate has no effect in presence of active statements (in break mode). /// </summary> [Fact] public void Update_Leaf_Reloadable() { var src1 = ReloadableAttributeSrc + """ [CreateNewOnMetadataUpdate] class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = ReloadableAttributeSrc + """ [CreateNewOnMetadataUpdate] class C { static void Main(string[] args) { while (true) { <AS:1>Goo(1);</AS:1> } } static void Goo(int a) { <AS:0>Console.WriteLine(a + 1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemantics(active, semanticEdits: [ SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Main"), preserveLocalVariables: true), SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Goo"), preserveLocalVariables: true) ]); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/846588")] public void Update_Leaf_Block() { var src1 = """ class C : System.IDisposable { public void Dispose() {} static void Main(string[] args) { using (<AS:0>C x = null</AS:0>) {} } } """; var src2 = """ class C : System.IDisposable { public void Dispose() {} static void Main(string[] args) { using (<AS:0>C x = new C()</AS:0>) {} } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Update_TopLevel() { var src1 = """ <AS:0>F();</AS:0> Map(1, () => 1); """; var src2 = """ <AS:0>F();</AS:0> Map(2, () => 1); """; var active = GetActiveStatements(src1, src2); var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Update_TopLevel_ActiveStatementInLambda() { var src1 = """ Map(1, () => <AS:0>1</AS:0>); """; var src2 = """ Map(2, () => <AS:0>1</AS:0>); """; var active = GetActiveStatements(src1, src2); var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "2", GetResource("top-level code"))); } [Fact] public void Update_RestartRequiredAttribute() { var src1 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { [RestartRequiredOnMetadataUpdateAttribute] public int F() => <AS:0>1</AS:0>; } """; var src2 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { [RestartRequiredOnMetadataUpdateAttribute] public int F() => <AS:0>2</AS:0>; } """; var active = GetActiveStatements(src1, src2); var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Delete in Method Body [Fact] public void Delete_Inner() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { while (true) { } <AS:1>}</AS:1> static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code)); } // TODO (tomat): considering a change [Fact] public void Delete_Inner_MultipleParents() { var src1 = """ class C : IDisposable { unsafe static void Main(string[] args) { { <AS:1>Goo(1);</AS:1> } if (true) { <AS:2>Goo(2);</AS:2> } else { <AS:3>Goo(3);</AS:3> } int x = 1; switch (x) { case 1: case 2: <AS:4>Goo(4);</AS:4> break; default: <AS:5>Goo(5);</AS:5> break; } checked { <AS:6>Goo(4);</AS:6> } unchecked { <AS:7>Goo(7);</AS:7> } while (true) <AS:8>Goo(8);</AS:8> do <AS:9>Goo(9);</AS:9> while (true); for (int i = 0; i < 10; i++) <AS:10>Goo(10);</AS:10> foreach (var i in new[] { 1, 2}) <AS:11>Goo(11);</AS:11> using (var z = new C()) <AS:12>Goo(12);</AS:12> fixed (char* p = "s") <AS:13>Goo(13);</AS:13> label: <AS:14>Goo(14);</AS:14> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C : IDisposable { unsafe static void Main(string[] args) { { <AS:1>}</AS:1> if (true) { <AS:2>}</AS:2> else { <AS:3>}</AS:3> int x = 1; switch (x) { case 1: case 2: <AS:4>break;</AS:4> default: <AS:5>break;</AS:5> } checked { <AS:6>}</AS:6> unchecked { <AS:7>}</AS:7> <AS:8>while (true)</AS:8> { } do { } <AS:9>while (true);</AS:9> for (int i = 0; i < 10; <AS:10>i++</AS:10>) { } foreach (var i <AS:11>in</AS:11> new[] { 1, 2 }) { } using (<AS:12>var z = new C()</AS:12>) { } fixed (<AS:13>char* p = "s"</AS:13>) { } label: <AS:14>{</AS:14> } } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "case 2:", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "default:", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "while (true)", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "do", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "for (int i = 0; i < 10; i++ )", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "foreach (var i in new[] { 1, 2 })", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "using ( var z = new C() )", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "fixed ( char* p = \"s\" )", FeaturesResources.code), Diagnostic(RudeEditKind.DeleteActiveStatement, "label", FeaturesResources.code)); } [Fact] public void Delete_Leaf1() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Delete_Leaf2() { var src1 = """ class C { static void Goo(int a) { Console.WriteLine(1); Console.WriteLine(2); <AS:0>Console.WriteLine(3);</AS:0> Console.WriteLine(4); } } """; var src2 = """ class C { static void Goo(int a) { Console.WriteLine(1); Console.WriteLine(2); <AS:0>Console.WriteLine(4);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Delete_Leaf_InTry() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { try { <AS:0>Console.WriteLine(a);</AS:0> } catch { } } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { try { <AS:0>}</AS:0> catch { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Delete_Leaf_InTry2() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { try { try { <AS:0>Console.WriteLine(a);</AS:0> } catch { } } catch { } } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { try { try { <AS:0>}</AS:0> catch { } } catch { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Delete_Inner_CommentActiveStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { //Goo(1); <AS:1>}</AS:1> static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755959")] public void Delete_Leaf_CommentActiveStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { //Console.WriteLine(a); <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Delete_Entire_Namespace() { var src1 = """ namespace N { class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = @"<AS:0/>"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.Delete, "", GetResource("class", "N.C")), Diagnostic(RudeEditKind.DeleteActiveStatement, "", GetResource("method", "N.C.F()"))); } [Fact] public void Delete_Entire_Type() { var src1 = """ namespace N { class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = @"<AS:0>namespace N</AS:0>;"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.Delete, "namespace N", GetResource("class", "C")), Diagnostic(RudeEditKind.DeleteActiveStatement, "namespace N", GetResource("method", "N.C.F()"))); } [Fact] public void Delete_Entire_Method() { var src1 = """ namespace N { class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ namespace N { <AS:0>class C</AS:0> { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "class C", GetResource("method", "N.C.F()"))); } #endregion #region Parameters & Returns [Fact] public void Parameter_Rename() { var src1 = "class C { int F(int a) => <AS:0>1</AS:0>; }"; var src2 = "class C { int F(int b) => <AS:0>1</AS:0>; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.UpdateParameters); } [Theory] [InlineData("int")] [InlineData("in byte")] [InlineData("ref byte")] [InlineData("out byte")] [InlineData("ref readonly byte")] public void Parameter_Update_TypeOrRefKind_RuntimeTypeChanged(string oldType) { var src1 = "class C { int F(" + oldType + " a) => <AS:0>throw null!</AS:0>; }"; var src2 = "class C { int F(byte a) => <AS:0>throw null!</AS:0>; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Can't remap to the new version of the method. // Even if we emitted trampoline we would not be able to remap to the exact instruction the active statement is at in the old version. edits.VerifySemanticDiagnostics(active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "byte a", GetResource("method"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Theory, CombinatorialData] public void Parameter_Update_RefKind_RuntimeTypeUnchanged( [CombinatorialValues("ref", "out", "in", "ref readonly")] string oldModifiers, [CombinatorialValues("ref", "out", "in", "ref readonly")] string newModifiers) { if (oldModifiers == newModifiers) { return; } var src1 = "class C { int F(" + oldModifiers + " int a) => <AS:0>throw null!</AS:0>; }"; var src2 = "class C { int F(" + newModifiers + " int a) => <AS:0>throw null!</AS:0>; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // We don't require a runtime capability to update attributes. // All runtimes support changing the attributes in metadata, some just don't reflect the changes in the Reflection model. // Having compiler-generated attributes visible via Reflaction API is not that important. // The same for [in] and [out] metadata flags. edits.VerifySemantics(active, [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true)], capabilities: EditAndContinueCapabilities.Baseline); } [Theory] [InlineData("params")] [InlineData("this")] public void Parameter_Update_Modifiers_RuntimeTypeUnchanged(string newModifiers) { var src1 = "static class C { static int F(int[] a) => <AS:0>throw null!</AS:0>; }"; var src2 = "static class C { static int F(" + newModifiers + " int[] a) => <AS:0>throw null!</AS:0>; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // We don't require a runtime capability to update attributes. // All runtimes support changing the attributes in metadata, some just don't reflect the changes in the Reflection model. // Having compiler-generated attributes visible via Reflaction API is not that important. // The same for [in] and [out] metadata flags. edits.VerifySemantics(active, [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true)], capabilities: EditAndContinueCapabilities.Baseline); } [Fact] public void Return_TypeChange() { var src1 = "class C { int F(int a) => <AS:0>1</AS:0>; }"; var src2 = "class C { byte F(int a) => <AS:0>1</AS:0>; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Can't remap to the new version of the method. // Even if we emitted trampoline we would not be able to remap to the exact instruction the active statement is at in the old version. edits.VerifySemanticDiagnostics(active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "byte F(int a)", GetResource("method"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Return_TypeChange_Ref() { var src1 = "class C { int X; int F(int a) => <AS:0>1</AS:0>; }"; var src2 = "class C { int X; ref int F(int a) => <AS:0>ref X</AS:0>; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Can't remap to the new version of the method. // Even if we emitted trampoline we would not be able to remap to the exact instruction the active statement is at in the old version. edits.VerifySemanticDiagnostics(active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "ref int F(int a)", GetResource("method"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Return_TypeChange_RefReadonly() { var src1 = "class C { int X; ref int F(int a) => <AS:0>ref X</AS:0>; }"; var src2 = "class C { int X; ref readonly int F(int a) => <AS:0>ref X</AS:0>; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Can't remap to the new version of the method. // Even if we emitted trampoline we would not be able to remap to the exact instruction the active statement is at in the old version. edits.VerifySemanticDiagnostics(active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "ref readonly int F(int a)", GetResource("method"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } #endregion #region Constructors [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/740949")] public void Updated_Inner_Constructor() { var src1 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5);</AS:1> } } class Goo { int value; public Goo(int a) { <AS:0>this.value = a;</AS:0> } } """; var src2 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5*2);</AS:1> } } class Goo { int value; public Goo(int a) { <AS:0>this.value = a;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "Goo f = new Goo(5*2);")); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/741249")] public void Updated_Leaf_Constructor() { var src1 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5);</AS:1> } } class Goo { int value; public Goo(int a) { <AS:0>this.value = a;</AS:0> } } """; var src2 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5);</AS:1> } } class Goo { int value; public Goo(int a) { <AS:0>this.value = a*2;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/742334")] public void Updated_Leaf_Constructor_Parameter() { var src1 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5);</AS:1> } } class Goo { int value; <AS:0>public Goo(int a)</AS:0> { this.value = a; } } """; var src2 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5);</AS:1> } } class Goo { int value; <AS:0>public Goo(int b)</AS:0> { this.value = b; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemantics( ActiveStatementsDescription.Empty, [ SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Goo..ctor"), preserveLocalVariables: true) ], capabilities: EditAndContinueTestVerifier.Net6RuntimeCapabilities); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/742334")] public void Updated_Leaf_Constructor_Parameter_DefaultValue() { var src1 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5);</AS:1> } } class Goo { int value; <AS:0>public Goo(int a = 5)</AS:0> { this.value = a; } } """; var src2 = """ using System; class Program { static void Main(string[] args) { <AS:1>Goo f = new Goo(5);</AS:1> } } class Goo { int value; <AS:0>public Goo(int a = 42)</AS:0> { this.value = a; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InitializerUpdate, "int a = 42", FeaturesResources.parameter)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/742334")] public void Updated_Leaf_ConstructorChaining1() { var src1 = """ using System; class Test { static void Main(string[] args) { <AS:1>B b = new B(2, 3);</AS:1> } } class B : A { public B(int x, int y) : <AS:0>base(x + y, x - y)</AS:0> { } } class A { public A(int x, int y) : this(5 + x, y, 0) { } public A(int x, int y, int z) { } } """; var src2 = """ using System; class Test { static void Main(string[] args) { <AS:1>B b = new B(2, 3);</AS:1> } } class B : A { public B(int x, int y) : <AS:0>base(x + y + 5, x - y)</AS:0> { } } class A { public A(int x, int y) : this(x, y, 0) { } public A(int x, int y, int z) { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/742334")] public void Updated_Leaf_ConstructorChaining2() { var src1 = """ using System; class Test { static void Main(string[] args) { <AS:2>B b = new B(2, 3);</AS:2> } } class B : A { public B(int x, int y) : <AS:1>base(x + y, x - y)</AS:1> { } } class A { public A(int x, int y) : <AS:0>this(x, y, 0)</AS:0> { } public A(int x, int y, int z) { } } """; var src2 = """ using System; class Test { static void Main(string[] args) { <AS:2>B b = new B(2, 3);</AS:2> } } class B : A { public B(int x, int y) : <AS:1>base(x + y, x - y)</AS:1> { } } class A { public A(int x, int y) : <AS:0>this(5 + x, y, 0)</AS:0> { } public A(int x, int y, int z) { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ImplicitInitializer() { var src1 = """ class C { int a = 5; <AS:0>public C(int a)</AS:0> { } static void Main(string[] args) { <AS:1>C c = new C(3);</AS:1> } } """; var src2 = """ class C { int a = 42; <AS:0>public C(int a)</AS:0> { } static void Main(string[] args) { <AS:1>C c = new C(3);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ExplicitInitializer_Update_Subexpression() { var src1 = """ class C { public C(int a) : base(a switch { 1 => <AS:0>1</AS:0>, _ => 2 }) {} } """; var src2 = """ class C { public C(int a) : base(1) <AS:0>{</AS:0>} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ExplicitInitializer_Update_Internal() { var src1 = """ class D { public D(int d) {} } class C : D { int a = 5; public C(int a) : <AS:2>this(true)</AS:2> { } public C(bool b) : <AS:1>base(F())</AS:1> {} static int F() { <AS:0>return 1;</AS:0> } static void Main(string[] args) { <AS:3>C c = new C(3);</AS:3> } } """; var src2 = """ class D { public D(int d) {} } class C : D { int a = 5; public C(int a) : <AS:2>this(false)</AS:2> { } public C(bool b) : <AS:1>base(F())</AS:1> {} static int F() { <AS:0>return 1;</AS:0> } static void Main(string[] args) { <AS:3>C c = new C(3);</AS:3> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "this(false)")); } [Fact] public void Constructor_Instance_ExplicitInitializer_Update_Leaf() { var src1 = """ class D { public D(int d) { } } class C : D { public C() : <AS:0>base(1)</AS:0> {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ class D { public D(int d) { } } class C : D { public C() : <AS:0>base(2)</AS:0> {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ImplicitInitializer_Update_ToExplicit_Leaf() { var src1 = """ class D { public D() { } public D(int d) { } } class C : D { <AS:0>public C()</AS:0> {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ class D { public D() { } public D(int d) { } } class C : D { public C() : <AS:0>base(2)</AS:0> {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ImplicitInitializer_Update_ToExplicit_Internal() { var src1 = """ class D { public D(int d) <AS:0>{</AS:0> } } class C : D { <AS:1>public C()</AS:1> {} } """; var src2 = """ class D { public D(int d) <AS:0>{</AS:0> } } class C : D { public C() : <AS:1>base(1)</AS:1> {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "base(1)")); } [Fact] public void Constructor_Instance_ExplicitInitializer_Update_ToImplicit_Internal() { var src1 = """ class D { public D(int d) {} } class C : D { public C() : <AS:1>base(F())</AS:1> {} static int F() { <AS:0>return 1;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var src2 = """ class D { public D(int d) {} } class C : D { <AS:1>public C()</AS:1> {} static int F() { <AS:0>return 1;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "public C()")); } [Fact] public void Constructor_Instance_ExplicitInitializer_Update_ToImplicit_Leaf() { var src1 = """ class D { public D() { } public D(int d) { } } class C : D { public C() : <AS:0>base(2)</AS:0> {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ class D { public D() { } public D(int d) { } } class C : D { <AS:0>public C()</AS:0> {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ExplicitInitializer_WithLambda_Update1() { var src1 = """ class C { public C() : this((a, b) => { <AS:0>Console.WriteLine(a + b);</AS:0> }) { } } """; var src2 = """ class C { public C() : base((a, b) => { <AS:0>Console.WriteLine(a - b);</AS:0> }) { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ExplicitInitializer_WithLambda_Update2() { var src1 = """ class C { public C() : <AS:1>this((a, b) => { <AS:0>Console.WriteLine(a + b);</AS:0> })</AS:1> { Console.WriteLine(1); } } """; var src2 = """ class C { public C() : <AS:1>this((a, b) => { <AS:0>Console.WriteLine(a + b);</AS:0> })</AS:1> { Console.WriteLine(2); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ExplicitInitializer_WithLambda_Update3() { var src1 = """ class C { public C() : <AS:1>this((a, b) => { <AS:0>Console.WriteLine(a + b);</AS:0> })</AS:1> { Console.WriteLine(1); } } """; var src2 = """ class C { public C() : <AS:1>this((a, b) => { <AS:0>Console.WriteLine(a - b);</AS:0> })</AS:1> { Console.WriteLine(1); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ExplicitInitializer_Delete() { var src1 = """ class C { public C(int a) : base(a switch { 1 => <AS:0>1</AS:0>, _ => 2 }) {} } """; var src2 = """ class C { public C(int a) <AS:0>{</AS:0>} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/68708")] public void Constructor_Instance_ImplicitInitializer_ParameterChange() { var src1 = "class C { <AS:0>C(int P)</AS:0> {} }"; var src2 = "class C { <AS:0>C(byte P)</AS:0> {} }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "byte P", GetResource("constructor"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Constructor_Instance_ImplicitInitializer_ParameterChange_WithActiveFieldInitializer_Unchanged() { var src1 = "class C { C(int P) {} <AS:0>int x = 1;</AS:0> }"; var src2 = "class C { C(byte P) {} <AS:0>int x = 1;</AS:0> }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "byte P", GetResource("constructor"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Constructor_Instance_ImplicitInitializer_ParameterChange_WithActiveFieldInitializer_Unchanged_Multiple() { var src1 = "class C { C(int P) {} static int s; int x = s switch { 1 => <AS:0>1</AS:0>, _ => <AS:1>2</AS:1> }; }"; var src2 = "class C { C(byte P) {} static int s; int x = s switch { 1 => <AS:0>1</AS:0>, _ => <AS:1>2</AS:1> }; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "byte P", GetResource("constructor"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Constructor_Instance_ImplicitInitializer_ParameterChange_WithActiveFieldInitializer_Changed() { var src1 = "class C { C(int P) {} <AS:0>int x = 1;</AS:0> }"; var src2 = "class C { C(byte P) {} <AS:0>int x = 2;</AS:0> }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "byte P", GetResource("constructor"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Constructor_Instance_ImplicitInitializer_ParameterChange_WithActiveLambdaInFieldInitializer() { var src1 = "class C { C(int P) {} System.Action x = () => <AS:0>{</AS:0>}; }"; var src2 = "class C { C(byte P) {} System.Action x = () => <AS:0>{</AS:0>}; }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Theory] [InlineData("class")] [InlineData("struct")] [WorkItem("https://github.com/dotnet/roslyn/issues/68708")] public void Constructor_Instance_Primary_ImplicitInitializer_ParameterChange(string keyword) { var src1 = keyword + " <AS:0>C(int P)</AS:0>;"; var src2 = keyword + " <AS:0>C(byte P)</AS:0>;"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "byte P", GetResource("constructor"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Theory] [InlineData("class")] [InlineData("record")] public void Constructor_Instance_Primary_ExplicitInitializer(string keyword) { var src1 = keyword + " C(int P) : <AS:0>B(1)</AS:0>;"; var src2 = keyword + " C(int P) : <AS:0>B(2)</AS:0>;"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_Primary_Record_Parameter_BaseInitializerChange() { var src1 = "record C(<AS:0>int P</AS:0>) : B(1);"; var src2 = "record C(<AS:0>int P</AS:0>) : B(2);"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("record")] [InlineData("record struct")] public void Constructor_Instance_Primary_Record_Parameter_TypeAttributeChange(string keyword) { var src1 = "class A(int x) : System.Attribute; [A( 1)]" + keyword + " C(<AS:0>int P</AS:0>);"; var src2 = "class A(int x) : System.Attribute; [A(10)]" + keyword + " C(<AS:0>int P</AS:0>);"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); } [Theory] [InlineData("record")] [InlineData("record struct")] public void Constructor_Instance_Primary_Record_Parameter_TypeParameterAttributeChange(string keyword) { var src1 = "class A(int x) : System.Attribute; " + keyword + " C<[A( 1)] T>(<AS:0>int P</AS:0>);"; var src2 = "class A(int x) : System.Attribute; " + keyword + " C<[A(10)] T>(<AS:0>int P</AS:0>);"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [ Diagnostic(RudeEditKind.GenericTypeUpdate, "T") ], capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); } [Fact] public void Constructor_Instance_Copy_BaseInitializerChange() { var src1 = "record <AS:0>C</AS:0>(int P) : B(1);"; var src2 = "record <AS:0>C</AS:0>(int P) : B(2);"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("record")] [InlineData("record struct")] public void Constructor_Instance_Copy_TypeAttributeChange(string keyword) { var src1 = "class A(int x) : System.Attribute; [A( 1)]" + keyword + " <AS:0>C</AS:0>(int P);"; var src2 = "class A(int x) : System.Attribute; [A(10)]" + keyword + " <AS:0>C</AS:0>(int P);"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); } [Theory] [InlineData("record")] [InlineData("record struct")] public void Constructor_Instance_Copy_TypeParameterAttributeChange(string keyword) { var src1 = "class A(int x) : System.Attribute; " + keyword + " <AS:0>C<[A( 1)] T></AS:0>(int P);"; var src2 = "class A(int x) : System.Attribute; " + keyword + " <AS:0>C<[A(10)] T></AS:0>(int P);"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [ Diagnostic(RudeEditKind.GenericTypeUpdate, "T"), ], capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); } [Fact] public void Constructor_Instance_Copy_ReplacingPrimaryWithNonPrimary() { var src1 = """ public record <AS:0>C</AS:0>(int P); """; var src2 = """ public record C { public int P { get; init; } public C(int P) { } <AS:0>protected C(C original)</AS:0> { P = original.P; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_Copy_ReplacingNonPrimaryWithPrimary_Initializer() { var src1 = """ public record C { public int P { get; init; } public C(int P) { } <AS:0>protected C(C original)</AS:0> { P = original.P; } } """; var src2 = """ public record <AS:0>C</AS:0>(int P); """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_Copy_ReplacingNonPrimaryWithPrimary_Body1() { var src1 = """ public record C { public int P { get; init; } public C(int P) { } protected C(C original) <AS:0>{</AS:0> P = original.P; } } """; var src2 = """ public record <AS:0>C</AS:0>(int P); """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_Copy_ReplacingNonPrimaryWithPrimary_Body2() { var src1 = """ public record C { public int P { get; init; } public C(int P) { } protected C(C original) { P = original.P; <AS:0>}</AS:0> } """; var src2 = """ public record <AS:0>C</AS:0>(int P); """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("class ")] [InlineData("struct")] public void Constructor_Instance_Delete_Parameterless(string typeKind) { var src1 = "partial " + typeKind + " C { public C() { <AS:0>System.Console.WriteLine(1);</AS:0> } }"; var src2 = "<AS:0>partial " + typeKind + " C</AS:0> { }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Synthesized constructor is generated and the active statement is remapped into it. edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("class")] [InlineData("struct")] [InlineData("record")] [InlineData("record struct")] public void Constructor_Instance_Delete_Primary(string typeKind) { var src1 = typeKind + " <AS:0>C()</AS:0> { }"; var src2 = "<AS:0>" + typeKind + " C</AS:0> { }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Synthesized constructor is generated and the active statement is remapped into it. edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("class")] [InlineData("record")] public void Constructor_Instance_Delete_BaseInitializer_Internal(string typeKind) { var src1 = "<AS:0>var c = new C();</AS:0> " + typeKind + " C() : <AS:1>B()</AS:1> { }"; var src2 = "<AS:0>var c = new C();</AS:0> " + typeKind + " <AS:1>C()</AS:1> : B { }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "C()")); } [Theory] [InlineData("class")] [InlineData("record")] public void Constructor_Instance_Delete_BaseInitializer_Leaf(string typeKind) { var src1 = typeKind + " C() : <AS:0>B()</AS:0> { }"; var src2 = typeKind + " <AS:0>C()</AS:0> : B { }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("class")] [InlineData("record")] public void Constructor_Instance_Insert_BaseInitializer_Internal(string typeKind) { var src1 = "<AS:0>var c = new C();</AS:0> " + typeKind + " <AS:1>C()</AS:1> : B { }"; var src2 = "<AS:0>var c = new C();</AS:0> " + typeKind + " C() : <AS:1>B()</AS:1> { }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "B()")); } [Theory] [InlineData("class")] [InlineData("record")] public void Constructor_Instance_Insert_BaseInitializer_Leaf(string typeKind) { var src1 = typeKind + " <AS:0>C()</AS:0> : B { }"; var src2 = typeKind + " C() : <AS:0>B()</AS:0> { }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("class")] [InlineData("struct")] [InlineData("record")] [InlineData("record struct")] public void Constructor_Instance_Unchanged(string typeKind) { var src1 = "<AS:0>var c = new C(1);</AS:0> " + typeKind + " <AS:1>C(int a)</AS:1>;"; var src2 = "<AS:0>var c = new C(2);</AS:0> " + typeKind + " <AS:1>C(int a)</AS:1>;"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_Primary_Record_ReplacingPrimaryWithNonPrimary() { var src1 = """ public record <AS:0>C(int P)</AS:0>; """; var src2 = """ public record C { public int P { get; init; } <AS:0>public C(int P)</AS:0> { } protected C(C original) { P = original.P; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_Primary_Record_ReplacingNonPrimaryWithPrimary_Initializer() { var src1 = """ public record C { public int P { get; init; } <AS:0>public C(int P)</AS:0> { } protected C(C original) { P = original.P; } } """; var src2 = """ public record <AS:0>C(int P)</AS:0>; """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_Primary_Record_ReplacingNonPrimaryWithPrimary_Body() { var src1 = """ public record C { public int P { get; init; } public C(int P) { <AS:0>}</AS:0> protected C(C original) { P = original.P; } } """; var src2 = """ public record <AS:0>C(int P)</AS:0>; """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Constructor_Instance_ReplacingNonPrimaryWithPrimary_Record() { var src1 = """ public record C { public int P { <AS:0>get;</AS:0> <AS:1>init;</AS:1> } <AS:2>public C(int P)</AS:2> { } protected C(C original) { <AS:3>P = original.P;</AS:3> } } """; var src2 = """ public record <AS:2,3>C</AS:3>(<AS:0,1>int P</AS:0,1>)</AS:2>; """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "C ( int P )"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "C"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "int P")); } [Fact] public void Constructor_Instance_ReplacingPrimaryWithNonPrimary_Record_PrimaryConstructor2() { var src1 = """ public record <AS:1,2>C</AS:2>(<AS:0>int P</AS:0>)</AS:1>; """; var src2 = """ public record C { public int P { <AS:0>get;</AS:0> init; } <AS:1>public C(int P)</AS:1> { } <AS:2>protected C(C original)</AS:2> { P = original.P; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "public C(int P)"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "protected C(C original)")); } #endregion #region Properties [Fact] public void Property_Update_Type_ActiveAccessors() { // only type is changed, no changes to the accessors (not even whitespace) var src1 = """ class C { public byte P { get => <AS:0>1</AS:0>; set <AS:1>{</AS:1> } } } """; var src2 = """ class C { public long P { get => <AS:0>1</AS:0>; set <AS:1>{</AS:1> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [ Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "public long P", GetResource("property getter")), Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "public long P", GetResource("property setter")) ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Property_Update_Type_ActiveInitializer() { // only type is changed, no changes to the accessors (not even whitespace) var src1 = """ class C { public byte P { get; } = <AS:0>1</AS:0>; } """; var src2 = """ class C { public long P { get; } = <AS:0>1</AS:0>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } [Fact] public void Property_Rename_ActiveAccessors() { var src1 = """ class C { public int P { get => <AS:0>1</AS:0>; set <AS:1>{</AS:1> } } } """; var src2 = """ class C { public int Q { get => <AS:0>1</AS:0>; set <AS:1>{</AS:1> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, diagnostics: [ Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "public int Q", GetResource("property getter")), Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "public int Q", GetResource("property setter")) ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Property_Update_ExpressionBodyToAutoProp_FieldAccess() { var src1 = """ class C { public int P => <AS:0>1</AS:0>; } """; var src2 = """ class C { public int P => <AS:0>field</AS:0>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } [Fact] public void Property_Update_Accessor_ExpressionBodyToAutoProp_FieldAccess() { var src1 = """ class C { public int P { get => <AS:0>1</AS:0>; } } """; var src2 = """ class C { public int P { get => <AS:0>field</AS:0>; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } [Fact] public void Property_Auto_Record_ReplacingNonPrimaryWithPrimary_Getter() { var src1 = """ public record C { public int P { <AS:0>get;</AS:0> init; } public C(int P) { } protected C(C original) {P = original.P; } } """; var src2 = """ public record C(<AS:0>int P</AS:0>); """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Property_Auto_Record_ReplacingNonPrimaryWithPrimary_Setter() { var src1 = """ public record C { public int P { get; <AS:0>init;</AS:0> } public C(int P) { } protected C(C original) {P = original.P; } } """; var src2 = """ public record C(<AS:0>int P</AS:0>); """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Property_Auto_Record_ReplacingPrimaryWithNonPrimary_Getter() { // Consider: Just looking at the span we do not know whether the active statement is in the getter of the setter. // We could resolve the method token associated with the method to find out and map the statement accordingly. var src1 = """ public record C(<AS:0>int P</AS:0>); """; var src2 = """ public record C { public int P { <AS:0>get;</AS:0> init; } public C(int P) { } protected C(C original) {P = original.P; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Property_Auto_Record_ReplacingPrimaryWithNonPrimary_Setter() { // Consider: Just looking at the span we do not know whether the active statement is in the getter of the setter. // We could resolve the method token associated with the method to find out and map the statement accordingly. var src1 = """ public record C(<AS:0>int P</AS:0>); """; var src2 = """ public record C { public int P { <AS:0>init;</AS:0> get; } public C(int P) { } protected C(C original) {P = original.P; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Field and Property Initializers [Theory] [InlineData("class ")] [InlineData("struct")] public void InstancePropertyInitializer_Leaf_Update(string typeKind) { var src1 = """ """ + typeKind + """ C { int a { get; } = <AS:0>1</AS:0>; public C() {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ """ + typeKind + """ C { int a { get; } = <AS:0>2</AS:0>; public C() {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("class ")] [InlineData("struct")] public void InstancePropertyInitializer_Leaf_Update_SynthesizedConstructor(string typeKind) { var src1 = """ """ + typeKind + """ C { int a { get; } = <AS:0>1</AS:0>; static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ """ + typeKind + """ C { int a { get; } = <AS:0>2</AS:0>; static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/742334")] [InlineData("class ")] [InlineData("struct")] public void InstanceFieldInitializer_Leaf_Update1(string typeKind) { var src1 = """ """ + typeKind + """ C { <AS:0>int a = 1</AS:0>, b = 2; public C() {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ """ + typeKind + """ C { <AS:0>int a = 2</AS:0>, b = 2; public C() {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory] [InlineData("class ")] [InlineData("struct")] public void InstanceFieldInitializer_Leaf_Update1_SynthesizedConstructor(string typeKind) { var src1 = """ """ + typeKind + """ C { <AS:0>int a = 1</AS:0>, b = 2; static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ """ + typeKind + """ C { <AS:0>int a = 2</AS:0>, b = 2; static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void InstanceFieldInitializer_Internal_Update1() { var src1 = """ class C { <AS:1>int a = F(1)</AS:1>, b = F(2); public C() {} public static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var src2 = """ class C { <AS:1>int a = F(2)</AS:1>, b = F(2); public C() {} public static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "int a = F(2)")); } [Fact] public void InstanceFieldInitializer_Internal_Update2() { var src1 = """ class C { int a = F(1), <AS:1>b = F(2)</AS:1>; public C() {} public static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var src2 = """ class C { int a = F(1), <AS:1>b = F(3)</AS:1>; public C() {} public static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "b = F(3)")); } [Fact] public void InstancePropertyInitializer_Internal_Delete1() { var src1 = """ class C { int a { get; } = <AS:0>1</AS:0>; int b { get; } = 2; } """; var src2 = """ class C { int a { get { return 1; } } int b { get; } = <AS:0>2</AS:0>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void InstancePropertyInitializer_Internal_Delete2() { var src1 = """ class C { int a { get; } = <AS:0>1</AS:0>; static int s { get; } = 2; int b { get; } = 2; public C() {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ class C { int a { get; } static int s { get; } = 2; int b { get; } = <AS:0>3</AS:0>; public C() { } static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void InstanceFieldInitializer_Internal_Delete1() { var src1 = """ class C { <AS:1>int a = F(1)</AS:1>, b = F(2); public C() {} public static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var src2 = """ class C { int a, <AS:1>b = F(2)</AS:1>; public C() {} public static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69249")] public void InstanceFieldInitializer_Internal_Delete2() { var src1 = """ class C { int a = F(1), <AS:1>b = F(2)</AS:1>; public static int F(int a) => <AS:0>1</AS:0>; } """; var src2 = """ class C { <AS:1>int a, b;</AS:1> public static int F(int a) => <AS:0>1</AS:0>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void InstancePropertyAndFieldInitializers_Delete1() { var src1 = """ class C { int a { get; } = <AS:0>1</AS:0>; static int s { get; } = 2; int b = 2; } """; var src2 = """ class C { int a { get; } static int s { get; } = 2; <AS:0>int b = 3;</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void InstancePropertyAndFieldInitializers_Delete2() { var src1 = """ class C { int a = <AS:0>1</AS:0>; static int s { get; } = 2; int b { get; } = 2; public C() {} static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var src2 = """ class C { int a; static int s { get; } = 2; int b { get; } = <AS:0>3</AS:0>; public C() { } static void Main(string[] args) { <AS:1>C c = new C();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void InstanceFieldInitializer_SingleDeclarator() { var src1 = """ class C { <AS:1>public static readonly int a = F(1);</AS:1> public C() {} public static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { <AS:2>C c = new C();</AS:2> } } """; var src2 = """ class C { <AS:1>public static readonly int <TS:1>a = F(1)</TS:1>;</AS:1> public C() {} public static int F(int a) { <TS:0><AS:0>return a + 1;</AS:0></TS:0> } static void Main(string[] args) { <TS:2><AS:2>C c = new C();</AS:2></TS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_Lambda1() { var src1 = """ class C { Func<int, int> a = z => <AS:0>z + 1</AS:0>; static void Main(string[] args) { <AS:1>new C().a(1);</AS:1> } } """; var src2 = """ class C { Func<int, int> a = F(z => <AS:0>z + 1</AS:0>); static void Main(string[] args) { <AS:1>new C().a(1);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void PropertyInitializer_Lambda1() { var src1 = """ class C { Func<int, int> a { get; } = z => <AS:0>z + 1</AS:0>; static void Main(string[] args) { <AS:1>new C().a(1);</AS:1> } } """; var src2 = """ class C { Func<int, int> a { get; } = F(z => <AS:0>z + 1</AS:0>); static void Main(string[] args) { <AS:1>new C().a(1);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_Lambda2() { var src1 = """ class C { Func<int, Func<int>> a = z => () => <AS:0>z + 1</AS:0>; static void Main(string[] args) { <AS:1>new C().a(1)();</AS:1> } } """; var src2 = """ class C { Func<int, Func<int>> a = z => () => <AS:0>z + 2</AS:0>; static void Main(string[] args) { <AS:1>new C().a(1)();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void PropertyInitializer_Lambda2() { var src1 = """ class C { Func<int, Func<int>> a { get; } = z => () => <AS:0>z + 1</AS:0>; static void Main(string[] args) { <AS:1>new C().a(1)();</AS:1> } } """; var src2 = """ class C { Func<int, Func<int>> a { get; } = z => () => <AS:0>z + 2</AS:0>; static void Main(string[] args) { <AS:1>new C().a(1)();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_InsertConst1() { var src1 = """ class C { <AS:0>int a = 1</AS:0>; public C() {} } """; var src2 = """ class C { <AS:0>const int a = 1;</AS:0> public C() {} } """; var edits = GetTopEdits(src1, src2); edits.VerifyEdits( "Update [int a = 1 ;]@24 -> [const int a = 1;]@24"); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ModifiersUpdate, "const int a = 1", GetResource("field"))); } [Fact] public void LocalInitializer_InsertConst1() { var src1 = """ class C { public void M() { <AS:0>int a = 1</AS:0>; } } """; var src2 = """ class C { public void M() { const int a = 1; <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_InsertConst2() { var src1 = """ class C { int <AS:0>a = 1</AS:0>, b = 2; public C() {} } """; var src2 = """ class C { <AS:0>const int a = 1, b = 2;</AS:0> public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ModifiersUpdate, "const int a = 1, b = 2", GetResource("field")), Diagnostic(RudeEditKind.ModifiersUpdate, "const int a = 1, b = 2", GetResource("field"))); } [Fact] public void LocalInitializer_InsertConst2() { var src1 = """ class C { public void M() { int <AS:0>a = 1</AS:0>, b = 2; } } """; var src2 = """ class C { public void M() { const int a = 1, b = 2; <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_Delete1() { var src1 = """ class C { <AS:0>int a = 1;</AS:0> int b = 1; public C() {} } """; var src2 = """ class C { int a; <AS:0>int b = 1;</AS:0> public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void LocalInitializer_Delete1() { var src1 = """ class C { public void M() { <AS:0>int a = 1</AS:0>; } } """; var src2 = """ class C { public void M() { int a; <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_Delete2() { var src1 = """ class C { int b = 1; int c; <AS:0>int a = 1;</AS:0> public C() {} } """; var src2 = """ class C { <AS:0>int b = 1;</AS:0> int c; int a; public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void LocalInitializer_Delete2() { var src1 = """ class C { public void M() { int b = 1; int c; <AS:0>int a = 1;</AS:0> } } """; var src2 = """ class C { public void M() { int b = 1; int c; int a; <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_Delete3() { var src1 = """ class C { int b = 1; int c; <AS:0>int a = 1;</AS:0> public C() {} } """; var src2 = """ class C { <AS:0>int b = 1;</AS:0> int c; public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "class C", GetResource("field", "C.a")), Diagnostic(RudeEditKind.Delete, "class C", GetResource("field", "a"))); } [Fact] public void LocalInitializer_Delete3() { var src1 = """ class C { public void M() { int b = 1; int c; <AS:0>int a = 1;</AS:0> } } """; var src2 = """ class C { public void M() { int b = 1; int c; <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_DeleteStaticInstance1() { var src1 = """ class C { <AS:0>int a = 1;</AS:0> static int b = 1; int c = 1; public C() {} } """; var src2 = """ class C { int a; static int b = 1; <AS:0>int c = 1;</AS:0> public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_DeleteStaticInstance2() { var src1 = """ class C { static int c = 1; <AS:0>static int a = 1;</AS:0> int b = 1; public C() {} } """; var src2 = """ class C { <AS:0>static int c = 1;</AS:0> static int a; int b = 1; public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_DeleteStaticInstance3() { var src1 = """ class C { <AS:0>static int a = 1;</AS:0> int b = 1; public C() {} } """; var src2 = """ class C { <AS:0>static int a;</AS:0> int b = 1; public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldInitializer_DeleteMove1() { var src1 = """ class C { int b = 1; int c; <AS:0>int a = 1;</AS:0> public C() {} } """; var src2 = """ class C { int c; <AS:0>int b = 1;</AS:0> public C() {} } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "class C", GetResource("field", "C.a")), Diagnostic(RudeEditKind.Delete, "class C", GetResource("field", "a"))); } [Fact] public void LocalInitializer_DeleteReorder1() { var src1 = """ class C { public void M() { int b = 1; <AS:0>int a = 1;</AS:0> int c; } } """; var src2 = """ class C { public void M() { int c; <AS:0>int b = 1;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FieldToProperty1() { var src1 = """ class C { int a = <AS:0>1</AS:0>; } """; // The placement of the active statement is not ideal, but acceptable. var src2 = """ <AS:0>class C</AS:0> { int a { get; } = 1; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "class C", GetResource("field", "C.a")), Diagnostic(RudeEditKind.Delete, "class C", GetResource("field", "a"))); } [Fact] public void PropertyToField1() { var src1 = """ class C { int a { get; } = <AS:0>1</AS:0>; } """; // The placement of the active statement is not ideal, but acceptable. var src2 = """ <AS:0>class C</AS:0> { int a = 1; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemantics( [ SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.a")), SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_a"), deletedSymbolContainerProvider: c => c.GetMember("C")), SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.a"), deletedSymbolContainerProvider: c => c.GetMember("C")), SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C..ctor"), preserveLocalVariables: true), ], capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } #endregion #region Lock Statement [Fact] public void LockBody_Update() { var src1 = """ class Test { private static object F() { <AS:0>return new object();</AS:0> } static void Main(string[] args) { <AS:1>lock (F())</AS:1> { System.Console.Write(0); } } } """; var src2 = """ class Test { private static object F() { <AS:0>return new object();</AS:0> } static void Main(string[] args) { <AS:1>lock (F())</AS:1> { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755749")] public void Lock_Insert_Leaf() { var src1 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { <AS:0>System.Console.Write(5);</AS:0> } } """; var src2 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock (lockThis) { <AS:0>System.Console.Write(5);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "lock (lockThis)", CSharpFeaturesResources.lock_statement)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755749")] public void Lock_Insert_Leaf2() { var src1 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { { System.Console.Write(5); <AS:0>}</AS:0> } } """; var src2 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock (lockThis) { System.Console.Write(5); <AS:0>}</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "lock (lockThis)", CSharpFeaturesResources.lock_statement)); } [Fact] public void Lock_Insert_Leaf3() { var src1 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { { System.Console.Write(5); } <AS:0>System.Console.Write(10);</AS:0> } } """; var src2 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock (lockThis) { System.Console.Write(5); } <AS:0>System.Console.Write(5);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lock_Insert_Leaf4() { var src1 = """ class Test { public static object a = new object(); public static object b = new object(); public static object c = new object(); public static object d = new object(); public static object e = new object(); static void Main(string[] args) { lock (a) { lock (b) { lock (c) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static object a = new object(); public static object b = new object(); public static object c = new object(); public static object d = new object(); public static object e = new object(); static void Main(string[] args) { lock (b) { lock (d) { lock (a) { lock (e) { <AS:0>System.Console.Write();</AS:0> } } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "lock (d)", CSharpFeaturesResources.lock_statement), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "lock (e)", CSharpFeaturesResources.lock_statement)); } [Fact] public void Lock_Insert_Leaf5() { var src1 = """ class Test { public static object a = new object(); public static object b = new object(); public static object c = new object(); public static object d = new object(); public static object e = new object(); static void Main(string[] args) { lock (a) { lock (c) { lock (b) { lock (e) { <AS:0>System.Console.Write();</AS:0> } } } } } } """; var src2 = """ class Test { public static object a = new object(); public static object b = new object(); public static object c = new object(); public static object d = new object(); public static object e = new object(); static void Main(string[] args) { lock (b) { lock (d) { lock (a) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "lock (d)", CSharpFeaturesResources.lock_statement)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755752")] public void Lock_Update_Leaf() { var src1 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock (lockThis) { <AS:0>System.Console.Write(5);</AS:0> } } } """; var src2 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock ("test") { <AS:0>System.Console.Write(5);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "lock (\"test\")", CSharpFeaturesResources.lock_statement)); } [Fact] public void Lock_Update_Leaf2() { var src1 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock (lockThis) { System.Console.Write(5); } <AS:0>System.Console.Write(5);</AS:0> } } """; var src2 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock ("test") { System.Console.Write(5); } <AS:0>System.Console.Write(5);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lock_Delete_Leaf() { var src1 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { lock (lockThis) { <AS:0>System.Console.Write(5);</AS:0> } } } """; var src2 = """ class Test { private static object lockThis = new object(); static void Main(string[] args) { <AS:0>System.Console.Write(5);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lock_Update_Lambda1() { var src1 = """ class C { static void Main(string[] args) { lock (F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static void Main(string[] args) { lock (F(a => a + 1)) { <AS:0>Console.WriteLine(2);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lock_Update_Lambda2() { var src1 = """ class C { static void Main(string[] args) { lock (F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static void Main(string[] args) { lock (G(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "lock (G(a => a))", CSharpFeaturesResources.lock_statement)); } [Fact] public void Lock_Update_Type() { var src1 = """ class C { static void F() { var a = new object(); var b = new C(); var c = ""; lock (a) { lock (b) { lock (c) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class C { static void F() { var a = new object(); var b = new object(); // type changed var c = ""; lock (a) { lock (b) { lock (c) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "lock (b)", CSharpFeaturesResources.lock_statement, "C", "object")); } [Fact] public void Lock_Update_Type_SemanticError() { var src1 = """ class C { static void F() { var a = new object(); lock (a) { <AS:0>System.Console.Write();</AS:0> } } } """; var src2 = """ class C { static void F() { lock (a) { <AS:0>System.Console.Write();</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "lock (a)", CSharpFeaturesResources.lock_statement, "object", "?")); } #endregion #region Fixed Statement [Fact] public void FixedBody_Update() { var src1 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { unsafe { char* px2; fixed (<AS:1>char* pj = &F()</AS:1>) { System.Console.WriteLine(0); } } } } """; var src2 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { unsafe { char* px2; fixed (<AS:1>char* pj = &F()</AS:1>) { System.Console.WriteLine(1); } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void FixedBody_Update_TypeChange() { var src1 = """ class C { static unsafe void F() { var x = new int[1]; var y = new int[1]; var z = new int[1,1]; fixed (int* p = x, q = y, r = z) { <AS:0>System.Console.WriteLine();</AS:0> } } } """; var src2 = """ class C { static unsafe void F() { var x = new int[1]; var y = new int[1,1]; var z = new int[1]; fixed (int* p = x, q = y, r = z) { <AS:0>System.Console.WriteLine();</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "fixed (int* p = x, q = y, r = z)", CSharpFeaturesResources.fixed_statement, "int[]", "int[*,*]"), Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "fixed (int* p = x, q = y, r = z)", CSharpFeaturesResources.fixed_statement, "int[*,*]", "int[]")); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755742")] public void Fixed_Insert_Leaf() { var src1 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; <AS:0>px2 = null;</AS:0> } } } """; var src2 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* pj = &value) { <AS:0>px2 = null;</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "fixed (int* pj = &value)", CSharpFeaturesResources.fixed_statement)); } [Fact] public void Fixed_Insert_Leaf2() { var src1 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; <AS:0>}</AS:0> } } """; var src2 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* pj = &value) { px2 = null; } <AS:0>}</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755742")] public void Fixed_Insert_Leaf3() { var src1 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; <AS:0>px2 = null;</AS:0> fixed (int* pj = &value) { } } } } """; var src2 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* pj = &value) { <AS:0>px2 = null;</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "fixed (int* pj = &value)", CSharpFeaturesResources.fixed_statement)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755742")] public void Fixed_Reorder_Leaf1() { var src1 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* a = &value) { fixed (int* b = &value) { <AS:0>px2 = null;</AS:0> } } } } } """; var src2 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* b = &value) { fixed (int* a = &value) { <AS:0>px2 = null;</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755746")] public void Fixed_Update_Leaf1() { var src1 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* pj = &value) { <AS:0>px2 = null;</AS:0> } } } } """; var src2 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* p = &value) { <AS:0>px2 = null;</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "fixed (int* p = &value)", CSharpFeaturesResources.fixed_statement)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755746")] public void Fixed_Update_Leaf2() { var src1 = """ class Test { public static int value1 = 10; public static int value2 = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* a = &value1) { fixed (int* b = &value1) { fixed (int* c = &value1) { <AS:0>px2 = null;</AS:0> } } } } } } """; var src2 = """ class Test { public static int value1 = 10; public static int value2 = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* c = &value1) { fixed (int* d = &value1) { fixed (int* a = &value2) { fixed (int* e = &value1) { <AS:0>px2 = null;</AS:0> } } } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "fixed (int* a = &value2)", CSharpFeaturesResources.fixed_statement), Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "fixed (int* d = &value1)", CSharpFeaturesResources.fixed_statement), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "fixed (int* e = &value1)", CSharpFeaturesResources.fixed_statement)); } [Fact] public void Fixed_Delete_Leaf() { var src1 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; fixed (int* pj = &value) { <AS:0>px2 = null;</AS:0> } } } } """; var src2 = """ class Test { static int value = 20; static void Main(string[] args) { unsafe { int* px2; <AS:0>px2 = null;</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Fixed_Update_Lambda1() { var src1 = """ class C { static unsafe void Main(string[] args) { fixed (byte* p = &F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static unsafe void Main(string[] args) { fixed (byte* p = &F(a => a + 1)) { <AS:0>Console.WriteLine(2);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Fixed_Update_Lambda2() { var src1 = """ class C { static unsafe void Main(string[] args) { fixed (byte* p = &F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static unsafe void Main(string[] args) { fixed (byte* p = &G(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "fixed (byte* p = &G(a => a))", CSharpFeaturesResources.fixed_statement)); } #endregion #region ForEach Statement [Fact] public void ForEachBody_Update_ExpressionActive() { var src1 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (char c in <AS:1>F()</AS:1>) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (char c in <AS:1>F()</AS:1>) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariableBody_Update_ExpressionActive() { var src1 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach ((string s, int i) in <AS:1>F()</AS:1>) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach ((string s, int i) in <AS:1>F()</AS:1>) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachBody_Update_InKeywordActive() { var src1 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (char c <AS:1>in</AS:1> F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (char c <AS:1>in</AS:1> F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariableBody_Update_InKeywordActive() { var src1 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach ((string s, int i) <AS:1>in</AS:1> F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach ((string s, int i) <AS:1>in</AS:1> F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachBody_Update_VariableActive() { var src1 = """ class Test { private static string[] F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (<AS:1>string c</AS:1> in F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static string[] F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (<AS:1>string c</AS:1> in F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariableBody_Update_VariableActive() { var src1 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (<AS:1>(string s, int i)</AS:1> in F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (<AS:1>(string s, int i)</AS:1> in F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachBody_Update_ForeachKeywordActive() { var src1 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { <AS:1>foreach</AS:1> (char c in F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static string F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { <AS:1>foreach</AS:1> (char c in F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariableBody_Update_ForeachKeywordActive() { var src1 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { <AS:1>foreach</AS:1> ((string s, int i) in F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static (string, int) F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { <AS:1>foreach</AS:1> ((string s, int i) in F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariable_Update() { var src1 = """ class Test { private static string[] F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (<AS:1>string c</AS:1> in F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static string[] F() { <AS:0>return null;</AS:0> } static void Main(string[] args) { foreach (<AS:1>object c</AS:1> in F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // not ideal, but good enough: edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "object c"), Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "foreach ( object c in F())", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEachDeconstructionVariable_Update() { var src1 = """ class Test { private static (int, (bool, double))[] F() { <AS:0>return new[] { (1, (true, 2.0)) };</AS:0> } static void Main(string[] args) { foreach (<AS:1>(int i, (bool b, double d))</AS:1> in F()) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static (int, (bool, double))[] F() { <AS:0>return new[] { (1, (true, 2.0)) };</AS:0> } static void Main(string[] args) { foreach (<AS:1>(int i, (var b, double d))</AS:1> in F()) { System.Console.Write(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "(int i, (var b, double d))"), Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "foreach ( (int i, (var b, double d)) in F())", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Reorder_Leaf() { var src1 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var a in e1) { foreach (var b in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var b in e1) { foreach (var c in e1) { foreach (var a in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariable_Reorder_Leaf() { var src1 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { foreach ((var a1, var a2) in e1) { foreach ((int b1, bool b2) in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { foreach ((int b1, bool b2) in e1) { foreach (var c in e1) { foreach ((var a1, var a2) in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEach_Update_Leaf() { var src1 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { <AS:0>System.Console.Write();</AS:0> } } """; var src2 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var b in e1) { foreach (var c in e1) { foreach (var a in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach (var b in e1)", CSharpFeaturesResources.foreach_statement), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach (var c in e1)", CSharpFeaturesResources.foreach_statement), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach (var a in e1)", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEachVariable_Update_Leaf() { var src1 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { <AS:0>System.Console.Write();</AS:0> } } """; var src2 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { foreach ((int b1, bool b2) in e1) { foreach (var c in e1) { foreach ((var a1, var a2) in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach (var c in e1)", CSharpFeaturesResources.foreach_statement), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach ((int b1, bool b2) in e1)", CSharpFeaturesResources.foreach_statement), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach ((var a1, var a2) in e1)", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Delete_Leaf1() { var src1 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var a in e1) { foreach (var b in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var a in e1) { foreach (var b in e1) { <AS:0>System.Console.Write();</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariable_Delete_Leaf1() { var src1 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { foreach ((var a1, var a2) in e1) { foreach ((int b1, bool b2) in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { foreach ((var a1, var a2) in e1) { foreach ((int b1, bool b2) in e1) { <AS:0>System.Console.Write();</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEach_Delete_Leaf2() { var src1 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var a in e1) { foreach (var b in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var b in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariable_Delete_Leaf2() { var src1 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { foreach ((var a1, var a2) in e1) { foreach ((int b1, bool b2) in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static (int, bool)[] e1 = new (int, bool)[1]; public static (int, bool)[] e2 = new (int, bool)[1]; static void Main(string[] args) { foreach ((int b1, bool b2) in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEach_Delete_Leaf3() { var src1 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var a in e1) { foreach (var b in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var a in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariable_Delete_Leaf3() { var src1 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach ((var a1, var a2) in e1) { foreach ((int b1, bool b2) in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var src2 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach ((var a1, var a2) in e1) { foreach (var c in e1) { <AS:0>System.Console.Write();</AS:0> } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEach_Lambda1() { var src1 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { Action a = () => { <AS:0>System.Console.Write();</AS:0> }; <AS:1>a();</AS:1> } } """; var src2 = """ class Test { public static int[] e1 = new int[1]; public static int[] e2 = new int[1]; static void Main(string[] args) { foreach (var b in e1) { foreach (var c in e1) { Action a = () => { foreach (var a in e1) { <AS:0>System.Console.Write();</AS:0> } }; } <AS:1>a();</AS:1> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach (var a in e1)", CSharpFeaturesResources.foreach_statement), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "foreach (var b in e1)", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Update_Lambda1() { var src1 = """ class C { static unsafe void Main(string[] args) { foreach (var a in F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static unsafe void Main(string[] args) { foreach (var a in F(a => a + 1)) { <AS:0>Console.WriteLine(2);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEach_Update_Lambda2() { var src1 = """ class C { static unsafe void Main(string[] args) { foreach (var a in F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static unsafe void Main(string[] args) { foreach (var a in G(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "foreach (var a in G(a => a))", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Update_Collection_01() { var src1 = """ class C { static void F() { var aa = new int[4]; var bb = new int[4]; foreach (var a in aa) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static void F() { var aa = new int[4]; var bb = new int[4]; foreach (var a in bb) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "foreach (var a in bb)", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Update_Collection_02() { var src1 = """ class C { static void F() { Buffer4 aa = default; Buffer4 bb = default; foreach (var a in aa) { <AS:0>Console.WriteLine(1);</AS:0> } } } [System.Runtime.CompilerServices.InlineArray(4)] struct Buffer4 { private int _f; } """; var src2 = """ class C { static void F() { Buffer4 aa = default; Buffer4 bb = default; foreach (var a in bb) { <AS:0>Console.WriteLine(1);</AS:0> } } } [System.Runtime.CompilerServices.InlineArray(4)] struct Buffer4 { private int _f; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "foreach (var a in bb)", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Update_Collection_03() { var src1 = """ class C { public readonly Buffer4 F = default; } class Program { static System.Collections.Generic.IEnumerable<int> Test(C x, C z) { foreach (var y in x.F) { <AS:0>Console.WriteLine(1);</AS:0> yield return -1; } } } [System.Runtime.CompilerServices.InlineArray(4)] struct Buffer4 { private int _f; } """; var src2 = """ class C { public readonly Buffer4 F = default; } class Program { static System.Collections.Generic.IEnumerable<int> Test(C x, C z) { foreach (var y in z.F) { <AS:0>Console.WriteLine(1);</AS:0> yield return -1; } } } [System.Runtime.CompilerServices.InlineArray(4)] struct Buffer4 { private int _f; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "foreach (var y in z.F)", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Update_Collection_04() { var src1 = """ class Program { static System.Collections.Generic.IEnumerable<int> Test() { foreach (var y in GetBuffer1()) { <AS:0>Console.WriteLine(1);</AS:0> yield return -1; } } static Buffer4 GetBuffer1() => default; static Buffer4 GetBuffer2() => default; } [System.Runtime.CompilerServices.InlineArray(4)] struct Buffer4 { private int _f; } """; var src2 = """ class Program { static System.Collections.Generic.IEnumerable<int> Test() { foreach (var y in GetBuffer2()) { <AS:0>Console.WriteLine(1);</AS:0> yield return -1; } } static Buffer4 GetBuffer1() => default; static Buffer4 GetBuffer2() => default; } [System.Runtime.CompilerServices.InlineArray(4)] struct Buffer4 { private int _f; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "foreach (var y in GetBuffer2())", CSharpFeaturesResources.foreach_statement)); } [Fact] public void ForEach_Update_Nullable_Struct() { var src1 = """ class C { static void F() { var arr = new int?[] { 0 }; foreach (var s in arr) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static void F() { var arr = new int[] { 0 }; foreach (var s in arr) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "foreach (var s in arr)", CSharpFeaturesResources.foreach_statement, "int?[]", "int[]")); } [Fact] public void ForEach_Update_Nullable_Class() { var src1 = """ class C { static void F() { var arr = new object?[] { 0 }; foreach (var s in arr) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static void F() { var arr = new object[] { 0 }; foreach (var s in arr) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEach_DeleteBody() { var src1 = """ class C { static void F() { foreach (var s in new[] { 1 }) <AS:0>G();</AS:0> } } """; var src2 = """ class C { static void F() { foreach (var s in new[] { 1 }) <AS:0>;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForEachVariable_DeleteBody() { var src1 = """ class C { static void F() { foreach ((var a1, var a2) in new[] { (1,1) }) <AS:0>G();</AS:0> } } """; var src2 = """ class C { static void F() { foreach ((var a1, var a2) in new[] { (1,1) }) <AS:0>;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region For Statement [Fact] public void ForStatement_Initializer1() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { int i; for (<AS:1>i = F(1)</AS:1>; i < 10; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { int i; for (<AS:1>i = F(2)</AS:1>; i < 10; i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "i = F(2)")); } [Fact] public void ForStatement_Initializer2() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { int i; for (<AS:1>i = F(1)</AS:1>, F(1); i < 10; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { int i; for (<AS:1>i = F(1)</AS:1>, F(2); i < 10; i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForStatement_Initializer_Delete() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { int i; for (<AS:1>i = F(1)</AS:1>; i < 10; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { int i; for (; <AS:1>i < 10</AS:1>; i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "for (; i < 10 ; i++)", FeaturesResources.code)); } [Fact] public void ForStatement_Declarator1() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (<AS:1>var i = F(1)</AS:1>; i < 10; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (<AS:1>var i = F(2)</AS:1>; i < 10; i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "var i = F(2)")); } [Fact] public void ForStatement_Declarator2() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (<AS:1>int i = F(1)</AS:1>, j = F(1); i < 10; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (<AS:1>int i = F(1)</AS:1>, j = F(2); i < 10; i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForStatement_Declarator3() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (<AS:1>int i = F(1)</AS:1>; i < 10; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (<AS:1>int i = F(1)</AS:1>, j = F(2); i < 10; i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForStatement_Condition1() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; <AS:1>i < F(10)</AS:1>; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; <AS:1>i < F(20)</AS:1>; i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "i < F(20)")); } [Fact] public void ForStatement_Condition_Delete() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; <AS:1>i < F(10)</AS:1>; i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; ; <AS:1>i++</AS:1>) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "for (int i = 1; ; i++ )", FeaturesResources.code)); } [Fact] public void ForStatement_Incrementors1() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(10); <AS:1>F(1)</AS:1>) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(20); <AS:1>F(1)</AS:1>) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForStatement_Incrementors2() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(10); <AS:1>F(1)</AS:1>) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(10); <AS:1>F(2)</AS:1>) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "F(2)")); } [Fact] public void ForStatement_Incrementors3() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(10); <AS:1>F(1)</AS:1>) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(10); <AS:1>F(1)</AS:1>, i++) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ForStatement_Incrementors4() { var src1 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(10); <AS:1>F(1)</AS:1>, i++) { System.Console.Write(0); } } } """; var src2 = """ class Test { private static int F(int a) { <AS:0>return a;</AS:0> } static void Main(string[] args) { for (int i = 1; i < F(10); i++, <AS:1>F(1)</AS:1>) { System.Console.Write(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Using Statement and Local Declaration [Fact] public void UsingStatement_Expression_Update_Leaf() { var src1 = """ class Test { public static System.IDisposable a = null; public static System.IDisposable b = null; public static System.IDisposable c = null; static void Main(string[] args) { using (a) { using (b) { <AS:0>System.Console.Write();</AS:0> } } } } """; var src2 = """ class Test { public static System.IDisposable a = null; public static System.IDisposable b = null; public static System.IDisposable c = null; static void Main(string[] args) { using (a) { using (c) { using (b) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Using with an expression generates code that stores the value of the expression in a compiler-generated temp. // This temp is not initialized when using is added around an active statement so the disposal is a no-op. // The user might expect that the object the field points to is disposed at the end of the using block, but it isn't. edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "using (c)", CSharpFeaturesResources.using_statement)); } [Fact] public void UsingStatement_Expression_Update_Leaf_TypeChange() { var src1 = """ using System; class C { static void F() { var x = new D1(); using (x) { <AS:0>System.Console.Write();</AS:0> } } } class D1 : IDisposable { public void Dispose() { } } class D2 : IDisposable { public void Dispose() { } } """; var src2 = """ using System; class C { static void F() { var x = new D2(); using (x) { <AS:0>System.Console.Write();</AS:0> } } } class D1 : IDisposable { public void Dispose() { } } class D2 : IDisposable { public void Dispose() { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "using (x)", CSharpFeaturesResources.using_statement, "D1", "D2")); } [Fact] public void UsingStatement_Declaration_Update_Leaf() { var src1 = """ class Test { static void Main(string[] args) { using (var a = new Disposable()) { using (var b = new Disposable()) { <AS:0>System.Console.Write();</AS:0> } } } } """; var src2 = """ class Test { static void Main(string[] args) { using (var a = new Disposable()) { using (var c = new Disposable()) { using (var b = new Disposable()) { <AS:0>System.Console.Write();</AS:0> } } } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Unlike using with an expression, using with a declaration does not introduce compiler-generated temps. // As with other local declarations that are added but not executed, the variable is not initialized and thus // there should be no expectation (or need) for its disposal. Hence we do not report a rude edit. edits.VerifySemanticDiagnostics(active); } [Fact] public void UsingLocalDeclaration_Update_Leaf1() { var src1 = """ class Test { static void Main(string[] args) { using var a = new Disposable(), b = new Disposable(); <AS:0>System.Console.Write();</AS:0> } } """; var src2 = """ class Test { static void Main(string[] args) { using var a = new Disposable(), c = new Disposable(), b = new Disposable(); <AS:0>System.Console.Write();</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Unlike using with an expression, using local declaration does not introduce compiler-generated temps. // As with other local declarations that are added but not executed, the variable is not initialized and thus // there should be no expectation (or need) for its disposal. Hence we do not report a rude edit. edits.VerifySemanticDiagnostics(active); } [Fact] public void UsingLocalDeclaration_Update_Leaf2() { var src1 = """ class Test { static void Main(string[] args) { using var a = new Disposable(); using var b = new Disposable(); <AS:0>System.Console.Write();</AS:0> } } """; var src2 = """ class Test { static void Main(string[] args) { using var a = new Disposable(); using var c = new Disposable(); using var b = new Disposable(); <AS:0>System.Console.Write();</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // Unlike using with an expression, using local declaration does not introduce compiler-generated temps. // As with other local declarations that are added but not executed, the variable is not initialized and thus // there should be no expectation (or need) for its disposal. Hence we do not report a rude edit. edits.VerifySemanticDiagnostics(active); } [Fact] public void UsingStatement_Update_NonLeaf1() { var src1 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { using (var a = new Disposable(1)) { System.Console.Write(); <AS:1>}</AS:1> } } """; var src2 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { using (var a = new Disposable(2)) { System.Console.Write(); <AS:1>}</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "}")); } [Fact] public void UsingStatement_Update_NonLeaf2() { var src1 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { using (Disposable a = new Disposable(1), b = Disposable(2)) { System.Console.Write(); <AS:1>}</AS:1> } } """; var src2 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { using (Disposable a = new Disposable(1)) { System.Console.Write(); <AS:1>}</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "}")); } [Fact] public void UsingStatement_Update_NonLeaf_Lambda() { var src1 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { using (var a = new Disposable(() => 1)) { System.Console.Write(); <AS:1>}</AS:1> } } """; var src2 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { using (var a = new Disposable(() => 2)) { System.Console.Write(); <AS:1>}</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UsingLocalDeclaration_Update_NonLeaf1() { var src1 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { if (F()) { using Disposable a = new Disposable(1); using Disposable b = new Disposable(2), c = new Disposable(3); <AS:1>}</AS:1> } } """; var src2 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { if (F()) { using Disposable a = new Disposable(1); using Disposable b = new Disposable(20), c = new Disposable(3); <AS:1>}</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "}")); } [Fact] public void UsingLocalDeclaration_Update_NonLeaf_Lambda() { var src1 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { if (F()) { using Disposable a = new Disposable(() => 1); { using var x = new Disposable(1); } using Disposable b = new Disposable(() => 2), c = new Disposable(() => 3); <AS:1>}</AS:1> } } """; var src2 = """ class Disposable : IDisposable { public void Dispose() <AS:0>{</AS:0>} } class Test { static void Main(string[] args) { if (F()) { using Disposable a = new Disposable(() => 10); { using var x = new Disposable(2); } Console.WriteLine(1); using Disposable b = new Disposable(() => 20), c = new Disposable(() => 30); <AS:1>}</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UsingStatement_Expression_InLambdaBody1() { var src1 = """ class Test { public static System.IDisposable a = null; public static System.IDisposable b = null; public static System.IDisposable c = null; public static System.IDisposable d = null; static void Main(string[] args) { using (a) { Action a = () => { using (b) { <AS:0>System.Console.Write();</AS:0> } }; } <AS:1>a();</AS:1> } } """; var src2 = """ class Test { public static System.IDisposable a = null; public static System.IDisposable b = null; public static System.IDisposable c = null; public static System.IDisposable d = null; static void Main(string[] args) { using (d) { Action a = () => { using (c) { using (b) { <AS:0>System.Console.Write();</AS:0> } } }; } <AS:1>a();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "using (c)", CSharpFeaturesResources.using_statement)); } [Fact] public void UsingStatement_Expression_Update_Lambda1() { var src1 = """ class C { static unsafe void Main(string[] args) { using (F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static unsafe void Main(string[] args) { using (F(a => a + 1)) { <AS:0>Console.WriteLine(2);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UsingStatement_Expression_Update_Lambda2() { var src1 = """ class C { static unsafe void Main(string[] args) { using (F(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var src2 = """ class C { static unsafe void Main(string[] args) { using (G(a => a)) { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "using (G(a => a))", CSharpFeaturesResources.using_statement)); } #endregion #region Conditional Block Statements (If, Switch, While, Do) [Fact] public void IfBody_Update1() { var src1 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>if (B())</AS:1> { System.Console.WriteLine(0); } } } """; var src2 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>if (B())</AS:1> { System.Console.WriteLine(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void IfBody_Update2() { var src1 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>if (B())</AS:1> { System.Console.WriteLine(0); } } } """; var src2 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>if (!B())</AS:1> { System.Console.WriteLine(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "if (!B())")); } [Fact] public void IfBody_Update_Lambda() { var src1 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { <AS:1>if (B(() => 1))</AS:1> { System.Console.WriteLine(0); } } } """; var src2 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { <AS:1>if (B(() => 2))</AS:1> { System.Console.WriteLine(0); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void WhileBody_Update1() { var src1 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>while (B())</AS:1> { System.Console.WriteLine(0); } } } """; var src2 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>while (B())</AS:1> { System.Console.WriteLine(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void WhileBody_Update2() { var src1 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>while (B())</AS:1> { System.Console.WriteLine(0); } } } """; var src2 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { <AS:1>while (!B())</AS:1> { System.Console.WriteLine(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "while (!B())")); } [Fact] public void WhileBody_Update_Lambda() { var src1 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { <AS:1>while (B(() => 1))</AS:1> { System.Console.WriteLine(0); } } } """; var src2 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { <AS:1>while (B(() => 2))</AS:1> { System.Console.WriteLine(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void DoWhileBody_Update1() { var src1 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { do { System.Console.WriteLine(0); } <AS:1>while (B());</AS:1> } } """; var src2 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { do { System.Console.WriteLine(1); } <AS:1>while (B());</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void DoWhileBody_Update2() { var src1 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { do { System.Console.WriteLine(0); } <AS:1>while (B());</AS:1> } } """; var src2 = """ class C { public static bool B() <AS:0>{</AS:0> return false; } public static void F() { do { System.Console.WriteLine(1); } <AS:1>while (!B());</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "while (!B());")); } [Fact] public void DoWhileBody_Update_Lambda() { var src1 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { do { System.Console.WriteLine(0); } <AS:1>while (B(() => 1));</AS:1> } } """; var src2 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { do { System.Console.WriteLine(1); } <AS:1>while (B(() => 2));</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void DoWhileBody_Delete() { var src1 = """ class C { static void F() { do <AS:0>G();</AS:0> while (true); } } """; var src2 = """ class C { static void F() { do <AS:0>;</AS:0> while (true); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void SwitchCase_Update1() { var src1 = """ class C { public static string F() <AS:0>{</AS:0> return null; } public static void G() { <AS:1>switch (F())</AS:1> { case "a": System.Console.WriteLine(0); break; case "b": System.Console.WriteLine(1); break; } } } """; var src2 = """ class C { public static string F() <AS:0>{</AS:0> return null; } public static void G() { <AS:1>switch (F())</AS:1> { case "a": System.Console.WriteLine(0); break; case "b": System.Console.WriteLine(2); break; } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void SwitchCase_Update_Lambda() { var src1 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { <AS:1>switch (B(() => 1))</AS:1> { case "a": System.Console.WriteLine(0); break; case "b": System.Console.WriteLine(1); break; } } } """; var src2 = """ class C { public static bool B(Func<int> a) => <AS:0>false</AS:0>; public static void F() { <AS:1>switch (B(() => 2))</AS:1> { case "a": System.Console.WriteLine(0); break; case "b": System.Console.WriteLine(2); break; } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Switch Statement When Clauses, Patterns [Fact] public void SwitchWhenClause_PatternUpdate1() { var src1 = """ class C { public static int Main() { switch (F()) { case int a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; case byte a when G5(a): return 10; case double b when G2(b): return 20; case C { X: 2 } when G4(9): return 30; case C { X: 2, Y: C { X: 1 } } c1 when G3(c1): return 40; } return 0; } } """; var src2 = """ class C { public static int Main() { switch (F()) { case int a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; case byte a when G5(a): return 10; case double b when G2(b): return 20; case C { X: 2 } when G4(9): return 30; case C { X: 2, Y: C { X: 2 } } c1 when G3(c1): return 40; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "switch (F())", CSharpFeaturesResources.switch_statement_case_clause)); } [Fact] public void SwitchWhenClause_PatternInsert() { var src1 = """ class C { public static int Main() { switch (F()) { case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var src2 = """ class C { public static int Main() { switch (F()) { case int a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "switch (F())", CSharpFeaturesResources.switch_statement_case_clause)); } [Fact] public void SwitchWhenClause_PatternDelete() { var src1 = """ class C { public static int Main() { switch (F()) { case int a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var src2 = """ class C { public static int Main() { switch (F()) { case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "switch (F())", CSharpFeaturesResources.switch_statement_case_clause)); } [Fact] public void SwitchWhenClause_WhenDelete() { var src1 = """ class C { public static int Main() { switch (F()) { case byte a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var src2 = """ class C { public static int Main() { switch (F()) { case byte a1: case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "switch (F())", CSharpFeaturesResources.switch_statement_case_clause)); } [Fact] public void SwitchWhenClause_WhenAdd() { var src1 = """ class C { public static int Main() { switch (F()) { case byte a1: case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var src2 = """ class C { public static int Main() { switch (F()) { case byte a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "switch (F())", CSharpFeaturesResources.switch_statement_case_clause)); } [Fact] public void SwitchWhenClause_WhenUpdate() { var src1 = """ class C { public static int Main() { switch (F()) { case byte a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var src2 = """ class C { public static int Main() { switch (F()) { case byte a1 when G1(a1 * 2): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void SwitchWhenClause_UpdateGoverningExpression() { var src1 = """ class C { public static int Main() { switch (F(1)) { case int a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var src2 = """ class C { public static int Main() { switch (F(2)) { case int a1 when G1(a1): case int a2 <AS:0>when G1(a2)</AS:0>: return 10; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "switch (F(2))", CSharpFeaturesResources.switch_statement)); } [Fact] public void Switch_PropertyPattern_Update_NonLeaf() { var src1 = """ class C { public int X { get => <AS:0>1</AS:0>; } public static int F(object obj) { <AS:1>switch (obj)</AS:1> { case C { X: 1 }: return 1; } return 0; } } """; var src2 = """ class C { public int X { get => <AS:0>1</AS:0>; } public static int F(object obj) { <AS:1>switch (obj)</AS:1> { case C { X: 2 }: return 1; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "switch (obj)")); } [Fact] public void Switch_PositionalPattern_Update_NonLeaf() { var src1 = """ class C { public void Deconstruct(out int x) => <AS:0>x = X</AS:0>; public static int F(object obj) { <AS:1>switch (obj)</AS:1> { case C ( x: 1 ): return 1; } return 0; } } """; var src2 = """ class C { public void Deconstruct(out int x) => <AS:0>x = X</AS:0>; public static int F(object obj) { <AS:1>switch (obj)</AS:1> { case C ( x: 2 ): return 1; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "switch (obj)")); } [Fact] public void Switch_VarPattern_Update_NonLeaf() { var src1 = """ class C { public static object G() => <AS:0>null</AS:0>; public static int F(object obj) { <AS:1>switch (G())</AS:1> { case var (x, y): return 1; case 2: return 2; } return 0; } } """; var src2 = """ class C { public static object G() => <AS:0>null</AS:0>; public static int F(object obj) { <AS:1>switch (G())</AS:1> { case var (x, y): return 1; case 3: return 2; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "switch (G())")); } [Fact] public void Switch_DiscardPattern_Update_NonLeaf() { var src1 = """ class C { public static object G() => <AS:0>null</AS:0>; public static int F(object obj) { <AS:1>switch (G())</AS:1> { case bool _: return 1; } return 0; } } """; var src2 = """ class C { public static object G() => <AS:0>null</AS:0>; public static int F(object obj) { <AS:1>switch (G())</AS:1> { case int _: return 1; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "switch (G())")); } [Fact] public void Switch_NoPatterns_Update_NonLeaf() { var src1 = """ class C { public static object G() => <AS:0>null</AS:0>; public static int F(object obj) { <AS:1>switch (G())</AS:1> { case 1: return 1; } return 0; } } """; var src2 = """ class C { public static object G() => <AS:0>null</AS:0>; public static int F(object obj) { <AS:1>switch (G())</AS:1> { case 2: return 1; } return 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Switch Expression [Fact] public void SwitchExpression() { var src1 = """ class C { public static int Main() { Console.WriteLine(1); <AS:4>return F() switch { int a <AS:0>when F1()</AS:0> => <AS:1>F2()</AS:1>, bool b => <AS:2>F3()</AS:2>, _ => <AS:3>F4()</AS:3> };</AS:4> } } """; var src2 = """ class C { public static int Main() { Console.WriteLine(2); <AS:4>return F() switch { int a <AS:0>when F1()</AS:0> => <AS:1>F2()</AS:1>, bool b => <AS:2>F3()</AS:2>, _ => <AS:3>F4()</AS:3> };</AS:4> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void SwitchExpression_Lambda1() { var src1 = """ class C { public static int Main() => <AS:1>F() switch { 0 => new Func<int>(() => <AS:0>1</AS:0>)(), _ => 2}</AS:1>; } """; var src2 = """ class C { public static int Main() => <AS:1>F() switch { 0 => new Func<int>(() => <AS:0>3</AS:0>)(), _ => 2}</AS:1>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void SwitchExpression_Lambda2() { var src1 = """ class C { public static int Main() => <AS:1>F() switch { i => new Func<int>(() => <AS:0>i + 1</AS:0>)(), _ => 2}</AS:1>; } """; var src2 = """ class C { public static int Main() => <AS:1>F() switch { i => new Func<int>(() => <AS:0>i + 3</AS:0>)(), _ => 2}</AS:1>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_MemberExpressionBody() { var src1 = """ class C { public static int Main() => <AS:0>F() switch { 0 => 1, _ => 2}</AS:0>; } """; var src2 = """ class C { public static int Main() => <AS:0>G() switch { 0 => 10, _ => 20}</AS:0>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_LambdaBody() { var src1 = """ class C { public static Func<int> M() => () => <AS:0>F() switch { 0 => 1, _ => 2}</AS:0>; } """; var src2 = """ class C { public static Func<int> M() => () => <AS:0>G() switch { 0 => 10, _ => 20}</AS:0>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_QueryLambdaBody() { var src1 = """ class C { public static IEnumerable<int> M() { return from a in new[] { 1 } where <AS:0>F() <AS:1>switch { 0 => true, _ => false}</AS:0,1> select a; } } """; var src2 = """ class C { public static IEnumerable<int> M() { return from a in new[] { 2 } where <AS:0>F() <AS:1>switch { 0 => true, _ => false}</AS:0,1> select a; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_NestedInGoverningExpression() { var src1 = """ class C { public static int Main() => <AS:1>(F() switch { 0 => 1, _ => 2 }) switch { 1 => <AS:0>10</AS:0>, _ => 20 }</AS:1>; } """; var src2 = """ class C { public static int Main() => <AS:1>(G() switch { 0 => 10, _ => 20 }) switch { 10 => <AS:0>100</AS:0>, _ => 200 }</AS:1>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "(G() switch { 0 => 10, _ => 20 }) switch { 10 => 100 , _ => 200 }")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_NestedInArm() { var src1 = """ class C { public static int Main() => F1() switch { 1 when F2() <AS:0>switch { 0 => true, _ => false }</AS:0> => F3() <AS:1>switch { 0 => 1, _ => 2 }</AS:1>, _ => 20 }; } """; var src2 = """ class C { public static int Main() => F1() switch { 1 when F2() <AS:0>switch { 0 => true, _ => false }</AS:0> => F3() <AS:1>switch { 0 => 1, _ => 2 }</AS:1>, _ => 20 }; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_Delete1() { var src1 = """ class C { public static int Main() { return Method() switch { true => G(), _ => F2() switch { 1 => <AS:0>0</AS:0>, _ => 2 } }; } } """; var src2 = """ class C { public static int Main() { return Method() switch { true => G(), _ => <AS:0>1</AS:0> }; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_Delete2() { var src1 = """ class C { public static int Main() { return F1() switch { 1 => 0, _ => F2() switch { 1 => <AS:0>0</AS:0>, _ => 2 } }; } } """; var src2 = """ class C { public static int Main() { return F1() switch { 1 => <AS:0>0</AS:0>, _ => 1 }; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43099")] public void SwitchExpression_Delete3() { var src1 = """ class C { public static int Main() { return F1() switch { 1 when F2() switch { 1 => <AS:0>true</AS:0>, _ => false } => 0, _ => 2 }; } } """; var src2 = """ class C { public static int Main() { return F1() switch { 1 <AS:0>when F3()</AS:0> => 0, _ => 1 }; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Try [Fact] public void Try_Add_Inner() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } catch { } } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "try", CSharpFeaturesResources.try_block)); } [Fact] public void Try_Add_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { <AS:0>Console.WriteLine(1);</AS:0> } catch { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Try_Delete_Inner() { var src1 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } <ER:1.0>catch { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "Goo();", CSharpFeaturesResources.try_block)); } [Fact] public void Try_Delete_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { <AS:0>Console.WriteLine(1);</AS:0> } catch { } } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Try_Update_Inner() { var src1 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } <ER:1.0>catch { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } <ER:1.0>catch (IOException) { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "try", CSharpFeaturesResources.try_block)); } [Fact] public void Try_Update_Inner2() { var src1 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } <ER:1.0>catch { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } <ER:1.0>catch { }</ER:1.0> Console.WriteLine(2); } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void TryFinally_Update_Inner() { var src1 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } <ER:1.0>finally { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { <AS:1>Goo();</AS:1> } <ER:1.0>finally { }</ER:1.0> Console.WriteLine(2); } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Try_Update_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { <AS:0>Console.WriteLine(1);</AS:0> } catch { } } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { <AS:0>Console.WriteLine(1);</AS:0> } catch (IOException) { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void TryFinally_DeleteStatement_Inner() { var src1 = """ class C { static void F() { <AS:0>Console.WriteLine(0);</AS:0> try { <AS:1>Console.WriteLine(1);</AS:1> } <ER:1.0>finally { Console.WriteLine(2); }</ER:1.0> } } """; var src2 = """ class C { static void F() { <AS:0>Console.WriteLine(0);</AS:0> try { <AS:1>}</AS:1> finally { Console.WriteLine(2); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code)); } [Fact] public void TryFinally_DeleteStatement_Leaf() { var src1 = """ class C { static void Main(string[] args) { <ER:0.0>try { Console.WriteLine(0); } finally { <AS:0>Console.WriteLine(1);</AS:0> }</ER:0.0> } } """; var src2 = """ class C { static void Main(string[] args) { try { Console.WriteLine(0); } finally { <AS:0>}</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "finally", CSharpFeaturesResources.finally_clause)); } [Fact] public void Try_DeleteStatement_Inner() { var src1 = """ class C { static void F() { <AS:0>Console.WriteLine(0);</AS:0> try { <AS:1>Console.WriteLine(1);</AS:1> } <ER:1.0>finally { Console.WriteLine(2); }</ER:1.0> } } """; var src2 = """ class C { static void F() { <AS:0>Console.WriteLine(0);</AS:0> try { <AS:1>}</AS:1> <ER:1.0>finally { Console.WriteLine(2); }</ER:1.0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code)); } [Fact] public void Try_DeleteStatement_Leaf() { var src1 = """ class C { static void F() { try { <AS:0>Console.WriteLine(1);</AS:0> } finally { Console.WriteLine(2); } } } """; var src2 = """ class C { static void F() { try { <AS:0>}</AS:0> finally { Console.WriteLine(2); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Catch [Fact] public void Catch_Add_Inner() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } catch { <AS:1>Goo();</AS:1> } } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } [Fact] public void Catch_Add_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { } catch { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } [Fact] public void Catch_Delete_Inner() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch { <AS:1>Goo();</AS:1> }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "Goo();", CSharpFeaturesResources.catch_clause)); } [Fact] public void Catch_Delete_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { } <ER:0.0>catch { <AS:0>Console.WriteLine(1);</AS:0> }</ER:0.0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "Console.WriteLine(1);", CSharpFeaturesResources.catch_clause)); } [Fact] public void Catch_Update_Inner() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch { <AS:1>Goo();</AS:1> }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException) { <AS:1>Goo();</AS:1> }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } [Fact] public void Catch_Update_InFilter_Inner() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException) <AS:1>when (Goo(1))</AS:1> { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (Exception) <AS:1>when (Goo(1))</AS:1> { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } [Fact] public void Catch_Update_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { } <ER:0.0>catch { <AS:0>Console.WriteLine(1);</AS:0> }</ER:0.0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { } <ER:0.0>catch (IOException) { <AS:0>Console.WriteLine(1);</AS:0> }</ER:0.0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } [Fact] public void CatchFilter_Update_Inner() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException) <AS:1>when (Goo(1))</AS:1> { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException) <AS:1>when (Goo(2))</AS:1> { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "when (Goo(2))"), Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } [Fact] public void CatchFilter_Update_Leaf1() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:0.0>catch (IOException) <AS:0>when (Goo(1))</AS:0> { }</ER:0.0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:0.0>catch (IOException) <AS:0>when (Goo(2))</AS:0> { }</ER:0.0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } [Fact] public void CatchFilter_Update_Leaf2() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:0.0>catch (IOException) <AS:0>when (Goo(1))</AS:0> { }</ER:0.0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:0.0>catch (Exception) <AS:0>when (Goo(1))</AS:0> { }<ER:0.0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause)); } #endregion #region Finally [Fact] public void Finally_Add_Inner() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } finally { <AS:1>Goo();</AS:1> } } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "finally", CSharpFeaturesResources.finally_clause)); } [Fact] public void Finally_Add_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { try { } finally { <AS:0>Console.WriteLine(1);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "finally", CSharpFeaturesResources.finally_clause)); } [Fact] public void Finally_Delete_Inner() { var src1 = """ class C { static void Main(string[] args) { <ER:1.0>try { } finally { <AS:1>Goo();</AS:1> }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "Goo();", CSharpFeaturesResources.finally_clause)); } [Fact] public void Finally_Delete_Leaf() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <ER:0.0>try { } finally { <AS:0>Console.WriteLine(1);</AS:0> }</ER:0.0> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>Goo();</AS:1> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "Console.WriteLine(1);", CSharpFeaturesResources.finally_clause)); } #endregion #region Try-Catch-Finally [Fact] public void TryCatchFinally() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException) { try { try { try { <AS:1>Goo();</AS:1> } catch { } } catch (Exception) { } } finally { } }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (Exception) { try { try { } finally { try { <AS:1>Goo();</AS:1> } catch { } } } catch (Exception) { } }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "catch", CSharpFeaturesResources.catch_clause), Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "try", CSharpFeaturesResources.try_block), Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "Goo();", CSharpFeaturesResources.try_block), Diagnostic(RudeEditKind.InsertAroundActiveStatement, "finally", CSharpFeaturesResources.finally_clause)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23865")] public void TryCatchFinally_Regions() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException) { try { try { try { <AS:1>Goo();</AS:1> } catch { } } catch (Exception) { } } finally { } }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException) { try { try { try { <AS:1>Goo();</AS:1> } catch { } } catch (Exception) { } } finally { } }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // TODO: this is incorrect, we need to report a rude edit: edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23865")] public void TryCatchFinally2_Regions() { var src1 = """ class C { static void Main(string[] args) { try { try { try { try { <AS:1>Goo();</AS:1> } <ER:1.3>catch { }</ER:1.3> } <ER:1.2>catch (Exception) { }</ER:1.2> } <ER:1.1>finally { }</ER:1.1> } <ER:1.0>catch (IOException) { } finally { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { try { try { try { <AS:1>Goo();</AS:1> } <ER:1.3>catch { }</ER:1.3> } <ER:1.2>catch (Exception) { }</ER:1.2> } <ER:1.1>finally { }</ER:1.1> } <ER:1.0>catch (IOException) { } finally { }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // TODO: this is incorrect, we need to report a rude edit since an ER span has been changed (empty line added): edits.VerifySemanticDiagnostics(active); } [Fact] public void TryFilter_Regions1() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException e) when (e == null) { <AS:1>Goo();</AS:1> }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException e) when (e == null) { <AS:1>Goo();</AS:1> }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void TryFilter_Regions2() { var src1 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException e) <AS:1>when (e == null)</AS:1> { Goo(); }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static void Main(string[] args) { try { } <ER:1.0>catch (IOException e) <AS:1>when (e == null)</AS:1> { Goo(); }</ER:1.0> } static void Goo() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Try_Lambda1() { var src1 = """ using System; using System.Linq; class C { static int Goo(int x) { <AS:0>return 1;</AS:0> } static void F() { Func<int, int> f = null; try { f = x => <AS:1>1 + Goo(x)</AS:1>; } catch { } <AS:2>Console.Write(f(2));</AS:2> } } """; var src2 = """ using System; using System.Linq; class C { static int Goo(int x) { <AS:0>return 1;</AS:0> } static void F() { Func<int, int> f = null; f = x => <AS:1>1 + Goo(x)</AS:1>; <AS:2>Console.Write(f(2));</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Try_Lambda2() { var src1 = """ using System; using System.Linq; class C { static int Goo(int x) { <AS:0>return 1;</AS:0> } static void F() { Func<int, int> f = x => { try { <AS:1>return 1 + Goo(x);</AS:1> } <ER:1.0>catch { }</ER:1.0> }; <AS:2>Console.Write(f(2));</AS:2> } } """; var src2 = """ using System; using System.Linq; class C { static int Goo(int x) { <AS:0>return 1;</AS:0> } static void F() { Func<int, int> f = x => { <AS:1>return 1 + Goo(x);</AS:1> }; <AS:2>Console.Write(f(2));</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "return 1 + Goo(x);", CSharpFeaturesResources.try_block)); } [Fact] public void Try_Query_Join1() { var src1 = """ class C { static int Goo(int x) { <AS:0>return 1;</AS:0> } static void F() { try { q = from x in xs join y in ys on <AS:1>F()</AS:1> equals G() select 1; } catch { } <AS:2>q.ToArray();</AS:2> } } """; var src2 = """ class C { static int Goo(int x) { <AS:0>return 1;</AS:0> } static void F() { q = from x in xs join y in ys on <AS:1>F()</AS:1> equals G() select 1; <AS:2>q.ToArray();</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Checked/Unchecked [Fact] public void CheckedUnchecked_Insert_Leaf() { var src1 = """ class Test { static void Main(string[] args) { int a = 1, b = 2; <AS:0>Console.WriteLine(a*b);</AS:0> } } """; var src2 = """ class Test { static void Main(string[] args) { int a = 1, b = 2; checked { <AS:0>Console.WriteLine(a*b);</AS:0> } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void CheckedUnchecked_Insert_Internal() { var src1 = """ class Test { static void Main(string[] args) { <AS:1>System.Console.WriteLine(5 * M(1, 2));</AS:1> } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var src2 = """ class Test { static void Main(string[] args) { checked { <AS:1>System.Console.WriteLine(5 * M(1, 2));</AS:1> } } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "checked", CSharpFeaturesResources.checked_statement)); } [Fact] public void CheckedUnchecked_Delete_Internal() { var src1 = """ class Test { static void Main(string[] args) { checked { <AS:1>System.Console.WriteLine(5 * M(1, 2));</AS:1> } } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var src2 = """ class Test { static void Main(string[] args) { <AS:1>System.Console.WriteLine(5 * M(1, 2));</AS:1> } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteAroundActiveStatement, "System.Console.WriteLine(5 * M(1, 2));", CSharpFeaturesResources.checked_statement)); } [Fact] public void CheckedUnchecked_Update_Internal() { var src1 = """ class Test { static void Main(string[] args) { unchecked { <AS:1>System.Console.WriteLine(5 * M(1, 2));</AS:1> } } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var src2 = """ class Test { static void Main(string[] args) { checked { <AS:1>System.Console.WriteLine(5 * M(1, 2));</AS:1> } } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "checked", CSharpFeaturesResources.checked_statement)); } [Fact] public void CheckedUnchecked_Lambda1() { var src1 = """ class Test { static void Main(string[] args) { unchecked { Action f = () => <AS:1>5 * M(1, 2)</AS:1>; } <AS:2>f();</AS:2> } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var src2 = """ class Test { static void Main(string[] args) { checked { Action f = () => <AS:1>5 * M(1, 2)</AS:1>; } <AS:2>f();</AS:2> } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "checked", CSharpFeaturesResources.checked_statement)); } [Fact] public void CheckedUnchecked_Query1() { var src1 = """ using System.Collections.Generic; using System.Linq; class Test { static void F() { IEnumerable<int> f; unchecked { f = from a in new[] { 5 } select <AS:1>M(a, int.MaxValue)</AS:1>; } <AS:2>f.ToArray();</AS:2> } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var src2 = """ using System.Collections.Generic; using System.Linq; class Test { static void F() { IEnumerable<int> f; checked { f = from a in new[] { 5 } select <AS:1>M(a, int.MaxValue)</AS:1>; } <AS:2>f.ToArray();</AS:2> } private static int M(int a, int b) { <AS:0>return a * b;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "checked", CSharpFeaturesResources.checked_statement)); } #endregion #region Lambdas [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_GeneralStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>F(a => <AS:0>1</AS:0>);</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>F(a => <AS:0>2</AS:0>);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_Nested1() { var src1 = """ class C { static void Main(string[] args) { <AS:2>F(b => <AS:1>F(a => <AS:0>1</AS:0>)</AS:1>);</AS:2> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:2>F(b => <AS:1>F(a => <AS:0>2</AS:0>)</AS:1>);</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_Nested2() { var src1 = """ class C { static void Main(string[] args) { <AS:2>F(b => <AS:1>F(a => <AS:0>1</AS:0>)</AS:1>);</AS:2> } } """; var src2 = """ class C { static void Main(string[] args) { <AS:2>F(b => <AS:1>G(a => <AS:0>2</AS:0>)</AS:1>);</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "G(a => 2 )")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_IfStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>if (F(a => <AS:0>1</AS:0>))</AS:1> { } } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>if (F(a => <AS:0>2</AS:0>))</AS:1> { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_WhileStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>while (F(a => <AS:0>1</AS:0>))</AS:1> { } } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>while (F(a => <AS:0>2</AS:0>))</AS:1> { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_DoStatement() { var src1 = """ class C { static void Main(string[] args) { do {} <AS:1>while (F(a => <AS:0>1</AS:0>));</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { do {} <AS:1>while (F(a => <AS:0>2</AS:0>));</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_SwitchStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>switch (F(a => <AS:0>1</AS:0>))</AS:1> { case 0: break; case 1: break; } } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>switch (F(a => <AS:0>2</AS:0>))</AS:1> { case 0: break; case 1: break; } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_LockStatement() { var src1 = """ class C { static void Main(string[] args) { <AS:1>lock (F(a => <AS:0>1</AS:0>))</AS:1> {} } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>lock (F(a => <AS:0>2</AS:0>))</AS:1> {} } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1359")] public void Lambdas_LeafEdits_UsingStatement1() { var src1 = """ class C { static void Main(string[] args) { <AS:1>using (F(a => <AS:0>1</AS:0>))</AS:1> {} } } """; var src2 = """ class C { static void Main(string[] args) { <AS:1>using (F(a => <AS:0>2</AS:0>))</AS:1> {} } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/22696")] public void Lambdas_ExpressionToStatements() { // TODO: The active statement should be mapped to the return statement. var src1 = """ class C { static void Main() { Func<int, int> f = a => <AS:0>1</AS:0>; } } """; var src2 = """ class C { static void Main() { <AS:0>Func<int, int> f = a => { return 1; };</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/22696")] public void Lambdas_ExpressionToStatements_WithSignatureChange() { // TODO: The active statement should be mapped to the return statement. var src1 = """ class C { static void Main() { Func<int, int> f = a => <AS:0>1</AS:0>; } } """; var src2 = """ class C { static void Main(string[] args) { <AS:0>Func<int, int> f = a => { return 1; };</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } [Fact] public void Lambdas_ExpressionToDelegate() { var src1 = """ using System; class C { static void F() { Func<int, int> f = a => <AS:0>1</AS:0>; } } """; var src2 = """ using System; class C { static void F() { <AS:0>Func<int, int> f = delegate(int a) { return 1; };</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61415")] public void Lambdas_EditAroundTry_WithActiveStatement() { var src1 = """ Action F = () => { try { <AS:1>G();</AS:1> } <ER:1.0>catch { }</ER:1.0> }; <AS:0>F();</AS:0> void G() <AS:2>{</AS:2> } """; var src2 = """ Action F = () => { System.Console.WriteLine(1); try { <AS:1>G();</AS:1> } <ER:1.0>catch { }</ER:1.0> }; <AS:0>F();</AS:0> void G() <AS:2>{</AS:2> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lambdas_StatementsToExpression() { var src1 = """ class C { static void Main(string[] args) { Func<int, int> f = a => { <AS:0>return 1;</AS:0> }; } } """; var src2 = """ class C { static void Main(string[] args) { <AS:0>Func<int, int> f = a => 1;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lambdas_DelegateToExpression() { var src1 = """ using System; class C { static void F() { Func<int, int> f = delegate(int a) { <AS:0>return 1;</AS:0> }; } } """; var src2 = """ using System; class C { static void F() { <AS:0>Func<int, int> f = a => 1;</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lambdas_StatementsToDelegate() { var src1 = """ using System; class C { static void F() { Func<int, int> f = a => { <AS:0>return 1;</AS:0> }; } } """; var src2 = """ using System; class C { static void F() { Func<int, int> f = delegate(int a) { <AS:0>return 2;</AS:0> }; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Lambdas_ActiveStatementUpdate() { var src1 = """ using System; class C { static void Main(string[] args) { Func<int, int, int> f = (int a, int b) => <AS:0>a + b + 1</AS:0>; <AS:1>f(2);</AS:1> } } """; var src2 = """ using System; class C { static void Main(string[] args) { Func<int, int, int> f = (_, _) => <AS:0>10</AS:0>; <AS:1>f(2);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, capabilities: EditAndContinueTestVerifier.Net6RuntimeCapabilities); } [Fact] public void Lambdas_ActiveStatementRemoved1() { var src1 = """ class C { static void Main(string[] args) { Func<int, Func<int, int>> f = a => { return b => { <AS:0>return b;</AS:0> }; }; var z = f(1); <AS:1>z(2);</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { Func<int, int> f = b => { <AS:0>return b;</AS:0> }; var z = f; <AS:1>z(2);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "return b;", CSharpFeaturesResources.lambda)); } [Fact] public void Lambdas_ActiveStatementRemoved2() { var src1 = """ class C { static void Main(string[] args) { Func<int, Func<int, int>> f = a => (b) => <AS:0>b</AS:0>; var z = f(1); <AS:1>z(2);</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { Func<int, int> f = <AS:0>(b)</AS:0> => b; var z = f; <AS:1>z(2);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "(b)", CSharpFeaturesResources.lambda)); } [Fact] public void Lambdas_ActiveStatementRemoved3() { var src1 = """ class C { static void Main(string[] args) { Func<int, Func<int, int>> f = a => { Func<int, int> z; F(b => { <AS:0>return b;</AS:0> }, out z); return z; }; var z = f(1); <AS:1>z(2);</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { Func<int, int> f = b => { <AS:0>F(b);</AS:0> return 1; }; var z = f; <AS:1>z(2);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "F(b);", GetResource("lambda"))); } [Fact] public void Lambdas_ActiveStatementRemoved4() { var src1 = """ class C { static void Main() { Func<int, Func<int, int>> f = a => { <AS:1>z(2);</AS:1> return b => { <AS:0>return b;</AS:0> }; }; } } """; var src2 = """ class C { static void Main() <AS:0,1>{</AS:0,1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, // reported because the old main body does not have active statement (only the lambda does): Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "static void Main()", GetResource("method")), Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "{", CSharpFeaturesResources.lambda), Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "{", CSharpFeaturesResources.lambda)); } [Fact] public void Lambdas_RestartRequired_ActiveStatementInLambda() { var src1 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int F([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public void G() { F(() => <AS:0>1</AS:0>); } } """; var src2 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int F([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public void G() { F(() => <AS:0>2</AS:0>); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemantics( active, [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.G"), preserveLocalVariables: true)]); } [Fact] public void Lambdas_RestartRequired_ActiveStatementInContainingMemberBody() { var src1 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int F([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public void G() <AS:0>{</AS:0> F(() => 1); } } """; var src2 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int F([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public void G() <AS:0>{</AS:0> F(() => 2); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemantics( active, [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.G"), preserveLocalVariables: true)]); } [Fact] public void Lambdas_RestartRequired_ActiveStatementInContainingLambda() { var src1 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int F([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public void M(System.Action a) => a(); public void G() { M(() => <AS:0>{</AS:0> F(() => 1); }); } } """; var src2 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int F([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public void M(System.Action a) => a(); public void G() { M(() => <AS:0>{</AS:0> F(() => 2); }); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemantics( active, [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.G"), preserveLocalVariables: true)]); } [Fact] public void Lambdas_RestartRequired_ActiveStatementInAnotherLambda() { var src1 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int R([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public int N(System.Func<int> f) => f(); public void G() { R(() => 1); N(() => <AS:0>10</AS:0>); } } """; var src2 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { public int R([RestartRequiredOnMetadataUpdateAttribute] System.Func<int> f) => f(); public int N(System.Func<int> f) => f(); public void G() { R(() => 2); N(() => <AS:0>10</AS:0>); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "()", GetResource("lambda"))); } [Fact] public void Lambdas_RestartRequired_ConstructorWithInitializers() { var src1 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { <AS:0>int x = 1;</AS:0> int y; [RestartRequiredOnMetadataUpdateAttribute] public C() { y = 3; } } """; var src2 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { <AS:0>int x = 1;</AS:0> int y; [RestartRequiredOnMetadataUpdateAttribute] public C() { y = 0; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // UpdateMightNotHaveAnyEffect not reported since the constructor is active edits.VerifySemanticDiagnostics(active); } [Fact] public void Lambdas_RestartRequired_ConstructorWithoutInitializers() { var src1 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { <AS:0>int x = 1;</AS:0> int y; public C(int a) { y = a; } [RestartRequiredOnMetadataUpdateAttribute] public C() : this(3) { } } """; var src2 = RestartRequiredOnMetadataUpdateAttributeSrc + """ public class C { <AS:0>int x = 1;</AS:0> int y; public C(int a) { y = a; } [RestartRequiredOnMetadataUpdateAttribute] public C() : this(0) { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "public C()", GetResource("constructor"))); } [Fact] public void Queries_ActiveStatementRemoved_WhereClause() { var src1 = """ class C { static void Main(string[] args) { var s = from a in b where <AS:0>b.goo</AS:0> select b.bar; <AS:1>s.ToArray();</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { var s = <AS:0>from</AS:0> a in b select b.bar; <AS:1>s.ToArray();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "from", CSharpFeaturesResources.where_clause)); } [Fact] public void Queries_ActiveStatementRemoved_LetClause() { var src1 = """ class C { static void Main(string[] args) { var s = from a in b let x = <AS:0>b.goo</AS:0> select x; <AS:1>s.ToArray();</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { var s = <AS:0>from</AS:0> a in b select a.bar; <AS:1>s.ToArray();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "from", CSharpFeaturesResources.let_clause)); } [Fact] public void Queries_ActiveStatementRemoved_JoinClauseLeft() { var src1 = """ class C { static void Main(string[] args) { var s = from a in b join c in d on <AS:0>a.goo</AS:0> equals c.bar select a.bar; <AS:1>s.ToArray();</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { var s = <AS:0>from</AS:0> a in b select a.bar; <AS:1>s.ToArray();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "from", CSharpFeaturesResources.join_clause)); } [Fact] public void Queries_ActiveStatementRemoved_OrderBy1() { var src1 = """ class C { static void Main(string[] args) { var s = from a in b orderby <AS:0>a.x</AS:0>, a.y descending, a.z ascending select a; <AS:1>s.ToArray();</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { var s = <AS:0>from</AS:0> a in b select a.bar; <AS:1>s.ToArray();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "from", CSharpFeaturesResources.orderby_clause)); } [Fact] public void Queries_ActiveStatementRemoved_OrderBy2() { var src1 = """ class C { static void Main(string[] args) { var s = from a in b orderby a.x, <AS:0>a.y</AS:0> descending, a.z ascending select a; <AS:1>s.ToArray();</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { var s = <AS:0>from</AS:0> a in b select a.bar; <AS:1>s.ToArray();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "from", CSharpFeaturesResources.orderby_clause)); } [Fact] public void Queries_ActiveStatementRemoved_OrderBy3() { var src1 = """ class C { static void Main(string[] args) { var s = from a in b orderby a.x, a.y descending, <AS:0>a.z</AS:0> ascending select a; <AS:1>s.ToArray();</AS:1> } } """; var src2 = """ class C { static void Main(string[] args) { var s = <AS:0>from</AS:0> a in b select a.bar; <AS:1>s.ToArray();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "from", CSharpFeaturesResources.orderby_clause)); } [Fact] public void Queries_Remove_JoinInto1() { var src1 = """ class C { static void F() { var q = from x in xs join y in ys on F() equals G() into g select <AS:0>1</AS:0>; } } """; var src2 = """ class C { static void F() { var q = from x in xs join y in ys on F() equals G() select <AS:0>1</AS:0>; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Queries_Remove_QueryContinuation1() { var src1 = """ class C { static void F() { var q = from x in xs group x by x.F() into g where <AS:0>g.F()</AS:0> select 1; } } """; var src2 = """ class C { static void F() { var q = from x in xs group x by x.F() <AS:0>into</AS:0> g select 1; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "into", CSharpFeaturesResources.where_clause)); } [Fact] public void Queries_Remove_QueryContinuation2() { var src1 = """ class C { static void F() { var q = from x in xs group x by x.F() into g select <AS:0>1</AS:0>; } } """; var src2 = """ class C { static void F() { var q = from x in xs <AS:0>join</AS:0> y in ys on F() equals G() into g select 1; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "join", CSharpFeaturesResources.select_clause)); } [Fact] public void Queries_Select_Reduced1() { var src1 = """ class C { static void F() { var q = from a in array where a > 0 select <AS:0>a + 1</AS:0>; } } """; var src2 = """ class C { static void F() { var q = from a in array where a > 0 <AS:0>select</AS:0> a; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "select", CSharpFeaturesResources.select_clause)); } [Fact] public void Queries_Select_Reduced2() { var src1 = """ class C { static int F(IEnumerable<int> e) => <AS:0>1</AS:0>; static void F() { <AS:1>F(from a in array where a > 0 select a + 1);</AS:1> } } """; var src2 = """ class C { static int F(IEnumerable<int> e) => <AS:0>1</AS:0>; static void F() { <AS:1>F(from a in array where a > 0 select a);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "F(from a in array where a > 0 select a);")); } [Fact] public void Queries_GroupBy_Reduced1() { var src1 = """ class C { static void F() { var q = from a in array group <AS:0>a + 1</AS:0> by a; } } """; var src2 = """ class C { static void F() { var q = from a in array <AS:0>group</AS:0> a by a; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "group", CSharpFeaturesResources.groupby_clause)); } [Fact] public void Queries_GroupBy_Reduced2() { var src1 = """ class C { static int F(IEnumerable<IGrouping<int, int>> e) => <AS:0>1</AS:0>; static void F() { <AS:1>F(from a in array group a by a);</AS:1> } } """; var src2 = """ class C { static int F(IEnumerable<IGrouping<int, int>> e) => <AS:0>1</AS:0>; static void F() { <AS:1>F(from a in array group a + 1 by a);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "F(from a in array group a + 1 by a);")); } #endregion #region State Machines [Fact] public void MethodToIteratorMethod_WithActiveStatement() { var src1 = """ class C { static IEnumerable<int> F() { <AS:0>Console.WriteLine(1);</AS:0> return new[] { 1, 2, 3 }; } } """; var src2 = """ class C { static IEnumerable<int> F() { <AS:0>Console.WriteLine(1);</AS:0> yield return 1; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static IEnumerable<int> F()")); } [Fact] public void MethodToIteratorMethod_WithActiveStatementInLambda() { var src1 = """ class C { static IEnumerable<int> F() { var f = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> }); return new[] { 1, 2, 3 }; } } """; var src2 = """ class C { static IEnumerable<int> F() { var f = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> }); yield return 1; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // should not contain RUDE_EDIT_INSERT_AROUND edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.NewTypeDefinition | EditAndContinueCapabilities.AddExplicitInterfaceImplementation); } [Fact] public void MethodToIteratorMethod_WithoutActiveStatement() { var src1 = """ class C { static IEnumerable<int> F() { Console.WriteLine(1); return new[] { 1, 2, 3 }; } } """; var src2 = """ class C { static IEnumerable<int> F() { Console.WriteLine(1); yield return 1; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.NewTypeDefinition | EditAndContinueCapabilities.AddExplicitInterfaceImplementation); } [Fact] public void MethodToAsyncMethod_WithActiveStatement_AwaitExpression() { var src1 = """ class C { static Task<int> F() { <AS:0>Console.WriteLine(1);</AS:0> return Task.FromResult(1); } } """; var src2 = """ class C { static async Task<int> F() { <AS:0>Console.WriteLine(1);</AS:0> return await Task.FromResult(1); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async Task<int> F()")); } [Fact] public void MethodToAsyncMethod_WithActiveStatement_AwaitForEach() { var src1 = """ class C { static Task<int> F() { <AS:0>Console.WriteLine(1);</AS:0> return Task.FromResult(1); } } """; var src2 = """ class C { static async Task<int> F() { <AS:0>Console.WriteLine(1);</AS:0> await foreach (var x in AsyncIter()) { } return 1; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async Task<int> F()")); } [Fact] public void MethodToAsyncMethod_WithActiveStatement_AwaitUsing() { var src1 = """ class C { static Task<int> F() { <AS:0>Console.WriteLine(1);</AS:0> return Task.FromResult(1); } } """; var src2 = """ class C { static async Task<int> F() { <AS:0>Console.WriteLine(1);</AS:0> await using IAsyncDisposable x = new AsyncDisposable(), y = new AsyncDisposable(); return 1; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async Task<int> F()")); } [Fact] public void MethodToAsyncMethod_WithActiveStatement_NoAwait1() { var src1 = """ class C { static void F() <AS:0>{</AS:0> Console.WriteLine(1); } } """; var src2 = """ class C { static async void F() <AS:0>{</AS:0> Console.WriteLine(1); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async void F()")); } [Fact] public void MethodToAsyncMethod_WithActiveStatement_NoAwait2() { var src1 = """ class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { static async void F() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async void F()")); } [Fact] public void MethodToAsyncMethod_WithActiveStatementInLambda1() { var src1 = """ class C { static Task<int> F() { var f = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> }); return Task.FromResult(1); } } """; var src2 = """ class C { static async Task<int> F() { var f = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> }); return await Task.FromResult(1); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // should not contain RUDE_EDIT_INSERT_AROUND edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.NewTypeDefinition | EditAndContinueCapabilities.AddExplicitInterfaceImplementation); } [Fact] public void MethodToAsyncMethod_WithActiveStatementInLambda_2() { var src1 = """ class C { static void F() { var f = new Action(() => { <AS:1>Console.WriteLine(1);</AS:1> }); <AS:0>f();</AS:0> } } """; var src2 = """ class C { static async void F() { var f = new Action(() => { <AS:1>Console.WriteLine(1);</AS:1> }); <AS:0>f();</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async void F()")); } [Fact] public void MethodToAsyncMethod_WithLambda() { var src1 = """ class C { static void F() <AS:0>{</AS:0> var f = new Action(() => { Console.WriteLine(1); }); f(); } } """; var src2 = """ class C { static async void F() <AS:0>{</AS:0> var f = new Action(() => { Console.WriteLine(1); }); f(); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async void F()")); } [Fact] public void MethodToAsyncMethod_WithoutActiveStatement_1() { var src1 = """ class C { static Task<int> F() { Console.WriteLine(1); return Task.FromResult(1); } } """; var src2 = """ class C { static async Task<int> F() { Console.WriteLine(1); return await Task.FromResult(1); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, capabilities: EditAndContinueCapabilities.NewTypeDefinition | EditAndContinueCapabilities.AddExplicitInterfaceImplementation); } [Fact] public void MethodToAsyncMethod_WithoutActiveStatement_2() { var src1 = """ class C { static void F() { Console.WriteLine(1); } } """; var src2 = """ class C { static async void F() { Console.WriteLine(1); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, capabilities: EditAndContinueCapabilities.NewTypeDefinition | EditAndContinueCapabilities.AddExplicitInterfaceImplementation); } [Fact] public void LambdaToAsyncLambda_WithActiveStatement() { var src1 = """ using System; using System.Threading.Tasks; class C { static void F() { var f = new Func<Task<int>>(() => { <AS:0>Console.WriteLine(1);</AS:0> return Task.FromResult(1); }); } } """; var src2 = """ using System; using System.Threading.Tasks; class C { static void F() { var f = new Func<Task<int>>(async () => { <AS:0>Console.WriteLine(1);</AS:0> return await Task.FromResult(1); }); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "()")); } [Fact] public void LambdaToAsyncLambda_WithActiveStatement_NoAwait() { var src1 = """ using System; class C { static void F() { var f = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> }); } } """; var src2 = """ using System; class C { static void F() { var f = new Action(async () => { <AS:0>Console.WriteLine(1);</AS:0> }); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "()")); } [Fact] public void LambdaToAsyncLambda_WithActiveStatement_NoAwait_Nested() { var src1 = """ class C { static void F() { var f = new Func<int, Func<int, int>>(a => <AS:0>b => 1</AS:0>); } } """; var src2 = """ class C { static void F() { var f = new Func<int, Func<int, int>>(async a => <AS:0>b => 1</AS:0>); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "a")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37054")] public void LocalFunctionToAsyncLocalFunction_BlockBody_WithActiveStatement() { var src1 = """ class C { static void F() { Task<int> f() { <AS:0>Console.WriteLine(1);</AS:0> return Task.FromResult(1); } } } """; var src2 = """ class C { static void F() { async Task<int> f() { <AS:0>Console.WriteLine(1);</AS:0> return await Task.FromResult(1); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "f")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61415")] public void LocalFunction_EditAroundTry_WithActiveStatement() { var src1 = """ <AS:0>F();</AS:0> void F() { try { <AS:1>G();</AS:1> } <ER:1.0>catch { }</ER:1.0> } void G() <AS:2>{</AS:2> } """; var src2 = """ <AS:0>F();</AS:0> void F() { System.Console.WriteLine(1); try { <AS:1>G();</AS:1> } <ER:1.0>catch { }</ER:1.0> } void G() <AS:2>{</AS:2> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37054")] public void LocalFunctionToAsyncLocalFunction_ExpressionBody_WithActiveStatement() { var src1 = """ class C { static void F() { Task<int> f() => <AS:0>Task.FromResult(1)</AS:0>; } } """; var src2 = """ class C { static void F() { async Task<int> f() => <AS:0>await Task.FromResult(1)</AS:0>; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "f")); } [Fact] public void AnonymousFunctionToAsyncAnonymousFunction_WithActiveStatement_NoAwait() { var src1 = """ using System.Threading.Tasks; class C { static void F() { var f = new Func<Task>(delegate() { <AS:0>Console.WriteLine(1);</AS:0> return Task.CompletedTask; }); } } """; var src2 = """ using System.Threading.Tasks; class C { static async void F() { var f = new Func<Task>(async delegate() { <AS:0>Console.WriteLine(1);</AS:0> }); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, FeaturesResources.delegate_)); } [Fact] public void AsyncMethodEdit_Semantics() { var src1 = """ using System; using System.Threading.Tasks; class C { static async Task<int> F() { await using var x = new AsyncDisposable(); await foreach (var x in AsyncIter()) { Console.WriteLine(x); } return await Task.FromResult(1); } } """; var src2 = """ using System; using System.Threading.Tasks; class C { static async Task<int> F() { await using var x = new AsyncDisposable(); await foreach (var x in AsyncIter()) { Console.WriteLine(x + 1); } return await Task.FromResult(2); } } """; var edits = GetTopEdits(src1, src2); _ = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } [Fact] public void IteratorMethodEdit_Semantics() { var src1 = """ using System; using System.Collections.Generic; class C { static IEnumerable<int> F() { Console.WriteLine(1); yield return 1; } } """; var src2 = """ using System; using System.Collections.Generic; class C { static IEnumerable<int> F() { Console.WriteLine(2); yield return 2; } } """; var edits = GetTopEdits(src1, src2); _ = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } [Fact] public void AsyncIteratorMethodEdit_Semantics() { var src1 = """ using System; using System.Collections.Generic; using System.Threading.Tasks; class C { static async IAsyncEnumerable<int> F() { Console.WriteLine(1); await Task.Delay(1); yield return 1; } } """; var src2 = """ using System; using System.Collections.Generic; using System.Threading.Tasks; class C { static async IAsyncEnumerable<int> F() { Console.WriteLine(2); await Task.Delay(2); yield return 2; } } """; var edits = GetTopEdits(src1, src2); _ = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( targetFrameworks: [TargetFramework.NetCoreApp], capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } [Fact] public void AsyncMethodToMethod() { var src1 = """ class C { static async void F() { } } """; var src2 = """ class C { static void F() { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ChangingFromAsynchronousToSynchronous, "static void F()", FeaturesResources.method)); } #endregion #region Misplaced AS [Fact] public void MisplacedActiveStatement1() { var src1 = """ <AS:1>class C</AS:1> { public static int F(int a) { <AS:0>return a;</AS:0> <AS:2>return a;</AS:2> } } """; var src2 = """ class C { public static int F(int a) { <AS:0>return a;</AS:0> <AS:2>return a;</AS:2> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void MisplacedActiveStatement2() { var src1 = """ class C { static <AS:0>void</AS:0> Main(string[] args) { } } """; var src2 = """ class C { static void Main(string[] args) <AS:0>{</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void MisplacedTrackingSpan1() { var src1 = """ class C { static <AS:0>void</AS:0> Main(string[] args) { } } """; var src2 = """ class C { static <TS:0>void</TS:0> Main(string[] args) <AS:0>{</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region C# 7.0 [Fact] public void UpdateAroundActiveStatement_IsPattern() { var src1 = """ class C { static void F(object x) { <AS:0>Console.WriteLine(1);</AS:0> if (x is int i) { Console.WriteLine("match"); } } } """; var src2 = """ class C { static void F(object x) { <AS:0>Console.WriteLine(1);</AS:0> if (x is string s) { Console.WriteLine("match"); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_DeconstructionDeclarationStatement() { var src1 = """ class C { static void F(object x) { <AS:0>Console.WriteLine(1);</AS:0> var (x, y) = (1, 2); } } """; var src2 = """ class C { static void F(object x) { <AS:0>Console.WriteLine(1);</AS:0> var (x, y) = x; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_DeconstructionForEach() { var src1 = """ class C { static void F(object o) { <AS:0>Console.WriteLine(1);</AS:0> foreach (var (x, y) in new[] { (1, 2) }) { Console.WriteLine(2); } } } """; var src2 = """ class C { static void F(object o) { <AS:0>Console.WriteLine(1);</AS:0> foreach (var (x, y) in new[] { o }) { Console.WriteLine(2); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_VarDeconstruction() { var src1 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> for (var (x, y) = o1; ; ) { } } } """; var src2 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> for (var (x, y) = o2; ; ) { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_TypedDeconstruction() { var src1 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> for ((int x, int y) = o1; ; ) { } } } """; var src2 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> for ((int x, int y) = o2; ; ) { } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_Tuple() { var src1 = """ class C { static void F(object o) { <AS:0>Console.WriteLine(1);</AS:0> (int, int) t; } } """; var src2 = """ class C { static void F(object o) { <AS:0>Console.WriteLine(1);</AS:0> (int, int) t = (1, 2); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_LocalFunction() { var src1 = """ class C { static void F(object o) { <AS:0>Console.WriteLine(1);</AS:0> void M() { Console.WriteLine(2); } } } """; var src2 = """ class C { static void F(object o) { <AS:0>Console.WriteLine(1);</AS:0> void M() { Console.WriteLine(3); } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_OutVar() { var src1 = """ class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> M(); } } """; var src2 = """ class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> M(out var x); } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_OutVarRemoved() { var src1 = """ class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> M(out var x); } } """; var src2 = """ class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_Ref() { var src1 = """ class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> ref int i = ref 1; } } """; var src2 = """ class C { static void F() { <AS:0>Console.WriteLine(1);</AS:0> ref int i = ref 2; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_DeconstructionDeclaration() { var src1 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> var (x, y) = o1; } } """; var src2 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> var (x, y) = o2; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_DeconstructionAssignment() { var src1 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> int x, y; (x, y) = o1; } } """; var src2 = """ class C { static void F(object o1, object o2) { <AS:0>Console.WriteLine(1);</AS:0> int x, y; (x, y) = o2; } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void UpdateAroundActiveStatement_SwitchWithPattern() { var src1 = """ class C { static void F(object o1, object o2) { <AS:0>System.Console.WriteLine(1);</AS:0> switch (o1) { case int i: break; } } } """; var src2 = """ class C { static void F(object o1, object o2) { <AS:0>System.Console.WriteLine(1);</AS:0> switch (o2) { case int i: break; } } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); edits.VerifySemanticDiagnostics(); } #endregion #region Nullable [Fact] public void ChangeLocalNullableToNonNullable() { var src1 = """ class C { static void F() { <AS:0>string? s = "a";</AS:0> } } """; var src2 = """ class C { static void F() { <AS:0>string s = "a";</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void ChangeLocalNonNullableToNullable() { var src1 = """ class C { static void F() { <AS:0>string s = "a";</AS:0> } } """; var src2 = """ class C { static void F() { <AS:0>string? s = "a";</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Partial Types [Fact] public void InsertDeleteMethod_Inactive() { // Moving inactive method declaration in a file with active statements. var srcA1 = "partial class C { void F1() { <AS:0>System.Console.WriteLine(1);</AS:0> } }"; var srcB1 = "partial class C { void F2() { } }"; var srcA2 = "partial class C { void F1() { <AS:0>System.Console.WriteLine(1);</AS:0> } void F2() { } }"; var srcB2 = "partial class C { }"; EditAndContinueValidation.VerifySemantics( [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], [ DocumentResults( activeStatements: GetActiveStatements(srcA1, srcA2, documentIndex: 0), semanticEdits: [ SemanticEdit(SemanticEditKind.Update, c => c.GetMember<INamedTypeSymbol>("C").GetMember("F2")), ]), DocumentResults( activeStatements: GetActiveStatements(srcB1, srcB2, documentIndex: 1)) ]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/51177")] [WorkItem("https://github.com/dotnet/roslyn/issues/54758")] public void InsertDeleteMethod_Active() { // Moving active method declaration in a file with active statements. // TODO: this is currently a rude edit var srcA1 = "partial class C { }"; var srcB1 = "partial class C { void F() { <AS:0>System.Console.WriteLine(1);</AS:0> } }"; var srcA2 = "partial class C { void F() { System.Console.WriteLine(1); } }"; var srcB2 = "<AS:0>partial class C</AS:0> { }"; EditAndContinueValidation.VerifySemantics( [GetTopEdits(srcA1, srcA2, documentIndex: 0), GetTopEdits(srcB1, srcB2, documentIndex: 1)], [ DocumentResults( activeStatements: GetActiveStatements(srcA1, srcA2, documentIndex: 0), semanticEdits: [ SemanticEdit(SemanticEditKind.Update, c => c.GetMember<INamedTypeSymbol>("C").GetMember("F")), ]), DocumentResults( activeStatements: GetActiveStatements(srcB1, srcB2, documentIndex: 1), diagnostics: [Diagnostic(RudeEditKind.DeleteActiveStatement, "partial class C", GetResource("method", "F()"))]) ]); } [Fact] public void InsertDeleteMethod_Active_EntirePartialTypeDeclaration() { var srcA1 = "partial class C { }"; var srcB1 = "partial class C { void F() { <AS:0>System.Console.WriteLine(1);</AS:0> } }"; var srcA2 = "partial class C { void F() { System.Console.WriteLine(1); } }"; var srcB2 = "<AS:0/>"; EditAndContinueValidation.VerifySemantics( [GetTopEdits(srcA1, srcA2, documentIndex: 0), GetTopEdits(srcB1, srcB2, documentIndex: 1)], [ DocumentResults( activeStatements: GetActiveStatements(srcA1, srcA2, documentIndex: 0), semanticEdits: [ SemanticEdit(SemanticEditKind.Update, c => c.GetMember<INamedTypeSymbol>("C").GetMember("F")), ]), DocumentResults( activeStatements: GetActiveStatements(srcB1, srcB2, documentIndex: 1), diagnostics: [Diagnostic(RudeEditKind.DeleteActiveStatement, "", GetResource("method", "C.F()"))]) ]); } #endregion #region Records [Fact] public void Record() { var src1 = """ record C(int X) { public int X { get; init; } = <AS:0>1</AS:0>; } """; var src2 = """ record C(int X) { public int X { get; init; } = <AS:0>2</AS:0>; } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Record_Constructor() { var src1 = """ record C(int X) { public int X { get; init; } = <AS:0>1</AS:0>; static void Main(string[] args) { <AS:1>var x = new C(1);</AS:1> } } """; var src2 = """ record C(int X) { public int X { get; init; } = <AS:0>2</AS:0>; static void Main(string[] args) { <AS:1>var x = new C(1);</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void Record_FieldInitializer_Lambda2() { var src1 = """ record C(int X) { Func<int, Func<int>> a = z => () => <AS:0>z + 1</AS:0>; static void Main(string[] args) { <AS:1>new C(1).a(1)();</AS:1> } } """; var src2 = """ record C(int X) { Func<int, Func<int>> a = z => () => <AS:0>z + 2</AS:0>; static void Main(string[] args) { <AS:1>new C(1).a(1)();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } #endregion #region Line Mapping /// <summary> /// Validates that changes in #line directives produce semantic updates of the containing method. /// </summary> [Fact] public void LineMapping_ChangeLineNumber_WithinMethod() { var src1 = """ class C { #line 1 "a" static void F() { <AS:0>A();</AS:0> #line 5 "b" B(1); <AS:1>B();</AS:1> #line 2 "c" <AS:2>C();</AS:2> <AS:3>C();</AS:3> #line hidden D(); #line default <AS:4>E();</AS:4> } } """; var src2 = """ class C { #line 1 "a" static void F() { <AS:0>A();</AS:0> #line 5 "b" B(2); <AS:1>B();</AS:1> #line 9 "c" <AS:2>C();</AS:2> <AS:3>C();</AS:3> #line hidden D(); #line default <AS:4>E();</AS:4> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void LineMapping_ChangeFilePath() { var src1 = """ class C { static void F() { <AS:0>A();</AS:0> #line 1 "a" <AS:1>B();</AS:1> } } """; var src2 = """ class C { static void F() { <AS:0>A();</AS:0> #line 1 "b" <AS:1>B();</AS:1> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "B();", string.Format(FeaturesResources._0_directive, "line"))); } [Fact] public void LineMapping_ExceptionRegions_ChangeLineNumber() { var src1 = """ class C { static void F() <AS:0>{</AS:0> try { try { <AS:1>Goo();</AS:1> } #line 20 "a" <ER:1.1>catch (E1 e) { }</ER:1.1> #line default } #line 20 "b" <ER:1.0>catch (E2 e) { }</ER:1.0> #line default } } """; var src2 = """ class C { static void F() <AS:0>{</AS:0> try { try { <AS:1>Goo();</AS:1> } #line 20 "a" <ER:1.1>catch (E1 e) { }</ER:1.1> #line default } #line 30 "b" <ER:1.0>catch (E2 e) { }</ER:1.0> #line default } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52971")] public void LineMapping_ExceptionRegions_ChangeFilePath() { var src1 = """ class C { static void F() <AS:0>{</AS:0> try { try { <AS:1>Goo();</AS:1> } #line 20 "a" <ER:1.1>catch (E1 e) { }</ER:1.1> #line default } #line 20 "b" <ER:1.0>catch (E2 e) { }</ER:1.0> #line default } } """; var src2 = """ class C { static void F() <AS:0>{</AS:0> try { try { <AS:1>Goo();</AS:1> } #line 20 "a" <ER:1.1>catch (E1 e) { }</ER:1.1> #line default } #line 20 "c" <ER:1.0>catch (E2 e) { }</ER:1.0> #line default } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // TODO: rude edit should be reported edits.VerifySemanticDiagnostics(active); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/52971"), WorkItem("https://github.com/dotnet/roslyn/issues/52971")] public void LineMapping_ExceptionRegions_LineChange_MultipleMappedFiles() { var src1 = """ class C { static void F() <AS:0>{</AS:0> try { <AS:1>Goo();</AS:1> } #line 20 "a" <ER:1.1>catch (E1 e) { }</ER:1.1> #line 20 "b" <ER:1.0>catch (E2 e) { }</ER:1.0> #line default } } """; var src2 = """ class C { static void F() <AS:0>{</AS:0> try { <AS:1>Goo();</AS:1> } #line 20 "a" <ER:1.1>catch (E1 e) { }</ER:1.1> #line 30 "b" <ER:1.0>catch (E2 e) { }</ER:1.0> #line default } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // TODO: rude edit? edits.VerifySemanticDiagnostics(active); } #endregion #region Misc [Fact] public void Delete_All_SourceText() { var src1 = """ class C { static void Main(string[] args) { <AS:1>Goo(1);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } } """; var src2 = @""; var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( Diagnostic(RudeEditKind.Delete, null, DeletedSymbolDisplay(FeaturesResources.class_, "C"))); } [Fact] public void PartiallyExecutedActiveStatement() { var src1 = """ class C { public static void F() { <AS:0>Console.WriteLine(1);</AS:0> <AS:1>Console.WriteLine(2);</AS:1> <AS:2>Console.WriteLine(3);</AS:2> <AS:3>Console.WriteLine(4);</AS:3> <AS:4>Console.WriteLine(5);</AS:4> } } """; var src2 = """ class C { public static void F() { <AS:0>Console.WriteLine(10);</AS:0> <AS:1>Console.WriteLine(20);</AS:1> <AS:2>Console.WriteLine(30);</AS:2> <AS:3>Console.WriteLine(40);</AS:3> <AS:4>Console.WriteLine(50);</AS:4> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2, flags: [ ActiveStatementFlags.PartiallyExecuted | ActiveStatementFlags.LeafFrame, ActiveStatementFlags.PartiallyExecuted | ActiveStatementFlags.NonLeafFrame, ActiveStatementFlags.LeafFrame, ActiveStatementFlags.NonLeafFrame, ActiveStatementFlags.NonLeafFrame | ActiveStatementFlags.LeafFrame ]); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.PartiallyExecutedActiveStatementUpdate, "Console.WriteLine(10);"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "Console.WriteLine(20);"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "Console.WriteLine(40);"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "Console.WriteLine(50);")); } [Fact] public void PartiallyExecutedActiveStatement_Deleted1() { var src1 = """ class C { public static void F() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { public static void F() { <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2, flags: [ ActiveStatementFlags.PartiallyExecuted | ActiveStatementFlags.LeafFrame ]); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.PartiallyExecutedActiveStatementDelete, "{", FeaturesResources.code)); } [Fact] public void PartiallyExecutedActiveStatement_Deleted2() { var src1 = """ class C { public static void F() { <AS:0>Console.WriteLine(1);</AS:0> } } """; var src2 = """ class C { public static void F() { <AS:0>}</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2, flags: [ ActiveStatementFlags.NonLeafFrame | ActiveStatementFlags.LeafFrame ]); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.DeleteActiveStatement, "{", FeaturesResources.code)); } [Fact] public void Block_Delete() { var src1 = """ class C { public static void F() { G(1); <AS:0>{</AS:0> G(2); } G(3); } } """; var src2 = """ class C { public static void F() { G(1); <AS:0>G(3);</AS:0> } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Theory, CombinatorialData] public void MemberBodyInternalError(bool outOfMemory) { var src1 = """ class C { public static void F() { <AS:1>G();</AS:1> } public static void G() { <AS:0>H(1);</AS:0> } public static void H(int x) { } } """; var src2 = """ class C { public static void F() { <AS:1>G();</AS:1> } public static void G() { <AS:0>H(2);</AS:0> } public static void H(int x) { } } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); var validator = new CSharpEditAndContinueTestVerifier(faultInjector: node => { if (node.Parent is MethodDeclarationSyntax methodDecl && methodDecl.Identifier.Text == "G") { throw outOfMemory ? new OutOfMemoryException() : new SimpleToStringException(); } }); var expectedDiagnostic = outOfMemory ? Diagnostic(RudeEditKind.MemberBodyTooBig, "public static void G()", "G") : Diagnostic(RudeEditKind.MemberBodyInternalError, "public static void G()", "G", SimpleToStringException.ToStringOutput); validator.VerifySemantics( [edits], TargetFramework.NetCoreApp, [DocumentResults(diagnostics: [expectedDiagnostic])]); } /// <summary> /// Custom exception class that has a fixed ToString so that tests aren't relying /// on stack traces, which could make them flaky /// </summary> private sealed class SimpleToStringException : Exception { public const string ToStringOutput = "<Exception>"; public override string ToString() { return ToStringOutput; } } #endregion #region Top Level Statements [Fact] public void TopLevelStatements_UpdateAroundActiveStatement_LocalFunction() { var src1 = """ using System; <AS:0>Console.WriteLine(1);</AS:0> void M() { Console.WriteLine(2); } """; var src2 = """ using System; <AS:0>Console.WriteLine(1);</AS:0> void M() { Console.WriteLine(3); } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void TopLevelStatements_UpdateAroundActiveStatement_OutVar() { var src1 = """ using System; <AS:0>Console.WriteLine(1);</AS:0> M(); """; var src2 = """ using System; <AS:0>Console.WriteLine(1);</AS:0> M(out var x); """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active); } [Fact] public void TopLevelStatements_Inner() { var src1 = """ using System; <AS:1>Goo(1);</AS:1> static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } """; var src2 = """ using System; while (true) { <AS:1>Goo(2);</AS:1> } static void Goo(int a) { <AS:0>Console.WriteLine(a);</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.ActiveStatementUpdate, "Goo(2);")); } [Fact] public void TopLevelStatements_RestartRequired() { var src1 = """ using System; while (true) { <AS:0>Console.WriteLine(1);</AS:0> } """; var src2 = """ using System; while (true) { <AS:0>Console.WriteLine(2);</AS:0> } """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); // UpdateMightNotHaveAnyEffect not reported since the top-level method is active edits.VerifySemanticDiagnostics(active); } [Fact] public void TopLevelStatements_RestartRequired_Lambda() { var src1 = """ using System; _ = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> }); Console.WriteLine(2); """; var src2 = """ using System; _ = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> }); Console.WriteLine(20); """; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics( active, Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "20", GetResource("top-level code"))); } #endregion }