diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index e5a4e66119b49..f254328b52e3a 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -674,6 +674,14 @@ public static string GetAssertMessage( var expectedString = string.Join(itemSeparator, expected.Take(10).Select(itemInspector)); var actualString = string.Join(itemSeparator, actual.Select(itemInspector)); + var diffString = DiffUtil.DiffReport(expected, actual, itemSeparator, comparer, itemInspector); + + if (DifferOnlyInWhitespace(expectedString, actualString)) + { + expectedString = VisualizeWhitespace(expectedString); + actualString = VisualizeWhitespace(actualString); + diffString = VisualizeWhitespace(diffString); + } var message = new StringBuilder(); @@ -693,7 +701,7 @@ public static string GetAssertMessage( message.AppendLine("Actual:"); message.AppendLine(actualString); message.AppendLine("Differences:"); - message.AppendLine(DiffUtil.DiffReport(expected, actual, itemSeparator, comparer, itemInspector)); + message.AppendLine(diffString); if (TryGenerateExpectedSourceFileAndGetDiffLink(actualString, expected.Count(), expectedValueSourcePath, expectedValueSourceLine, out var link)) { @@ -703,6 +711,38 @@ public static string GetAssertMessage( return message.ToString(); } + private static bool DifferOnlyInWhitespace(IEnumerable expected, IEnumerable actual) + => expected.Where(c => !char.IsWhiteSpace(c)).SequenceEqual(actual.Where(c => !char.IsWhiteSpace(c))); + + private static string VisualizeWhitespace(string str) + { + var result = new StringBuilder(str.Length); + + var i = 0; + while (i < str.Length) + { + var c = str[i++]; + if (c == '\r' && i < str.Length && str[i] == '\n') + { + result.Append("␍␊\r\n"); + i++; + } + else + { + result.Append(c switch + { + ' ' => "·", + '\t' => "→", + '\r' => "␍\r", + '\n' => "␊\n", + _ => c, + }); + } + } + + return result.ToString(); + } + public static string GetAssertMessage( ReadOnlySpan expected, ReadOnlySpan actual, diff --git a/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs b/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs index 2fe58e3c168d2..b331170087eb5 100644 --- a/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs @@ -109,7 +109,7 @@ public void Update_Inner_Reloadable() [CreateNewOnMetadataUpdate] class C { - static void Main() + static void F() { Goo(1); } @@ -123,7 +123,7 @@ static void Goo(int a) [CreateNewOnMetadataUpdate] class C { - static void Main() + static void F() { while (true) { @@ -733,7 +733,7 @@ namespace N { class C { - static void Main() + static void F() { Console.WriteLine(1); } @@ -746,7 +746,7 @@ static void Main() edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.Delete, "", GetResource("class", "N.C")), - Diagnostic(RudeEditKind.DeleteActiveStatement, "", GetResource("method", "N.C.Main()"))); + Diagnostic(RudeEditKind.DeleteActiveStatement, "", GetResource("method", "N.C.F()"))); } [Fact] @@ -757,7 +757,7 @@ namespace N { class C { - static void Main() + static void F() { Console.WriteLine(1); } @@ -770,7 +770,7 @@ static void Main() edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.Delete, "namespace N", GetResource("class", "C")), - Diagnostic(RudeEditKind.DeleteActiveStatement, "namespace N", GetResource("method", "N.C.Main()"))); + Diagnostic(RudeEditKind.DeleteActiveStatement, "namespace N", GetResource("method", "N.C.F()"))); } [Fact] @@ -781,7 +781,7 @@ namespace N { class C { - static void Main() + static void F() { Console.WriteLine(1); } @@ -800,7 +800,7 @@ namespace N var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, - Diagnostic(RudeEditKind.DeleteActiveStatement, "class C", GetResource("method", "N.C.Main()"))); + Diagnostic(RudeEditKind.DeleteActiveStatement, "class C", GetResource("method", "N.C.F()"))); } #endregion @@ -4999,7 +4999,7 @@ public void ForEach_Update_Collection_01() var src1 = @" class C { - static void Main() + static void F() { var aa = new int[4]; var bb = new int[4]; @@ -5014,7 +5014,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { var aa = new int[4]; var bb = new int[4]; @@ -5039,7 +5039,7 @@ public void ForEach_Update_Collection_02() var src1 = @" class C { - static void Main() + static void F() { Buffer4 aa = default; Buffer4 bb = default; @@ -5060,7 +5060,7 @@ struct Buffer4 var src2 = @" class C { - static void Main() + static void F() { Buffer4 aa = default; Buffer4 bb = default; @@ -6236,7 +6236,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { if (B()) { @@ -6249,7 +6249,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { if (B()) { @@ -6271,7 +6271,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { if (B()) { @@ -6284,7 +6284,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { if (!B()) { @@ -6307,7 +6307,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { if (B(() => 1)) { @@ -6320,7 +6320,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { if (B(() => 2)) { @@ -6342,7 +6342,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { while (B()) { @@ -6355,7 +6355,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { while (B()) { @@ -6377,7 +6377,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { while (B()) { @@ -6390,7 +6390,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { while (!B()) { @@ -6413,7 +6413,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { while (B(() => 1)) { @@ -6426,7 +6426,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { while (B(() => 2)) { @@ -6448,7 +6448,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { do { @@ -6462,7 +6462,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { do { @@ -6485,7 +6485,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { do { @@ -6499,7 +6499,7 @@ class C { public static bool B() { return false; } - public static void Main() + public static void F() { do { @@ -6523,7 +6523,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { do { @@ -6537,7 +6537,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { do { @@ -6587,7 +6587,7 @@ class C { public static string F() { return null; } - public static void Main() + public static void G() { switch (F()) { @@ -6601,7 +6601,7 @@ class C { public static string F() { return null; } - public static void Main() + public static void G() { switch (F()) { @@ -6624,7 +6624,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { switch (B(() => 1)) { @@ -6638,7 +6638,7 @@ class C { public static bool B(Func a) => false; - public static void Main() + public static void F() { switch (B(() => 2)) { @@ -7821,7 +7821,7 @@ public void TryFinally_DeleteStatement_Inner() var src1 = @" class C { - static void Main() + static void F() { Console.WriteLine(0); @@ -7838,7 +7838,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { Console.WriteLine(0); @@ -7903,7 +7903,7 @@ public void Try_DeleteStatement_Inner() var src1 = @" class C { - static void Main() + static void F() { Console.WriteLine(0); @@ -7920,7 +7920,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { Console.WriteLine(0); @@ -7946,7 +7946,7 @@ public void Try_DeleteStatement_Leaf() var src1 = @" class C { - static void Main() + static void F() { try { @@ -7961,7 +7961,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { try { @@ -8951,7 +8951,7 @@ static int Goo(int x) return 1; } - static void Main() + static void F() { Func f = null; try @@ -8975,7 +8975,7 @@ static int Goo(int x) return 1; } - static void Main() + static void F() { Func f = null; @@ -9004,7 +9004,7 @@ static int Goo(int x) return 1; } - static void Main() + static void F() { Func f = x => { @@ -9030,7 +9030,7 @@ static int Goo(int x) return 1; } - static void Main() + static void F() { Func f = x => { @@ -9059,7 +9059,7 @@ static int Goo(int x) return 1; } - static void Main() + static void F() { try { @@ -9082,7 +9082,7 @@ static int Goo(int x) return 1; } - static void Main() + static void F() { q = from x in xs join y in ys on F() equals G() @@ -9307,7 +9307,7 @@ public void CheckedUnchecked_Query1() class Test { - static void Main() + static void F() { IEnumerable f; unchecked @@ -9329,7 +9329,7 @@ private static int M(int a, int b) class Test { - static void Main() + static void F() { IEnumerable f; checked @@ -9609,21 +9609,24 @@ static void Main(string[] args) } [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(string[] args) + static void Main() { - Func f = a => 1; + Func f = a => 1; } } "; var src2 = @" class C { - static void Main(string[] args) + static void Main() { Func f = a => { return 1; }; } @@ -9635,6 +9638,38 @@ static void Main(string[] args) 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 f = a => 1; + } +} +"; + var src2 = @" +class C +{ + static void Main(string[] args) + { + Func f = a => { return 1; }; + } +} +"; + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + edits.VerifySemanticDiagnostics( + active, + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + [Fact] public void Lambdas_ExpressionToDelegate() { @@ -9642,7 +9677,7 @@ public void Lambdas_ExpressionToDelegate() using System; class C { - static void Main() + static void F() { Func f = a => 1; } @@ -9652,7 +9687,7 @@ static void Main() using System; class C { - static void Main() + static void F() { Func f = delegate(int a) { return 1; }; } @@ -9747,7 +9782,7 @@ public void Lambdas_DelegateToExpression() using System; class C { - static void Main() + static void F() { Func f = delegate(int a) { return 1; }; } @@ -9757,7 +9792,7 @@ static void Main() using System; class C { - static void Main() + static void F() { Func f = a => 1; } @@ -9776,7 +9811,7 @@ public void Lambdas_StatementsToDelegate() using System; class C { - static void Main() + static void F() { Func f = a => { return 1; }; } @@ -9786,7 +9821,7 @@ static void Main() using System; class C { - static void Main() + static void F() { Func f = delegate(int a) { return 2; }; } @@ -9958,7 +9993,7 @@ public void Lambdas_ActiveStatementRemoved4() var src1 = @" class C { - static void Main(string[] args) + static void Main() { Func> f = a => { @@ -9974,7 +10009,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void Main() { } @@ -9984,6 +10019,8 @@ static void Main(string[] args) 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)); } @@ -10180,7 +10217,7 @@ public void Queries_Remove_JoinInto1() var src1 = @" class C { - static void Main() + static void F() { var q = from x in xs join y in ys on F() equals G() into g @@ -10190,7 +10227,7 @@ join y in ys on F() equals G() into g var src2 = @" class C { - static void Main() + static void F() { var q = from x in xs join y in ys on F() equals G() @@ -10210,7 +10247,7 @@ public void Queries_Remove_QueryContinuation1() var src1 = @" class C { - static void Main() + static void F() { var q = from x in xs group x by x.F() into g @@ -10221,7 +10258,7 @@ group x by x.F() into g var src2 = @" class C { - static void Main() + static void F() { var q = from x in xs group x by x.F() into g @@ -10242,7 +10279,7 @@ public void Queries_Remove_QueryContinuation2() var src1 = @" class C { - static void Main() + static void F() { var q = from x in xs group x by x.F() into g @@ -10252,7 +10289,7 @@ group x by x.F() into g var src2 = @" class C { - static void Main() + static void F() { var q = from x in xs join y in ys on F() equals G() into g @@ -10273,7 +10310,7 @@ public void Queries_Select_Reduced1() var src1 = @" class C { - static void Main() + static void F() { var q = from a in array where a > 0 @@ -10283,7 +10320,7 @@ where a > 0 var src2 = @" class C { - static void Main() + static void F() { var q = from a in array where a > 0 @@ -10306,7 +10343,7 @@ class C { static int F(IEnumerable e) => 1; - static void Main() + static void F() { F(from a in array where a > 0 select a + 1); } @@ -10316,7 +10353,7 @@ class C { static int F(IEnumerable e) => 1; - static void Main() + static void F() { F(from a in array where a > 0 select a); } @@ -10335,7 +10372,7 @@ public void Queries_GroupBy_Reduced1() var src1 = @" class C { - static void Main() + static void F() { var q = from a in array group a + 1 by a; @@ -10344,7 +10381,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { var q = from a in array group a by a; @@ -10366,7 +10403,7 @@ class C { static int F(IEnumerable> e) => 1; - static void Main() + static void F() { F(from a in array group a by a); } @@ -10376,7 +10413,7 @@ class C { static int F(IEnumerable> e) => 1; - static void Main() + static void F() { F(from a in array group a + 1 by a); } @@ -11961,7 +11998,7 @@ public void LineMapping_ExceptionRegions_ChangeLineNumber() var src1 = @" class C { - static void Main() + static void F() { try { @@ -11981,7 +12018,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { try { @@ -12010,7 +12047,7 @@ public void LineMapping_ExceptionRegions_ChangeFilePath() var src1 = @" class C { - static void Main() + static void F() { try { @@ -12030,7 +12067,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { try { @@ -12060,7 +12097,7 @@ public void LineMapping_ExceptionRegions_LineChange_MultipleMappedFiles() var src1 = @" class C { - static void Main() + static void F() { try { @@ -12076,7 +12113,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { try { diff --git a/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index 8c76e4a890056..e20ba81845de9 100644 --- a/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -472,7 +472,7 @@ public static void Main() Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); Assert.False(result.HasChangesAndSyntaxErrors); - Assert.True(result.RudeEditErrors.IsEmpty); + Assert.True(result.RudeEdits.IsEmpty); } [Fact] @@ -520,7 +520,7 @@ public static void Main() Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); Assert.False(result.HasChangesAndSyntaxErrors); - Assert.Equal(RudeEditKind.ExperimentalFeaturesEnabled, result.RudeEditErrors.Single().Kind); + Assert.Equal(RudeEditKind.ExperimentalFeaturesEnabled, result.RudeEdits.Single().Kind); } } @@ -680,7 +680,7 @@ public class D } Assert.True(result.IsSingle()); - Assert.Empty(result.Single().RudeEditErrors); + Assert.Empty(result.Single().RudeEdits); } [Fact] @@ -726,7 +726,7 @@ class D } Assert.True(result.IsSingle()); - Assert.Empty(result.Single().RudeEditErrors); + Assert.Empty(result.Single().RudeEdits); } [Theory, CombinatorialData] @@ -765,7 +765,7 @@ public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) // here so that any trailing punctuation is removed from the translated template string. : $"ENC0080: {string.Format(FeaturesResources.Modifying_source_file_0_requires_restarting_the_application_due_to_internal_error_1, filePath, "System.NullReferenceException: NullRef!\n")}".Split('\n').First(); - AssertEx.Equal(new[] { expectedDiagnostic }, result.RudeEditErrors.Select(d => d.ToDiagnostic(newSyntaxTree)) + AssertEx.Equal(new[] { expectedDiagnostic }, result.RudeEdits.Select(d => d.ToDiagnostic(newSyntaxTree)) .Select(d => $"{d.Id}: {d.GetMessage().Split(new[] { Environment.NewLine }, StringSplitOptions.None).First()}")); } @@ -801,7 +801,7 @@ public static void Main() var result = await AnalyzeDocumentAsync(oldProject, newDocument, capabilities: EditAndContinueCapabilities.None); - Assert.Equal(RudeEditKind.NotSupportedByRuntime, result.RudeEditErrors.Single().Kind); + Assert.Equal(RudeEditKind.NotSupportedByRuntime, result.RudeEdits.Single().Kind); } } } diff --git a/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs b/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs index 9e42352af2e27..8d5660ddd5a6b 100644 --- a/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs +++ b/src/Features/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs @@ -112,6 +112,18 @@ internal static void VerifySemantics( VerifySemantics(editScript, ActiveStatementsDescription.Empty, semanticEdits, capabilities: null); } + internal static void VerifySemantics( + this EditScript editScript, + SemanticEditDescription[] semanticEdits, + RudeEditDiagnosticDescription[] warnings, + EditAndContinueCapabilities? capabilities = null) + { + VerifySemantics( + [editScript], + [new DocumentAnalysisResultsDescription(ActiveStatementsDescription.Empty, semanticEdits: semanticEdits, diagnostics: warnings)], + capabilities: capabilities); + } + internal static void VerifySemantics( EditScript[] editScripts, DocumentAnalysisResultsDescription[] results, diff --git a/src/Features/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/Features/CSharpTest/EditAndContinue/StatementEditingTests.cs index 147cfafd24b9a..c56e5d7a4d47e 100644 --- a/src/Features/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -4,16 +4,13 @@ #nullable disable -using System; using System.IO; using System.Linq; using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; -using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditAndContinue; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; @@ -9654,7 +9651,9 @@ public void LocalFunctions_WithoutBody_SemanticError() var src2 = "Console.WriteLine(2); int C(int X);"; var edits = GetTopEdits(src1, src2); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.WriteLine(2);", GetResource("top-level code"))]); } #endregion @@ -13136,6 +13135,45 @@ public void WithExpression_PropertyValueReorder() #region Top Level Statements + [Fact] + public void TopLevelStatement_Lambda_Update() + { + var src1 = @" +using System; + +var x = new Func(() => 1); +"; + var src2 = @" +using System; + +var x = new Func(() => 2); +"; + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), preserveLocalVariables: true)]); + } + + [Fact] + public void TopLevelStatement_Lambda_Insert() + { + var src1 = @" +using System; + +Console.WriteLine(1); +"; + var src2 = @" +using System; + +Console.WriteLine(1); +var x = new Func(() => 2); +"; + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), preserveLocalVariables: true)], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.WriteLine(1);", GetResource("top-level code"))], + capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddStaticFieldToExistingType | EditAndContinueCapabilities.NewTypeDefinition); + } + [Fact] public void TopLevelStatement_Capture_Args() { @@ -13151,7 +13189,7 @@ public void TopLevelStatement_Capture_Args() "; var edits = GetTopEdits(src1, src2); edits.VerifySemantics( - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), preserveLocalVariables: true)); + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), preserveLocalVariables: true)]); } [Fact] @@ -13203,34 +13241,46 @@ public void TopLevelStatement_CeaseCapture_Args_Closure() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21499")] public void TopLevelStatement_InsertMultiScopeCapture() { - var src1 = @" -using System; + var src1 = """ + using System; -foreach (int x0 in new[] { 1 }) // Group #0 -{ // Group #1 - int x1 = 0; + foreach (int x0 in new[] { 1 }) // Group #0 + { // Group #1 + int x1 = 0; - int f0(int a) => x0; - int f1(int a) => x1; -} -"; - var src2 = @" -using System; + int f0(int a) => x0; + int f1(int a) => x1; + } + """; -foreach (int x0 in new[] { 1 }) // Group #0 -{ // Group #1 - int x1 = 0; + var src2 = """ + using System; - int f0(int a) => x0; - int f1(int a) => x1; + foreach (int x0 in new[] { 1 }) // Group #0 + { // Group #1 + int x1 = 0; - int f2(int a) => x0 + x1; // runtime rude edit: connecting previously disconnected closures -} -"; + int f0(int a) => x0; + int f1(int a) => x1; + + int f2(int a) => x0 + x1; // runtime rude edit: connecting previously disconnected closures + } + """; var edits = GetTopEdits(src1, src2); edits.VerifySemantics( [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), preserveLocalVariables: true)], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, """ + foreach (int x0 in new[] { 1 }) // Group #0 + { // Group #1 + int x1 = 0; + + int f0(int a) => x0; + int f1(int a) => x1; + + int f2(int a) => x0 + x1; // runtime rude edit: connecting previously disconnected closures + } + """, GetResource("top-level code"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.NewTypeDefinition | EditAndContinueCapabilities.UpdateParameters); } diff --git a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index dc32458ce0022..6185a4947f2e0 100644 --- a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -405,7 +405,7 @@ namespace N { class Program { - static void Main(string[] args) + static void F() { } } @@ -417,7 +417,7 @@ namespace N { class Program { - static void Main(string[] args) + static void F() { Console.WriteLine(""Hello World!""); } @@ -426,7 +426,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("N.Program.Main"))); + edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("N.Program.F"))); } [Fact] @@ -439,7 +439,7 @@ namespace N { class Program { - static void Main(string[] args) + static void F() { Console.WriteLine(""Hello World!""); } @@ -450,7 +450,7 @@ namespace N { class Program { - static void Main(string[] args) + static void F() { } } @@ -458,7 +458,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("N.Program.Main"))); + edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("N.Program.F"))); } [Fact] @@ -7777,7 +7777,7 @@ public void Method_Update() var src1 = @" class C { - static void Main(string[] args) + static void F() { int a = 1; int b = 2; @@ -7788,7 +7788,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void F() { int b = 2; int a = 1; @@ -7798,12 +7798,12 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifyEdits( - @"Update [static void Main(string[] args) + @"Update [static void F() { int a = 1; int b = 2; System.Console.WriteLine(a + b); - }]@18 -> [static void Main(string[] args) + }]@18 -> [static void F() { int b = 2; int a = 1; @@ -7814,7 +7814,7 @@ static void Main(string[] args) edits.VerifySemantics( ActiveStatementsDescription.Empty, - [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Main"), preserveLocalVariables: false)]); + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: false)]); } [Fact] @@ -7823,26 +7823,26 @@ public void MethodWithExpressionBody_Update() var src1 = @" class C { - static int Main(string[] args) => F(1); + static int M() => F(1); static int F(int a) => 1; } "; var src2 = @" class C { - static int Main(string[] args) => F(2); + static int M() => F(2); static int F(int a) => 1; }"; var edits = GetTopEdits(src1, src2); edits.VerifyEdits( - @"Update [static int Main(string[] args) => F(1);]@18 -> [static int Main(string[] args) => F(2);]@18"); + @"Update [static int M() => F(1);]@18 -> [static int M() => F(2);]@18"); edits.VerifySemanticDiagnostics(); edits.VerifySemantics( ActiveStatementsDescription.Empty, - [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Main"), preserveLocalVariables: false)]); + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"), preserveLocalVariables: false)]); } [Fact] @@ -7919,7 +7919,7 @@ public void MethodUpdate_LocalVariableDeclaration() var src1 = @" class C { - static void Main(string[] args) + static void F() { int x = 1; Console.WriteLine(x); @@ -7929,7 +7929,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void F() { int x = 2; Console.WriteLine(x); @@ -7938,11 +7938,11 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifyEdits( -@"Update [static void Main(string[] args) +@"Update [static void F() { int x = 1; Console.WriteLine(x); - }]@18 -> [static void Main(string[] args) + }]@18 -> [static void F() { int x = 2; Console.WriteLine(x); @@ -8114,7 +8114,7 @@ public void PrivateMethodInsert() var src1 = @" class C { - static void Main(string[] args) + static void F() { Console.ReadLine(); } @@ -8124,7 +8124,7 @@ class C { void goo() { } - static void Main(string[] args) + static void F() { Console.ReadLine(); } @@ -8148,7 +8148,7 @@ public void PrivateMethodInsert_WithParameters() class C { - static void Main(string[] args) + static void F() { Console.ReadLine(); } @@ -8160,7 +8160,7 @@ class C { void goo(int a) { } - static void Main(string[] args) + static void F() { Console.ReadLine(); } @@ -8184,7 +8184,7 @@ public void PrivateMethodInsert_WithAttribute() var src1 = @" class C { - static void Main(string[] args) + static void F() { Console.ReadLine(); } @@ -8195,7 +8195,7 @@ class C [System.Obsolete] void goo(int a) { } - static void Main(string[] args) + static void F() { Console.ReadLine(); } @@ -8424,7 +8424,7 @@ public void Method_Update_Parameter_Insert() var src1 = @" class C { - static void Main() + static void F() { } @@ -8432,7 +8432,7 @@ static void Main() var src2 = @" class C { - static void Main(string[] args) + static void F(int a) { } @@ -8440,17 +8440,17 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifyEdits( - "Insert [string[] args]@35"); + "Insert [int a]@32"); edits.VerifySemantics( [ - SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.Main"), deletedSymbolContainerProvider: c => c.GetMember("C")), - SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.Main")) + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.F"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.F")) ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "string[] args", GetResource("method"))], + [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "int a", GetResource("method"))], capabilities: EditAndContinueCapabilities.Baseline); } @@ -8597,7 +8597,7 @@ public void Method_Update_Parameter_Delete() var src1 = @" class C { - static void Main(string[] args) + static void F(int a) { } @@ -8605,7 +8605,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main() + static void F() { } @@ -8613,17 +8613,17 @@ static void Main() var edits = GetTopEdits(src1, src2); edits.VerifyEdits( - "Delete [string[] args]@35"); + "Delete [int a]@32"); edits.VerifySemantics( [ - SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.Main"), deletedSymbolContainerProvider: c => c.GetMember("C")), - SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.Main")) + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.F"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.F")) ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "static void Main()", GetResource("method"))], + [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "static void F()", GetResource("method"))], capabilities: EditAndContinueCapabilities.Baseline); } @@ -8666,7 +8666,7 @@ public void Method_Update_Parameter_Rename() var src1 = @" class C { - static void Main(string[] args) + static void F(int a) { } @@ -8674,7 +8674,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] b) + static void F(int b) { } @@ -8682,15 +8682,15 @@ static void Main(string[] b) var edits = GetTopEdits(src1, src2); edits.VerifyEdits( - "Update [string[] args]@35 -> [string[] b]@35"); + "Update [int a]@32 -> [int b]@32"); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "string[] b", FeaturesResources.parameter)], + [Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter)], capabilities: EditAndContinueCapabilities.Baseline); edits.VerifySemantics( [ - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Main")) + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) ], capabilities: EditAndContinueCapabilities.UpdateParameters); } @@ -8701,7 +8701,7 @@ public void Method_Update_Parameter_Rename_WithBodyUpdate() var src1 = @" class C { - static void Main(string[] args) + static void F(int a) { } @@ -8709,7 +8709,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] b) + static void F(int b) { System.Console.Write(1); } @@ -8717,12 +8717,12 @@ static void Main(string[] b) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "string[] b", FeaturesResources.parameter)], + [Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter)], capabilities: EditAndContinueCapabilities.Baseline); edits.VerifySemantics( [ - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Main")) + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) ], capabilities: EditAndContinueCapabilities.UpdateParameters); } @@ -8733,7 +8733,7 @@ public void Method_Rename() var src1 = @" class C { - static void Main(string[] args) + static void F(int a) { } @@ -8741,17 +8741,17 @@ static void Main(string[] args) var src2 = @" class C { - static void EntryPoint(string[] args) + static void G(int a) { } }"; var edits = GetTopEdits(src1, src2); - var expectedEdit = @"Update [static void Main(string[] args) + var expectedEdit = @"Update [static void F(int a) { - }]@18 -> [static void EntryPoint(string[] args) + }]@18 -> [static void G(int a) { }]@18"; @@ -8760,13 +8760,13 @@ static void EntryPoint(string[] args) edits.VerifySemantics( [ - SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.Main"), deletedSymbolContainerProvider: c => c.GetMember("C")), - SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.EntryPoint")) + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.F"), deletedSymbolContainerProvider: c => c.GetMember("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.G")) ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "static void EntryPoint(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "static void G(int a)", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -8933,46 +8933,52 @@ public async Task F() [Fact] public void MethodUpdate_AsyncMethod1() { - var src1 = @" -class Test -{ - static void Main(string[] args) - { - Test f = new Test(); - string result = f.WaitAsync().Result; - } + var src1 = """ + class Test + { + static void F() + { + Test f = new Test(); + string result = f.WaitAsync().Result; + } - public async Task WaitAsync() - { - await Task.Delay(1000); - return ""Done""; - } -}"; - var src2 = @" -class Test -{ - static void Main(string[] args) - { - Test f = new Test(); - string result = f.WaitAsync().Result; - } + public async Task WaitAsync() + { + await Task.Delay(1000); + return "Done"; + } + } + """; + + var src2 = """ + class Test + { + static void F() + { + Test f = new Test(); + string result = f.WaitAsync().Result; + } + + public async Task WaitAsync() + { + await Task.Delay(1000); + return "Not Done"; + } + } + """; - public async Task WaitAsync() - { - await Task.Delay(1000); - return ""Not Done""; - } -}"; var edits = GetTopEdits(src1, src2); - var expectedEdit = @"Update [public async Task WaitAsync() - { - await Task.Delay(1000); - return ""Done""; - }]@151 -> [public async Task WaitAsync() - { - await Task.Delay(1000); - return ""Not Done""; - }]@151"; + var expectedEdit = """ + Update [public async Task WaitAsync() + { + await Task.Delay(1000); + return "Done"; + }]@133 -> [public async Task WaitAsync() + { + await Task.Delay(1000); + return "Not Done"; + }]@133 + """; edits.VerifyEdits(expectedEdit); @@ -9024,7 +9030,7 @@ public void MethodUpdate_AddReturnTypeAttribute() class Test { - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9035,24 +9041,24 @@ static void Main(string[] args) class Test { [return: Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } }"; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits(@"Update [static void Main(string[] args) + edits.VerifyEdits(@"Update [static void F() { System.Console.Write(5); }]@38 -> [[return: Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); }]@38"); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9064,7 +9070,7 @@ public void MethodUpdate_AddAttribute() class Test { - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9075,24 +9081,24 @@ static void Main(string[] args) class Test { [Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } }"; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits(@"Update [static void Main(string[] args) + edits.VerifyEdits(@"Update [static void F() { System.Console.Write(5); }]@38 -> [[Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); }]@38"); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9125,41 +9131,46 @@ public void MethodUpdate_AttributeWithTypeAtConstructor2() [Fact] public void MethodUpdate_AddAttribute_SupportedByRuntime() { - var src1 = @" -using System; + var src1 = """ + using System; -class Test -{ - static void Main(string[] args) - { - System.Console.Write(5); - } -}"; - var src2 = @" -using System; + class Test + { + static void F() + { + System.Console.Write(5); + } + } + """; + + var src2 = """ + using System; + + class Test + { + [Obsolete] + static void F() + { + System.Console.Write(5); + } + } + """; -class Test -{ - [Obsolete] - static void Main(string[] args) - { - System.Console.Write(5); - } -}"; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits(@"Update [static void Main(string[] args) - { - System.Console.Write(5); - }]@38 -> [[Obsolete] - static void Main(string[] args) - { - System.Console.Write(5); - }]@38"); + edits.VerifyEdits(""" + Update [static void F() + { + System.Console.Write(5); + }]@36 -> [[Obsolete] + static void F() + { + System.Console.Write(5); + }]@36 + """); edits.VerifySemantics( - ActiveStatementsDescription.Empty, - [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Test.Main"))], + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Test.F"))], capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); } @@ -9249,7 +9260,7 @@ public void MethodUpdate_AddAttribute2() class Test { [Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9260,7 +9271,7 @@ static void Main(string[] args) class Test { [Obsolete, STAThread] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9268,7 +9279,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9281,7 +9292,7 @@ public void MethodUpdate_AddAttribute3() class Test { [Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9293,7 +9304,7 @@ class Test { [Obsolete] [STAThread] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9301,7 +9312,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9313,7 +9324,7 @@ public void MethodUpdate_AddAttribute4() class Test { - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9324,7 +9335,7 @@ static void Main(string[] args) class Test { [Obsolete, STAThread] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9332,7 +9343,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9345,7 +9356,7 @@ public void MethodUpdate_UpdateAttribute() class Test { [Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9356,7 +9367,7 @@ static void Main(string[] args) class Test { [Obsolete("""")] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9364,7 +9375,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9377,7 +9388,7 @@ public void MethodUpdate_DeleteAttribute() class Test { [Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9387,7 +9398,7 @@ static void Main(string[] args) class Test { - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9395,7 +9406,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9408,7 +9419,7 @@ public void MethodUpdate_DeleteAttribute2() class Test { [Obsolete, STAThread] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9419,7 +9430,7 @@ static void Main(string[] args) class Test { [Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9427,7 +9438,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9441,7 +9452,7 @@ class Test { [Obsolete] [STAThread] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9452,7 +9463,7 @@ static void Main(string[] args) class Test { [Obsolete] - static void Main(string[] args) + static void F() { System.Console.Write(5); } @@ -9460,7 +9471,7 @@ static void Main(string[] args) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void Main(string[] args)", FeaturesResources.method)], + [Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "static void F()", FeaturesResources.method)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -9553,7 +9564,10 @@ static void Main() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc char[16]", FeaturesResources.method)); + [ + Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc char[16]", FeaturesResources.method), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "static void Main()", GetResource("method")) + ]); } [Fact] @@ -9562,7 +9576,7 @@ public void MethodUpdate_StackAlloc_Insert() var src1 = @" class C { - static void Main() + static void F() { int i = 10; unsafe @@ -9574,7 +9588,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { int i = 10; unsafe @@ -9596,7 +9610,7 @@ public void MethodUpdate_StackAlloc_Delete() var src1 = @" class C { - static void Main() + static void F() { int i = 10; unsafe @@ -9609,7 +9623,7 @@ static void Main() var src2 = @" class C { - static void Main() + static void F() { int i = 10; unsafe @@ -9621,7 +9635,7 @@ static void Main() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.StackAllocUpdate, "static void Main()", FeaturesResources.method)); + Diagnostic(RudeEditKind.StackAllocUpdate, "static void F()", FeaturesResources.method)); } [Fact] @@ -9784,7 +9798,7 @@ public void MethodUpdate_LabeledStatement() var src1 = @" class C { - static void Main(string[] args) + static void F() { goto Label1; @@ -9797,7 +9811,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void F() { goto Label1; @@ -21822,7 +21836,9 @@ public void TopLevelStatements_Update() edits.VerifyEdits("Update [Console.WriteLine(\"Hello\");]@19 -> [Console.WriteLine(\"Hello World\");]@19"); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, @"Console.WriteLine(""Hello World"");", GetResource("top-level code"))]); } [Fact] @@ -21847,7 +21863,9 @@ public void TopLevelStatements_InsertAndUpdate() "Insert [Console.WriteLine(\"What is your name?\");]@54", "Insert [var name = Console.ReadLine();]@96"); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, @"Console.WriteLine(""Hello World"");", GetResource("top-level code"))]); } [Fact] @@ -21888,7 +21906,9 @@ public void TopLevelStatements_Insert_ImplicitMain() edits.VerifyEdits("Insert [Console.WriteLine(\"World\");]@48"); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, @"Console.WriteLine(""Hello"");", GetResource("top-level code"))]); } [Fact] @@ -21929,7 +21949,9 @@ public void TopLevelStatements_Delete_ImplicitMain() edits.VerifyEdits("Delete [Console.WriteLine(\"World\");]@48"); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, @"Console.WriteLine(""Hello"");", GetResource("top-level code"))]); } [Fact] @@ -21941,7 +21963,10 @@ public void TopLevelStatements_StackAlloc() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc int[2]", GetResource("top-level code"))); + [ + Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc int[2]", GetResource("top-level code")), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Span = stackalloc int[2];", GetResource("top-level code")) + ]); } [Fact] @@ -21953,7 +21978,10 @@ public void TopLevelStatements_StackAllocInUnsafeBlock() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc int[3]", GetResource("top-level code"))); + [ + Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc int[3]", GetResource("top-level code")), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "unsafe { var x = stackalloc int[3]; System.Console.Write(2); }", GetResource("top-level code")) + ]); } [Fact] @@ -21965,7 +21993,10 @@ public void TopLevelStatements_StackAllocInTopBlock() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc int[3]", GetResource("top-level code"))); + [ + Diagnostic(RudeEditKind.StackAllocUpdate, "stackalloc int[3]", GetResource("top-level code")), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "{ var x = stackalloc int[3]; System.Console.Write(2); }", GetResource("top-level code")) + ]); } [Fact] @@ -21986,7 +22017,8 @@ public void TopLevelStatements_VoidToInt1() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22009,7 +22041,8 @@ public void TopLevelStatements_VoidToInt2() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22040,7 +22073,8 @@ int Goo() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22061,7 +22095,10 @@ public void TopLevelStatements_Await_Insert_First() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "await Task.Delay(200);")]); + [ + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "await Task.Delay(200);"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(200);", GetResource("top-level code")) + ]); } [Fact] @@ -22083,10 +22120,14 @@ public void TopLevelStatements_Await_Insert_Second() edits.VerifySemantics( [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), preserveLocalVariables: true)], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(100);", GetResource("top-level code"))], capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.UpdatingStateMachineMethodNotSupportedByRuntime, "await Task.Delay(100);")], + [ + Diagnostic(RudeEditKind.UpdatingStateMachineMethodNotSupportedByRuntime, "await Task.Delay(100);"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(100);", GetResource("top-level code")) + ], capabilities: EditAndContinueCapabilities.Baseline); } @@ -22109,7 +22150,9 @@ public void TopLevelStatements_Await_Delete_Last() edits.VerifySemanticDiagnostics( [ - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;") + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;"), + Diagnostic(RudeEditKind.ChangingFromAsynchronousToSynchronous, "return 1;", GetResource("top-level code")), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "return 1;", GetResource("top-level code")) ], capabilities: EditAndContinueCapabilities.Baseline); } @@ -22133,10 +22176,14 @@ public void TopLevelStatements_Await_Delete_Second() edits.VerifySemantics( [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), preserveLocalVariables: true)], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(100);", GetResource("top-level code"))], capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.UpdatingStateMachineMethodNotSupportedByRuntime, "await Task.Delay(100);")], + [ + Diagnostic(RudeEditKind.UpdatingStateMachineMethodNotSupportedByRuntime, "await Task.Delay(100);"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(100);", GetResource("top-level code")) + ], capabilities: EditAndContinueCapabilities.Baseline); } @@ -22160,7 +22207,8 @@ public void TopLevelStatements_VoidToTask() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "await Task.Delay(100);")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "await Task.Delay(100);"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(100);", GetResource("top-level code"))); } [Fact] @@ -22185,7 +22233,8 @@ public void TopLevelStatements_TaskToTaskInt() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return 1;"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(100);", GetResource("top-level code"))); } [Fact] @@ -22213,7 +22262,8 @@ Task GetInt() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return await GetInt();")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return await GetInt();"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22235,7 +22285,8 @@ public void TopLevelStatements_IntToVoid1() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22258,7 +22309,8 @@ public void TopLevelStatements_IntToVoid2() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return;")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "return;"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22289,7 +22341,13 @@ int Goo() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "int Goo()\r\n{\r\n return 1;\r\n}")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, """ + int Goo() + { + return 1; + } + """), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22326,7 +22384,8 @@ public int Goo() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22349,7 +22408,9 @@ public void TopLevelStatements_TaskToVoid() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);"), + Diagnostic(RudeEditKind.ChangingFromAsynchronousToSynchronous, "Console.Write(1);", GetResource("top-level code")), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22374,7 +22435,8 @@ public void TopLevelStatements_TaskIntToTask() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);"), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "await Task.Delay(100);", GetResource("top-level code"))); } [Fact] @@ -22402,7 +22464,9 @@ Task GetInt() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);")); + Diagnostic(RudeEditKind.ChangeImplicitMainReturnType, "Console.Write(1);"), + Diagnostic(RudeEditKind.ChangingFromAsynchronousToSynchronous, "Console.Write(1);", GetResource("top-level code")), + Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.Write(1);", GetResource("top-level code"))); } [Fact] @@ -22426,8 +22490,8 @@ public void TopLevelStatements_WithLambda_Insert() var syntaxMap = GetSyntaxMap(src1, src2); edits.VerifySemantics( - ActiveStatementsDescription.Empty, - [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), syntaxMap[0])]); + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), syntaxMap[0])], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Func a = () => { return 1; };", GetResource("top-level code"))]); } [Fact] @@ -22457,8 +22521,8 @@ public class C { } var syntaxMap = GetSyntaxMap(src1, src2); edits.VerifySemantics( - ActiveStatementsDescription.Empty, - [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), syntaxMap[0])]); + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), syntaxMap[0])], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Func a = () => { return 1; };", GetResource("top-level code"))]); } [Fact] @@ -22486,8 +22550,8 @@ public class C { } var syntaxMap = GetSyntaxMap(src1, src2); edits.VerifySemantics( - ActiveStatementsDescription.Empty, - [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), syntaxMap[0])]); + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"), syntaxMap[0])], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Func a = () => { return 1; };", GetResource("top-level code"))]); } [Fact] @@ -22513,7 +22577,9 @@ public class C { } // Since each individual statement is a separate update to a separate node, this just validates we correctly // only analyze the things once - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.WriteLine(3);", GetResource("top-level code"))]); } [Fact] @@ -22553,7 +22619,9 @@ public class B [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], [ DocumentResults(), - DocumentResults(semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))]), + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + diagnostics: [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "Console.WriteLine(2);", GetResource("top-level code"))]), ]); } @@ -22572,7 +22640,9 @@ public void TopLevelStatements_BlockReorder() edits.VerifyEdits("Reorder [{ int b; }]@14 -> @2"); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "{ int b; }", GetResource("top-level code"))]); } [Fact] @@ -22590,7 +22660,9 @@ public void TopLevelStatements_Reorder() edits.VerifyEdits("Reorder [System.Console.Write(2);]@28 -> @2"); - edits.VerifySemantics(SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Program.
$"))], + [Diagnostic(RudeEditKind.UpdateMightNotHaveAnyEffect, "System.Console.Write(2);", GetResource("top-level code"))]); } #endregion diff --git a/src/Features/CSharpTest/EditAndContinue/TrackingSpanTests.cs b/src/Features/CSharpTest/EditAndContinue/TrackingSpanTests.cs index 982acbe37f6f3..6b6124525190f 100644 --- a/src/Features/CSharpTest/EditAndContinue/TrackingSpanTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/TrackingSpanTests.cs @@ -20,7 +20,7 @@ public void MovedOutsideOfMethod1() var src1 = @" class C { - static void Main(string[] args) + static void F() { Goo(1); } @@ -28,7 +28,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void F() { } @@ -53,7 +53,7 @@ public void MovedOutsideOfMethod2() var src1 = @" class C { - static void Main(string[] args) + static void F() { Goo(1); } @@ -61,7 +61,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void F() { Goo(1); } @@ -86,7 +86,7 @@ public void MovedOutsideOfLambda1() var src1 = @" class C { - static void Main(string[] args) + static void F() { Action a = () => { Goo(1); }; } @@ -94,7 +94,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void F() { Action a = () => { }; Goo(1); @@ -113,7 +113,7 @@ public void MovedOutsideOfLambda2() var src1 = @" class C { - static void Main(string[] args) + static void F() { Action a = () => { Goo(1); }; Action b = () => { Goo(2); }; @@ -122,7 +122,7 @@ static void Main(string[] args) var src2 = @" class C { - static void Main(string[] args) + static void F() { Action a = () => { Goo(1); }; Action b = () => { Goo(2); }; diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 91e07ddb08d02..b610ea3f5b805 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -667,8 +667,7 @@ public async Task AnalyzeDocumentAsync( AnalyzeUnchangedActiveMemberBodies(diagnostics, syntacticEdits.Match, newText, oldActiveStatements, newActiveStatementSpans, newActiveStatements, newExceptionRegions, cancellationToken); Debug.Assert(newActiveStatements.All(a => a != null)); - var hasRudeEdits = diagnostics.Count > 0; - if (hasRudeEdits) + if (!diagnostics.IsEmpty()) { LogRudeEdits(diagnostics, newText, filePath); } @@ -677,19 +676,22 @@ public async Task AnalyzeDocumentAsync( Log.Write("Capabilities required by '{0}': {1}", filePath, capabilities.GrantedCapabilities); } + var hasBlockingRudeEdits = diagnostics.HasBlockingRudeEdits(); + return new DocumentAnalysisResults( newDocument.Id, filePath, newActiveStatements.MoveToImmutable(), diagnostics.ToImmutable(), syntaxError: null, - hasRudeEdits ? default : semanticEdits, - hasRudeEdits ? default : newExceptionRegions.MoveToImmutable(), - hasRudeEdits ? default : lineEdits.ToImmutable(), - hasRudeEdits ? default : capabilities.GrantedCapabilities, + hasBlockingRudeEdits ? default : semanticEdits, + hasBlockingRudeEdits ? default : newExceptionRegions.MoveToImmutable(), + hasBlockingRudeEdits ? default : lineEdits.ToImmutable(), + hasBlockingRudeEdits ? default : capabilities.GrantedCapabilities, analysisStopwatch.Elapsed, hasChanges: true, - hasSyntaxErrors: false); + hasSyntaxErrors: false, + hasBlockingRudeEdits); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { @@ -845,6 +847,9 @@ private void AnalyzeUnchangedActiveMemberBodies( { Contract.ThrowIfFalse(statementPart == -1); oldBody.FindStatementAndPartner(oldStatementSpan, newBody, out newStatement, out statementPart); + + // We should find a partner statement since we are analyzing method body that has not been changed. + // If this fails we should have calculated the new active statement during the analysis of the updated method body. Contract.ThrowIfNull(newStatement); } @@ -949,11 +954,6 @@ private void AnalyzeChangedMemberBody( var activeStatementIndices = oldMemberBody?.GetOverlappingActiveStatementIndices(oldActiveStatements)?.ToArray() ?? []; - if (isMemberReplaced && !activeStatementIndices.IsEmpty()) - { - diagnosticContext.Report(RudeEditKind.ChangingNameOrSignatureOfActiveMember, cancellationToken); - } - try { if (newMemberBody != null) @@ -1047,6 +1047,7 @@ private void AnalyzeChangedMemberBody( } var activeNodesInBody = activeNodes.Where(n => n.EnclosingLambdaBody == null).ToArray(); + var bodyHasActiveStatement = activeNodesInBody.Length != 0; var memberBodyMap = ComputeDeclarationBodyMap(oldMemberBody, newMemberBody, activeNodesInBody); var aggregateBodyMap = IncludeLambdaBodyMaps(memberBodyMap, activeNodes, ref lazyActiveOrMatchedLambdas); @@ -1054,7 +1055,7 @@ private void AnalyzeChangedMemberBody( var oldStateMachineInfo = oldMemberBody?.GetStateMachineInfo() ?? StateMachineInfo.None; var newStateMachineInfo = newMemberBody?.GetStateMachineInfo() ?? StateMachineInfo.None; - ReportStateMachineBodyUpdateRudeEdits(diagnosticContext, memberBodyMap, oldStateMachineInfo, newStateMachineInfo, hasActiveStatement: activeNodesInBody.Length != 0, cancellationToken); + ReportStateMachineBodyUpdateRudeEdits(diagnosticContext, memberBodyMap, oldStateMachineInfo, newStateMachineInfo, bodyHasActiveStatement, cancellationToken); ReportMemberOrLambdaBodyUpdateRudeEdits( diagnosticContext, @@ -1086,9 +1087,24 @@ private void AnalyzeChangedMemberBody( capabilities, diagnostics, out var newBodyHasLambdas, + out var hasLambdaBodyUpdate, out var runtimeRudeEdits, cancellationToken); + // Report rude edit only if the body itself has active statement, not when only a lambda in the body has one. + if (isMemberReplaced && bodyHasActiveStatement) + { + diagnosticContext.Report(RudeEditKind.ChangingNameOrSignatureOfActiveMember, cancellationToken); + } + + // Updating entry point that doesn't have an active statement will most likely have no effect, unless the update is in a lambda body. + // In theory, the code could be updating the entry point while executing static constructor of module initializer, + // but those cases are rare. + if (!hasLambdaBodyUpdate && !bodyHasActiveStatement && oldMember == oldCompilation.GetEntryPoint(cancellationToken)) + { + diagnosticContext.Report(RudeEditKind.UpdateMightNotHaveAnyEffect, cancellationToken); + } + // We need to provide syntax map to the compiler if // 1) The new member has a active statement // The values of local variables declared or synthesized in the method have to be preserved. @@ -3047,13 +3063,16 @@ void ReportDeletedMemberActiveStatementsRudeEdits() var replaceMember = IsMemberOrDelegate(oldSymbol) && IsMemberOrDelegateReplaced(oldSymbol, newSymbol); + var signatureRudeEdit = RudeEditKind.None; if (replaceMember && oldSymbol.Name == newSymbol.Name) { - var signatureRudeEdit = GetSignatureChangeRudeEdit(oldSymbol, newSymbol, capabilities); + signatureRudeEdit = GetSignatureChangeRudeEdit(oldSymbol, newSymbol, capabilities); if (signatureRudeEdit != RudeEditKind.None) { diagnosticContext.Report(signatureRudeEdit, cancellationToken); - continue; + + // Note: Continue analysis - we need to analyze the changed body and + // update any active statements to avoid contract failures. } } @@ -3092,6 +3111,12 @@ void ReportDeletedMemberActiveStatementsRudeEdits() } } + // Skip further symbol update analysis if the member signature change is unsupported: + if (signatureRudeEdit != RudeEditKind.None) + { + continue; + } + AnalyzeSymbolUpdate(diagnosticContext, capabilities, semanticEdits, out var hasAttributeChange, cancellationToken); if (newSymbol is IParameterSymbol or ITypeParameterSymbol) @@ -5396,10 +5421,12 @@ private void ReportLambdaAndClosureRudeEdits( EditAndContinueCapabilitiesGrantor capabilities, ArrayBuilder diagnostics, out bool syntaxMapRequired, + out bool hasLambdaBodyUpdate, out Func? runtimeRudeEdits, CancellationToken cancellationToken) { syntaxMapRequired = false; + hasLambdaBodyUpdate = false; runtimeRudeEdits = null; if (activeOrMatchedLambdas != null) @@ -5443,6 +5470,8 @@ private void ReportLambdaAndClosureRudeEdits( if (!oldLambdaBody.IsSyntaxEquivalentTo(newLambdaBody)) { + hasLambdaBodyUpdate = true; + ReportMemberOrLambdaBodyUpdateRudeEdits( diagnosticContext, oldModel.Compilation, diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 62ba99219f3af..e6aa59659e9ad 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -493,15 +493,15 @@ CommittedSolution.DocumentState.Indeterminate or } } - if (analysis.RudeEditErrors.IsEmpty) + if (analysis.RudeEdits.IsEmpty) { return []; } - EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, project.State.Attributes.TelemetryId); + EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEdits, project.State.Attributes.TelemetryId); var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - return analysis.RudeEditErrors.SelectAsArray((e, t) => e.ToDiagnostic(t), tree); + return analysis.RudeEdits.SelectAsArray((e, t) => e.ToDiagnostic(t), tree); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { diff --git a/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs b/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs index 29b2995679e37..ff62953f3d4f8 100644 --- a/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs +++ b/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs @@ -2,13 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Contracts.EditAndContinue; -using System; namespace Microsoft.CodeAnalysis.EditAndContinue; @@ -32,9 +31,9 @@ internal sealed class DocumentAnalysisResults /// /// Diagnostics for rude edits in the document, or empty if the document is unchanged or has syntax errors. - /// If the compilation has semantic errors only syntactic rude edits are calculated. + /// Includes errors, should block the update and warnings, which should not. /// - public ImmutableArray RudeEditErrors { get; } + public ImmutableArray RudeEdits { get; } /// /// The first syntax error, or null if the document does not have syntax errors reported by the compiler. @@ -100,6 +99,11 @@ internal sealed class DocumentAnalysisResults /// public bool HasChanges { get; } + /// + /// True if any of the are blocking. + /// + public bool HasBlockingRudeEdits { get; } + public DocumentAnalysisResults( DocumentId documentId, string filePath, @@ -112,9 +116,11 @@ public DocumentAnalysisResults( EditAndContinueCapabilities requiredCapabilities, TimeSpan elapsedTime, bool hasChanges, - bool hasSyntaxErrors) + bool hasSyntaxErrors, + bool hasBlockingRudeEdits) { Debug.Assert(!rudeEdits.IsDefault); + Debug.Assert(hasBlockingRudeEdits == (!rudeEdits.IsDefault && rudeEdits.HasBlockingRudeEdits())); if (hasSyntaxErrors || !hasChanges) { @@ -122,7 +128,7 @@ public DocumentAnalysisResults( Debug.Assert(semanticEditsOpt.IsDefault); Debug.Assert(exceptionRegionsOpt.IsDefault); Debug.Assert(lineEditsOpt.IsDefault); - Debug.Assert(syntaxError != null || !rudeEdits.IsEmpty || !hasChanges); + Debug.Assert(syntaxError != null || hasBlockingRudeEdits || !hasChanges); Debug.Assert(requiredCapabilities == EditAndContinueCapabilities.None); } else @@ -130,7 +136,7 @@ public DocumentAnalysisResults( Debug.Assert(!activeStatementsOpt.IsDefault); Debug.Assert(syntaxError == null); - if (!rudeEdits.IsEmpty) + if (hasBlockingRudeEdits) { Debug.Assert(semanticEditsOpt.IsDefault); Debug.Assert(exceptionRegionsOpt.IsDefault); @@ -157,7 +163,7 @@ public DocumentAnalysisResults( DocumentId = documentId; FilePath = filePath; - RudeEditErrors = rudeEdits; + RudeEdits = rudeEdits; SyntaxError = syntaxError; SemanticEdits = semanticEditsOpt; ActiveStatements = activeStatementsOpt; @@ -167,10 +173,11 @@ public DocumentAnalysisResults( ElapsedTime = elapsedTime; HasSyntaxErrors = hasSyntaxErrors; HasChanges = hasChanges; + HasBlockingRudeEdits = hasBlockingRudeEdits; } public bool HasChangesAndErrors - => HasChanges && (HasSyntaxErrors || !RudeEditErrors.IsEmpty); + => HasChanges && (HasSyntaxErrors || HasBlockingRudeEdits); public bool HasChangesAndSyntaxErrors => HasChanges && HasSyntaxErrors; @@ -194,7 +201,8 @@ public static DocumentAnalysisResults SyntaxErrors(DocumentId documentId, string EditAndContinueCapabilities.None, elapsedTime, hasChanges, - hasSyntaxErrors: true); + hasSyntaxErrors: true, + hasBlockingRudeEdits: !rudeEdits.IsEmpty); /// /// Report unchanged document results. @@ -212,5 +220,6 @@ public static DocumentAnalysisResults Unchanged(DocumentId documentId, string fi EditAndContinueCapabilities.None, elapsedTime, hasChanges: false, - hasSyntaxErrors: false); + hasSyntaxErrors: false, + hasBlockingRudeEdits: false); } diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index f63f39b3cee2b..0a4f36236f738 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -54,8 +54,8 @@ void add(int index, int id, string resourceName, LocalizableResourceString title customTags: DiagnosticCustomTags.EditAndContinue); } - void AddRudeEdit(RudeEditKind kind, string resourceName) - => add(GetDescriptorIndex(kind), (int)kind, resourceName, s_rudeEditLocString, DiagnosticSeverity.Error); + void AddRudeEdit(RudeEditKind kind, string resourceName, DiagnosticSeverity severity = DiagnosticSeverity.Error) + => add(GetDescriptorIndex(kind), (int)kind, resourceName, s_rudeEditLocString, severity); void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, DiagnosticSeverity severity = DiagnosticSeverity.Error) => add(GetDescriptorIndex(code), GeneralDiagnosticBaseId + (int)code, resourceName, s_encLocString, severity); @@ -147,6 +147,7 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.NotCapturingPrimaryConstructorParameter, nameof(FeaturesResources.Ceasing_to_capture_primary_constructor_parameter_0_of_1_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.ChangingAttribute, nameof(FeaturesResources.Changing_attribute_0_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.ChangingNameOrSignatureOfActiveMember, nameof(FeaturesResources.Changing_name_or_signature_of_0_that_contains_an_active_statement_requires_restarting_the_application)); + AddRudeEdit(RudeEditKind.UpdateMightNotHaveAnyEffect, nameof(FeaturesResources.Changing_0_might_not_have_any_effect_until_the_application_is_restarted), DiagnosticSeverity.Warning); // VB specific AddRudeEdit(RudeEditKind.HandlesClauseUpdate, nameof(FeaturesResources.Updating_the_Handles_clause_of_0_requires_restarting_the_application)); diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 51057d7b7bcef..51f77259f4dc9 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -570,7 +570,7 @@ private static ProjectAnalysisSummary GetProjectAnalysisSummary(ImmutableArray EmitSolutionUpdateAsync(Solution solution } else if (projectSummary == ProjectAnalysisSummary.RudeEdits) { - foreach (var analysis in changedDocumentAnalyses) + isBlocked = true; + } + + // Report rude edit diagnostics - these can be blocking (errors) or non-blocking (warnings): + foreach (var analysis in changedDocumentAnalyses) + { + if (!analysis.RudeEdits.IsEmpty) { - if (analysis.RudeEditErrors.Length > 0) - { - documentsWithRudeEdits.Add((analysis.DocumentId, analysis.RudeEditErrors)); - Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, newProject.State.Attributes.TelemetryId); - } + documentsWithRudeEdits.Add((analysis.DocumentId, analysis.RudeEdits)); + Telemetry.LogRudeEditDiagnostics(analysis.RudeEdits, newProject.State.Attributes.TelemetryId); } - - isBlocked = true; } if (isModuleEncBlocked || projectSummary != ProjectAnalysisSummary.ValidChanges) diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs index bc02952a2a205..fa44813915315 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs @@ -2,7 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; +using System.Linq; +using System.Collections.Generic; using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Text; @@ -42,3 +43,15 @@ internal Diagnostic ToDiagnostic(SyntaxTree tree) return Diagnostic.Create(descriptor, tree.GetLocation(Span), Arguments); } } + +internal static class RudeEditExtensions +{ + internal static DiagnosticSeverity GetSeverity(this RudeEditKind kind) + => EditAndContinueDiagnosticDescriptors.GetDescriptor(kind).DefaultSeverity; + + internal static bool IsBlocking(this RudeEditKind kind) + => kind.GetSeverity() == DiagnosticSeverity.Error; + + public static bool HasBlockingRudeEdits(this IEnumerable diagnostics) + => diagnostics.Any(static e => e.Kind.IsBlocking()); +} diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs index e7aeb09fff695..b7ebc68e84176 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -142,4 +142,5 @@ internal enum RudeEditKind : ushort NotCapturingPrimaryConstructorParameter = 115, ChangingAttribute = 116, ChangingNameOrSignatureOfActiveMember = 117, + UpdateMightNotHaveAnyEffect = 118, } diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index 89a689d9c110b..2225e8f58b5b9 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -378,6 +378,9 @@ Changing attribute '{0}' requires restarting the application. + + Changing '{0}' might not have any effect until the application is restarted. + Capturing primary constructor parameter '{0}' that hasn't been capture before requires restarting the application. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 23dc84fb88357..662bcde363b2d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -405,6 +405,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Změna {0} z asynchronního na synchronní vyžaduje restartování aplikace. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Změna {0} na {1} vyžaduje restartování aplikace, protože mění tvar stavového stroje. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 45a6398c4cf84..d05a219198d42 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -405,6 +405,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Das Ändern von {0} von asynchron zu synchron erfordert einen Neustart der Anwendung. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Das Ändern von „{0}“ zu „{1}“ erfordert einen Neustart der Anwendung, da dadurch die Form des Zustandsautomaten geändert wird. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 71531aa60b319..2c7434f428c5b 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -405,6 +405,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Para cambiar {0} de asíncrona a sincrónica, es necesario reiniciar la aplicación. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Para cambiar "{0}" a "{1}" se requiere reiniciar la aplicación porque cambia la forma de la máquina de estados. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index cd2b70bc32a42..6a248c207bda6 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -405,6 +405,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Le passage de {0} d'asynchrone à synchrone requiert le redémarrage de l'application. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Le passage de « {0} » en « {1} » nécessite le redémarrage de l’application, car elle modifie la forme de la machine à états. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 4bb62acc56dbf..a65093aaab2a0 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -405,6 +405,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Se si modifica {0} da asincrono a sincrono, è necessario riavviare l'applicazione. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Se si modifica '{0}' in '{1}', è necessario il riavvio dell'applicazione perché l'operazione comporta la modifica della forma della macchina a stati. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 614bf87b47d2b..29bffc47fc8ce 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma {0} を非同期から同期に変更するには、アプリケーションを再起動する必要があります。 + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. '{0}' を '{1}' に変更すると、ステート マシンの形状が変更されるため、アプリケーションを再起動する必要があります。 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 375f752f611ab..83e06bf77cd6e 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 비동기에서 동기로 {0}을(를) 변경하려면 애플리케이션을 다시 시작해야 합니다. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. '{0}'을(를) '{1}'(으)로 변경하려면 상태 시스템의 모양을 변경하므로 애플리케이션을 다시 시작해야 합니다. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index b0ef2b9c0c2c7..b73679e0be2a4 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -405,6 +405,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Zmiana elementu {0} z asynchronicznego na synchroniczny wymaga ponownego uruchomienia aplikacji. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Zmiana elementu „{0}” na „{1}” wymaga ponownego uruchomienia aplikacji, ponieważ zmienia on kształt automatu stanów. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 2a0f5278d86fd..c17ca786a735b 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -405,6 +405,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Alterar {0} de assíncrono para síncrono requer a reinicialização do aplicativo. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Alterar '{0}' para '{1}' requer a reinicialização do aplicativo porque altera a forma da máquina de estado. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 5a5d439d0e939..3e2fc03737a78 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Для изменения {0} с асинхронного на синхронный требуется перезапустить приложение. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. Для изменения "{0}" на "{1}" требуется перезапустить приложение, так как при этом изменяется форма конечного автомата. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index c6ed18ace5570..f3bd3471457d6 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -405,6 +405,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be {0} öğesinin zaman uyumsuzdan zaman uyumluya değiştirilmesi, uygulamanın yeniden başlatılmasını gerektirir. + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. '{0}' öğesinin '{1}' olarak değiştirilmesi, durum makinesinin şeklini değiştirdiği için uygulamanın yeniden başlatılmasını gerektirir. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index 9853290a52d4e..a1599d83bdfbe 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 将 {0} 从异步更改为同步需要重启应用程序。 + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. 将“{0}”更改为“{1}”需要重启应用程序,因为它会更改状态机的形状。 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 824278aac6021..a00fe366736a0 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 將 {0} 從非同步變更為同步需要重新啟動應用程式。 + + Changing '{0}' might not have any effect until the application is restarted. + Changing '{0}' might not have any effect until the application is restarted. + + Changing '{0}' to '{1}' requires restarting the application because it changes the shape of the state machine. 將 '{0}' 變更為 '{1}' 需要重新啟動應用程式,因為它會變更狀態機器的圖形。 diff --git a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index df6d379295bcf..1e7e943143e3a 100644 --- a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -167,7 +167,7 @@ internal void VerifySemantics( actualRequiredCapabilities |= result.RequiredCapabilities; hasValidChanges &= result.HasSignificantValidChanges; - VerifyDiagnostics(expectedResult.Diagnostics, result.RudeEditErrors.ToDescription(newText, includeFirstLineInDiagnostics), assertMessagePrefix); + VerifyDiagnostics(expectedResult.Diagnostics, result.RudeEdits.ToDescription(newText, includeFirstLineInDiagnostics), assertMessagePrefix); if (!expectedResult.SemanticEdits.IsDefault) { @@ -193,7 +193,7 @@ internal void VerifySemantics( else { // exception regions not available in presence of rude edits: - Assert.Equal(!expectedResult.Diagnostics.IsEmpty, result.ExceptionRegions.IsDefault); + Assert.Equal(expectedResult.Diagnostics.Any(d => d.RudeEditKind.IsBlocking()), result.ExceptionRegions.IsDefault); VerifyDocumentActiveStatementsAndExceptionRegions( expectedResult.ActiveStatements, @@ -203,7 +203,7 @@ internal void VerifySemantics( result.ExceptionRegions); } - if (!result.RudeEditErrors.IsEmpty) + if (result.HasBlockingRudeEdits) { Assert.True(result.LineEdits.IsDefault); Assert.True(expectedResult.LineEdits.IsDefaultOrEmpty); diff --git a/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs b/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs index fb3f122ab925e..e2b1c7288c47c 100644 --- a/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs +++ b/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs @@ -11,14 +11,14 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { internal readonly struct RudeEditDiagnosticDescription : IEquatable { - private readonly RudeEditKind _rudeEditKind; + public readonly RudeEditKind RudeEditKind; private readonly string? _firstLine; private readonly string? _squiggle; private readonly string[] _arguments; internal RudeEditDiagnosticDescription(RudeEditKind rudeEditKind, string? squiggle, string[] arguments, string? firstLine) { - _rudeEditKind = rudeEditKind; + RudeEditKind = rudeEditKind; _squiggle = squiggle; _firstLine = firstLine; _arguments = arguments ?? []; @@ -27,11 +27,11 @@ internal RudeEditDiagnosticDescription(RudeEditKind rudeEditKind, string? squigg public string? FirstLine => _firstLine; public RudeEditDiagnosticDescription WithFirstLine(string value) - => new(_rudeEditKind, _squiggle, _arguments, value.Trim()); + => new(RudeEditKind, _squiggle, _arguments, value.Trim()); public bool Equals(RudeEditDiagnosticDescription other) { - return _rudeEditKind == other._rudeEditKind + return RudeEditKind == other.RudeEditKind && _squiggle == other._squiggle && (_firstLine == other._firstLine || _firstLine == null || other._firstLine == null) && _arguments.SequenceEqual(other._arguments, object.Equals); @@ -44,7 +44,7 @@ public override int GetHashCode() { return Hash.Combine(_squiggle, - Hash.CombineValues(_arguments, (int)_rudeEditKind)); + Hash.CombineValues(_arguments, (int)RudeEditKind)); } public override string ToString() @@ -52,18 +52,21 @@ public override string ToString() public string ToString(Func? tryGetResource) { - var arguments = - new[] { (_squiggle != null) ? "\"" + _squiggle.Replace("\r\n", "\\r\\n") + "\"" : "null" } - .Concat(_arguments.Select(a => tryGetResource?.Invoke(a) is { } ? $"GetResource(\"{a}\")" : $"\"{a}\"")); + var formattedSquiggle = _squiggle is null + ? "null" + : _squiggle.IndexOfAny(['\r', '\n']) >= 0 + ? $"\"\"\"{Environment.NewLine}{_squiggle}{Environment.NewLine}\"\"\"" + : $"\"{_squiggle}\""; + string[] arguments = [formattedSquiggle, .. _arguments.Select(a => tryGetResource?.Invoke(a) is { } ? $"GetResource(\"{a}\")" : $"\"{a}\"")]; var withLine = (_firstLine != null) ? $".WithFirstLine(\"{_firstLine}\")" : null; - return $"Diagnostic(RudeEditKind.{_rudeEditKind}, {string.Join(", ", arguments)}){withLine}"; + return $"Diagnostic(RudeEditKind.{RudeEditKind}, {string.Join(", ", arguments)}){withLine}"; } internal void VerifyMessageFormat() { - var descriptior = EditAndContinueDiagnosticDescriptors.GetDescriptor(_rudeEditKind); + var descriptior = EditAndContinueDiagnosticDescriptors.GetDescriptor(RudeEditKind); var format = descriptior.MessageFormat.ToString(); try { @@ -71,7 +74,7 @@ internal void VerifyMessageFormat() } catch (FormatException) { - Assert.True(false, $"Message format string was not supplied enough arguments.\nRudeEditKind: {_rudeEditKind}\nArguments supplied: {_arguments.Length}\nFormat string: {format}"); + Assert.True(false, $"Message format string was not supplied enough arguments.\nRudeEditKind: {RudeEditKind}\nArguments supplied: {_arguments.Length}\nFormat string: {format}"); } } } diff --git a/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb b/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb index e00b01e5dd200..9cec27573c6f9 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb @@ -2,10 +2,9 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis.Contracts.EditAndContinue Imports Microsoft.CodeAnalysis.EditAndContinue Imports Microsoft.CodeAnalysis.Emit -Imports Microsoft.CodeAnalysis.Contracts.EditAndContinue -Imports Microsoft.CodeAnalysis.EditAndContinue.UnitTests Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests @@ -2403,9 +2402,9 @@ Class C End Class " - Dim src2 = " + Dim src2 = " Class C - Dim a,b(1),c As Integer + Dim a,b(1),c As Integer Sub New End Sub @@ -4708,7 +4707,7 @@ End Class Public Sub Lambdas_ActiveStatementRemoved4() Dim src1 = " Class C - Shared Sub Main() + Shared Sub F() Dim f = Function(a) z(2) @@ -4720,7 +4719,7 @@ Class C End Class" Dim src2 = " Class C - Shared Sub Main() + Shared Sub F() End Sub End Class " @@ -4728,8 +4727,8 @@ End Class Dim active = GetActiveStatements(src1, src2) edits.VerifySemanticDiagnostics(active, - Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "Shared Sub Main()", VBFeaturesResources.Lambda), - Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "Shared Sub Main()", VBFeaturesResources.Lambda)) + Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "Shared Sub F()", VBFeaturesResources.Lambda), + Diagnostic(RudeEditKind.ActiveStatementLambdaRemoved, "Shared Sub F()", VBFeaturesResources.Lambda)) End Sub diff --git a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb index b1dd74eafa024..d64699c5aa775 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb @@ -4815,7 +4815,7 @@ End Structure Public Sub MethodUpdate1() Dim src1 As String = "Class C" & vbLf & - "Shared Sub Main()" & vbLf & + "Shared Sub F()" & vbLf & "Dim a As Integer = 1 : " & "Dim b As Integer = 2 : " & "Console.ReadLine(a + b) : " & @@ -4824,7 +4824,7 @@ End Structure Dim src2 As String = "Class C" & vbLf & - "Shared Sub Main()" & vbLf & + "Shared Sub F()" & vbLf & "Dim a As Integer = 2 : " & "Dim b As Integer = 1 : " & "Console.ReadLine(a + b) : " & @@ -4833,13 +4833,13 @@ End Structure Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Shared Sub Main()" & vbLf & "Dim a As Integer = 1 : Dim b As Integer = 2 : Console.ReadLine(a + b) : End Sub]@8 -> " & - "[Shared Sub Main()" & vbLf & "Dim a As Integer = 2 : Dim b As Integer = 1 : Console.ReadLine(a + b) : End Sub]@8") + "Update [Shared Sub F()" & vbLf & "Dim a As Integer = 1 : Dim b As Integer = 2 : Console.ReadLine(a + b) : End Sub]@8 -> " & + "[Shared Sub F()" & vbLf & "Dim a As Integer = 2 : Dim b As Integer = 1 : Console.ReadLine(a + b) : End Sub]@8") edits.VerifySemanticDiagnostics() edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"), preserveLocalVariables:=False)}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"), preserveLocalVariables:=False)}) End Sub @@ -5594,99 +5594,99 @@ End Interface Public Sub MethodUpdate_LocalWithCollectionInitializer() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim numbers() = {1, 2, 3} : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim numbers() = {1, 2, 3, 4} : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim numbers() = {1, 2, 3} : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim numbers() = {1, 2, 3, 4} : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Main()" & vbLf & "Dim numbers() = {1, 2, 3} : End Sub]@12 -> [Sub Main()" & vbLf & "Dim numbers() = {1, 2, 3, 4} : End Sub]@12") + "Update [Sub F()" & vbLf & "Dim numbers() = {1, 2, 3} : End Sub]@12 -> [Sub F()" & vbLf & "Dim numbers() = {1, 2, 3, 4} : End Sub]@12") edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"))}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub Public Sub MethodUpdate_CatchVariableType() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Try : Catch a As Exception : End Try : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Try : Catch a As IOException : End Try : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Try : Catch a As Exception : End Try : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Try : Catch a As IOException : End Try : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Main()" & vbLf & "Try : Catch a As Exception : End Try : End Sub]@12 -> " & - "[Sub Main()" & vbLf & "Try : Catch a As IOException : End Try : End Sub]@12") + "Update [Sub F()" & vbLf & "Try : Catch a As Exception : End Try : End Sub]@12 -> " & + "[Sub F()" & vbLf & "Try : Catch a As IOException : End Try : End Sub]@12") edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"))}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub Public Sub MethodUpdate_CatchVariableName() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Try : Catch a As Exception : End Try : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Try : Catch b As Exception : End Try : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Try : Catch a As Exception : End Try : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Try : Catch b As Exception : End Try : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Main()" & vbLf & "Try : Catch a As Exception : End Try : End Sub]@12 -> " & - "[Sub Main()" & vbLf & "Try : Catch b As Exception : End Try : End Sub]@12") + "Update [Sub F()" & vbLf & "Try : Catch a As Exception : End Try : End Sub]@12 -> " & + "[Sub F()" & vbLf & "Try : Catch b As Exception : End Try : End Sub]@12") edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"))}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub Public Sub MethodUpdate_LocalVariableType1() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a As Exception : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a As IOException : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a As Exception : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a As IOException : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Main()" & vbLf & "Dim a As Exception : End Sub]@12 -> " & - "[Sub Main()" & vbLf & "Dim a As IOException : End Sub]@12") + "Update [Sub F()" & vbLf & "Dim a As Exception : End Sub]@12 -> " & + "[Sub F()" & vbLf & "Dim a As IOException : End Sub]@12") edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"))}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub Public Sub MethodUpdate_LocalVariableType2() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a As New Exception : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a As New IOException : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a As New Exception : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a As New IOException : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Main()" & vbLf & "Dim a As New Exception : End Sub]@12 -> " & - "[Sub Main()" & vbLf & "Dim a As New IOException : End Sub]@12") + "Update [Sub F()" & vbLf & "Dim a As New Exception : End Sub]@12 -> " & + "[Sub F()" & vbLf & "Dim a As New IOException : End Sub]@12") edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"))}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub Public Sub MethodUpdate_LocalVariableName1() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a As Exception : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim b As Exception : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a As Exception : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim b As Exception : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Main()" & vbLf & "Dim a As Exception : End Sub]@12 -> " & - "[Sub Main()" & vbLf & "Dim b As Exception : End Sub]@12") + "Update [Sub F()" & vbLf & "Dim a As Exception : End Sub]@12 -> " & + "[Sub F()" & vbLf & "Dim b As Exception : End Sub]@12") edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"))}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub Public Sub MethodUpdate_LocalVariableName2() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a,b As Exception : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a,c As Exception : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a,b As Exception : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a,c As Exception : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Main()" & vbLf & "Dim a,b As Exception : End Sub]@12 -> " & - "[Sub Main()" & vbLf & "Dim a,c As Exception : End Sub]@12") + "Update [Sub F()" & vbLf & "Dim a,b As Exception : End Sub]@12 -> " & + "[Sub F()" & vbLf & "Dim a,c As Exception : End Sub]@12") edits.VerifySemantics(ActiveStatementsDescription.Empty, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Main"))}) + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub @@ -5828,8 +5828,8 @@ End Interface Public Sub MethodUpdate_StaticLocal() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Static a = 0 : a = 1 : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Static a = 0 : a = 2 : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Static a = 0 : a = 1 : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Static a = 0 : a = 2 : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( @@ -5838,8 +5838,8 @@ End Interface Public Sub MethodUpdate_StaticLocal_Insert() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a = 0 : a = 1 : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Static a = 0 : a = 2 : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a = 0 : a = 1 : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Static a = 0 : a = 2 : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( @@ -5848,12 +5848,12 @@ End Interface Public Sub MethodUpdate_StaticLocal_Delete() - Dim src1 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Static a = 0 : a = 1 : End Sub : End Module" - Dim src2 = "Module C : " & vbLf & "Sub Main()" & vbLf & "Dim a = 0 : a = 2 : End Sub : End Module" + Dim src1 = "Module C : " & vbLf & "Sub F()" & vbLf & "Static a = 0 : a = 1 : End Sub : End Module" + Dim src2 = "Module C : " & vbLf & "Sub F()" & vbLf & "Dim a = 0 : a = 2 : End Sub : End Module" Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.UpdateStaticLocal, "Sub Main()", GetResource("method"))) + Diagnostic(RudeEditKind.UpdateStaticLocal, "Sub F()", GetResource("method"))) End Sub diff --git a/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb b/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb index e6af37ce7b3a3..77275be19363d 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb @@ -689,7 +689,7 @@ End Class Next Assert.True(result.IsSingle()) - Assert.Empty(result.Single().RudeEditErrors) + Assert.Empty(result.Single().RudeEdits) End Using End Function End Class