|
// 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 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);
}
#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, "int F(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, "C(byte P)", GetResource("constructor"))],
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, "get", GetResource("property getter")),
Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "set", GetResource("property setter"))
],
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
}
[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, "get", GetResource("property getter")),
Diagnostic(RudeEditKind.ChangingNameOrSignatureOfActiveMember, "set", GetResource("property setter"))
],
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
}
[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 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 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);"));
}
#endregion
}
|