diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs index 6ce641947edec..422c7a34e5536 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs @@ -62,26 +62,26 @@ static void Main(string[] args) public void Method_Body_Delete1() { var src1 = "class C { int M() { return 1; } }"; - var src2 = "class C { int M(); }"; + var src2 = "class C { extern int M(); }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.MethodBodyDelete, "int M()", FeaturesResources.method)); + Diagnostic(RudeEditKind.ModifiersUpdate, "extern int M()", FeaturesResources.method)); } [Fact] public void Method_ExpressionBody_Delete1() { var src1 = "class C { int M() => 1; }"; - var src2 = "class C { int M(); }"; + var src2 = "class C { extern int M(); }"; var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.MethodBodyDelete, "int M()", FeaturesResources.method)); + Diagnostic(RudeEditKind.ModifiersUpdate, "extern int M()", FeaturesResources.method)); } [Fact] @@ -232,7 +232,7 @@ static void Swap(T lhs, T rhs) where T : System.IComparable var active = GetActiveStatements(src1, src2); edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.GenericMethodUpdate, "static void Swap(T lhs, T rhs)", FeaturesResources.method)); + Diagnostic(RudeEditKind.GenericMethodUpdate, "static void Swap(T lhs, T rhs)")); } // Async @@ -711,7 +711,7 @@ public T this[int i] var active = GetActiveStatements(src1, src2); edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.GenericTypeUpdate, "set", CSharpFeaturesResources.indexer_setter)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "set")); } [WorkItem(750244, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/750244")] @@ -765,7 +765,7 @@ public T this[int i] // Rude edits of active statements (AS:1) are not reported if the top-level edits are rude. edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.GenericTypeUpdate, "set", CSharpFeaturesResources.indexer_setter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "set"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "stringCollection[1] = \"hello\";")); } @@ -816,7 +816,7 @@ public T this[int i] var active = GetActiveStatements(src1, src2); edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.GenericTypeUpdate, "get", CSharpFeaturesResources.indexer_getter)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "get")); } [WorkItem(750244, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/750244")] @@ -868,7 +868,7 @@ public T this[int i] // Rude edits of active statements (AS:1) are not reported if the top-level edits are rude. edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.GenericTypeUpdate, "get", CSharpFeaturesResources.indexer_getter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "get"), Diagnostic(RudeEditKind.ActiveStatementUpdate, "Console.WriteLine(stringCollection[1]);")); } @@ -919,7 +919,7 @@ public T this[int i] var active = GetActiveStatements(src1, src2); edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.GenericTypeUpdate, "set", CSharpFeaturesResources.indexer_setter)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "set")); } [Fact] @@ -1018,7 +1018,7 @@ public T this[int i] var active = GetActiveStatements(src1, src2); edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.GenericTypeUpdate, "get", CSharpFeaturesResources.indexer_getter)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "get")); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs index eeb0066db42c8..d0dd3d4d2180e 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs @@ -1496,8 +1496,7 @@ class C var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); - edits.VerifyRudeDiagnostics(active, - Diagnostic(RudeEditKind.MethodBodyAdd, "get", CSharpFeaturesResources.property_getter)); + edits.VerifyRudeDiagnostics(active); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs index 739938b3d8fd4..52c058b281df5 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs @@ -52,30 +52,30 @@ internal static void VerifyRudeDiagnostics( internal static void VerifyLineEdits( this EditScript editScript, - IEnumerable expectedLineEdits, - IEnumerable expectedNodeUpdates, - params RudeEditDiagnosticDescription[] expectedDiagnostics) + SourceLineUpdate[] lineEdits, + SemanticEditDescription[]? semanticEdits = null, + RudeEditDiagnosticDescription[]? diagnostics = null) { - Assert.NotEmpty(expectedLineEdits); + Assert.NotEmpty(lineEdits); VerifyLineEdits( editScript, - new[] { new SequencePointUpdates(editScript.Match.OldRoot.SyntaxTree.FilePath, expectedLineEdits.ToImmutableArray()) }, - expectedNodeUpdates, - expectedDiagnostics); + new[] { new SequencePointUpdates(editScript.Match.OldRoot.SyntaxTree.FilePath, lineEdits.ToImmutableArray()) }, + semanticEdits, + diagnostics); } internal static void VerifyLineEdits( this EditScript editScript, - IEnumerable expectedLineEdits, - IEnumerable expectedNodeUpdates, - params RudeEditDiagnosticDescription[] expectedDiagnostics) + SequencePointUpdates[] lineEdits, + SemanticEditDescription[]? semanticEdits = null, + RudeEditDiagnosticDescription[]? diagnostics = null) { new CSharpEditAndContinueTestHelpers().VerifyLineEdits( editScript, - expectedLineEdits, - expectedNodeUpdates, - expectedDiagnostics); + lineEdits, + semanticEdits, + diagnostics); } internal static void VerifySemanticDiagnostics( diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs index 794c9d3f61a9e..fd25bce6cc13c 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs @@ -64,18 +64,18 @@ internal static DocumentAnalysisResultsDescription DocumentResults( ActiveStatementsDescription? activeStatements = null, SemanticEditDescription[]? semanticEdits = null, RudeEditDiagnosticDescription[]? diagnostics = null) - => new(activeStatements, semanticEdits, diagnostics); + => new(activeStatements, semanticEdits, lineEdits: null, diagnostics); - private static SyntaxTree ParseSource(string markedSource) + private static SyntaxTree ParseSource(string markedSource, int documentIndex = 0) => SyntaxFactory.ParseSyntaxTree( ActiveStatementsDescription.ClearTags(markedSource), CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview), - path: "test.cs"); + path: documentIndex.ToString()); - internal static EditScript GetTopEdits(string src1, string src2) + internal static EditScript GetTopEdits(string src1, string src2, int documentIndex = 0) { - var tree1 = ParseSource(src1); - var tree2 = ParseSource(src2); + var tree1 = ParseSource(src1, documentIndex); + var tree2 = ParseSource(src2, documentIndex); tree1.GetDiagnostics().Verify(); tree2.GetDiagnostics().Verify(); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs index 1f9085b4ae8d2..2ff87944d57d0 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Immutable; +using System.Linq; using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; @@ -59,8 +60,7 @@ static void Goo() new SourceLineUpdate(4, 9), AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(7), new SourceLineUpdate(9, 4) - }, - Array.Empty()); + }); } [Fact] @@ -112,8 +112,7 @@ static int Bar() AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(8), new SourceLineUpdate(10, 4), AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(13), - }, - Array.Empty()); + }); } [Fact] @@ -141,7 +140,7 @@ static void Bar() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - Array.Empty()); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Bar")) }); } [Fact] @@ -172,7 +171,7 @@ void F() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new[] { "void F()" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) }); } [Fact] @@ -199,8 +198,7 @@ static void Bar() }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(4, 6) }, - Array.Empty()); + new[] { new SourceLineUpdate(4, 6) }); } [Fact] @@ -226,8 +224,7 @@ static void Bar() }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(4, 5) }, - Array.Empty()); + new[] { new SourceLineUpdate(4, 5) }); } [Fact] @@ -254,8 +251,7 @@ class C { new SourceLineUpdate(3, 4), AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(4) - }, - Array.Empty()); + }); } [Fact] @@ -281,7 +277,7 @@ static void Bar() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "static void Bar()" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Bar")) }); } [Fact] @@ -307,8 +303,7 @@ static void Bar() }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(6, 5) }, - Array.Empty()); + new[] { new SourceLineUpdate(6, 5) }); } [Fact] @@ -335,8 +330,7 @@ static void Bar() }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(5, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(5, 4) }); } [Fact] @@ -366,7 +360,7 @@ static void Bar() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "static void Bar()" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Bar")) }); var active = GetActiveStatements(src1, src2); var syntaxMap = GetSyntaxMap(src1, src2); @@ -388,7 +382,7 @@ class C { /*--*/static void Bar() { } }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "static void Bar() { }" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Bar")) }); } [Fact] @@ -415,8 +409,7 @@ static void Bar() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(6, 5) }, - Array.Empty()); + new[] { new SourceLineUpdate(6, 5) }); } [Fact] @@ -443,8 +436,7 @@ static void Bar() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "static void Bar()" }, - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "\r\n /*edit*/", FeaturesResources.method)); + diagnostics: new[] { Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "\r\n /*edit*/", FeaturesResources.method) }); } [Fact] @@ -471,8 +463,7 @@ static void Bar() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "static void Bar()" }, - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "\r\n ", FeaturesResources.method)); + diagnostics: new[] { Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "\r\n ", FeaturesResources.method) }); } [Fact] @@ -501,7 +492,7 @@ static async Task Bar() var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "static async Task Bar()" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.Bar"), preserveLocalVariables: true) }); } #endregion @@ -541,8 +532,7 @@ public C(int a) new SourceLineUpdate(4, 8), AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(6), new SourceLineUpdate(8, 4) - }, - Array.Empty()); + }); } [Fact] @@ -568,8 +558,7 @@ public C(int a) }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(4, 5) }, - Array.Empty()); + new[] { new SourceLineUpdate(4, 5) }); } [Fact] @@ -593,8 +582,7 @@ public C(int a) => }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(5, 6) }, - Array.Empty()); + new[] { new SourceLineUpdate(5, 6) }); } [Fact] @@ -618,8 +606,7 @@ public C(int a) }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(5, 6) }, - Array.Empty()); + new[] { new SourceLineUpdate(5, 6) }); } [Fact] @@ -643,8 +630,7 @@ public C(int a) => }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(5, 6) }, - Array.Empty()); + new[] { new SourceLineUpdate(5, 6) }); } [Fact] @@ -671,8 +657,7 @@ public C(int a) }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(6, 8) }, - Array.Empty()); + new[] { new SourceLineUpdate(6, 8) }); } [Fact] @@ -696,8 +681,7 @@ public C(int a) }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(5, 6) }, - Array.Empty()); + new[] { new SourceLineUpdate(5, 6) }); } [Fact] @@ -722,8 +706,7 @@ public C(int a) }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new SourceLineUpdate[] { new(5, 6) }, - Array.Empty()); + new SourceLineUpdate[] { new(5, 6) }); } [Fact] @@ -748,7 +731,7 @@ public C(int a) var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "public C(int a)" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").InstanceConstructors.Single(), preserveLocalVariables: true) }); } [Fact] @@ -774,8 +757,7 @@ public C(int a) }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new SourceLineUpdate[] { new(5, 6) }, - Array.Empty()); + new SourceLineUpdate[] { new(5, 6) }); } [Fact] @@ -801,7 +783,7 @@ public C(int a) var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "public C(int a)" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").InstanceConstructors.Single(), preserveLocalVariables: true) }); } [Fact] @@ -827,8 +809,7 @@ public C(int a) var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "public C(int a)" }, - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, " ", FeaturesResources.constructor)); + diagnostics: new[] { Diagnostic(RudeEditKind.GenericTypeUpdate, "public C(int a)") }); } #endregion @@ -856,8 +837,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(5, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(5, 4) }); } [Fact] @@ -877,8 +857,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -898,8 +877,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } #endregion @@ -923,8 +901,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - Array.Empty(), - Array.Empty()); + Array.Empty()); } [Fact] @@ -944,8 +921,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - Array.Empty(), - Array.Empty()); + Array.Empty()); } [Fact] @@ -966,8 +942,8 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4), new SourceLineUpdate(4, 3) }, - Array.Empty()); + Array.Empty(), + diagnostics: new[] { Diagnostic(RudeEditKind.Move, "static int Bar = 2", FeaturesResources.field) }); } [Fact] @@ -989,8 +965,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 6) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 6) }); } [Fact] @@ -1011,7 +986,10 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new[] { "Bar = 2" }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").InstanceConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -1031,8 +1009,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new SourceLineUpdate[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new SourceLineUpdate[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1053,7 +1030,10 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "Goo = " }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").StaticConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -1074,7 +1054,10 @@ static int Goo var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "Goo " }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").StaticConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -1095,7 +1078,10 @@ static int var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "Goo = 1" }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").StaticConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -1116,7 +1102,10 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "Goo = 1" }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").StaticConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -1137,7 +1126,10 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "Goo = 1" }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").StaticConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -1157,7 +1149,10 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "Goo = 1 + 1" }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").StaticConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -1177,8 +1172,10 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "Goo = 1 + 1" }, - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, " ", FeaturesResources.field)); + diagnostics: new[] + { + Diagnostic(RudeEditKind.GenericTypeUpdate, "class C") + }); } #endregion @@ -1203,7 +1200,7 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "get { return " }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P").GetMethod) }); } [Fact] @@ -1222,9 +1219,7 @@ int P { get { return 1; } } }"; var edits = GetTopEdits(src1, src2); - edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + edits.VerifyLineEdits(new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1244,8 +1239,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1265,8 +1259,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1286,8 +1279,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1307,8 +1299,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1328,8 +1319,7 @@ int P { }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1349,8 +1339,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1370,7 +1359,7 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "int P { get; } = 1;" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").InstanceConstructors.Single(), preserveLocalVariables: true) }); } #endregion @@ -1395,7 +1384,7 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "get { return " }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.this[]").GetMethod) }); } [Fact] @@ -1414,9 +1403,7 @@ int this[int a] { get { return 1; } } }"; var edits = GetTopEdits(src1, src2); - edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + edits.VerifyLineEdits(new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1435,9 +1422,7 @@ class C int this[int a] { get { return 1; } set { } } }"; var edits = GetTopEdits(src1, src2); - edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + edits.VerifyLineEdits(new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1457,8 +1442,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1478,8 +1462,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1499,8 +1482,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } #endregion @@ -1524,8 +1506,7 @@ event Action E { add { } remove { } } }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(3, 4) }, - Array.Empty()); + new[] { new SourceLineUpdate(3, 4) }); } [Fact] @@ -1546,7 +1527,7 @@ event Action E { add { } remove { } } var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( new[] { new SourceLineUpdate(4, 3) }, - new string[] { "add { }" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.E").AddMethod) }); } [Fact] @@ -1567,7 +1548,7 @@ event Action E { add { } remove { } } var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "remove { }" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.E").RemoveMethod) }); } [Fact] @@ -1587,8 +1568,7 @@ event Action E { add { } remove { } } }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(4, 3) }, - Array.Empty()); + new[] { new SourceLineUpdate(4, 3) }); } [Fact] @@ -1610,7 +1590,7 @@ event Action E { add { } remove var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new[] { "remove " }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.E").RemoveMethod) }); } [Fact, WorkItem(53263, "https://github.com/dotnet/roslyn/issues/53263")] @@ -1632,7 +1612,7 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( new[] { new SourceLineUpdate(3, 4) }, - new[] { "remove => " }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.E").RemoveMethod) }); } [Fact] @@ -1653,8 +1633,7 @@ class C }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( - new[] { new SourceLineUpdate(4, 3), new SourceLineUpdate(5, 3) }, - Array.Empty()); + new[] { new SourceLineUpdate(4, 3), new SourceLineUpdate(5, 3) }); } #endregion @@ -1697,8 +1676,7 @@ class C new SourceLineUpdate(3, 9), AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(5), new SourceLineUpdate(9, 3) - }, - Array.Empty()); + }); } #endregion @@ -1737,7 +1715,7 @@ static void F() // Line deltas can't be applied on the whole breakpoint span hence recompilation. edits.VerifyLineEdits( Array.Empty(), - new[] { "static void F()" }); + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) }); } /// @@ -1760,10 +1738,10 @@ class D public D() {} #line 5 ""a"" - public F3() {} + void F3() {} #line 6 ""a"" - public F4() {} + void F4() {} }"; var src2 = @" #line 11 ""a"" @@ -1779,8 +1757,8 @@ class D public D() {} #line 5 ""a"" - public F3() {} - public F4() {} + void F3() {} + void F4() {} } "; var edits = GetTopEdits(src1, src2); @@ -1793,10 +1771,10 @@ public F4() {} AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(6), // lines between F2 and D ctor new(9, 19))) // D ctor }, - new[] + semanticEdits: new[] { - "public F3() {}", // overlaps with "void F1() { }" - "public F4() {}" // overlaps with "void F2() { }" + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("D.F3")), // overlaps with "void F1() { }" + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("D.F4")), // overlaps with "void F2() { }" }); } @@ -1858,8 +1836,7 @@ static void F() { new("a", ImmutableArray.Create(new SourceLineUpdate(0, 1))), new("b", ImmutableArray.Create(new SourceLineUpdate(0, 1))), - }, - Array.Empty()); + }); } [Fact] @@ -1901,12 +1878,10 @@ static void F() { new("a", ImmutableArray.Create(new SourceLineUpdate(6, 4))), }, - expectedNodeUpdates: new[] { "static void F()" }); - - edits.VerifySemantics(ActiveStatementsDescription.Empty, new[] - { - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F")) - }); + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) + }); } [Fact] @@ -1923,8 +1898,10 @@ class C { static void Bar() { } }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - new string[] { "static void Bar() { }" }, - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "{", FeaturesResources.method)); + diagnostics: new[] + { + Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "{", FeaturesResources.method) + }); } #endregion diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 27e7ed214b1a2..610c6ff3870b8 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -1825,9 +1825,15 @@ interface I { void F() {} } DocumentResults( diagnostics: new[] { - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "void F()", FeaturesResources.method), - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "void F()", FeaturesResources.method), - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "void F()", FeaturesResources.method), + Diagnostic(RudeEditKind.GenericTypeUpdate, "class C"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "struct S"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "interface I"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "void F()"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "void F()"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "void F()"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T"), }) }); } @@ -3358,7 +3364,6 @@ public void EnumInitializerUpdate2() "Update [Blue = 2]@22 -> [Blue = 2 << 1]@27"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.InitializerUpdate, "Red = 1 << 0", FeaturesResources.enum_value), Diagnostic(RudeEditKind.InitializerUpdate, "Blue = 2 << 1", FeaturesResources.enum_value)); } @@ -3855,7 +3860,8 @@ public void Delegates_TypeParameter_Rename() "Update [T]@22 -> [S]@22"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Renamed, "S", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.Renamed, "S", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "S")); } [Fact] @@ -3870,7 +3876,8 @@ public void Delegates_TypeParameter_Variance1() "Update [T]@22 -> [in T]@22"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -3885,7 +3892,8 @@ public void Delegates_TypeParameter_Variance2() "Update [out T]@22 -> [T]@22"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -3900,7 +3908,8 @@ public void Delegates_TypeParameter_Variance3() "Update [out T]@22 -> [in T]@22"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -3916,13 +3925,9 @@ public void Delegates_TypeParameter_AddAttribute() edits.VerifyEdits( "Update [T]@70 -> [[A]T]@70"); - edits.VerifySemantics( - ActiveStatementsDescription.Empty, - new[] - { - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("D")), - }, - capabilities: EditAndContinueTestHelpers.Net6RuntimeCapabilities); + edits.VerifyRudeDiagnostics( + EditAndContinueTestHelpers.Net6RuntimeCapabilities, + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -4614,7 +4619,9 @@ public void NestedPartialTypeInPartialType_InsertDeleteAndChange_TypeParameterAt DocumentResults( diagnostics: new[] { - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter) + Diagnostic(RudeEditKind.GenericTypeUpdate, "partial class C<[A]T>"), + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T") }), DocumentResults(), @@ -4641,7 +4648,9 @@ public void NestedPartialTypeInPartialType_InsertDeleteAndChange_Constraint() DocumentResults( diagnostics: new[] { - Diagnostic(RudeEditKind.ChangingConstraints, "where T : new()", FeaturesResources.type_parameter) + Diagnostic(RudeEditKind.GenericTypeUpdate, "partial class C"), + Diagnostic(RudeEditKind.ChangingConstraints, "where T : new()", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "where T : new()") }), DocumentResults(), @@ -5077,8 +5086,8 @@ public void PartialMember_DeleteInsert_GenericMethod() DocumentResults(), DocumentResults(diagnostics: new[] { - // TODO: better message - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "void F()", FeaturesResources.method) + Diagnostic(RudeEditKind.GenericMethodUpdate, "void F()"), + Diagnostic(RudeEditKind.GenericMethodUpdate, "T") }) }); } @@ -5098,8 +5107,7 @@ public void PartialMember_DeleteInsert_GenericType() DocumentResults(), DocumentResults(diagnostics: new[] { - // TODO: better message - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "void F()", FeaturesResources.method) + Diagnostic(RudeEditKind.GenericTypeUpdate, "void F()") }) }); } @@ -7446,19 +7454,14 @@ public void PartialMethod_Swap_ImplementationAndDefinitionParts() var srcA2 = "partial class C { partial void F() { } }"; var srcB2 = "partial class C { partial void F(); }"; - // current: - GetTopEdits(srcA1, srcA2).VerifyRudeDiagnostics(Diagnostic(RudeEditKind.MethodBodyAdd, "partial void F()", FeaturesResources.method)); - GetTopEdits(srcB1, srcB2).VerifyRudeDiagnostics(Diagnostic(RudeEditKind.MethodBodyDelete, "partial void F()", FeaturesResources.method)); - - // correct: TODO - //EditAndContinueValidation.VerifySemantics( - // new[] { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, - // new[] - // { - // DocumentResults(), - // DocumentResults( - // semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F")) }), - // }); + EditAndContinueValidation.VerifySemantics( + new[] { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, + new[] + { + DocumentResults( + semanticEdits: new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F").PartialImplementationPart) }), + DocumentResults(), + }); } [Fact] @@ -7575,7 +7578,19 @@ public void Operator_Conversion_ExternModifiers_Add() var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.MethodBodyDelete, "extern public static implicit operator bool (C c)", CSharpFeaturesResources.conversion_operator)); + Diagnostic(RudeEditKind.ModifiersUpdate, "extern public static implicit operator bool (C c)", CSharpFeaturesResources.conversion_operator)); + } + + [Fact] + public void Operator_Conversion_ExternModifiers_Remove() + { + var src1 = "class C { extern public static implicit operator bool (C c); }"; + var src2 = "class C { public static implicit operator bool (C c) => default; }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyRudeDiagnostics( + Diagnostic(RudeEditKind.ModifiersUpdate, "public static implicit operator bool (C c)", CSharpFeaturesResources.conversion_operator)); } [Fact] @@ -7864,8 +7879,9 @@ public void Constructor_ExternModifier_Add() "Insert [public extern C();]@10", "Insert [()]@25"); - // The compiler generates an empty constructor. - edits.VerifySemanticDiagnostics(); + // This can be allowed as the compiler generates an empty constructor, but it's not worth the complexity. + edits.VerifyRudeDiagnostics( + Diagnostic(RudeEditKind.ModifiersUpdate, "public extern C()", FeaturesResources.constructor)); } [Fact] @@ -7908,7 +7924,7 @@ public C(int a) { } "Update [public C(int a) : base(a) { }]@21 -> [public C(int a) { }]@21"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericTypeUpdate, "public C(int a)", FeaturesResources.constructor)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "public C(int a)")); } [Fact] @@ -7951,7 +7967,7 @@ public C(int a) : base(a + 1) { } "Update [public C(int a) : base(a) { }]@21 -> [public C(int a) : base(a + 1) { }]@21"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericTypeUpdate, "public C(int a)", FeaturesResources.constructor)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "public C(int a)")); } [WorkItem(743552, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/743552")] @@ -9352,8 +9368,31 @@ public void PropertyInitializer_Update2() "Update [int a { get; } = 0;]@10 -> [int a { get { return 1; } }]@10", "Update [get;]@18 -> [get { return 1; }]@18"); - edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.MethodBodyAdd, "get", CSharpFeaturesResources.property_getter)); + edits.VerifySemantics( + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.a").GetMethod), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").Constructors.Single(), preserveLocalVariables: true)); + } + + [Fact] + public void PropertyInitializer_InsertDelete() + { + var srcA1 = "partial class C { }"; + var srcB1 = "partial class C { int a { get; } = 0; }"; + var srcA2 = "partial class C { int a { get { return 1; } } }"; + var srcB2 = "partial class C { }"; + + EditAndContinueValidation.VerifySemantics( + new[] { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, + new[] + { + DocumentResults( + semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.a").GetMethod), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").Constructors.Single(), partialType: "C", preserveLocalVariables: true) + }), + DocumentResults() + }); } [Fact] @@ -9384,8 +9423,13 @@ public void PropertyInitializer_Update3() "Update [int a { get { return 1; } }]@10 -> [int a { get; } = 0;]@10", "Update [get { return 1; }]@18 -> [get;]@18"); - edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.MethodBodyDelete, "get", CSharpFeaturesResources.property_getter)); + edits.VerifySemantics( + ActiveStatementsDescription.Empty, + new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.a").GetMethod), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").InstanceConstructors.Single(), preserveLocalVariables: true) + }); } [Fact] @@ -9701,7 +9745,8 @@ public void FieldInitializerUpdate_GenericType() "Update [a = 1]@17 -> [a = 2]@17"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericTypeInitializerUpdate, "a = 2", FeaturesResources.field)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "a = 2"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "class C")); } [Fact] @@ -9713,7 +9758,8 @@ public void PropertyInitializerUpdate_GenericType() var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericTypeInitializerUpdate, "int a", FeaturesResources.auto_property)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "int a"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "class C")); } [Fact] @@ -10905,15 +10951,18 @@ public void Field_Attribute_Add_InsertDelete() [Fact] public void Field_FixedSize_Update() { - var src1 = "struct S { public unsafe fixed byte bs[1]; }"; - var src2 = "struct S { public unsafe fixed byte bs[2]; }"; + var src1 = "struct S { public unsafe fixed byte a[1], b[2]; }"; + var src2 = "struct S { public unsafe fixed byte a[2], b[3]; }"; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits("Update [bs[1]]@36 -> [bs[2]]@36"); + edits.VerifyEdits( + "Update [a[1]]@36 -> [a[2]]@36", + "Update [b[2]]@42 -> [b[3]]@42"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.FixedSizeFieldUpdate, "bs[2]", FeaturesResources.field)); + Diagnostic(RudeEditKind.FixedSizeFieldUpdate, "a[2]", FeaturesResources.field), + Diagnostic(RudeEditKind.FixedSizeFieldUpdate, "b[3]", FeaturesResources.field)); } [WorkItem(1120407, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1120407")] @@ -10928,7 +10977,7 @@ public void Field_Const_Update() edits.VerifyEdits("Update [x = 0]@20 -> [x = 1]@20"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Update, "x = 1", FeaturesResources.const_field)); + Diagnostic(RudeEditKind.InitializerUpdate, "x = 1", FeaturesResources.const_field)); } [Fact] @@ -14398,8 +14447,9 @@ public void MethodTypeParameter_Attribute_Insert1() "Update [T]@72 -> [[A]T]@72"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "", FeaturesResources.method), - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericMethodUpdate, "T"), + Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "", FeaturesResources.method)); } [Fact] @@ -14417,8 +14467,9 @@ public void MethodTypeParameter_Attribute_Insert2() "Update [[A]T]@120 -> [[A, B]T]@120"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "", FeaturesResources.method), - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericMethodUpdate, "T"), + Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "", FeaturesResources.method)); } [Fact] @@ -14435,8 +14486,9 @@ public void MethodTypeParameter_Attribute_Delete() "Update [[A]T]@72 -> [T]@72"); edits.VerifyRudeDiagnostics( + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "", FeaturesResources.method), - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.GenericMethodUpdate, "T")); } [Fact] @@ -14454,7 +14506,8 @@ public void MethodTypeParameter_Attribute_Update_NotSupportedByRuntime() "Update [[System.Obsolete(\"1\"), B]T]@120 -> [[System.Obsolete(\"2\"), A]T]@120"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericMethodUpdate, "T")); } [Fact] @@ -14470,10 +14523,9 @@ public void MethodTypeParameter_Attribute_Update() edits.VerifyEdits( "Update [[A(0)]T]@67 -> [[A(1)]T]@67"); - edits.VerifySemantics( - ActiveStatementsDescription.Empty, - new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) }, - capabilities: EditAndContinueTestHelpers.Net6RuntimeCapabilities); + edits.VerifyRudeDiagnostics( + EditAndContinueTestHelpers.Net6RuntimeCapabilities, + Diagnostic(RudeEditKind.GenericMethodUpdate, "T")); } [Fact] @@ -14491,8 +14543,9 @@ public void MethodTypeParameter_Attribute_Update_WithBodyUpdate() "Update [[A(0)]T]@67 -> [[A(1)]T]@67"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericMethodUpdate, "void F<[A(1)]T>(T a)", FeaturesResources.method), - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.GenericMethodUpdate, "void F<[A(1)]T>(T a)"), + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericMethodUpdate, "T")); } #endregion @@ -14571,7 +14624,8 @@ public void TypeTypeParameterUpdate() "Update [A]@8 -> [B]@8"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Renamed, "B", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.Renamed, "B", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "B")); } [Fact] @@ -14603,7 +14657,8 @@ public void TypeTypeParameterReorderAndUpdate() edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.Move, "B", FeaturesResources.type_parameter), - Diagnostic(RudeEditKind.Renamed, "C", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.Renamed, "C", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "C")); } [Fact] @@ -14620,7 +14675,8 @@ public void TypeTypeParameterAttributeInsert1() "Update [T]@56 -> [[A]T]@56"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -14638,7 +14694,8 @@ public void TypeTypeParameterAttributeInsert2() "Update [[A]T]@104 -> [[A, B]T]@104"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -14654,10 +14711,9 @@ public void TypeTypeParameterAttributeInsert_SupportedByRuntime() edits.VerifyEdits( "Update [T]@56 -> [[A]T]@56"); - edits.VerifySemantics( - ActiveStatementsDescription.Empty, - new[] { SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C")) }, - capabilities: EditAndContinueTestHelpers.Net6RuntimeCapabilities); + edits.VerifyRudeDiagnostics( + EditAndContinueTestHelpers.Net6RuntimeCapabilities, + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -14674,7 +14730,8 @@ public void TypeTypeParameterAttributeDelete() "Update [[A]T]@56 -> [T]@56"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Fact] @@ -14692,7 +14749,8 @@ public void TypeTypeParameterAttributeUpdate() "Update [[System.Obsolete(\"1\"), B]T]@104 -> [[System.Obsolete(\"2\"), A]T]@104"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } #endregion @@ -14718,7 +14776,8 @@ public void TypeConstraint_Insert(string newConstraint) "Insert [where T : " + newConstraint + "]@13"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "where T : " + newConstraint, FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingConstraints, "where T : " + newConstraint, FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "where T : " + newConstraint)); } [Theory] @@ -14740,7 +14799,8 @@ public void TypeConstraint_Delete(string oldConstraint) "Delete [where T : " + oldConstraint + "]@13"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")); } [Theory] @@ -14754,8 +14814,8 @@ public void TypeConstraint_Update_RuntimeTypeUnchanged(string oldType, string ne var edits = GetTopEdits(src1, src2); - edits.VerifySemantics( - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C"))); + edits.VerifyRudeDiagnostics( + Diagnostic(RudeEditKind.GenericTypeUpdate, "where T : System.Collections.Generic.List<" + newType + ">")); } [Theory] @@ -14770,7 +14830,8 @@ public void TypeConstraint_Update_RuntimeTypeChanged(string oldType, string newT var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "where T : System.Collections.Generic.List<" + newType + ">", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingConstraints, "where T : System.Collections.Generic.List<" + newType + ">", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "where T : System.Collections.Generic.List<" + newType + ">")); } [Fact] @@ -14797,7 +14858,8 @@ public void TypeConstraint_MultipleClauses_Insert() "Insert [where S : unmanaged]@13"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "where S : unmanaged", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingConstraints, "where S : unmanaged", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "where S : unmanaged")); } [Fact] @@ -14812,7 +14874,8 @@ public void TypeConstraint_MultipleClauses_Delete() "Delete [where S : new()]@13"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "S")); } [Fact] @@ -14846,7 +14909,9 @@ public void TypeConstraint_MultipleClauses_UpdateAndReorder() edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.Move, "T", FeaturesResources.type_parameter), Diagnostic(RudeEditKind.ChangingConstraints, "where T : class, I", FeaturesResources.type_parameter), - Diagnostic(RudeEditKind.ChangingConstraints, "where S : class, new()", FeaturesResources.type_parameter)); + Diagnostic(RudeEditKind.GenericTypeUpdate, "where T : class, I"), + Diagnostic(RudeEditKind.ChangingConstraints, "where S : class, new()", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "where S : class, new()")); } #endregion diff --git a/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs b/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs index 6cb4b1af0b2ae..3ab0c795fd1a9 100644 --- a/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs @@ -37,8 +37,6 @@ public void ToDiagnostic() RudeEditKind.DeclareLibraryUpdate, RudeEditKind.DeclareAliasUpdate, RudeEditKind.InsertDllImport, - RudeEditKind.MethodBodyAdd, - RudeEditKind.MethodBodyDelete, RudeEditKind.GenericMethodUpdate, RudeEditKind.GenericTypeUpdate, RudeEditKind.ExperimentalFeaturesEnabled, diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/DocumentAnalysisResultsDescription.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/DocumentAnalysisResultsDescription.cs index bb569665adeb3..549ee0fd6b8bc 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/DocumentAnalysisResultsDescription.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/DocumentAnalysisResultsDescription.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { @@ -15,14 +16,17 @@ internal readonly struct DocumentAnalysisResultsDescription /// public readonly ImmutableArray SemanticEdits; + public readonly ImmutableArray LineEdits; + public readonly ImmutableArray Diagnostics; public DocumentAnalysisResultsDescription( ActiveStatementsDescription? activeStatements = null, SemanticEditDescription[]? semanticEdits = null, + SequencePointUpdates[]? lineEdits = null, RudeEditDiagnosticDescription[]? diagnostics = null) { - // The test must validate semantic edits, diagnostics or both. + // The test must validate semantic edits, lineEdits, diagnostics or all of the above. // If neither is specified then assume the expectation is that // the documents has no edits and no diagnostics. if (semanticEdits is null && diagnostics is null) @@ -36,6 +40,7 @@ public DocumentAnalysisResultsDescription( Diagnostics = diagnostics.AsImmutableOrEmpty(); } + LineEdits = lineEdits.AsImmutableOrNull(); ActiveStatements = activeStatements ?? ActiveStatementsDescription.Empty; } } diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index c016d6cc6552d..8c4f13303c736 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -81,48 +81,15 @@ private void VerifyDocumentActiveStatementsAndExceptionRegions( internal void VerifyLineEdits( EditScript editScript, - IEnumerable expectedLineEdits, - IEnumerable expectedNodeUpdates, - RudeEditDiagnosticDescription[] expectedDiagnostics) + SequencePointUpdates[] expectedLineEdits, + SemanticEditDescription[]? expectedSemanticEdits, + RudeEditDiagnosticDescription[]? expectedDiagnostics) { - var newText = SourceText.From(editScript.Match.NewRoot.SyntaxTree.ToString()); - - var diagnostics = new ArrayBuilder(); - var editMap = BuildEditMap(editScript); - - var triviaEdits = new ArrayBuilder<(SyntaxNode OldNode, SyntaxNode NewNode)>(); - var actualLineEdits = new ArrayBuilder(); - - Analyzer.GetTestAccessor().AnalyzeTrivia( - editScript.Match, - editMap, - triviaEdits, - actualLineEdits, - diagnostics, - default); - - VerifyDiagnostics(expectedDiagnostics, diagnostics, newText); - - // check files are matching: - AssertEx.Equal( - expectedLineEdits.Select(e => e.FileName), - actualLineEdits.Select(e => e.FileName), - itemSeparator: ",\r\n"); - - // check lines are matching: - _ = expectedLineEdits.Zip(actualLineEdits, (expected, actual) => - { - AssertEx.Equal( - expected.LineUpdates, - actual.LineUpdates, - itemSeparator: ",\r\n", - itemInspector: s => $"new({s.OldLine}, {s.NewLine})"); - - return true; - }).ToArray(); - - var actualNodeUpdates = triviaEdits.Select(e => e.NewNode.ToString().ToLines().First()); - AssertEx.Equal(expectedNodeUpdates, actualNodeUpdates, itemSeparator: ",\r\n"); + VerifySemantics( + new[] { editScript }, + TargetFramework.NetStandard20, + new[] { new DocumentAnalysisResultsDescription(semanticEdits: expectedSemanticEdits, lineEdits: expectedLineEdits, diagnostics: expectedDiagnostics) }, + capabilities: Net5RuntimeCapabilities); } internal void VerifySemantics(EditScript[] editScripts, TargetFramework targetFramework, DocumentAnalysisResultsDescription[] expectedResults, EditAndContinueCapabilities? capabilities = null) @@ -205,6 +172,34 @@ internal void VerifySemantics(EditScript[] editScripts, TargetFramew result.ActiveStatements, result.ExceptionRegions); } + + if (!result.RudeEditErrors.IsEmpty) + { + Assert.True(result.LineEdits.IsDefault); + Assert.True(expectedResult.LineEdits.IsDefaultOrEmpty); + } + else if (!expectedResult.LineEdits.IsDefault) + { + // check files of line edits: + AssertEx.Equal( + expectedResult.LineEdits.Select(e => e.FileName), + result.LineEdits.Select(e => e.FileName), + itemSeparator: ",\r\n", + message: "File names of line edits differ in " + assertMessagePrefix); + + // check lines of line edits: + _ = expectedResult.LineEdits.Zip(result.LineEdits, (expected, actual) => + { + AssertEx.Equal( + expected.LineUpdates, + actual.LineUpdates, + itemSeparator: ",\r\n", + itemInspector: s => $"new({s.OldLine}, {s.NewLine})", + message: "Line deltas differ in " + assertMessagePrefix); + + return true; + }).ToArray(); + } } // check if we can merge edits without throwing: diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditAndContinueValidation.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditAndContinueValidation.vb index 2e153ed184fe0..c540b86ec0dd5 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditAndContinueValidation.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditAndContinueValidation.vb @@ -28,25 +28,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests Friend Sub VerifyLineEdits(editScript As EditScript(Of SyntaxNode), - expectedLineEdits As IEnumerable(Of SourceLineUpdate), - expectedNodeUpdates As IEnumerable(Of String), - ParamArray expectedDiagnostics As RudeEditDiagnosticDescription()) - Assert.NotEmpty(expectedLineEdits) + lineEdits As SourceLineUpdate(), + Optional semanticEdits As SemanticEditDescription() = Nothing, + Optional diagnostics As RudeEditDiagnosticDescription() = Nothing) + Assert.NotEmpty(lineEdits) VerifyLineEdits( editScript, - {New SequencePointUpdates(editScript.Match.OldRoot.SyntaxTree.FilePath, expectedLineEdits.ToImmutableArray())}, - expectedNodeUpdates, - expectedDiagnostics) + {New SequencePointUpdates(editScript.Match.OldRoot.SyntaxTree.FilePath, lineEdits.ToImmutableArray())}, + semanticEdits, + diagnostics) End Sub Friend Sub VerifyLineEdits(editScript As EditScript(Of SyntaxNode), - expectedLineEdits As IEnumerable(Of SequencePointUpdates), - expectedNodeUpdates As IEnumerable(Of String), - ParamArray expectedDiagnostics As RudeEditDiagnosticDescription()) + lineEdits As SequencePointUpdates(), + Optional semanticEdits As SemanticEditDescription() = Nothing, + Optional diagnostics As RudeEditDiagnosticDescription() = Nothing) Dim validator = New VisualBasicEditAndContinueTestHelpers() - validator.VerifyLineEdits(editScript, expectedLineEdits, expectedNodeUpdates, expectedDiagnostics) + validator.VerifyLineEdits(editScript, lineEdits, semanticEdits, diagnostics) End Sub @@ -76,7 +76,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests Optional capabilities As EditAndContinueCapabilities? = Nothing) VerifySemantics( {editScript}, - {New DocumentAnalysisResultsDescription(activeStatements, semanticEdits, diagnostics)}, + {New DocumentAnalysisResultsDescription(activeStatements, semanticEdits, lineEdits:=Nothing, diagnostics)}, targetFrameworks, capabilities) End Sub diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb index 5a6a8a423c7ee..062db44057304 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/Helpers/EditingTestBase.vb @@ -82,19 +82,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests Optional activeStatements As ActiveStatementsDescription = Nothing, Optional semanticEdits As SemanticEditDescription() = Nothing, Optional diagnostics As RudeEditDiagnosticDescription() = Nothing) As DocumentAnalysisResultsDescription - Return New DocumentAnalysisResultsDescription(activeStatements, semanticEdits, diagnostics) + Return New DocumentAnalysisResultsDescription(activeStatements, semanticEdits, lineEdits:=Nothing, diagnostics) End Function - Private Shared Function ParseSource(markedSource As String) As SyntaxTree + Private Shared Function ParseSource(markedSource As String, Optional documentIndex As Integer = 0) As SyntaxTree Return SyntaxFactory.ParseSyntaxTree( ActiveStatementsDescription.ClearTags(markedSource), VisualBasicParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest), - path:="test.vb") + path:=documentIndex.ToString()) End Function - Friend Shared Function GetTopEdits(src1 As String, src2 As String) As EditScript(Of SyntaxNode) - Dim tree1 = ParseSource(src1) - Dim tree2 = ParseSource(src2) + Friend Shared Function GetTopEdits(src1 As String, src2 As String, Optional documentIndex As Integer = 0) As EditScript(Of SyntaxNode) + Dim tree1 = ParseSource(src1, documentIndex) + Dim tree2 = ParseSource(src2, documentIndex) tree1.GetDiagnostics().Verify() tree2.GetDiagnostics().Verify() diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb index a3b70d11715e1..4f9a5ed622202 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb @@ -38,7 +38,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), Array.Empty(Of String)) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"))}) End Sub @@ -190,7 +192,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Shared Sub _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + semanticEdits:={SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"))}) End Sub @@ -212,7 +216,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Shared Sub Bar()"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + semanticEdits:={SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"))}) End Sub @@ -286,13 +292,16 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Shared Sub Bar()"}) - Dim active = GetActiveStatements(src1, src2) Dim syntaxMap = GetSyntaxMap(src1, src2) - edits.VerifySemantics(active, - {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"), syntaxMap(0))}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"))}) + + edits.VerifySemantics( + active, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"), syntaxMap:=syntaxMap(0))}) End Sub @@ -310,7 +319,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Shared Sub Bar() : End Sub"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"))}) End Sub @@ -333,8 +344,8 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits({New SourceLineUpdate(4, 3)}, - Array.Empty(Of String)) + edits.VerifyLineEdits( + {New SourceLineUpdate(4, 3)}) End Sub @@ -355,9 +366,9 @@ Class C(Of T) End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), - {"Shared Sub Bar()"}, - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, vbCrLf & " ", FeaturesResources.method)) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + diagnostics:={Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, vbCrLf & " ", FeaturesResources.method)}) End Sub @@ -379,9 +390,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), - {"Shared Sub Bar(Of T)()"}, - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, vbCrLf & " ", FeaturesResources.method)) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + diagnostics:={Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, vbCrLf & " ", FeaturesResources.method)}) End Sub @@ -404,8 +415,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), - {"Shared Async Function Bar() As Task(Of Integer)"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.Bar"), preserveLocalVariables:=True)}) End Sub #End Region @@ -430,7 +442,9 @@ End Class" End Class" Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Shared Sub _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").SharedConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -451,7 +465,9 @@ End Class" End Class" Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Shared Sub _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").SharedConstructors.Single())}) End Sub #End Region @@ -473,7 +489,9 @@ Class C End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits({New SourceLineUpdate(2, 3), New SourceLineUpdate(3, 2)}, {}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + diagnostics:={Diagnostic(RudeEditKind.Move, "Shared Bar As Integer = 2", FeaturesResources.field)}) End Sub @@ -491,7 +509,9 @@ Class C End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits({New SourceLineUpdate(2, 3), New SourceLineUpdate(3, 2)}, {}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + diagnostics:={Diagnostic(RudeEditKind.Move, "Shared c As New C()", FeaturesResources.field)}) End Sub @@ -511,8 +531,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits({New SourceLineUpdate(2, 3), - New SourceLineUpdate(3, 2)}, {}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + diagnostics:={Diagnostic(RudeEditKind.Move, "Shared c, d As New C()", FeaturesResources.field)}) End Sub @@ -606,7 +627,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits({New SourceLineUpdate(2, 3)}, {"Goo"}) + edits.VerifyLineEdits( + {New SourceLineUpdate(2, 3)}, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -662,7 +685,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo = _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -681,7 +706,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo _ "}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -700,7 +727,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -718,7 +747,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo = 1"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -736,7 +767,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo As Integer = 1 + 1"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -755,7 +788,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo As _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -774,7 +809,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -795,7 +832,9 @@ End Class Dim edits = GetTopEdits(src1, src2) ' to make it simpler, we recompile the constructor (by reporting a field as a node update) - edits.VerifyLineEdits({New SourceLineUpdate(2, 3)}, {"Goo"}) + edits.VerifyLineEdits( + {New SourceLineUpdate(2, 3)}, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -815,7 +854,9 @@ End Class Dim edits = GetTopEdits(src1, src2) ' we treat "Goo + New D()" as a whole for simplicity - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo", "Bar"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -833,7 +874,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo", "Bar"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -852,7 +895,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo", "Bar"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -869,7 +914,9 @@ Class C End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Goo(1)"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -887,9 +934,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), - {"Goo As Integer = 1 + 1"}, - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, " ", FeaturesResources.field)) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + diagnostics:={Diagnostic(RudeEditKind.GenericTypeUpdate, "Class C(Of T)")}) End Sub #End Region @@ -1043,7 +1090,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Property Goo _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -1062,7 +1111,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Property Goo As _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -1081,7 +1132,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Property Goo As Integer _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -1100,7 +1153,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Property Goo As Integer = _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -1119,7 +1174,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Property Goo As _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -1138,7 +1195,9 @@ End Class " Dim edits = GetTopEdits(src1, src2) - edits.VerifyLineEdits(Array.Empty(Of SequencePointUpdates), {"Property Goo$ = _"}) + edits.VerifyLineEdits( + Array.Empty(Of SequencePointUpdates), + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub #End Region @@ -1195,9 +1254,10 @@ End Class AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(5),' lines between F2 And D ctor New SourceLineUpdate(7, 17)))' D ctor }, + semanticEdits:= { - "Sub F3() : End Sub", ' overlaps with "Sub F1" - "Sub F4() : End Sub" ' overlaps with "Sub F2" + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("D.F3")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("D.F4")) }) End Sub @@ -1257,8 +1317,7 @@ End Class" { New SequencePointUpdates("a", ImmutableArray.Create(New SourceLineUpdate(0, 1))), New SequencePointUpdates("b", ImmutableArray.Create(New SourceLineUpdate(0, 1))) - }, - Array.Empty(Of String)) + }) End Sub @@ -1298,7 +1357,7 @@ End Class" { New SequencePointUpdates("a", ImmutableArray.Create(New SourceLineUpdate(6, 4))) }, - {"Sub F()"}) + semanticEdits:={SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) edits.VerifySemantics(ActiveStatementsDescription.Empty, { @@ -1328,8 +1387,7 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifyLineEdits( Array.Empty(Of SequencePointUpdates)(), - {"Sub Bar(Of T)()"}, - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "Sub Bar(Of T)()", FeaturesResources.method)) + diagnostics:={Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "Sub Bar(Of T)()", FeaturesResources.method)}) End Sub #End Region diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb index d0750b0576f5e..76ea68af92414 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb @@ -1061,7 +1061,8 @@ End Class" Diagnostic(RudeEditKind.InsertIntoGenericType, "F4 As New Object", FeaturesResources.field), Diagnostic(RudeEditKind.InsertIntoGenericType, "F5(1, 2)", FeaturesResources.field), Diagnostic(RudeEditKind.InsertIntoGenericType, "F6?", FeaturesResources.field), - Diagnostic(RudeEditKind.InsertIntoGenericType, "WE As Object", VBFeaturesResources.WithEvents_field)) + Diagnostic(RudeEditKind.InsertIntoGenericType, "WE As Object", VBFeaturesResources.WithEvents_field), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Class C(Of T)")) End Sub @@ -1253,9 +1254,15 @@ End Interface DocumentResults( diagnostics:= { - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "Sub F()", FeaturesResources.method), - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "Sub F()", FeaturesResources.method), - Diagnostic(RudeEditKind.GenericTypeTriviaUpdate, "Sub F()", FeaturesResources.method) + Diagnostic(RudeEditKind.GenericTypeUpdate, "Class C(Of T)"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Structure S(Of T)"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Interface I(Of T)"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Sub F()"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Sub F()"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Sub F()"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T") }) }) End Sub @@ -1574,21 +1581,20 @@ End Class "Update [Blue = 2]@23 -> [Blue = 2 << 1]@28") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.InitializerUpdate, "Red = 1 << 0", FeaturesResources.enum_value), Diagnostic(RudeEditKind.InitializerUpdate, "Blue = 2 << 1", FeaturesResources.enum_value)) End Sub Public Sub Enum_MemberInitializer_Update3() - Dim src1 = "Enum Color : Red = int.MinValue : End Enum" - Dim src2 = "Enum Color : Red = int.MaxValue : End Enum" + Dim src1 = "Enum Color : Red = Integer.MinValue : End Enum" + Dim src2 = "Enum Color : Red = Integer.MaxValue : End Enum" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Red = int.MinValue]@13 -> [Red = int.MaxValue]@13") + "Update [Red = Integer.MinValue]@13 -> [Red = Integer.MaxValue]@13") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.InitializerUpdate, "Red = int.MaxValue", FeaturesResources.enum_value)) + Diagnostic(RudeEditKind.InitializerUpdate, "Red = Integer.MaxValue", FeaturesResources.enum_value)) End Sub @@ -1886,7 +1892,8 @@ End Class "Update [T]@30 -> [S]@30") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Renamed, "S", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.Renamed, "S", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "S")) End Sub @@ -1899,7 +1906,8 @@ End Class "Update [T]@30 -> [In T]@30") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")) End Sub @@ -1912,7 +1920,8 @@ End Class "Update [Out T]@30 -> [T]@30") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")) End Sub @@ -1925,7 +1934,8 @@ End Class "Update [Out T]@30 -> [In T]@30") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.VarianceUpdate, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")) End Sub @@ -2497,7 +2507,12 @@ End Structure { DocumentResults(), DocumentResults( - diagnostics:={Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter)}), + diagnostics:= + { + Diagnostic(RudeEditKind.GenericTypeUpdate, "Partial Class C(Of T As New)"), + Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T") + }), DocumentResults() }) End Sub @@ -2804,14 +2819,14 @@ End Class Dim srcA2 = "Partial Class C : End Class" Dim srcB2 = "Partial Class C" + vbCrLf + "Sub F(Of T)() : End Sub : End Class" - ' TODO better message EditAndContinueValidation.VerifySemantics( {GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)}, { DocumentResults(), DocumentResults(diagnostics:= { - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "Sub F(Of T)()", FeaturesResources.method) + Diagnostic(RudeEditKind.GenericMethodUpdate, "Sub F(Of T)()"), + Diagnostic(RudeEditKind.GenericMethodUpdate, "T") }) }) End Sub @@ -2830,7 +2845,8 @@ End Class DocumentResults(), DocumentResults(diagnostics:= { - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, "Sub F(Of T)()", FeaturesResources.method) + Diagnostic(RudeEditKind.GenericMethodUpdate, "Sub F(Of T)()"), + Diagnostic(RudeEditKind.GenericMethodUpdate, "T") }) }) End Sub @@ -3893,12 +3909,48 @@ End Class Public Sub MethodUpdate_ImplementsDelete() - Dim src1 = "Class C : Implements I, J : " & vbLf & "Sub Goo Implements I.Goo : End Sub : " & vbLf & "Sub JGoo Implements J.Goo : End Sub : End Class" - Dim src2 = "Class C : Implements I, J : " & vbLf & "Sub Goo : End Sub : " & vbLf & "Sub JGoo Implements J.Goo : End Sub : End Class" + Dim src1 = " +Class C + Implements I, J + + Sub Goo Implements I.Goo + End Sub + + Sub JGoo Implements J.Goo + End Sub +End Class + +Interface I + Sub Goo +End Interface + +Interface J + Sub Goo +End Interface +" + Dim src2 = " +Class C + Implements I, J + + Sub Goo + End Sub + + Sub JGoo Implements J.Goo + End Sub +End Class + +Interface I + Sub Goo +End Interface + +Interface J + Sub Goo +End Interface +" Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Goo Implements I.Goo]@29 -> [Sub Goo]@29") + "Update [Sub Goo Implements I.Goo]@39 -> [Sub Goo]@39") edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.ImplementsClauseUpdate, "Sub Goo", FeaturesResources.method)) @@ -3906,12 +3958,49 @@ End Class Public Sub MethodUpdate_ImplementsInsert() - Dim src1 = "Class C : Implements I, J : " & vbLf & "Sub Goo : End Sub : " & vbLf & "Sub JGoo Implements J.Goo : End Sub : End Class" - Dim src2 = "Class C : Implements I, J : " & vbLf & "Sub Goo Implements I.Goo : End Sub : " & vbLf & "Sub JGoo Implements J.Goo : End Sub : End Class" + Dim src1 = " +Class C + Implements I, J + + Sub Goo + End Sub + + Sub JGoo Implements J.Goo + End Sub +End Class + +Interface I + Sub Goo +End Interface + +Interface J + Sub Goo +End Interface +" + Dim src2 = " +Class C + Implements I, J + + Sub Goo Implements I.Goo + End Sub + + Sub JGoo Implements J.Goo + End Sub +End Class + +Interface I + Sub Goo +End Interface + +Interface J + Sub Goo +End Interface +" + Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub Goo]@29 -> [Sub Goo Implements I.Goo]@29") + "Update [Sub Goo]@39 -> [Sub Goo Implements I.Goo]@39") edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.ImplementsClauseUpdate, "Sub Goo", FeaturesResources.method)) @@ -3919,16 +4008,53 @@ End Class Public Sub MethodUpdate_ImplementsUpdate() - Dim src1 = "Class C : Implements I, J : " & vbLf & "Sub IGoo Implements I.Goo : End Sub : " & vbLf & "Sub JGoo Implements J.Goo : End Sub : End Class" - Dim src2 = "Class C : Implements I, J : " & vbLf & "Sub IGoo Implements J.Goo : End Sub : " & vbLf & "Sub JGoo Implements I.Goo : End Sub : End Class" + Dim src1 = " +Class C + Implements I, J + + Sub Goo Implements I.Goo + End Sub + + Sub JGoo Implements J.Goo + End Sub +End Class + +Interface I + Sub Goo +End Interface + +Interface J + Sub Goo +End Interface +" + Dim src2 = " +Class C + Implements I, J + + Sub Goo Implements J.Goo + End Sub + + Sub JGoo Implements I.Goo + End Sub +End Class + +Interface I + Sub Goo +End Interface + +Interface J + Sub Goo +End Interface +" + Dim edits = GetTopEdits(src1, src2) edits.VerifyEdits( - "Update [Sub IGoo Implements I.Goo]@29 -> [Sub IGoo Implements J.Goo]@29", - "Update [Sub JGoo Implements J.Goo]@68 -> [Sub JGoo Implements I.Goo]@68") + "Update [Sub Goo Implements I.Goo]@39 -> [Sub Goo Implements J.Goo]@39", + "Update [Sub JGoo Implements J.Goo]@84 -> [Sub JGoo Implements I.Goo]@84") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ImplementsClauseUpdate, "Sub IGoo", FeaturesResources.method), + Diagnostic(RudeEditKind.ImplementsClauseUpdate, "Sub Goo", FeaturesResources.method), Diagnostic(RudeEditKind.ImplementsClauseUpdate, "Sub JGoo", FeaturesResources.method)) End Sub @@ -4538,7 +4664,7 @@ End Class "[Public Sub New(a As Integer) : End Sub]@14") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericTypeUpdate, "Public Sub New(a As Integer)", FeaturesResources.constructor)) + Diagnostic(RudeEditKind.GenericTypeUpdate, "Public Sub New(a As Integer)")) End Sub @@ -7582,7 +7708,8 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericTypeInitializerUpdate, "a As Integer = 2", FeaturesResources.field)) + Diagnostic(RudeEditKind.GenericTypeUpdate, "a As Integer = 2"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Class C(Of T)")) End Sub @@ -7592,7 +7719,8 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericTypeInitializerUpdate, "Property a", FeaturesResources.auto_property)) + Diagnostic(RudeEditKind.GenericTypeUpdate, "Property a"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "Class C(Of T)")) End Sub @@ -8023,7 +8151,7 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Update, "x = 1", FeaturesResources.const_field)) + Diagnostic(RudeEditKind.InitializerUpdate, "x = 1", FeaturesResources.const_field)) End Sub @@ -9576,7 +9704,6 @@ End Class "Insert [A]@27") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, " ", FeaturesResources.method), Diagnostic(RudeEditKind.Insert, "A", FeaturesResources.type_parameter)) End Sub @@ -9606,7 +9733,8 @@ End Class "Delete [A]@27") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Delete, "Public Sub M()", DeletedSymbolDisplay(FeaturesResources.type_parameter, "A"))) + Diagnostic(RudeEditKind.Delete, "Public Sub M()", DeletedSymbolDisplay(FeaturesResources.type_parameter, "A")), + Diagnostic(RudeEditKind.GenericMethodTriviaUpdate, " : ", FeaturesResources.method)) End Sub @@ -9634,7 +9762,8 @@ End Class "Update [A]@27 -> [B]@27") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Renamed, "B", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.Renamed, "B", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericMethodUpdate, "B")) End Sub @@ -9662,7 +9791,8 @@ End Class edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.Move, "B", FeaturesResources.type_parameter), - Diagnostic(RudeEditKind.Renamed, "C", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.Renamed, "C", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericMethodUpdate, "C")) End Sub #End Region @@ -9734,7 +9864,8 @@ End Class "Update [A]@11 -> [B]@11") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.Renamed, "B", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.Renamed, "B", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "B")) End Sub @@ -9762,7 +9893,8 @@ End Class edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.Move, "B", FeaturesResources.type_parameter), - Diagnostic(RudeEditKind.Renamed, "C", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.Renamed, "C", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "C")) End Sub #End Region @@ -9778,7 +9910,8 @@ End Class "Update [T]@11 -> [T As Class]@11") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")) End Sub @@ -9791,7 +9924,8 @@ End Class "Update [S]@11 -> [S As New]@11") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "S")) End Sub @@ -9804,7 +9938,8 @@ End Class "Update [T As Class]@14 -> [T]@14") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")) End Sub @@ -9818,7 +9953,8 @@ End Class "Update [S As New]@11 -> [S]@11") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "S")) End Sub @@ -9833,7 +9969,9 @@ End Class edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter), - Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.GenericTypeUpdate, "S"), + Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")) End Sub @@ -9848,7 +9986,9 @@ End Class edits.VerifyRudeDiagnostics( Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter), - Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.GenericTypeUpdate, "S"), + Diagnostic(RudeEditKind.ChangingConstraints, "T", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T")) End Sub @@ -9862,7 +10002,10 @@ End Class "Update [T As Class]@21 -> [T As {Class}]@23", "Update [U As I]@33 -> [U As {I}]@37") - edits.VerifyRudeDiagnostics() + edits.VerifyRudeDiagnostics( + Diagnostic(RudeEditKind.GenericTypeUpdate, "S"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "T"), + Diagnostic(RudeEditKind.GenericTypeUpdate, "U")) End Sub @@ -9875,7 +10018,8 @@ End Class "Update [S As {I, J}]@11 -> [S As {J, I}]@11") edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter)) + Diagnostic(RudeEditKind.ChangingConstraints, "S", FeaturesResources.type_parameter), + Diagnostic(RudeEditKind.GenericTypeUpdate, "S")) End Sub #End Region diff --git a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs index 362af78ee0b3a..79fedf833dda5 100644 --- a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs +++ b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs @@ -186,6 +186,27 @@ protected override ImmutableArray GetCapturedVariables(SemanticModel mo return model.AnalyzeDataFlow(memberBody).Captured; } + protected override bool AreFixedSizeBufferSizesEqual(IFieldSymbol oldField, IFieldSymbol newField, CancellationToken cancellationToken) + { + // TODO: replace with symbolic API once available (https://github.com/dotnet/roslyn/issues/54799) + + Debug.Assert(oldField.IsFixedSizeBuffer); + Debug.Assert(oldField.DeclaringSyntaxReferences.Length == 1); + Debug.Assert(newField.IsFixedSizeBuffer); + Debug.Assert(newField.DeclaringSyntaxReferences.Length == 1); + + var oldSyntax = (VariableDeclaratorSyntax)oldField.DeclaringSyntaxReferences.Single().GetSyntax(cancellationToken); + var newSyntax = (VariableDeclaratorSyntax)newField.DeclaringSyntaxReferences.Single().GetSyntax(cancellationToken); + + Debug.Assert(oldSyntax.ArgumentList != null); + Debug.Assert(newSyntax.ArgumentList != null); + + return AreEquivalent(oldSyntax.ArgumentList, newSyntax.ArgumentList); + } + + protected override bool AreHandledEventsEqual(IMethodSymbol oldMethod, IMethodSymbol newMethod) + => true; + internal override bool HasParameterClosureScope(ISymbol member) { // in instance constructor parameters are lifted to a closure different from method body @@ -1372,6 +1393,7 @@ join newVariable in newVariables on oldVariable.Identifier.Text equals newVariab var symbol = model.GetDeclaredSymbol(node, cancellationToken); + // TODO: this is incorrect (https://github.com/dotnet/roslyn/issues/54800) // Ignore partial method definition parts. // Partial method that does not have implementation part is not emitted to metadata. // Partial method without a definition part is a compilation error. @@ -1880,6 +1902,7 @@ internal override string GetDisplayName(IMethodSymbol symbol) { // top-level + case SyntaxKind.CompilationUnit: case SyntaxKind.GlobalStatement: return CSharpFeaturesResources.global_statement; @@ -2238,8 +2261,6 @@ public void ClassifyEdit() } } - #region Move and Reorder - private void ClassifyMove(SyntaxNode newNode) { if (newNode.IsKind(SyntaxKind.LocalFunctionStatement)) @@ -2261,38 +2282,6 @@ private void ClassifyReorder(SyntaxNode newNode) switch (newNode.Kind()) { - case SyntaxKind.GlobalStatement: - return; - - case SyntaxKind.ExternAliasDirective: - case SyntaxKind.UsingDirective: - case SyntaxKind.NamespaceDeclaration: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.StructDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.RecordDeclaration: - case SyntaxKind.RecordStructDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.DelegateDeclaration: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.ConversionOperatorDeclaration: - case SyntaxKind.OperatorDeclaration: - case SyntaxKind.ConstructorDeclaration: - case SyntaxKind.DestructorDeclaration: - case SyntaxKind.IndexerDeclaration: - case SyntaxKind.EventDeclaration: - case SyntaxKind.GetAccessorDeclaration: - case SyntaxKind.SetAccessorDeclaration: - case SyntaxKind.InitAccessorDeclaration: - case SyntaxKind.AddAccessorDeclaration: - case SyntaxKind.RemoveAccessorDeclaration: - case SyntaxKind.TypeParameterConstraintClause: - case SyntaxKind.AttributeList: - case SyntaxKind.Attribute: - // We'll ignore these edits. A general policy is to ignore edits that are only discoverable via reflection. - return; - case SyntaxKind.PropertyDeclaration: case SyntaxKind.FieldDeclaration: case SyntaxKind.EventFieldDeclaration: @@ -2311,38 +2300,19 @@ private void ClassifyReorder(SyntaxNode newNode) case SyntaxKind.Parameter: ReportError(RudeEditKind.Move); return; - - default: - throw ExceptionUtilities.UnexpectedValue(newNode.Kind()); } } - #endregion - - #region Insert - private void ClassifyInsert(SyntaxNode node) { switch (node.Kind()) { - case SyntaxKind.GlobalStatement: - // An insert of a global statement is actually an update to the synthesized main so we need to check some extra things - ClassifyUpdate((GlobalStatementSyntax)node); - return; - case SyntaxKind.ExternAliasDirective: case SyntaxKind.NamespaceDeclaration: + case SyntaxKind.FileScopedNamespaceDeclaration: ReportError(RudeEditKind.Insert); return; - case SyntaxKind.ArrowExpressionClause: - if (node.Parent.IsKind(SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration)) - { - return; - } - - break; - case SyntaxKind.Attribute: case SyntaxKind.AttributeList: // To allow inserting of attributes we need to check if the inserted attribute @@ -2359,33 +2329,18 @@ private void ClassifyInsert(SyntaxNode node) } } - #endregion - - #region Delete - private void ClassifyDelete(SyntaxNode oldNode) { switch (oldNode.Kind()) { - case SyntaxKind.GlobalStatement: - return; - case SyntaxKind.ExternAliasDirective: case SyntaxKind.NamespaceDeclaration: + case SyntaxKind.FileScopedNamespaceDeclaration: // To allow removal of declarations we would need to update method bodies that // were previously binding to them but now are binding to another symbol that was previously hidden. ReportError(RudeEditKind.Delete); return; - case SyntaxKind.ArrowExpressionClause: - // We do not report error here since it will be reported in semantic analysis. - if (oldNode.Parent.IsKind(SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration)) - { - return; - } - - break; - case SyntaxKind.AttributeList: case SyntaxKind.Attribute: // To allow removal of attributes we need to check if the removed attribute @@ -2402,18 +2357,10 @@ private void ClassifyDelete(SyntaxNode oldNode) } } - #endregion - - #region Update - private void ClassifyUpdate(SyntaxNode oldNode, SyntaxNode newNode) { switch (newNode.Kind()) { - case SyntaxKind.GlobalStatement: - ClassifyUpdate((GlobalStatementSyntax)newNode); - return; - case SyntaxKind.ExternAliasDirective: ReportError(RudeEditKind.Update); return; @@ -2423,58 +2370,6 @@ private void ClassifyUpdate(SyntaxNode oldNode, SyntaxNode newNode) ClassifyUpdate((BaseNamespaceDeclarationSyntax)oldNode, (BaseNamespaceDeclarationSyntax)newNode); return; - case SyntaxKind.VariableDeclaration: - if (!oldNode.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration)) - { - ClassifyUpdate((VariableDeclarationSyntax)oldNode, (VariableDeclarationSyntax)newNode); - } - - return; - - case SyntaxKind.VariableDeclarator: - ClassifyUpdate((VariableDeclaratorSyntax)oldNode, (VariableDeclaratorSyntax)newNode); - return; - - case SyntaxKind.MethodDeclaration: - ClassifyUpdate((MethodDeclarationSyntax)oldNode, (MethodDeclarationSyntax)newNode); - return; - - case SyntaxKind.ConversionOperatorDeclaration: - ClassifyUpdate((ConversionOperatorDeclarationSyntax)oldNode, (ConversionOperatorDeclarationSyntax)newNode); - return; - - case SyntaxKind.OperatorDeclaration: - ClassifyUpdate((OperatorDeclarationSyntax)oldNode, (OperatorDeclarationSyntax)newNode); - return; - - case SyntaxKind.ConstructorDeclaration: - ClassifyUpdate((ConstructorDeclarationSyntax)oldNode, (ConstructorDeclarationSyntax)newNode); - return; - - case SyntaxKind.DestructorDeclaration: - ClassifyUpdate((DestructorDeclarationSyntax)oldNode, (DestructorDeclarationSyntax)newNode); - return; - - case SyntaxKind.PropertyDeclaration: - ClassifyUpdate((PropertyDeclarationSyntax)oldNode, (PropertyDeclarationSyntax)newNode); - return; - - case SyntaxKind.IndexerDeclaration: - ClassifyUpdate((IndexerDeclarationSyntax)oldNode, (IndexerDeclarationSyntax)newNode); - return; - - case SyntaxKind.EnumMemberDeclaration: - ClassifyUpdate((EnumMemberDeclarationSyntax)oldNode, (EnumMemberDeclarationSyntax)newNode); - return; - - case SyntaxKind.GetAccessorDeclaration: - case SyntaxKind.SetAccessorDeclaration: - case SyntaxKind.InitAccessorDeclaration: - case SyntaxKind.AddAccessorDeclaration: - case SyntaxKind.RemoveAccessorDeclaration: - ClassifyUpdate((AccessorDeclarationSyntax)oldNode, (AccessorDeclarationSyntax)newNode); - return; - case SyntaxKind.Attribute: // To allow update of attributes we need to check if the updated attribute // is a pseudo-custom attribute that CLR allows us to change, or if it is a compiler well-know attribute @@ -2490,230 +2385,12 @@ private void ClassifyUpdate(SyntaxNode oldNode, SyntaxNode newNode) } } - private void ClassifyUpdate(GlobalStatementSyntax node) - { - ClassifyDeclarationBodyRudeUpdates(node.Statement); - } - private void ClassifyUpdate(BaseNamespaceDeclarationSyntax oldNode, BaseNamespaceDeclarationSyntax newNode) { Debug.Assert(!SyntaxFactory.AreEquivalent(oldNode.Name, newNode.Name)); ReportError(RudeEditKind.Renamed); } - private void ClassifyUpdate(VariableDeclarationSyntax oldNode, VariableDeclarationSyntax newNode) - { - if (!SyntaxFactory.AreEquivalent(oldNode.Type, newNode.Type)) - { - ReportError(RudeEditKind.TypeUpdate); - return; - } - } - - private void ClassifyUpdate(VariableDeclaratorSyntax oldNode, VariableDeclaratorSyntax newNode) - { - // If the argument lists are mismatched the field must have mismatched "fixed" modifier, - // which is reported by the field declaration. - if (oldNode.ArgumentList is null == newNode.ArgumentList is null) - { - if (!SyntaxFactory.AreEquivalent(oldNode.ArgumentList, newNode.ArgumentList)) - { - ReportError(RudeEditKind.FixedSizeFieldUpdate); - return; - } - } - - var typeDeclaration = (TypeDeclarationSyntax?)oldNode.Parent!.Parent!.Parent!; - if (typeDeclaration.Arity > 0) - { - ReportError(RudeEditKind.GenericTypeInitializerUpdate); - return; - } - - // Check if a constant field is updated: - var fieldDeclaration = (BaseFieldDeclarationSyntax)oldNode.Parent.Parent; - if (fieldDeclaration.Modifiers.Any(SyntaxKind.ConstKeyword)) - { - ReportError(RudeEditKind.Update); - return; - } - - ClassifyDeclarationBodyRudeUpdates(newNode); - } - - private void ClassifyUpdate(MethodDeclarationSyntax oldNode, MethodDeclarationSyntax newNode) - { - ClassifyMethodBodyRudeUpdate( - (SyntaxNode?)oldNode.Body ?? oldNode.ExpressionBody?.Expression, - (SyntaxNode?)newNode.Body ?? newNode.ExpressionBody?.Expression, - containingMethod: newNode, - containingType: (TypeDeclarationSyntax?)newNode.Parent); - } - - private void ClassifyUpdate(ConversionOperatorDeclarationSyntax oldNode, ConversionOperatorDeclarationSyntax newNode) - { - ClassifyMethodBodyRudeUpdate( - (SyntaxNode?)oldNode.Body ?? oldNode.ExpressionBody?.Expression, - (SyntaxNode?)newNode.Body ?? newNode.ExpressionBody?.Expression, - containingMethod: null, - containingType: (TypeDeclarationSyntax?)newNode.Parent); - } - - private void ClassifyUpdate(OperatorDeclarationSyntax oldNode, OperatorDeclarationSyntax newNode) - { - ClassifyMethodBodyRudeUpdate( - (SyntaxNode?)oldNode.Body ?? oldNode.ExpressionBody?.Expression, - (SyntaxNode?)newNode.Body ?? newNode.ExpressionBody?.Expression, - containingMethod: null, - containingType: (TypeDeclarationSyntax?)newNode.Parent); - } - - private void ClassifyUpdate(AccessorDeclarationSyntax oldNode, AccessorDeclarationSyntax newNode) - { - if (oldNode.Kind() != newNode.Kind()) - { - return; - } - - RoslynDebug.Assert(newNode.Parent is AccessorListSyntax); - RoslynDebug.Assert(newNode.Parent.Parent is BasePropertyDeclarationSyntax); - - ClassifyMethodBodyRudeUpdate( - (SyntaxNode?)oldNode.Body ?? oldNode.ExpressionBody?.Expression, - (SyntaxNode?)newNode.Body ?? newNode.ExpressionBody?.Expression, - containingMethod: null, - containingType: (TypeDeclarationSyntax?)newNode.Parent.Parent.Parent); - } - - private void ClassifyUpdate(EnumMemberDeclarationSyntax oldNode, EnumMemberDeclarationSyntax newNode) - { - if (!SyntaxFactory.AreEquivalent(oldNode.EqualsValue, newNode.EqualsValue)) - { - ReportError(RudeEditKind.InitializerUpdate); - return; - } - - // Attributes are processed during semantic analysis - } - - private void ClassifyUpdate(ConstructorDeclarationSyntax oldNode, ConstructorDeclarationSyntax newNode) - { - ClassifyMethodBodyRudeUpdate( - (SyntaxNode?)oldNode.Body ?? oldNode.ExpressionBody?.Expression, - (SyntaxNode?)newNode.Body ?? newNode.ExpressionBody?.Expression, - containingMethod: null, - containingType: (TypeDeclarationSyntax?)newNode.Parent); - } - - private void ClassifyUpdate(DestructorDeclarationSyntax oldNode, DestructorDeclarationSyntax newNode) - { - ClassifyMethodBodyRudeUpdate( - (SyntaxNode?)oldNode.Body ?? oldNode.ExpressionBody?.Expression, - (SyntaxNode?)newNode.Body ?? newNode.ExpressionBody?.Expression, - containingMethod: null, - containingType: (TypeDeclarationSyntax?)newNode.Parent); - } - - private void ClassifyUpdate(PropertyDeclarationSyntax oldNode, PropertyDeclarationSyntax newNode) - { - var containingType = (TypeDeclarationSyntax)newNode.Parent!; - - // TODO: We currently don't support switching from auto-props to properties with accessors and vice versa. - // If we do we should also allow it for expression bodies. - - if (!SyntaxFactory.AreEquivalent(oldNode.ExpressionBody, newNode.ExpressionBody)) - { - var oldBody = SyntaxUtilities.TryGetEffectiveGetterBody(oldNode.ExpressionBody, oldNode.AccessorList); - var newBody = SyntaxUtilities.TryGetEffectiveGetterBody(newNode.ExpressionBody, newNode.AccessorList); - - ClassifyMethodBodyRudeUpdate( - oldBody, - newBody, - containingMethod: null, - containingType: containingType); - - return; - } - - if (!SyntaxFactory.AreEquivalent(oldNode.Initializer, newNode.Initializer)) - { - if (containingType.Arity > 0) - { - ReportError(RudeEditKind.GenericTypeInitializerUpdate); - return; - } - - if (newNode.Initializer != null) - { - ClassifyDeclarationBodyRudeUpdates(newNode.Initializer); - } - } - } - - private void ClassifyUpdate(IndexerDeclarationSyntax oldNode, IndexerDeclarationSyntax newNode) - { - if (SyntaxFactory.AreEquivalent(oldNode.ExpressionBody, newNode.ExpressionBody)) - { - var oldBody = SyntaxUtilities.TryGetEffectiveGetterBody(oldNode.ExpressionBody, oldNode.AccessorList); - var newBody = SyntaxUtilities.TryGetEffectiveGetterBody(newNode.ExpressionBody, newNode.AccessorList); - - ClassifyMethodBodyRudeUpdate( - oldBody, - newBody, - containingMethod: null, - containingType: (TypeDeclarationSyntax?)newNode.Parent); - } - } - - private void ClassifyMethodBodyRudeUpdate( - SyntaxNode? oldBody, - SyntaxNode? newBody, - MethodDeclarationSyntax? containingMethod, - TypeDeclarationSyntax? containingType) - { - Debug.Assert(oldBody is BlockSyntax || oldBody is ExpressionSyntax || oldBody == null); - Debug.Assert(newBody is BlockSyntax || newBody is ExpressionSyntax || newBody == null); - - if ((oldBody == null) != (newBody == null)) - { - if (oldBody == null) - { - ReportError(RudeEditKind.MethodBodyAdd); - return; - } - else - { - ReportError(RudeEditKind.MethodBodyDelete); - return; - } - } - - ClassifyMemberBodyRudeUpdate(containingMethod, containingType, isTriviaUpdate: false); - - if (newBody != null) - { - ClassifyDeclarationBodyRudeUpdates(newBody); - } - } - - public void ClassifyMemberBodyRudeUpdate( - MethodDeclarationSyntax? containingMethod, - TypeDeclarationSyntax? containingType, - bool isTriviaUpdate) - { - if (SyntaxUtilities.Any(containingMethod?.TypeParameterList)) - { - ReportError(isTriviaUpdate ? RudeEditKind.GenericMethodTriviaUpdate : RudeEditKind.GenericMethodUpdate); - return; - } - - if (SyntaxUtilities.Any(containingType?.TypeParameterList)) - { - ReportError(isTriviaUpdate ? RudeEditKind.GenericTypeTriviaUpdate : RudeEditKind.GenericTypeUpdate); - return; - } - } - public void ClassifyDeclarationBodyRudeUpdates(SyntaxNode newDeclarationOrBody) { foreach (var node in newDeclarationOrBody.DescendantNodesAndSelf(LambdaUtilities.IsNotLambda)) @@ -2727,8 +2404,6 @@ public void ClassifyDeclarationBodyRudeUpdates(SyntaxNode newDeclarationOrBody) } } } - - #endregion } internal override void ReportTopLevelSyntacticRudeEdits( @@ -2746,15 +2421,9 @@ internal override void ReportTopLevelSyntacticRudeEdits( classifier.ClassifyEdit(); } - internal override void ReportMemberUpdateRudeEdits(ArrayBuilder diagnostics, SyntaxNode newMember, TextSpan? span) + internal override void ReportMemberBodyUpdateRudeEdits(ArrayBuilder diagnostics, SyntaxNode newMember, TextSpan? span) { var classifier = new EditClassifier(this, diagnostics, oldNode: null, newMember, EditKind.Update, span: span); - - classifier.ClassifyMemberBodyRudeUpdate( - newMember as MethodDeclarationSyntax, - newMember.FirstAncestorOrSelf(), - isTriviaUpdate: true); - classifier.ClassifyDeclarationBodyRudeUpdates(newMember); } diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 8fe1d00a96ea2..176a52ebd9c13 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -287,6 +287,9 @@ protected virtual bool StateMachineSuspensionPointKindEquals(SyntaxNode suspensi /// protected abstract IEnumerable GetVariableUseSites(IEnumerable roots, ISymbol localOrParameter, SemanticModel model, CancellationToken cancellationToken); + protected abstract bool AreFixedSizeBufferSizesEqual(IFieldSymbol oldField, IFieldSymbol newField, CancellationToken cancellationToken); + protected abstract bool AreHandledEventsEqual(IMethodSymbol oldMethod, IMethodSymbol newMethod); + // diagnostic spans: protected abstract TextSpan? TryGetDiagnosticSpan(SyntaxNode node, EditKind editKind); @@ -400,7 +403,7 @@ protected virtual string GetSuspensionPointDisplayName(SyntaxNode node, EditKind internal abstract void ReportTopLevelSyntacticRudeEdits(ArrayBuilder diagnostics, Match match, Edit edit, Dictionary editMap); internal abstract void ReportEnclosingExceptionHandlingRudeEdits(ArrayBuilder diagnostics, IEnumerable> exceptionHandlingEdits, SyntaxNode oldStatement, TextSpan newStatementSpan); internal abstract void ReportOtherRudeEditsAroundActiveStatement(ArrayBuilder diagnostics, Match match, SyntaxNode oldStatement, SyntaxNode newStatement, bool isNonLeaf); - internal abstract void ReportMemberUpdateRudeEdits(ArrayBuilder diagnostics, SyntaxNode newMember, TextSpan? span); + internal abstract void ReportMemberBodyUpdateRudeEdits(ArrayBuilder diagnostics, SyntaxNode newMember, TextSpan? span); internal abstract void ReportInsertedMemberSymbolRudeEdits(ArrayBuilder diagnostics, ISymbol newSymbol, SyntaxNode newNode, bool insertingIntoExistingContainingType); internal abstract void ReportStateMachineSuspensionPointRudeEdits(ArrayBuilder diagnostics, SyntaxNode oldNode, SyntaxNode newNode); @@ -604,30 +607,17 @@ public async Task AnalyzeDocumentAsync( cancellationToken.ThrowIfCancellationRequested(); - using var _3 = ArrayBuilder<(SyntaxNode OldNode, SyntaxNode NewNode)>.GetInstance(out var triviaEdits); + using var _3 = ArrayBuilder<(SyntaxNode OldNode, SyntaxNode NewNode, TextSpan DiagnosticSpan)>.GetInstance(out var triviaEdits); using var _4 = ArrayBuilder.GetInstance(out var lineEdits); - // Do not analyze trivia in presence of syntactic rude edits. - // The implementation depends on edit map capturing all updates and inserts, - // which might not be the case when rude edits are reported. - if (diagnostics.Count == 0) - { - AnalyzeTrivia( - topMatch, - editMap, - triviaEdits, - lineEdits, - diagnostics, - cancellationToken); - - if (diagnostics.Count > 0 && !hasRudeEdits) - { - DocumentAnalysisResults.Log.Write("{0} trivia rude edits, first: {1}@{2}", diagnostics.Count, newDocument.FilePath, diagnostics.First().Span.Start); - hasRudeEdits = true; - } + AnalyzeTrivia( + topMatch, + editMap, + triviaEdits, + lineEdits, + cancellationToken); - cancellationToken.ThrowIfCancellationRequested(); - } + cancellationToken.ThrowIfCancellationRequested(); var oldActiveStatements = (oldTree == null) ? ImmutableArray.Empty : oldActiveStatementMap.GetOldActiveStatements(this, oldTree, oldText, oldRoot, cancellationToken); @@ -705,11 +695,6 @@ private void ReportTopLevelSyntacticRudeEdits(ArrayBuilder d /// internal virtual void ReportDeclarationInsertDeleteRudeEdits(ArrayBuilder diagnostics, SyntaxNode oldNode, SyntaxNode newNode, ISymbol oldSymbol, ISymbol newSymbol, CancellationToken cancellationToken) { - if (oldSymbol is ITypeParameterSymbol or IParameterSymbol) - { - return; - } - // When a method is moved to a different declaration and its parameters are changed at the same time // the new method symbol key will not resolve to the old one since the parameters are different. // As a result we will report separate delete and insert rude edits. @@ -723,25 +708,7 @@ internal virtual void ReportDeclarationInsertDeleteRudeEdits(ArrayBuilder BuildEditMap(EditScript editScript) @@ -974,6 +941,8 @@ private void AnalyzeChangedMemberBody( try { + ReportMemberBodyUpdateRudeEdits(diagnostics, newDeclaration, GetDiagnosticSpan(newDeclaration, EditKind.Update)); + _testFaultInjector?.Invoke(newBody); // Populated with active lambdas and matched lambdas. @@ -2036,13 +2005,10 @@ private static int IndexOfEquivalent(SyntaxNode newNode, List topMatch, IReadOnlyDictionary editMap, - [Out] ArrayBuilder<(SyntaxNode OldNode, SyntaxNode NewNode)> triviaEdits, + [Out] ArrayBuilder<(SyntaxNode OldNode, SyntaxNode NewNode, TextSpan DiagnosticSpan)> triviaEdits, [Out] ArrayBuilder lineEdits, - [Out] ArrayBuilder diagnostics, CancellationToken cancellationToken) { - Debug.Assert(diagnostics.Count == 0); - var oldTree = topMatch.OldRoot.SyntaxTree; var newTree = topMatch.NewRoot.SyntaxTree; @@ -2211,8 +2177,6 @@ void AddCurrentSegment() // All tokens of a member body have been processed now. if (requiresUpdate) { - triviaEdits.Add((oldNode, newNode)); - // report the rude edit for the span of tokens that forced recompilation: if (rudeEditSpan.IsEmpty) { @@ -2221,7 +2185,7 @@ void AddCurrentSegment() newTokensEnum.Current.SpanStart); } - ReportMemberUpdateRudeEdits(diagnostics, newNode, rudeEditSpan); + triviaEdits.Add((oldNode, newNode, rudeEditSpan)); // remove all segments added for the current member body: segments.Count = firstSegmentIndex; @@ -2274,8 +2238,7 @@ void AddCurrentSegment() { // The segment overlaps the previous one that has a different line delta. We need to recompile the method. // The debugger filters out line deltas that correspond to recompiled methods so we don't need to. - triviaEdits.Add((segment.oldNode, segment.newNode)); - ReportMemberUpdateRudeEdits(diagnostics, segment.newNode, span: null); + triviaEdits.Add((segment.oldNode, segment.newNode, segment.newNode.Span)); continue; } @@ -2358,6 +2321,9 @@ public int GetHashCode(IAssemblySymbol? obj) private static readonly SymbolEquivalenceComparer s_exactSymbolEqualityComparer = new( AssemblyEqualityComparer.Instance, distinguishRefFromOut: true, tupleNamesMustMatch: true, ignoreNullableAnnotations: false); + protected static bool SymbolsEquivalent(ISymbol oldSymbol, ISymbol newSymbol) + => s_exactSymbolEqualityComparer.Equals(oldSymbol, newSymbol); + protected static bool SignaturesEquivalent(ImmutableArray oldParameters, ITypeSymbol oldReturnType, ImmutableArray newParameters, ITypeSymbol newReturnType) => ParametersEquivalent(oldParameters, newParameters, exact: false) && s_runtimeSymbolEqualityComparer.Equals(oldReturnType, newReturnType); // TODO: should check ref, ref readonly, custom mods @@ -2369,18 +2335,21 @@ protected static bool CustomModifiersEquivalent(CustomModifier oldModifier, Cust => oldModifier.IsOptional == newModifier.IsOptional && TypesEquivalent(oldModifier.Modifier, newModifier.Modifier, exact); + protected static bool CustomModifiersEquivalent(ImmutableArray oldModifiers, ImmutableArray newModifiers, bool exact) + => oldModifiers.SequenceEqual(newModifiers, exact, (x, y, exact) => CustomModifiersEquivalent(x, y, exact)); + protected static bool ReturnTypesEquivalent(IMethodSymbol oldMethod, IMethodSymbol newMethod, bool exact) => oldMethod.ReturnsByRef == newMethod.ReturnsByRef && oldMethod.ReturnsByRefReadonly == newMethod.ReturnsByRefReadonly && - oldMethod.ReturnTypeCustomModifiers.SequenceEqual(newMethod.ReturnTypeCustomModifiers, exact, (x, y, exact) => CustomModifiersEquivalent(x, y, exact)) && - oldMethod.RefCustomModifiers.SequenceEqual(newMethod.RefCustomModifiers, exact, (x, y, exact) => CustomModifiersEquivalent(x, y, exact)) && + CustomModifiersEquivalent(oldMethod.ReturnTypeCustomModifiers, newMethod.ReturnTypeCustomModifiers, exact) && + CustomModifiersEquivalent(oldMethod.RefCustomModifiers, newMethod.RefCustomModifiers, exact) && TypesEquivalent(oldMethod.ReturnType, newMethod.ReturnType, exact); protected static bool ReturnTypesEquivalent(IPropertySymbol oldProperty, IPropertySymbol newProperty, bool exact) => oldProperty.ReturnsByRef == newProperty.ReturnsByRef && oldProperty.ReturnsByRefReadonly == newProperty.ReturnsByRefReadonly && - oldProperty.TypeCustomModifiers.SequenceEqual(newProperty.TypeCustomModifiers, exact, (x, y, exact) => CustomModifiersEquivalent(x, y, exact)) && - oldProperty.RefCustomModifiers.SequenceEqual(newProperty.RefCustomModifiers, exact, (x, y, exact) => CustomModifiersEquivalent(x, y, exact)) && + CustomModifiersEquivalent(oldProperty.TypeCustomModifiers, newProperty.TypeCustomModifiers, exact) && + CustomModifiersEquivalent(oldProperty.RefCustomModifiers, newProperty.RefCustomModifiers, exact) && TypesEquivalent(oldProperty.Type, newProperty.Type, exact); protected static bool ReturnTypesEquivalent(IEventSymbol oldEvent, IEventSymbol newEvent, bool exact) @@ -2390,11 +2359,14 @@ protected static bool ReturnTypesEquivalent(IEventSymbol oldEvent, IEventSymbol protected static bool TypesEquivalent(ITypeSymbol? oldType, ITypeSymbol? newType, bool exact) => (exact ? s_exactSymbolEqualityComparer : (IEqualityComparer)s_runtimeSymbolEqualityComparer.SignatureTypeEquivalenceComparer).Equals(oldType, newType); + protected static bool TypesEquivalent(ImmutableArray oldTypes, ImmutableArray newTypes, bool exact) where T : ITypeSymbol + => oldTypes.SequenceEqual(newTypes, exact, (x, y, exact) => TypesEquivalent(x, y, exact)); + protected static bool ParameterTypesEquivalent(IParameterSymbol oldParameter, IParameterSymbol newParameter, bool exact) => (exact ? s_exactSymbolEqualityComparer : s_runtimeSymbolEqualityComparer).ParameterEquivalenceComparer.Equals(oldParameter, newParameter); protected static bool TypeParameterConstraintsEquivalent(ITypeParameterSymbol oldParameter, ITypeParameterSymbol newParameter, bool exact) - => oldParameter.ConstraintTypes.SequenceEqual(newParameter.ConstraintTypes, exact, (x, y, exact) => TypesEquivalent(x, y, exact)) && + => TypesEquivalent(oldParameter.ConstraintTypes, newParameter.ConstraintTypes, exact) && oldParameter.HasReferenceTypeConstraint == newParameter.HasReferenceTypeConstraint && oldParameter.HasValueTypeConstraint == newParameter.HasValueTypeConstraint && oldParameter.HasConstructorConstraint == newParameter.HasConstructorConstraint && @@ -2407,7 +2379,7 @@ protected static bool TypeParametersEquivalent(ImmutableArray TypesEquivalent(oldType.BaseType, newType.BaseType, exact) && - oldType.AllInterfaces.SequenceEqual(newType.AllInterfaces, exact, (x, y, exact) => TypesEquivalent(x, y, exact)); + TypesEquivalent(oldType.AllInterfaces, newType.AllInterfaces, exact); protected static bool MemberSignaturesEquivalent( ISymbol? oldMember, @@ -2470,7 +2442,7 @@ private async Task> AnalyzeSemanticsAsync( IReadOnlyDictionary editMap, ImmutableArray oldActiveStatements, ImmutableArray newActiveStatementSpans, - IReadOnlyList<(SyntaxNode OldNode, SyntaxNode NewNode)> triviaEdits, + IReadOnlyList<(SyntaxNode OldNode, SyntaxNode NewNode, TextSpan DiagnosticSpan)> triviaEdits, Project oldProject, Document? oldDocument, Document newDocument, @@ -2553,19 +2525,14 @@ private async Task> AnalyzeSemanticsAsync( // Treat the edit as Insert/Delete. This may happen e.g. when all C# global statements are removed, the first one is added or they are moved to another file. if (syntacticEditKind == EditKind.Update) { - if (oldSymbol == null) + if (oldSymbol == null || oldDeclaration != null && oldDeclaration.SyntaxTree != oldModel?.SyntaxTree) { syntacticEditKind = EditKind.Insert; } - else if (newSymbol == null) + else if (newSymbol == null || newDeclaration != null && newDeclaration.SyntaxTree != newModel.SyntaxTree) { syntacticEditKind = EditKind.Delete; } - else if (oldDeclaration != null && oldModel != null && oldDeclaration.SyntaxTree != oldModel.SyntaxTree || - newDeclaration != null && newDeclaration.SyntaxTree != newModel.SyntaxTree) - { - syntacticEditKind = edit.Kind; - } } switch (syntacticEditKind) @@ -3035,24 +3002,7 @@ private async Task> AnalyzeSemanticsAsync( Contract.ThrowIfNull(oldSymbol); AnalyzeSymbolUpdate(oldSymbol, newSymbol, edit.NewNode, newCompilation, capabilities, diagnostics, semanticEdits, syntaxMap, cancellationToken); - - // The only update to the type itself that's supported is an addition or removal of the partial modifier, - // which does not have impact on the emitted type metadata. - if (newSymbol is INamedTypeSymbol) - { - continue; - } - - // The field/property/event itself is being updated. Currently we do not allow any modifiers to be updated. - // Attribute updates will have been handled already. - if (newSymbol is IFieldSymbol or IPropertySymbol or IEventSymbol) - { - continue; - } - - // The only updates allowed for a parameter or type parameter is an attribute change, but we only need the edit - // for the containing symbol which will be handled elsewhere. - if (newSymbol is IParameterSymbol or ITypeParameterSymbol) + if (newSymbol is INamedTypeSymbol or IFieldSymbol or IPropertySymbol or IEventSymbol or IParameterSymbol or ITypeParameterSymbol) { continue; } @@ -3064,7 +3014,7 @@ private async Task> AnalyzeSemanticsAsync( } } - foreach (var (oldEditNode, newEditNode) in triviaEdits) + foreach (var (oldEditNode, newEditNode, diagnosticSpan) in triviaEdits) { Contract.ThrowIfNull(oldModel); Contract.ThrowIfNull(newModel); @@ -3120,6 +3070,16 @@ private async Task> AnalyzeSemanticsAsync( continue; } + ReportMemberBodyUpdateRudeEdits(diagnostics, newDeclaration, diagnosticSpan); + + // updating generic methods and types + if (InGenericContext(oldSymbol, out var oldIsGenericMethod)) + { + var rudeEdit = oldIsGenericMethod ? RudeEditKind.GenericMethodTriviaUpdate : RudeEditKind.GenericTypeTriviaUpdate; + diagnostics.Add(new RudeEditDiagnostic(rudeEdit, diagnosticSpan, newEditNode, new[] { GetDisplayName(newEditNode) })); + continue; + } + // Edits in data member initializers and constructors are deferred, edits of other members (even on partial types) // do not need merging accross partial type declarations. var symbolKey = SymbolKey.Create(newSymbol, cancellationToken); @@ -3247,7 +3207,8 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( if (oldSymbol.IsStatic != newSymbol.IsStatic || oldSymbol.IsVirtual != newSymbol.IsVirtual || oldSymbol.IsAbstract != newSymbol.IsAbstract || - oldSymbol.IsOverride != newSymbol.IsOverride) + oldSymbol.IsOverride != newSymbol.IsOverride || + oldSymbol.IsExtern != newSymbol.IsExtern) { // Do not report for accessors as the error will be reported on their associated symbol. if (oldSymbol is not IMethodSymbol { AssociatedSymbol: not null }) @@ -3265,6 +3226,21 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( rudeEdit = RudeEditKind.ModifiersUpdate; } + // Report rude edit for updating const fields and values of enums. + // The latter is only reported whne the enum underlying type does not change to avoid cascading rude edits. + if (oldField.IsConst && newField.IsConst && !Equals(oldField.ConstantValue, newField.ConstantValue) && + TypesEquivalent(oldField.ContainingType.EnumUnderlyingType, newField.ContainingType.EnumUnderlyingType, exact: false)) + { + rudeEdit = RudeEditKind.InitializerUpdate; + } + + if (oldField.IsFixedSizeBuffer && + newField.IsFixedSizeBuffer && + !AreFixedSizeBufferSizesEqual(oldField, newField, cancellationToken)) + { + rudeEdit = RudeEditKind.FixedSizeFieldUpdate; + } + AnalyzeType(oldField.Type, newField.Type, ref rudeEdit, ref hasGeneratedAttributeChange); } else if (oldSymbol is IMethodSymbol oldMethod && newSymbol is IMethodSymbol newMethod) @@ -3312,6 +3288,18 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( } } + // VB implements clause + if (!oldMethod.ExplicitInterfaceImplementations.SequenceEqual(newMethod.ExplicitInterfaceImplementations, (x, y) => SymbolsEquivalent(x, y))) + { + rudeEdit = RudeEditKind.ImplementsClauseUpdate; + } + + // VB handles clause + if (!AreHandledEventsEqual(oldMethod, newMethod)) + { + rudeEdit = RudeEditKind.HandlesClauseUpdate; + } + // Check return type - do not report for accessors, their containing symbol will report the rude edits and attribute updates. if (rudeEdit == RudeEditKind.None && oldMethod.AssociatedSymbol == null && newMethod.AssociatedSymbol == null) { @@ -3550,6 +3538,13 @@ private void AnalyzeSymbolUpdate( { AddCustomAttributeSemanticEdits(semanticEdits, newSymbol, syntaxMap, hasAttributeChange, hasReturnTypeAttributeChange, cancellationToken); } + + // updating generic methods and types + if (InGenericContext(oldSymbol, out var oldIsGenericMethod) || InGenericContext(newSymbol, out _)) + { + var rudeEdit = oldIsGenericMethod ? RudeEditKind.GenericMethodUpdate : RudeEditKind.GenericTypeUpdate; + ReportUpdateRudeEdit(diagnostics, rudeEdit, newSymbol, newNode, cancellationToken); + } } private static void AddCustomAttributeSemanticEdits( @@ -3874,7 +3869,12 @@ private void ReportUpdateRudeEdit(ArrayBuilder diagnostics, { var node = newNode ?? GetRudeEditDiagnosticNode(newSymbol, cancellationToken); var span = (rudeEdit == RudeEditKind.ChangeImplicitMainReturnType) ? GetGlobalStatementDiagnosticSpan(node) : GetDiagnosticSpan(node, EditKind.Update); - var arguments = (rudeEdit is RudeEditKind.TypeKindUpdate or RudeEditKind.ChangeImplicitMainReturnType) ? Array.Empty() : new[] { GetDisplayName(newSymbol) }; + + var arguments = (rudeEdit is + RudeEditKind.TypeKindUpdate or + RudeEditKind.ChangeImplicitMainReturnType or + RudeEditKind.GenericMethodUpdate or + RudeEditKind.GenericTypeUpdate) ? Array.Empty() : new[] { GetDisplayName(newSymbol) }; diagnostics.Add(new RudeEditDiagnostic(rudeEdit, span, node, arguments)); } @@ -4236,7 +4236,7 @@ static bool IsNotInDocument(SyntaxReference reference, SyntaxTree syntaxTree) (accumulate, node) => (node.SpanStart < accumulate.min) ? (node.SpanStart, node.Span) : accumulate).span; Contract.ThrowIfTrue(firstSpan.IsEmpty); - ReportMemberUpdateRudeEdits(diagnostics, newDeclaration, firstSpan); + ReportMemberBodyUpdateRudeEdits(diagnostics, newDeclaration, firstSpan); } // When explicitly implementing the copy constructor of a record the parameter name must match for symbol matching to work @@ -4251,9 +4251,8 @@ static bool IsNotInDocument(SyntaxReference reference, SyntaxTree syntaxTree) diagnostics.Add(new RudeEditDiagnostic( RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, GetDiagnosticSpan(newDeclaration, EditKind.Update), - arguments: new[] { - oldCtor.ToDisplayString(SymbolDisplayFormats.NameFormat) - })); + arguments: new[] { oldCtor.ToDisplayString(SymbolDisplayFormats.NameFormat) })); + continue; } } @@ -5226,7 +5225,7 @@ private void ReportStateMachineRudeEdits( #endregion - #region Helpers + #region Helpers private static SyntaxNode? TryGetNode(SyntaxNode root, int position) => root.FullSpan.Contains(position) ? root.FindToken(position).Parent : null; @@ -5287,6 +5286,33 @@ private static bool IsGlobalMain(ISymbol symbol) => symbol is IMethodSymbol { Name: WellKnownMemberNames.TopLevelStatementsEntryPointMethodName, ContainingType.Name: WellKnownMemberNames.TopLevelStatementsEntryPointTypeName }; #pragma warning restore format + private static bool InGenericContext(ISymbol symbol, out bool isGenericMethod) + { + var current = symbol; + + while (true) + { + if (current is IMethodSymbol { Arity: > 0 }) + { + isGenericMethod = true; + return true; + } + + if (current is INamedTypeSymbol { Arity: > 0 }) + { + isGenericMethod = false; + return true; + } + + current = current.ContainingSymbol; + if (current == null) + { + isGenericMethod = false; + return false; + } + } + } + #endregion #region Testing @@ -5323,17 +5349,6 @@ internal Match ComputeBodyMatch( { return _abstractEditAndContinueAnalyzer.ComputeBodyMatch(oldBody, newBody, activeNodes, diagnostics, out oldHasStateMachineSuspensionPoint, out newHasStateMachineSuspensionPoint); } - - internal void AnalyzeTrivia( - Match topMatch, - IReadOnlyDictionary editMap, - [Out] ArrayBuilder<(SyntaxNode OldNode, SyntaxNode NewNode)> triviaEdits, - [Out] ArrayBuilder lineEdits, - [Out] ArrayBuilder diagnostics, - CancellationToken cancellationToken) - { - _abstractEditAndContinueAnalyzer.AnalyzeTrivia(topMatch, editMap, triviaEdits, lineEdits, diagnostics, cancellationToken); - } } #endregion diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index bbc3e647a839d..edf44e821eef1 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -96,8 +96,6 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.InsertGenericMethod, nameof(FeaturesResources.Adding_a_generic_0_will_prevent_the_debug_session_from_continuing)); AddRudeEdit(RudeEditKind.Move, nameof(FeaturesResources.Moving_0_will_prevent_the_debug_session_from_continuing)); AddRudeEdit(RudeEditKind.Delete, nameof(FeaturesResources.Deleting_0_will_prevent_the_debug_session_from_continuing)); - AddRudeEdit(RudeEditKind.MethodBodyAdd, nameof(FeaturesResources.Adding_a_method_body_will_prevent_the_debug_session_from_continuing)); - AddRudeEdit(RudeEditKind.MethodBodyDelete, nameof(FeaturesResources.Deleting_a_method_body_will_prevent_the_debug_session_from_continuing)); AddRudeEdit(RudeEditKind.GenericMethodUpdate, nameof(FeaturesResources.Modifying_a_generic_method_will_prevent_the_debug_session_from_continuing)); AddRudeEdit(RudeEditKind.GenericMethodTriviaUpdate, nameof(FeaturesResources.Modifying_whitespace_or_comments_in_a_generic_0_will_prevent_the_debug_session_from_continuing)); AddRudeEdit(RudeEditKind.GenericTypeUpdate, nameof(FeaturesResources.Modifying_a_method_inside_the_context_of_a_generic_type_will_prevent_the_debug_session_from_continuing)); diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs index 6a641e23d4379..a976f5eb8e78a 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -47,8 +47,8 @@ internal enum RudeEditKind : ushort InsertIntoClassWithLayout = 31, Move = 32, Delete = 33, - MethodBodyAdd = 34, - MethodBodyDelete = 35, + // MethodBodyAdd = 34, + // MethodBodyDelete = 35, GenericMethodUpdate = 36, GenericMethodTriviaUpdate = 37, GenericTypeUpdate = 38, diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index 97bd53da30702..73ee20ce8e880 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -507,12 +507,6 @@ Deleting '{0}' around an active statement will prevent the debug session from continuing. - - Adding a method body will prevent the debug session from continuing. - - - Deleting a method body will prevent the debug session from continuing. - An active statement has been removed from its original method. You must revert your changes to continue or restart the debugging session. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 7d0d239fdc2d9..cc356be6ece44 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -3304,16 +3304,6 @@ Pokud se specifikátor formátu g použije bez dalších specifikátorů vlastn Odstranění prvku {0} v okolí aktivního příkazu zabrání v pokračování relace ladění. - - Adding a method body will prevent the debug session from continuing. - Přidání těla metody zabrání v pokračování relace ladění. - - - - Deleting a method body will prevent the debug session from continuing. - Odstranění těla metody zabrání v pokračování relace ladění. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. Aktualizace modifikátoru async nebo iterator kolem aktivního příkazu bude bránit relaci ladění v tom, aby pokračovala. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 339902abb3b37..be3144797f9e3 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -3304,16 +3304,6 @@ Bei Verwendung des Formatbezeichners "g" ohne weitere benutzerdefinierte Formatb Durch Löschen von "{0}" um eine aktive Anweisung herum wird verhindert, dass die Debuggingsitzung fortgesetzt wird. - - Adding a method body will prevent the debug session from continuing. - Durch Hinzufügen eines Methodenkörpers wird verhindert, dass die Debuggingsitzung fortgesetzt wird. - - - - Deleting a method body will prevent the debug session from continuing. - Durch Löschen eines Methodenkörpers wird verhindert, dass eine Debuggingsitzung fortgesetzt wird. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. Eine asynchrone Aktualisierung oder ein iteratormodifizierer um eine aktive Anweisung verhindert, dass die Debugsitzung fortgesetzt wird. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index bdc894f0c2e1a..eaa1749cb69f4 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -3304,16 +3304,6 @@ Si el especificador de formato "g" se usa sin otros especificadores de formato p Eliminar '{0}' en una instrucción activa impedirá que continúe la sesión de depuración. - - Adding a method body will prevent the debug session from continuing. - Agregar un cuerpo de método impedirá que continúe la sesión de depuración. - - - - Deleting a method body will prevent the debug session from continuing. - Eliminar un cuerpo de método impedirá que continúe la sesión de depuración. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. La actualización del modificador async o iterator en una instrucción activa impedirá que la sesión de depuración continúe. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index f92ccdedc18bf..3129470c0141e 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -3304,16 +3304,6 @@ Si le spécificateur de format "g" est utilisé sans autres spécificateurs de f La suppression de '{0}' autour d'une instruction active empêche la session de débogage de se poursuivre. - - Adding a method body will prevent the debug session from continuing. - L'ajout d'un corps de méthode empêche la session de débogage de se poursuivre. - - - - Deleting a method body will prevent the debug session from continuing. - La suppression d'un corps de méthode empêche la session de débogage de se poursuivre. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. La mise à jour d'un modificateur async ou iterator autour d'une instruction active empêche la session de débogage de se poursuivre. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 9d13a938e5066..819457a5f11b1 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -3304,16 +3304,6 @@ Se l'identificatore di formato "g" viene usato senza altri identificatori di for Se si elimina '{0}' in prossimità di un'istruzione attiva, la sessione di debug non potrà continuare. - - Adding a method body will prevent the debug session from continuing. - Se si aggiunge un corpo del metodo, la sessione di debug non potrà continuare. - - - - Deleting a method body will prevent the debug session from continuing. - Se si elimina un corpo del metodo, la sessione di debug non potrà continuare. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. Se si aggiorna un modificatore iterator o async in prossimità di un'istruzione attiva, la sessione di debug non potrà continuare. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 66d41c2fd01fe..16381ccc5f2c9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -3304,16 +3304,6 @@ If the "g" format specifier is used without other custom format specifiers, it's アクティブ ステートメントの前後の '{0}' を削除すると、デバッグ セッションは続行されません。 - - Adding a method body will prevent the debug session from continuing. - メソッド本体を追加すると、デバッグ セッションは続行されません。 - - - - Deleting a method body will prevent the debug session from continuing. - メソッド本体を削除すると、デバッグ セッションは続行されません。 - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. アクティブ ステートメントの前後の async 修飾子または iterator 修飾子を更新すると、デバッグ セッションが継続しなくなります。 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 4a5730dd76c44..1a5b762cd534d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -3304,16 +3304,6 @@ If the "g" format specifier is used without other custom format specifiers, it's 활성 문 주위에서 '{0}'을(를) 삭제하면 디버그 세션을 계속할 수 없습니다. - - Adding a method body will prevent the debug session from continuing. - 메서드 본문을 추가하면 디버그 세션을 계속할 수 없습니다. - - - - Deleting a method body will prevent the debug session from continuing. - 메서드 본문을 삭제하면 디버그 세션을 계속할 수 없습니다. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. 활성 문 주위의 async 또는 iterator 한정자를 업데이트하면 디버그 세션이 계속되지 않습니다. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 66f37d7e2207f..9a1aebfd64925 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -3304,16 +3304,6 @@ Jeśli specyfikator formatu „g” jest używany bez innych niestandardowych sp Usunięcie elementu „{0}” w ramach aktywnej instrukcji uniemożliwi kontynuowanie sesji debugowania. - - Adding a method body will prevent the debug session from continuing. - Dodanie treści metody uniemożliwi kontynuowanie sesji debugowania. - - - - Deleting a method body will prevent the debug session from continuing. - Usunięcie treści metody uniemożliwi kontynuowanie sesji debugowania. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. Aktualizowanie modyfikatora asynchronicznego lub powiązanego z iteratorem w pobliżu aktywnej instrukcji uniemożliwi kontynuowanie sesji debugowania. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index abb54b4699b88..055c7b78a3e82 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -3304,16 +3304,6 @@ Se o especificador de formato "g" for usado sem outros especificadores de format Excluir "{0}" em uma instrução ativa impedirá que a sessão de depuração continue. - - Adding a method body will prevent the debug session from continuing. - Adicionar um corpo do método impedirá que a sessão de depuração continue. - - - - Deleting a method body will prevent the debug session from continuing. - Excluir um corpo de método impedirá que a sessão de depuração continue. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. A atualização do modificador "async" ou "iterator" em torno de uma instrução ativa impedirá a sessão de depuração de continuar. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 11e679e57d815..cdb668ea6c403 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -3304,16 +3304,6 @@ If the "g" format specifier is used without other custom format specifiers, it's Удаление "{0}" рядом с активным оператором сделает продолжение сеанса отладки невозможным. - - Adding a method body will prevent the debug session from continuing. - Добавление тела метода сделает продолжение сеанса отладки невозможным. - - - - Deleting a method body will prevent the debug session from continuing. - Удаление тела метода сделает продолжение сеанса отладки невозможным. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. Обновление модификатора async или iterator рядом с активным оператором сделает продолжение сеанса отладки невозможным. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index f640b1efd5fb7..dfc553f36d4db 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -3304,16 +3304,6 @@ If the "g" format specifier is used without other custom format specifiers, it's Etkin bir deyimin etrafından '{0}' öğesini silme, hata ayıklama oturumunun devam etmesini engelleyecek. - - Adding a method body will prevent the debug session from continuing. - Bir yöntem gövdesi ekleme, hata ayıklama oturumunun devam etmesini engelleyecek. - - - - Deleting a method body will prevent the debug session from continuing. - Bir yöntem gövdesi silme, hata ayıklama oturumunun devam etmesini engelleyecek. - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. Etkin bir deyimin etrafındaki async ya da iterator değiştiricisini güncelleştirmek hata ayıklama oturumunun devam etmesini önler. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index eeb8e3f0073fe..8d5a4962c373a 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -3304,16 +3304,6 @@ If the "g" format specifier is used without other custom format specifiers, it's 删除活动语句周围的“{0}”将阻止调试会话继续。 - - Adding a method body will prevent the debug session from continuing. - 添加方法主体将阻止调试会话继续。 - - - - Deleting a method body will prevent the debug session from continuing. - 删除方法主体将阻止调试会话继续。 - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. 更新当前语句的 async 或 iterator 修饰符可以阻止调试会话继续。 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 7bfbd66b92237..2e434493caf66 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -3304,16 +3304,6 @@ If the "g" format specifier is used without other custom format specifiers, it's 刪除現用陳述式前後的 '{0}',會造成偵錯工作階段無法繼續。 - - Adding a method body will prevent the debug session from continuing. - 加入方法主體,會造成偵錯工作階段無法繼續。 - - - - Deleting a method body will prevent the debug session from continuing. - 刪除方法主體,會造成偵錯工作階段無法繼續。 - - Updating async or iterator modifier around an active statement will prevent the debug session from continuing. 更新作用中陳述式前後的 async 或 iterator 修飾元,會造成偵錯工作階段無法繼續。 diff --git a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb index 48c816486ac67..bd5083287b434 100644 --- a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb @@ -2289,52 +2289,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue ClassifyUpdate(DirectCast(oldNode, NamespaceStatementSyntax), DirectCast(newNode, NamespaceStatementSyntax)) Return - Case SyntaxKind.VariableDeclarator - ClassifyUpdate(DirectCast(oldNode, VariableDeclaratorSyntax), DirectCast(newNode, VariableDeclaratorSyntax)) - Return - - Case SyntaxKind.ModifiedIdentifier - ClassifyUpdate(DirectCast(newNode, ModifiedIdentifierSyntax)) - Return - - Case SyntaxKind.SubBlock, - SyntaxKind.FunctionBlock - ClassifyUpdate(DirectCast(oldNode, MethodBlockSyntax), DirectCast(newNode, MethodBlockSyntax)) - Return - - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement - ClassifyUpdate(DirectCast(oldNode, MethodStatementSyntax), DirectCast(newNode, MethodStatementSyntax)) - Return - - Case SyntaxKind.OperatorBlock - ClassifyUpdate(DirectCast(oldNode, OperatorBlockSyntax), DirectCast(newNode, OperatorBlockSyntax)) - Return - - Case SyntaxKind.ConstructorBlock - ClassifyUpdate(DirectCast(oldNode, ConstructorBlockSyntax), DirectCast(newNode, ConstructorBlockSyntax)) - Return - - Case SyntaxKind.PropertyStatement - ClassifyUpdate(DirectCast(oldNode, PropertyStatementSyntax), DirectCast(newNode, PropertyStatementSyntax)) - Return - - Case SyntaxKind.EventStatement - ClassifyUpdate(DirectCast(oldNode, EventStatementSyntax), DirectCast(newNode, EventStatementSyntax)) - Return - - Case SyntaxKind.GetAccessorBlock, - SyntaxKind.SetAccessorBlock, - SyntaxKind.AddHandlerAccessorBlock, - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxKind.RaiseEventAccessorBlock - ClassifyUpdate(DirectCast(oldNode, AccessorBlockSyntax), DirectCast(newNode, AccessorBlockSyntax)) - Return - - Case SyntaxKind.EnumMemberDeclaration - ClassifyUpdate(DirectCast(oldNode, EnumMemberDeclarationSyntax), DirectCast(newNode, EnumMemberDeclarationSyntax)) - Return - Case SyntaxKind.AttributesStatement ReportError(RudeEditKind.Update) Return @@ -2354,161 +2308,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue ReportError(RudeEditKind.Renamed) End Sub - Private Sub ClassifyUpdate(newNode As ModifiedIdentifierSyntax) - ' Otherwise only the size of the array changed, which is a legal initializer update - ' unless it contains lambdas, queries etc. - ClassifyDeclarationBodyRudeUpdates(newNode) - End Sub - - Private Sub ClassifyUpdate(oldNode As VariableDeclaratorSyntax, newNode As VariableDeclaratorSyntax) - Dim typeDeclaration = DirectCast(oldNode.Parent.Parent, TypeBlockSyntax) - If typeDeclaration.BlockStatement.Arity > 0 Then - ReportError(RudeEditKind.GenericTypeInitializerUpdate) - Return - End If - - If ClassifyTypeAndInitializerUpdates(oldNode.Initializer, - oldNode.AsClause, - newNode.Initializer, - newNode.AsClause) Then - ' Check if a constant field is updated: - Dim fieldDeclaration = DirectCast(oldNode.Parent, FieldDeclarationSyntax) - If fieldDeclaration.Modifiers.Any(SyntaxKind.ConstKeyword) Then - ReportError(RudeEditKind.Update) - Return - End If - End If - End Sub - - Private Sub ClassifyUpdate(oldNode As PropertyStatementSyntax, newNode As PropertyStatementSyntax) - If Not SyntaxFactory.AreEquivalent(oldNode.ImplementsClause, newNode.ImplementsClause) Then - ReportError(RudeEditKind.ImplementsClauseUpdate) - Return - End If - - If ClassifyTypeAndInitializerUpdates(oldNode.Initializer, oldNode.AsClause, newNode.Initializer, newNode.AsClause) Then - ' change in an initializer of an auto-property - Dim typeDeclaration = DirectCast(oldNode.Parent, TypeBlockSyntax) - If typeDeclaration.BlockStatement.Arity > 0 Then - ReportError(RudeEditKind.GenericTypeInitializerUpdate) - Return - End If - End If - End Sub - - ' Returns true if the initializer has changed. - Private Function ClassifyTypeAndInitializerUpdates(oldEqualsValue As EqualsValueSyntax, - oldClause As AsClauseSyntax, - newEqualsValue As EqualsValueSyntax, - newClause As AsClauseSyntax) As Boolean - - Dim oldInitializer = GetInitializerExpression(oldEqualsValue, oldClause) - Dim newInitializer = GetInitializerExpression(newEqualsValue, newClause) - - If newInitializer IsNot Nothing AndAlso Not SyntaxFactory.AreEquivalent(oldInitializer, newInitializer) Then - ClassifyDeclarationBodyRudeUpdates(newInitializer) - Return True - End If - - Return False - End Function - - Private Sub ClassifyUpdate(oldNode As EventStatementSyntax, newNode As EventStatementSyntax) - ' A custom event can't be matched with a field event and vice versa: - Debug.Assert(SyntaxFactory.AreEquivalent(oldNode.CustomKeyword, newNode.CustomKeyword)) - - If Not SyntaxFactory.AreEquivalent(oldNode.ImplementsClause, newNode.ImplementsClause) Then - ReportError(RudeEditKind.ImplementsClauseUpdate) - Return - End If - End Sub - - Private Sub ClassifyUpdate(oldNode As MethodBlockSyntax, newNode As MethodBlockSyntax) - ClassifyMethodBodyRudeUpdate(oldNode, - newNode, - containingMethod:=newNode, - containingType:=DirectCast(newNode.Parent, TypeBlockSyntax)) - End Sub - - Private Sub ClassifyUpdate(oldNode As MethodStatementSyntax, newNode As MethodStatementSyntax) - ' TODO (tomat): We can support this - If Not SyntaxFactory.AreEquivalent(oldNode.HandlesClause, newNode.HandlesClause) Then - ReportError(RudeEditKind.HandlesClauseUpdate) - Return - End If - - If Not SyntaxFactory.AreEquivalent(oldNode.ImplementsClause, newNode.ImplementsClause) Then - ReportError(RudeEditKind.ImplementsClauseUpdate) - Return - End If - End Sub - - Private Sub ClassifyUpdate(oldNode As OperatorBlockSyntax, newNode As OperatorBlockSyntax) - ClassifyMethodBodyRudeUpdate(oldNode, - newNode, - containingMethod:=Nothing, - containingType:=DirectCast(newNode.Parent, TypeBlockSyntax)) - End Sub - - Private Sub ClassifyUpdate(oldNode As AccessorBlockSyntax, newNode As AccessorBlockSyntax) - Debug.Assert(newNode.Parent.IsKind(SyntaxKind.EventBlock) OrElse - newNode.Parent.IsKind(SyntaxKind.PropertyBlock)) - - ClassifyMethodBodyRudeUpdate(oldNode, - newNode, - containingMethod:=Nothing, - containingType:=DirectCast(newNode.Parent.Parent, TypeBlockSyntax)) - End Sub - - Private Sub ClassifyUpdate(oldNode As EnumMemberDeclarationSyntax, newNode As EnumMemberDeclarationSyntax) - If Not SyntaxFactory.AreEquivalent(oldNode.Initializer, newNode.Initializer) Then - ReportError(RudeEditKind.InitializerUpdate) - Return - End If - End Sub - - Private Sub ClassifyUpdate(oldNode As ConstructorBlockSyntax, newNode As ConstructorBlockSyntax) - ClassifyMethodBodyRudeUpdate(oldNode, - newNode, - containingMethod:=Nothing, - containingType:=DirectCast(newNode.Parent, TypeBlockSyntax)) - End Sub - - Private Sub ClassifyMethodBodyRudeUpdate(oldBody As MethodBlockBaseSyntax, - newBody As MethodBlockBaseSyntax, - containingMethod As MethodBlockSyntax, - containingType As TypeBlockSyntax) - - If (oldBody.EndBlockStatement Is Nothing) <> (newBody.EndBlockStatement Is Nothing) Then - If oldBody.EndBlockStatement Is Nothing Then - ReportError(RudeEditKind.MethodBodyAdd) - Return - Else - ReportError(RudeEditKind.MethodBodyDelete) - Return - End If - End If - - ' The method only gets called if there are no other changes to the method declaration. - ' Since we got the update edit something has to be different in the body. - Debug.Assert(newBody.EndBlockStatement IsNot Nothing) - - ClassifyMemberBodyRudeUpdate(containingMethod, containingType, isTriviaUpdate:=False) - ClassifyDeclarationBodyRudeUpdates(newBody) - End Sub - - Public Sub ClassifyMemberBodyRudeUpdate(containingMethodOpt As MethodBlockSyntax, containingTypeOpt As TypeBlockSyntax, isTriviaUpdate As Boolean) - If containingMethodOpt?.SubOrFunctionStatement.TypeParameterList IsNot Nothing Then - ReportError(If(isTriviaUpdate, RudeEditKind.GenericMethodTriviaUpdate, RudeEditKind.GenericMethodUpdate)) - Return - End If - - If containingTypeOpt?.BlockStatement.Arity > 0 Then - ReportError(If(isTriviaUpdate, RudeEditKind.GenericTypeTriviaUpdate, RudeEditKind.GenericTypeUpdate)) - Return - End If - End Sub - Public Sub ClassifyDeclarationBodyRudeUpdates(newDeclarationOrBody As SyntaxNode) For Each node In newDeclarationOrBody.DescendantNodesAndSelf() Select Case node.Kind @@ -2565,20 +2364,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue classifier.ClassifyEdit() End Sub - Friend Overrides Sub ReportMemberUpdateRudeEdits(diagnostics As ArrayBuilder(Of RudeEditDiagnostic), newMember As SyntaxNode, span As TextSpan?) + Friend Overrides Sub ReportMemberBodyUpdateRudeEdits(diagnostics As ArrayBuilder(Of RudeEditDiagnostic), newMember As SyntaxNode, span As TextSpan?) Dim classifier = New EditClassifier(Me, diagnostics, Nothing, newMember, EditKind.Update, span:=span) - - classifier.ClassifyMemberBodyRudeUpdate( - TryCast(newMember, MethodBlockSyntax), - newMember.FirstAncestorOrSelf(Of TypeBlockSyntax)(), - isTriviaUpdate:=True) - classifier.ClassifyDeclarationBodyRudeUpdates(newMember) End Sub #End Region #Region "Semantic Rude Edits" + Protected Overrides Function AreFixedSizeBufferSizesEqual(oldField As IFieldSymbol, newField As IFieldSymbol, cancellationToken As CancellationToken) As Boolean + Throw ExceptionUtilities.Unreachable + End Function + + Protected Overrides Function AreHandledEventsEqual(oldMethod As IMethodSymbol, newMethod As IMethodSymbol) As Boolean + Return oldMethod.HandledEvents.SequenceEqual( + newMethod.HandledEvents, + Function(x, y) + Return x.HandlesKind = y.HandlesKind AndAlso + SymbolsEquivalent(x.EventContainer, y.EventContainer) AndAlso + SymbolsEquivalent(x.EventSymbol, y.EventSymbol) AndAlso + SymbolsEquivalent(x.WithEventsSourceProperty, y.WithEventsSourceProperty) + End Function) + End Function + Friend Overrides Sub ReportInsertedMemberSymbolRudeEdits(diagnostics As ArrayBuilder(Of RudeEditDiagnostic), newSymbol As ISymbol, newNode As SyntaxNode, insertingIntoExistingContainingType As Boolean) Dim kind = GetInsertedMemberSymbolRudeEditKind(newSymbol, insertingIntoExistingContainingType)