diff --git a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs index 741cb2f524f5d..992eb701d479b 100644 --- a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs +++ b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs @@ -1200,10 +1200,10 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && // int P => expr; // int P { get => expr; } = init // - // Note: An update of a partial property/indexer definition can only affect its attributes. The partial definition does not have a body. - // In that case we do not need to update/analyze the accessors since attribute update has no impact on them. + // Note: An update of a partial property/indexer definition can only affect its attributes and accessibility. The partial definition does not have a body. + // In that case we do not need to update/analyze the accessors since attribute/accessibility update has no impact on them. // - // 2) Property/indexer declarations differ in readonly keyword. + // 2) Property/indexer declarations differ in readonly keyword or accessibility. // 3) Property signature changes // 4) Property name changes @@ -1216,7 +1216,7 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && { if (oldHasExpressionBody || newHasExpressionBody || - DiffersInReadOnlyModifier(oldPropertySymbol.GetMethod, newPropertySymbol.GetMethod) || + DiffersInReadOnlyOrAccessibilityModifiers(oldPropertySymbol.GetMethod, newPropertySymbol.GetMethod) || IsMemberOrDelegateReplaced(oldPropertySymbol, newPropertySymbol)) { result.Add((oldPropertySymbol.GetMethod, newPropertySymbol.GetMethod, editKind)); @@ -1225,7 +1225,7 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && if (oldPropertySymbol.SetMethod != null || newPropertySymbol.SetMethod != null) { - if (DiffersInReadOnlyModifier(oldPropertySymbol.SetMethod, newPropertySymbol.SetMethod) || + if (DiffersInReadOnlyOrAccessibilityModifiers(oldPropertySymbol.SetMethod, newPropertySymbol.SetMethod) || IsMemberOrDelegateReplaced(oldPropertySymbol, newPropertySymbol)) { result.Add((oldPropertySymbol.SetMethod, newPropertySymbol.SetMethod, editKind)); @@ -1237,7 +1237,7 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && if (oldSymbol is IEventSymbol oldEventSymbol && newSymbol is IEventSymbol newEventSymbol) { - // 1) Event declarations differ in readonly keyword. + // 1) Event declarations differ in readonly keyword or accessibility. // 2) Event signature changes // 3) Event name changes @@ -1245,7 +1245,7 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && if (oldEventSymbol.AddMethod != null || newEventSymbol.AddMethod != null) { - if (DiffersInReadOnlyModifier(oldEventSymbol.AddMethod, newEventSymbol.AddMethod) || + if (DiffersInReadOnlyOrAccessibilityModifiers(oldEventSymbol.AddMethod, newEventSymbol.AddMethod) || IsMemberOrDelegateReplaced(oldEventSymbol, newEventSymbol)) { result.Add((oldEventSymbol.AddMethod, newEventSymbol.AddMethod, editKind)); @@ -1254,7 +1254,7 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && if (oldEventSymbol.RemoveMethod != null || newEventSymbol.RemoveMethod != null) { - if (DiffersInReadOnlyModifier(oldEventSymbol.RemoveMethod, newEventSymbol.RemoveMethod) || + if (DiffersInReadOnlyOrAccessibilityModifiers(oldEventSymbol.RemoveMethod, newEventSymbol.RemoveMethod) || IsMemberOrDelegateReplaced(oldEventSymbol, newEventSymbol)) { result.Add((oldEventSymbol.RemoveMethod, newEventSymbol.RemoveMethod, editKind)); @@ -1264,8 +1264,10 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && return; } - static bool DiffersInReadOnlyModifier(IMethodSymbol? oldMethod, IMethodSymbol? newMethod) - => oldMethod != null && newMethod != null && oldMethod.IsReadOnly != newMethod.IsReadOnly; + static bool DiffersInReadOnlyOrAccessibilityModifiers(IMethodSymbol? oldMethod, IMethodSymbol? newMethod) + => oldMethod != null && + newMethod != null && + (oldMethod.IsReadOnly != newMethod.IsReadOnly || oldMethod.DeclaredAccessibility != newMethod.DeclaredAccessibility); // Update to a type declaration with primary constructor may also need to update // the primary constructor, copy-constructor and/or synthesized record auto-properties. diff --git a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index b09c53ff6a0df..225620ff619d6 100644 --- a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -632,7 +632,7 @@ public void Reorder_TopLevelAttribute() [InlineData("class", "record struct")] [InlineData("class", "interface")] [InlineData("struct", "record struct")] // TODO: Allow this conversion: https://github.com/dotnet/roslyn/issues/51874 - public void Type_Kind_Update(string oldKeyword, string newKeyword) + public void Type_Update_Kind(string oldKeyword, string newKeyword) { var src1 = oldKeyword + " C { }"; var src2 = newKeyword + " C { }"; @@ -652,7 +652,7 @@ public void Type_Kind_Update(string oldKeyword, string newKeyword) [InlineData("class", "record struct")] [InlineData("class", "interface")] [InlineData("struct", "record struct")] - public void Type_Kind_Update_Reloadable(string oldKeyword, string newKeyword) + public void Type_Update_Kind_Reloadable(string oldKeyword, string newKeyword) { var src1 = ReloadableAttributeSrc + "[CreateNewOnMetadataUpdate]" + oldKeyword + " C { }"; var src2 = ReloadableAttributeSrc + "[CreateNewOnMetadataUpdate]" + newKeyword + " C { }"; @@ -668,7 +668,7 @@ public void Type_Kind_Update_Reloadable(string oldKeyword, string newKeyword) } [Fact] - public void Type_Modifiers_Static_Remove() + public void Type_Update_Modifiers_Static_Remove() { var src1 = "public static class C { }"; var src2 = "public class C { }"; @@ -684,11 +684,7 @@ public void Type_Modifiers_Static_Remove() [Theory] [InlineData("public")] - [InlineData("protected")] - [InlineData("private")] - [InlineData("private protected")] - [InlineData("internal protected")] - public void Type_Modifiers_Accessibility_Change(string accessibility) + public void Type_Update_Modifiers_Accessibility_Significant(string accessibility) { var src1 = accessibility + " class C { }"; var src2 = "class C { }"; @@ -698,8 +694,50 @@ public void Type_Modifiers_Accessibility_Change(string accessibility) edits.VerifyEdits( "Update [" + accessibility + " class C { }]@0 -> [class C { }]@0"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "class C", FeaturesResources.class_)); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C"))]); + } + + [Fact] + public void Type_Update_Modifiers_Accessibility_Insignificant() + { + var src1 = "internal interface C { }"; + var src2 = "interface C { }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + "Update [internal interface C { }]@0 -> [interface C { }]@0"); + + edits.VerifySemantics(); + } + + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("internal")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Type_Update_Modifiers_Accessibility_Nested_Significant(string accessibility) + { + var src1 = "class D { " + accessibility + " class C { } }"; + var src2 = "class D { class C { } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("D.C"))]); + } + + [Fact] + public void Type_Update_Modifiers_Accessibility_Nested_Insignificant() + { + var src1 = "class D { private class C { } }"; + var src2 = "class D { class C { } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics(); } [Theory] @@ -711,7 +749,7 @@ public void Type_Modifiers_Accessibility_Change(string accessibility) [InlineData("private", "private")] [InlineData("private protected", "private protected")] [InlineData("internal protected", "internal protected")] - public void Type_Modifiers_Accessibility_Partial(string accessibilityA, string accessibilityB) + public void Type_Update_Modifiers_Accessibility_Partial(string accessibilityA, string accessibilityB) { var srcA1 = accessibilityA + " partial class C { }"; var srcB1 = "partial class C { }"; @@ -727,27 +765,7 @@ public void Type_Modifiers_Accessibility_Partial(string accessibilityA, string a } [Fact] - public void Type_Modifiers_Internal_Remove() - { - var src1 = "internal interface C { }"; - var src2 = "interface C { }"; - - var edits = GetTopEdits(src1, src2); - edits.VerifySemantics(); - } - - [Fact] - public void Type_Modifiers_Internal_Add() - { - var src1 = "struct C { }"; - var src2 = "internal struct C { }"; - - var edits = GetTopEdits(src1, src2); - edits.VerifySemantics(); - } - - [Fact] - public void Type_Modifiers_Accessibility_Reloadable() + public void Type_Update_Modifiers_Accessibility_Reloadable() { var src1 = ReloadableAttributeSrc + "[CreateNewOnMetadataUpdate]public class C { }"; var src2 = ReloadableAttributeSrc + "[CreateNewOnMetadataUpdate]internal class C { }"; @@ -768,14 +786,14 @@ public void Type_Modifiers_Accessibility_Reloadable() [InlineData("interface")] [InlineData("record")] [InlineData("record struct")] - public void Type_Modifiers_NestedPrivateInInterface_Remove(string keyword) + public void Type_Update_Modifiers_NestedPrivateInInterface_Remove(string keyword) { var src1 = "interface C { private " + keyword + " S { } }"; var src2 = "interface C { " + keyword + " S { } }"; var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, keyword + " S", GetResource(keyword))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.S"))]); } [Theory] @@ -784,7 +802,7 @@ public void Type_Modifiers_NestedPrivateInInterface_Remove(string keyword) [InlineData("interface")] [InlineData("record")] [InlineData("record struct")] - public void Type_Modifiers_NestedPrivateInClass_Add(string keyword) + public void Type_Update_Modifiers_NestedPrivateInClass_Add(string keyword) { var src1 = "class C { " + keyword + " S { } }"; var src2 = "class C { private " + keyword + " S { } }"; @@ -799,7 +817,7 @@ public void Type_Modifiers_NestedPrivateInClass_Add(string keyword) [InlineData("interface")] [InlineData("record")] [InlineData("record struct")] - public void Type_Modifiers_NestedPublicInInterface_Add(string keyword) + public void Type_Update_Modifiers_NestedPublicInInterface_Add(string keyword) { var src1 = "interface C { " + keyword + " S { } }"; var src2 = "interface C { public " + keyword + " S { } }"; @@ -809,7 +827,7 @@ public void Type_Modifiers_NestedPublicInInterface_Add(string keyword) } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/48628")] - public void Type_Modifiers_Unsafe_Add() + public void Type_Update_Modifiers_Unsafe_Add() { var src1 = "public class C { }"; var src2 = "public unsafe class C { }"; @@ -823,7 +841,7 @@ public void Type_Modifiers_Unsafe_Add() } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/48628")] - public void Type_Modifiers_Unsafe_Remove() + public void Type_Update_Modifiers_Unsafe_Remove() { var src1 = @" using System; @@ -870,7 +888,7 @@ public event Action A { add { } remove { } } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/48628")] - public void Type_Modifiers_Unsafe_DeleteInsert() + public void Type_Update_Modifiers_Unsafe_DeleteInsert() { var srcA1 = "partial class C { unsafe void F() { } }"; var srcB1 = "partial class C { }"; @@ -889,7 +907,7 @@ public void Type_Modifiers_Unsafe_DeleteInsert() } [Fact] - public void Type_Modifiers_Ref_Add() + public void Type_Update_Modifiers_Ref_Add() { var src1 = "public struct C { }"; var src2 = "public ref struct C { }"; @@ -904,7 +922,7 @@ public void Type_Modifiers_Ref_Add() } [Fact] - public void Type_Modifiers_Ref_Remove() + public void Type_Update_Modifiers_Ref_Remove() { var src1 = "public ref struct C { }"; var src2 = "public struct C { }"; @@ -919,7 +937,7 @@ public void Type_Modifiers_Ref_Remove() } [Fact] - public void Type_Modifiers_ReadOnly_Add() + public void Type_Update_Modifiers_ReadOnly_Add() { var src1 = "public struct C { }"; var src2 = "public readonly struct C { }"; @@ -934,7 +952,7 @@ public void Type_Modifiers_ReadOnly_Add() } [Fact] - public void Type_Modifiers_ReadOnly_Remove() + public void Type_Update_Modifiers_ReadOnly_Remove() { var src1 = "public readonly struct C { }"; var src2 = "public struct C { }"; @@ -4483,8 +4501,7 @@ public void EnumAccessibilityChange() edits.VerifyEdits( "Update [public enum Color { Red = 1, Blue = 2, }]@0 -> [enum Color { Red = 1, Blue = 2, }]@0"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "enum Color", FeaturesResources.enum_)); + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetMember("Color"))]); } [Fact] @@ -4847,8 +4864,8 @@ public void Delegate_Accessibility_Update() edits.VerifyEdits( "Update [public delegate void D();]@0 -> [private delegate void D();]@0"); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "private delegate void D()", FeaturesResources.delegate_)); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("D"))]); } [Fact] @@ -7448,13 +7465,55 @@ public void PartialMember_DeleteInsert_MethodAddTypeParameter() #region Methods + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Method_Update_Modifiers_Accessibility_Significant(string accessibility) + { + var src1 = $$""" + class C + { + {{accessibility}} + int F() => 0; + } + """; + + var src2 = """ + class C + { + + int F() => 0; + } + """; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) + ]); + } + + [Fact] + public void Method_Update_Modifiers_Accessibility_Insignificant() + { + var src1 = "class C { private int F() => 0; }"; + var src2 = "class C { int F() => 0; }"; + + var edits = GetTopEdits(src1, src2); + + // the update is not necessary and can be eliminated: + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F"))]); + } + [Theory] [InlineData("static")] [InlineData("virtual")] [InlineData("abstract")] [InlineData("override")] [InlineData("sealed override", "override")] - public void Method_Modifiers_Update(string oldModifiers, string newModifiers = "") + public void Method_Update_Modifiers_Update(string oldModifiers, string newModifiers = "") { if (oldModifiers != "") { @@ -7478,7 +7537,7 @@ public void Method_Modifiers_Update(string oldModifiers, string newModifiers = " } [Fact] - public void Method_NewModifier_Add() + public void Method_Update_Modifiers_New_Add() { var src1 = "class C { int F() => 0; }"; var src2 = "class C { new int F() => 0; }"; @@ -7493,7 +7552,7 @@ public void Method_NewModifier_Add() } [Fact] - public void Method_NewModifier_Remove() + public void Method_Update_Modifiers_New_Remove() { var src1 = "class C { new int F() => 0; }"; var src2 = "class C { int F() => 0; }"; @@ -7508,7 +7567,7 @@ public void Method_NewModifier_Remove() } [Fact] - public void Method_ReadOnlyModifier_Add_InMutableStruct() + public void Method_Update_Modifiers_ReadOnly_Add_InMutableStruct() { var src1 = @" struct S @@ -7526,7 +7585,7 @@ struct S } [Fact] - public void Method_ReadOnlyModifier_Add_InReadOnlyStruct1() + public void Method_Update_Modifiers_ReadOnly_Add_InReadOnlyStruct1() { var src1 = @" readonly struct S @@ -7549,7 +7608,7 @@ public readonly int M() } [Fact] - public void Method_ReadOnlyModifier_Add_InReadOnlyStruct2() + public void Method_Update_Modifiers_ReadOnly_Add_InReadOnlyStruct2() { var src1 = @" readonly struct S @@ -7567,7 +7626,7 @@ struct S } [Fact] - public void Method_AsyncModifier_Remove() + public void Method_Update_Modifiers_Async_Remove() { var src1 = @" class Test @@ -7591,7 +7650,7 @@ public Task WaitAsync() } [Fact] - public void Method_AsyncModifier_Add() + public void Method_Update_Modifiers_Async_Add() { var src1 = @" class Test @@ -7618,7 +7677,7 @@ public async Task WaitAsync() } [Fact] - public void Method_AsyncModifier_Add_NotSupported() + public void Method_Update_Modifiers_Async_Add_NotSupported() { var src1 = @" class Test @@ -10671,6 +10730,53 @@ public void Operator_Delete() #region Constructor + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Constructor_Update_Modifiers_Accessibility_Significant(string accessibility) + { + var src1 = $$""" + class C + { + {{accessibility}} + C() + { + } + } + """; + var src2 = """ + class C + { + + C() + { + } + } + """; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true) + ]); + } + + [Fact] + public void Constructor_Update_Modifiers_Accessibility_Insignificant() + { + var src1 = "class C { private C() {} }"; + var src2 = "class C { C() {} }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + // the update is not necessary and can be eliminated: + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true) + ]); + } + [Fact] public void Constructor_Parameter_AddAttribute() { @@ -13065,10 +13171,8 @@ public void Constructor_Instance_Insert_ReplacingSynthesizedWithCustom_ChangingA var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - [ - Diagnostic(RudeEditKind.ChangingAccessibility, (accessibility + " C()").Trim(), GetResource("constructor")) - ], + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -13082,10 +13186,8 @@ public void Constructor_Instance_Insert_ReplacingSynthesizedWithCustom_ChangingA var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - [ - Diagnostic(RudeEditKind.ChangingAccessibility, (accessibility + " C()").Trim(), FeaturesResources.constructor) - ], + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -13240,8 +13342,8 @@ public void Constructor_Instance_Delete_SemanticError() var edits = GetTopEdits(src1, src2); // The compiler interprets D() as a constructor declaration. - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "class C", DeletedSymbolDisplay(FeaturesResources.constructor, "C()"))); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)]); } [Theory, CombinatorialData] @@ -13398,7 +13500,7 @@ public void Constructor_Instance_Delete_ReplacingCustomWithSynthesized( var edits = GetTopEdits(src1, src2); edits.VerifySemantics( - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").InstanceConstructors.Single(c => c.Parameters is []), preserveLocalVariables: true)); + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)); } [Theory, CombinatorialData] @@ -13411,10 +13513,8 @@ public void Constructor_Instance_Delete_ReplacingCustomWithSynthesized_ChangingA var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - [ - Diagnostic(RudeEditKind.ChangingAccessibility, keyword + " C", DeletedSymbolDisplay(FeaturesResources.constructor, "C()")) - ], + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -13441,10 +13541,8 @@ public void Constructor_Instance_Delete_ReplacingCustomWithSynthesized_AbstractT var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - [ - Diagnostic(RudeEditKind.ChangingAccessibility, "abstract " + keyword + " C", DeletedSymbolDisplay(FeaturesResources.constructor, "C()")) - ], + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)], capabilities: EditAndContinueCapabilities.Baseline); } @@ -13498,34 +13596,67 @@ public void Constructor_Instance_Delete_Primary_ReplacingWithSynthesized_Record( [Theory, CombinatorialData] public void Constructor_Instance_Delete_Primary_ReplacingWithRegular( - [CombinatorialValues("record", "class")] string keyword, [CombinatorialValues("", "private", "protected", "internal", "private protected", "internal protected")] string accessibility) { - var src1 = keyword + " C() { }"; - var src2 = keyword + " C { " + accessibility + " C() { } }"; + var src1 = "class C() { }"; + var src2 = "class C { " + accessibility + " C() { } }"; var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)], + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Theory, CombinatorialData] + public void Constructor_Instance_Delete_Primary_ReplacingWithRegular_Record( + [CombinatorialValues("", "private", "protected", "internal", "private protected", "internal protected")] string accessibility) + { + var src1 = "record C() { }"; + var src2 = "record C { " + accessibility + " C() { } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( [ - Diagnostic(RudeEditKind.ChangingAccessibility, (accessibility + " C()").Trim(), GetResource("constructor")) + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true), + SemanticEdit(SemanticEditKind.Update, c => c.GetCopyConstructor("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetSpecializedEqualsOverload("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.GetHashCode")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.PrintMembers")), ], capabilities: EditAndContinueCapabilities.Baseline); } [Theory, CombinatorialData] public void Constructor_Instance_Delete_Primary_ReplacingWithRegular_AbstractType( - [CombinatorialValues("record", "class")] string keyword, [CombinatorialValues("", "private", "public", "internal", "private protected", "internal protected")] string accessibility) { - var src1 = "abstract " + keyword + " C() { }"; - var src2 = "abstract " + keyword + " C { " + accessibility + " C() { } }"; + var src1 = "abstract class C() { }"; + var src2 = "abstract class C { " + accessibility + " C() { } }"; var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)], + capabilities: EditAndContinueCapabilities.Baseline); + } + + [Theory, CombinatorialData] + public void Constructor_Instance_Delete_Primary_ReplacingWithRegular_AbstractType_Record( + [CombinatorialValues("", "private", "public", "internal", "private protected", "internal protected")] string accessibility) + { + var src1 = "abstract record C() { }"; + var src2 = "abstract record C { " + accessibility + " C() { } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( [ - Diagnostic(RudeEditKind.ChangingAccessibility, (accessibility + " C()").Trim(), GetResource("constructor")) + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true), + SemanticEdit(SemanticEditKind.Update, c => c.GetCopyConstructor("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetSpecializedEqualsOverload("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.GetHashCode")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.PrintMembers")), ], capabilities: EditAndContinueCapabilities.Baseline); } @@ -13626,12 +13757,14 @@ public void Constructor_Instance_Partial_DeletePrivateInsertPublic() EditAndContinueValidation.VerifySemantics( [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], [ - // delete of the constructor in partial part will be reported as rude edit in the other document where it was inserted back with changed accessibility DocumentResults( semanticEdits: NoSemanticEdits), DocumentResults( - diagnostics: [Diagnostic(RudeEditKind.ChangingAccessibility, "public C()", FeaturesResources.constructor)]), + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), partialType: "C", preserveLocalVariables: true) + ]), ]); } @@ -13740,9 +13873,11 @@ public void Constructor_Instance_Partial_InsertPublicDeletePrivate() [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], [ DocumentResults( - diagnostics: [Diagnostic(RudeEditKind.ChangingAccessibility, "public C()", FeaturesResources.constructor)]), + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), partialType: "C", preserveLocalVariables: true) + ]), - // delete of the constructor in partial part will be reported as rude in the the other document where it was inserted with changed accessibility DocumentResults(), ]); } @@ -13760,8 +13895,10 @@ public void Constructor_Instance_Partial_InsertInternalDeletePrivate() [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], [ DocumentResults( - diagnostics: [Diagnostic(RudeEditKind.ChangingAccessibility, "internal C()", FeaturesResources.constructor)]), - + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), partialType: "C", preserveLocalVariables: true) + ]), DocumentResults(), ]); } @@ -14368,7 +14505,6 @@ public void DestructorDelete_InsertConstructor() "Delete [~B() { }]@10"); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "B()", FeaturesResources.constructor), Diagnostic(RudeEditKind.Delete, "class B", DeletedSymbolDisplay(CSharpFeaturesResources.destructor, "~B()"))); } @@ -14737,7 +14873,6 @@ public void MemberInitializer_Update_Field_InstanceCtorUpdate_Private() edits.VerifySemanticDiagnostics( [ Diagnostic(RudeEditKind.ChangingAttributesNotSupportedByRuntime, $"class C", DeletedSymbolDisplay(FeaturesResources.constructor, "C()")), - Diagnostic(RudeEditKind.ChangingAccessibility, $"class C", DeletedSymbolDisplay(FeaturesResources.constructor, "C()")) ], capabilities: EditAndContinueCapabilities.Baseline); } @@ -14750,8 +14885,8 @@ public void MemberInitializer_Update_Property_InstanceCtorUpdate_Private() var edits = GetTopEdits(src1, src2); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, $"class C", DeletedSymbolDisplay(FeaturesResources.constructor, "C()"))); + edits.VerifySemantics( + SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)); } [Fact] @@ -16408,6 +16543,33 @@ public void Field_Modifiers_Update(string oldModifiers, string newModifiers = "" Diagnostic(RudeEditKind.ModifiersUpdate, newModifiers + "int F = 0", GetResource(oldModifiers.Contains("const") ? "const field" : "field"))); } + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Field_Modifiers_Accessibility_Update_Significant(string accessibility) + { + var src1 = "class C { " + accessibility + " int F; }"; + var src2 = "class C { int F; }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")) + ]); + } + + [Fact] + public void Field_Modifiers_Accessibility_Update_Insignificant() + { + var src1 = "class C { private int F; }"; + var src2 = "class C { int F; }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics(); + } + [Fact] public void Field_Modifier_Add_InsertDelete() { @@ -17138,6 +17300,154 @@ public void Field_Type_Update_ReorderRemoveAdd() #region Properties + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Property_Update_Modifiers_Accessibility_ExpressionBody_Significant(string accessibility) + { + var src1 = $$""" + class C + { + {{accessibility}} + int P => 1; + } + """; + + var src2 = """ + class C + { + + int P => 1; + } + """; + + var edits = GetTopEdits(src1, src2); + + // update of the property itself is not necessary and could be eliminated: + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P")) + ]); + } + + [Fact] + public void Property_Update_Modifiers_Accessibility_ExpressionBody_Insignificant() + { + var src1 = "class C { private int P => 1; }"; + var src2 = "class C { int P => 1; }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P")) + ]); + } + + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Property_Update_Modifiers_Accessibility_ReadOnly_Significant(string accessibility) + { + var src1 = $$""" + class C + { + {{accessibility}} + int P { get; } + } + """; + + var src2 = """ + class C + { + + int P { get; } + } + """; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P")) + ]); + } + + [Fact] + public void Property_Update_Modifiers_Accessibility_Mix() + { + var src1 = """ + class C + { + public + int P + { + protected + get; + set; + } + } + """; + + var src2 = """ + class C + { + protected + int P + { + + get; + set; + } + } + """; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.set_P")), + // The update is not necessary and could be eliminated: + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P")) + ]); + } + + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Property_Update_Modifiers_Accessibility_Writable_Significant(string accessibility) + { + var src1 = $$""" + class C + { + {{accessibility}} + int P { get; set; } + } + """; + + var src2 = """ + class C + { + + int P { get; set; } + } + """; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.set_P")) + ]); + } + [Theory] [InlineData("static")] [InlineData("virtual")] @@ -19097,12 +19407,81 @@ public void Property_Partial_Parameter_TypeChange() #region Indexers + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Indexer_Update_Modifiers_Accessibility_ExpressionBody_Significant(string accessibility) + { + var src1 = "class C { " + accessibility + " int this[int index] => 1; }"; + var src2 = "class C { int this[int index] => 1; }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.this[]")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_Item")) + ]); + } + + [Fact] + public void Indexer_Update_Modifiers_Accessibility_ExpressionBody_Insignificant() + { + var src1 = "class C { private int this[int index] => 1; }"; + var src2 = "class C { int this[int index] => 1; }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.this[]")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_Item")) + ]); + } + + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Indexer_Update_Modifiers_Accessibility_ReadOnly_Significant(string accessibility) + { + var src1 = "class C { " + accessibility + " int this[int index] { get; } }"; + var src2 = "class C { int this[int index] { get; } }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.this[]")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_Item")) + ]); + } + + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Indexer_Update_Modifiers_Accessibility_Writable_Significant(string accessibility) + { + var src1 = "class C { " + accessibility + " int this[int index] { get; set; } }"; + var src2 = "class C { int this[int index] { get; set; } }"; + + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.this[]")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_Item")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.set_Item")) + ]); + } + [Theory] [InlineData("virtual")] [InlineData("abstract")] [InlineData("override")] [InlineData("sealed override", "override")] - public void Indexer_Modifiers_Update(string oldModifiers, string newModifiers = "") + public void Indexer_Update_Modifiers(string oldModifiers, string newModifiers = "") { if (oldModifiers != "") { @@ -19126,7 +19505,7 @@ public void Indexer_Modifiers_Update(string oldModifiers, string newModifiers = } [Fact] - public void Indexer_GetterUpdate() + public void Indexer_Getter() { var src1 = "class C { int this[int a] { get { return 1; } } }"; var src2 = "class C { int this[int a] { get { return 2; } } }"; @@ -20271,6 +20650,41 @@ readonly struct S #region Events + [Theory] + [InlineData("public")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("internal protected")] + public void Event_Update_Modifiers_Accessibility(string accessibility) + { + var src1 = $$""" + using System; + class C + { + {{accessibility}} + event Action E { add {} remove {} } + } + """; + + var src2 = """ + using System; + class C + { + + event Action E { add {} remove {} } + } + """; + + // update of the event itself is not necessary and could be eliminated: + var edits = GetTopEdits(src1, src2); + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.E")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.add_E")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.remove_E")) + ]); + } + [Theory] [InlineData("static")] [InlineData("virtual")] diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index f3643b0c755b4..3c9b4265d7543 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -3172,7 +3172,7 @@ void ReportDeletedMemberActiveStatementsRudeEdits() continue; } - AnalyzeSymbolUpdate(diagnosticContext, capabilities, semanticEdits, out var hasAttributeChange, cancellationToken); + AnalyzeSymbolUpdate(diagnosticContext, capabilities, semanticEdits, out var hasAttributeChange, out var hasAccessibilityChange, cancellationToken); if (newSymbol is IParameterSymbol or ITypeParameterSymbol) { @@ -3219,11 +3219,13 @@ void ReportDeletedMemberActiveStatementsRudeEdits() } // Avoid creating unnecessary updates that are easy to determine. - if (!hasAttributeChange && newSymbol is - INamedTypeSymbol { IsGenericType: false } or // changes in type parameter attributes and constraints need type update - IPropertySymbol { IsIndexer: false } or // changes in parameter attributes need indexer update - IFieldSymbol or - IEventSymbol) + if (!hasAttributeChange && + !hasAccessibilityChange && + newSymbol is + INamedTypeSymbol { IsGenericType: false } or // changes in type parameter attributes and constraints need type update + IPropertySymbol { IsIndexer: false } or // changes in parameter attributes need indexer update + IFieldSymbol or + IEventSymbol) { continue; } @@ -3303,7 +3305,7 @@ IFieldSymbol or var diagnosticContext = CreateDiagnosticContext(diagnostics, oldSymbol, newSymbol, newDeclaration, newModel, editScript.Match, diagnosticSpan); - AnalyzeSymbolUpdate(diagnosticContext, capabilities, semanticEdits, out var _, cancellationToken); + AnalyzeSymbolUpdate(diagnosticContext, capabilities, semanticEdits, out var _, out var _, cancellationToken); // if the member doesn't have a body triva changes have no effect: var oldBody = TryGetDeclarationBody(oldDeclaration, oldSymbol); @@ -3993,6 +3995,7 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( EditAndContinueCapabilitiesGrantor capabilities, out bool hasGeneratedAttributeChange, out bool hasGeneratedReturnTypeAttributeChange, + out bool hasAccessibilityChange, CancellationToken cancellationToken) { var rudeEdit = RudeEditKind.None; @@ -4001,6 +4004,7 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( hasGeneratedAttributeChange = false; hasGeneratedReturnTypeAttributeChange = false; + hasAccessibilityChange = false; if (oldSymbol.Kind != newSymbol.Kind) { @@ -4085,7 +4089,7 @@ private void ReportUpdatedSymbolDeclarationRudeEdits( if (oldSymbol.DeclaredAccessibility != newSymbol.DeclaredAccessibility) { - rudeEdit = RudeEditKind.ChangingAccessibility; + hasAccessibilityChange = true; } if (oldSymbol.IsStatic != newSymbol.IsStatic || @@ -4394,13 +4398,14 @@ private void AnalyzeSymbolUpdate( EditAndContinueCapabilitiesGrantor capabilities, ArrayBuilder semanticEdits, out bool hasAttributeChange, + out bool hasAccessibilityChange, CancellationToken cancellationToken) { // TODO: fails in VB on delegate parameter https://github.com/dotnet/roslyn/issues/53337 // Contract.ThrowIfFalse(newSymbol.IsImplicitlyDeclared == newDeclaration is null); ReportUpdatedSymbolDeclarationRudeEdits( - diagnosticContext, capabilities, out var hasGeneratedAttributeChange, out var hasGeneratedReturnTypeAttributeChange, cancellationToken); + diagnosticContext, capabilities, out var hasGeneratedAttributeChange, out var hasGeneratedReturnTypeAttributeChange, out hasAccessibilityChange, cancellationToken); // We don't check capabilities of the runtime to update compiler generated attributes. // All runtimes support changing the attributes in metadata, some just don't reflect the changes in the Reflection model. diff --git a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb index 109cee82f9651..e507b278961cb 100644 --- a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb @@ -828,13 +828,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue result.Add((oldPropertySymbol, newPropertySymbol, EditKind.Update)) If oldPropertySymbol.GetMethod IsNot Nothing OrElse newPropertySymbol.GetMethod IsNot Nothing Then - If IsMemberOrDelegateReplaced(oldPropertySymbol, newPropertySymbol) Then + If DiffersInAccessibilityModifiers(oldPropertySymbol.GetMethod, newPropertySymbol.GetMethod) OrElse + IsMemberOrDelegateReplaced(oldPropertySymbol, newPropertySymbol) Then result.Add((oldPropertySymbol.GetMethod, newPropertySymbol.GetMethod, editKind)) End If End If If oldPropertySymbol.SetMethod IsNot Nothing OrElse newPropertySymbol.SetMethod IsNot Nothing Then - If IsMemberOrDelegateReplaced(oldPropertySymbol, newPropertySymbol) Then + If DiffersInAccessibilityModifiers(oldPropertySymbol.SetMethod, newPropertySymbol.SetMethod) OrElse + IsMemberOrDelegateReplaced(oldPropertySymbol, newPropertySymbol) Then result.Add((oldPropertySymbol.SetMethod, newPropertySymbol.SetMethod, editKind)) End If End If @@ -848,13 +850,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue result.Add((oldEventSymbol, newEventSymbol, EditKind.Update)) If oldEventSymbol.AddMethod IsNot Nothing OrElse newEventSymbol.AddMethod IsNot Nothing Then - If IsMemberOrDelegateReplaced(oldEventSymbol, newEventSymbol) Then + If DiffersInAccessibilityModifiers(oldEventSymbol.AddMethod, newEventSymbol.AddMethod) OrElse + IsMemberOrDelegateReplaced(oldEventSymbol, newEventSymbol) Then result.Add((oldEventSymbol.AddMethod, newEventSymbol.AddMethod, editKind)) End If End If If oldEventSymbol.RemoveMethod IsNot Nothing OrElse newEventSymbol.RemoveMethod IsNot Nothing Then - If IsMemberOrDelegateReplaced(oldEventSymbol, newEventSymbol) Then + If DiffersInAccessibilityModifiers(oldEventSymbol.RemoveMethod, newEventSymbol.RemoveMethod) OrElse + IsMemberOrDelegateReplaced(oldEventSymbol, newEventSymbol) Then result.Add((oldEventSymbol.RemoveMethod, newEventSymbol.RemoveMethod, editKind)) End If End If @@ -888,6 +892,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue End Select End Sub + Private Shared Function DiffersInAccessibilityModifiers(oldMethod As IMethodSymbol, newMethod As IMethodSymbol) As Boolean + Return oldMethod IsNot Nothing AndAlso + newMethod IsNot Nothing AndAlso + oldMethod.DeclaredAccessibility <> newMethod.DeclaredAccessibility + End Function + Private Function TryGetSyntaxNodesForEdit( editKind As EditKind, node As SyntaxNode, diff --git a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb index ca321cab826b5..4bd9cc914ffee 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb @@ -446,7 +446,7 @@ Option Strict Off - Public Sub Type_Kind_Update(oldKeyword As String, newKeyword As String) + Public Sub Type_Update_Kind(oldKeyword As String, newKeyword As String) Dim src1 = oldKeyword & " C : End " & oldKeyword Dim src2 = newKeyword & " C : End " & newKeyword Dim edits = GetTopEdits(src1, src2) @@ -459,7 +459,7 @@ Option Strict Off - Public Sub Type_Kind_Update_Reloadable(oldKeyword As String, newKeyword As String) + Public Sub Type_Update_Kind_Reloadable(oldKeyword As String, newKeyword As String) Dim src1 = ReloadableAttributeSrc & "" & oldKeyword & " C : End " & oldKeyword Dim src2 = ReloadableAttributeSrc & "" & newKeyword & " C : End " & newKeyword Dim edits = GetTopEdits(src1, src2) @@ -471,7 +471,7 @@ Option Strict Off - Public Sub Type_Modifiers_Accessibility_Change(accessibility As String) + Public Sub Type_Update_Modifiers_Accessibility_Significant(accessibility As String) Dim src1 = accessibility + " Class C : End Class" Dim src2 = "Class C : End Class" @@ -481,8 +481,65 @@ Option Strict Off edits.VerifyEdits( "Update [" + accessibility + " Class C]@0 -> [Class C]@0") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "Class C", FeaturesResources.class_)) + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C"))}) + End Sub + + + Public Sub Type_Update_Modifiers_Accessibility_Insignificant() + + Dim src1 = "Friend Interface C : End Interface" + Dim src2 = "Interface C : End Interface" + + Dim edits = GetTopEdits(src1, src2) + + edits.VerifyEdits( + "Update [Friend Interface C]@0 -> [Interface C]@0") + + edits.VerifySemantics() + End Sub + + + + + + + Public Sub Type_Update_Modifiers_Accessibility_Nested_Significant(accessibility As String) + + Dim src1 = " +Class D + " + accessibility + " Class C + End Class +End Class" + Dim src2 = " +Class D + Class C + End Class +End Class" + + Dim edits = GetTopEdits(src1, src2) + + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("D.C"))}) + End Sub + + + Public Sub Type_Update_Modifiers_Accessibility_NestedInsignificant() + + Dim src1 = " +Class D + Public Class C + End Class +End Class" + Dim src2 = " +Class D + Class C + End Class +End Class" + + Dim edits = GetTopEdits(src1, src2) + + edits.VerifySemantics() End Sub @@ -494,7 +551,7 @@ Option Strict Off - Public Sub Type_Modifiers_Accessibility_Partial(accessibilityA As String, accessibilityB As String) + Public Sub Type_Update_Modifiers_Accessibility_Partial(accessibilityA As String, accessibilityB As String) Dim srcA1 = accessibilityA + " Partial Class C : End Class" Dim srcB1 = "Partial Class C : End Class" @@ -509,34 +566,8 @@ Option Strict Off }) End Sub - - - - - - Public Sub Type_Modifiers_Friend_Remove(keyword As String) - Dim src1 = "Friend " & keyword & " C : End " & keyword - Dim src2 = keyword & " C : End " & keyword - - Dim edits = GetTopEdits(src1, src2) - edits.VerifySemantics() - End Sub - - - - - - - Public Sub Type_Modifiers_Friend_Add(keyword As String) - Dim src1 = keyword & " C : End " & keyword - Dim src2 = "Friend " & keyword & " C : End " & keyword - - Dim edits = GetTopEdits(src1, src2) - edits.VerifySemantics() - End Sub - - Public Sub Type_Modifiers_Accessibility_Reloadable() + Public Sub Type_Update_Modifiers_Accessibility_Reloadable() Dim src1 = ReloadableAttributeSrc + "Friend Class C : End Class" Dim src2 = ReloadableAttributeSrc + "Public Class C : End Class" @@ -550,20 +581,20 @@ Option Strict Off - Public Sub Type_Modifiers_NestedPrivateInInterface_Remove(keyword As String) + Public Sub Type_Update_Modifiers_NestedPrivateInInterface_Remove(keyword As String) Dim src1 = "Interface C : Private " & keyword & " S : End " & keyword & " : End Interface" Dim src2 = "Interface C : " & keyword & " S : End " & keyword & " : End Interface" Dim edits = GetTopEdits(src1, src2) - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, keyword + " S", GetResource(keyword))) + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.S"))}) End Sub - Public Sub Type_Modifiers_NestedPublicInClass_Add(keyword As String) + Public Sub Type_Update_Modifiers_NestedPublicInClass_Add(keyword As String) Dim src1 = "Class C : " & keyword & " S : End " & keyword & " : End Class" Dim src2 = "Class C : Public " & keyword & " S : End " & keyword & " : End Class" @@ -575,7 +606,7 @@ Option Strict Off - Public Sub Type_Modifiers_NestedPublicInInterface_Add(keyword As String) + Public Sub Type_Update_Modifiers_NestedPublicInInterface_Add(keyword As String) Dim src1 = "Interface I : " + keyword + " S : End " & keyword & " : End Interface" Dim src2 = "Interface I : Public " + keyword + " S : End " & keyword & " : End Interface" Dim edits = GetTopEdits(src1, src2) @@ -587,7 +618,7 @@ Option Strict Off - Public Sub Type_PartialModifier_Add(keyword As String) + Public Sub Type_Update_PartialModifier_Add(keyword As String) Dim src1 = keyword & " C : End " & keyword Dim src2 = "Partial " & keyword & " C : End " & keyword Dim edits = GetTopEdits(src1, src2) @@ -599,7 +630,7 @@ Option Strict Off End Sub - Public Sub Module_PartialModifier_Remove() + Public Sub Module_Update_PartialModifier_Remove() Dim src1 = "Partial Module C : End Module" Dim src2 = "Module C : End Module" Dim edits = GetTopEdits(src1, src2) @@ -611,7 +642,7 @@ Option Strict Off End Sub - Public Sub Type_Attribute_Update_NotSupportedByRuntime1() + Public Sub Type_Update_Attribute_NotSupportedByRuntime1() Dim attribute = "Public Class A1Attribute : Inherits System.Attribute : End Class" & vbCrLf & "Public Class A2Attribute : Inherits System.Attribute : End Class" & vbCrLf @@ -632,7 +663,7 @@ Option Strict Off - Public Sub Type_Attribute_Update_NotSupportedByRuntime(keyword As String) + Public Sub Type_Update_Attribute_NotSupportedByRuntime(keyword As String) Dim src1 = "" & keyword & " C : End " & keyword Dim src2 = "" & keyword & " C : End " & keyword Dim edits = GetTopEdits(src1, src2) @@ -646,7 +677,7 @@ Option Strict Off End Sub - Public Sub Type_Attribute_Change_Reloadable() + Public Sub Type_Update_Attribute_Reloadable() Dim attributeSrc = " Public Class A1 : Inherits System.Attribute : End Class Public Class A2 : Inherits System.Attribute : End Class @@ -665,7 +696,7 @@ Public Class A3 : Inherits System.Attribute : End Class End Sub - Public Sub Type_Attribute_ReloadableRemove() + Public Sub Type_Update_Attribute_Reloadable_Remove() Dim src1 = ReloadableAttributeSrc & "Class C : End Class" Dim src2 = ReloadableAttributeSrc & "Class C : End Class" @@ -678,7 +709,7 @@ Public Class A3 : Inherits System.Attribute : End Class End Sub - Public Sub Type_Attribute_ReloadableAdd() + Public Sub Type_Update_Attribute_Reloadable_Add() Dim src1 = ReloadableAttributeSrc & "Class C : End Class" Dim src2 = ReloadableAttributeSrc & "Class C : End Class" @@ -691,7 +722,7 @@ Public Class A3 : Inherits System.Attribute : End Class End Sub - Public Sub Type_Attribute_ReloadableBase() + Public Sub Type_Update_Attribute_ReloadableBase() Dim src1 = ReloadableAttributeSrc & " @@ -2094,8 +2125,7 @@ End Class edits.VerifyEdits( "Update [Public Enum Color]@0 -> [Enum Color]@0") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "Enum Color", FeaturesResources.enum_)) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("Color"))}) End Sub @@ -2393,8 +2423,8 @@ End Class edits.VerifyEdits( "Update [Public Delegate Sub D()]@0 -> [Private Delegate Sub D()]@0") - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "Private Delegate Sub D()", FeaturesResources.delegate_)) + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("D"))}) End Sub @@ -4713,12 +4743,57 @@ End Structure #End Region #Region "Methods" + + + + + + Public Sub Method_Update_Modifiers_Accessibility_Significant(accessibility As String) + Dim src1 = " +Class C + " & accessibility & " _ + Sub F() + End Sub +End Class" + + Dim src2 = " +Class C + + Sub F() + End Sub +End Class" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) + End Sub + + + Public Sub Method_Update_Modifiers_Accessibility_Insignificant() + Dim src1 = " +Class C + Public _ + Sub F() + End Sub +End Class" + + Dim src2 = " +Class C + + Sub F() + End Sub +End Class" + + ' the update is not necessary and can be eliminated: + Dim edits = GetTopEdits(src1, src2) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) + End Sub + - Public Sub Method_Modifiers_Update(oldModifiers As String, Optional newModifiers As String = "") + Public Sub Method_Update_Modifiers(oldModifiers As String, Optional newModifiers As String = "") If oldModifiers <> "" Then oldModifiers &= " " End If @@ -4741,7 +4816,7 @@ End Structure End Sub - Public Sub Method_MustOverrideModifier_Update() + Public Sub Method_Update_MustOverrideModifier() Dim src1 = "Class C" & vbCrLf & "MustOverride Sub F() : End Class" Dim src2 = "Class C" & vbCrLf & "Sub F() : End Sub : End Class" @@ -4754,7 +4829,7 @@ End Structure - Public Sub Method_Modifiers_Update_NoImpact(oldModifiers As String, Optional newModifiers As String = "") + Public Sub Method_Update_Modifiers_NoImpact(oldModifiers As String, Optional newModifiers As String = "") If oldModifiers <> "" Then oldModifiers &= " " End If @@ -4778,7 +4853,7 @@ End Structure End Sub - Public Sub Method_AsyncModifier_Add() + Public Sub Method_Update_AsyncModifier_Add() Dim src1 = "Class C : " & vbLf & "Function F() As Task(Of String) : End Function : End Class" Dim src2 = "Class C : " & vbLf & "Async Function F() As Task(Of String) : End Function : End Class" @@ -4797,7 +4872,7 @@ End Structure End Sub - Public Sub Method_AsyncModifier_Remove() + Public Sub Method_Update_AsyncModifier_Remove() Dim src1 = "Class C : " & vbLf & "Async Function F() As Task(Of String) : End Function : End Class" Dim src2 = "Class C : " & vbLf & "Function F() As Task(Of String) : End Function : End Class" @@ -4812,7 +4887,7 @@ End Structure End Sub - Public Sub MethodUpdate1() + Public Sub Method_Update_Body1() Dim src1 As String = "Class C" & vbLf & "Shared Sub F()" & vbLf & @@ -4843,7 +4918,7 @@ End Structure End Sub - Public Sub MethodUpdate2() + Public Sub Method_Update_Body2() Dim src1 As String = "Class C" & vbLf & "Sub Goo() : End Sub : End Class" Dim src2 As String = "Class C" & vbLf & "Function Goo() : End Function : End Class" @@ -4862,7 +4937,7 @@ End Structure End Sub - Public Sub InterfaceMethodUpdate1() + Public Sub Method_Update_Interface1() Dim src1 As String = "Interface I" & vbLf & "Sub Goo() : End Interface" Dim src2 As String = "Interface I" & vbLf & "Function Goo() : End Interface" @@ -4876,7 +4951,7 @@ End Structure End Sub - Public Sub InterfaceMethodUpdate2() + Public Sub Method_Update_Interface2() Dim src1 As String = "Interface I" & vbLf & "Sub Goo() : End Interface" Dim src2 As String = "Interface I" & vbLf & "Sub Goo(a As Boolean) : End Interface" @@ -4887,7 +4962,7 @@ End Structure End Sub - Public Sub MethodDelete() + Public Sub Method_Delete() Dim src1 As String = "Class C" & vbLf & "Sub goo() : End Sub : End Class" Dim src2 As String = "Class C : End Class" @@ -4906,7 +4981,7 @@ End Structure End Sub - Public Sub InterfaceMethodDelete() + Public Sub Method_Delete_Interface() Dim src1 As String = "Interface C" & vbLf & "Sub Goo() : End Interface" Dim src2 As String = "Interface C : End Interface" @@ -4917,7 +4992,7 @@ End Structure End Sub - Public Sub MethodDelete_WithParameters() + Public Sub Method_Delete_WithParameters() Dim src1 As String = "Class C" & vbLf & "Sub goo(a As Integer) : End Sub : End Class" Dim src2 As String = "Class C : End Class" @@ -4938,7 +5013,7 @@ End Structure End Sub - Public Sub MethodDelete_WithAttribute() + Public Sub Method_Delete_WithAttribute() Dim src1 As String = "Class C : " & vbLf & " Sub goo(a As Integer) : End Sub : End Class" Dim src2 As String = "Class C : End Class" @@ -4959,7 +5034,7 @@ End Structure End Sub - Public Sub MethodInsert_Private() + Public Sub Method_Insert_Private() Dim src1 = "Class C : End Class" Dim src2 = "Class C : " & vbLf & "Private Function F : End Function : End Class" @@ -4973,7 +5048,7 @@ End Structure End Sub - Public Sub MethodInsert_PrivateWithParameters() + Public Sub Method_Insert_PrivateWithParameters() Dim src1 = "Class C : End Class" Dim src2 = "Class C : " & vbLf & "Private Function F(a As Integer) : End Function : End Class" Dim edits = GetTopEdits(src1, src2) @@ -4992,7 +5067,7 @@ End Structure End Sub - Public Sub MethodInsert_PrivateWithOptionalParameters() + Public Sub Method_Insert_PrivateWithOptionalParameters() Dim src1 = "Class C : End Class" Dim src2 = "Class C : " & vbLf & "Private Function F(Optional a As Integer = 1) : End Function : End Class" Dim edits = GetTopEdits(src1, src2) @@ -5011,7 +5086,7 @@ End Structure End Sub - Public Sub MethodInsert_PrivateWithAttribute() + Public Sub Method_Insert_PrivateWithAttribute() Dim src1 = "Class C : End Class" Dim src2 = "Class C : " & vbLf & "Private Sub F : End Sub : End Class" Dim edits = GetTopEdits(src1, src2) @@ -5027,7 +5102,7 @@ End Structure End Sub - Public Sub MethodInsert_Overridable() + Public Sub Method_Insert_Overridable() Dim src1 = "Class C : End Class" Dim src2 = "Class C : " & vbLf & "Overridable Sub F : End Sub : End Class" @@ -5038,7 +5113,7 @@ End Structure End Sub - Public Sub MethodInsert_MustOverride() + Public Sub Method_Insert_MustOverride() Dim src1 = "MustInherit Class C : End Class" Dim src2 = "MustInherit Class C : " & vbLf & "MustOverride Sub F : End Class" @@ -5060,7 +5135,7 @@ End Structure End Sub - Public Sub ExternMethodDeleteInsert() + Public Sub Method_DeleteInsert_Extern() Dim srcA1 = " Imports System Imports System.Runtime.InteropServices @@ -5102,7 +5177,7 @@ Imports System.Runtime.InteropServices End Sub - Public Sub InterfaceMethod_Reorder1() + Public Sub Method_Reorder1_Interface() Dim src1 = "Interface I : " & vbLf & "Sub f(a As Integer, b As Integer)" & vbLf & "Sub g() : End Interface" Dim src2 = "Interface I : " & vbLf & "Sub g() : " & vbLf & "Sub f(a As Integer, b As Integer) : End Interface" Dim edits = GetTopEdits(src1, src2) @@ -6210,6 +6285,51 @@ End Class #End Region #Region "Constructors" + + + + + + Public Sub Constructor_Update_Modifiers_Accessibility_Significant(accessibility As String) + Dim src1 = " +Class C + " & accessibility & " _ + Sub New() + End Sub +End Class" + + Dim src2 = " +Class C + + Sub New() + End Sub +End Class" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) + End Sub + + + Public Sub Constructor_Update_Modifiers_Accessibility_Insignificant() + Dim src1 = " +Class C + Public _ + Sub New() + End Sub +End Class" + + Dim src2 = " +Class C + + Sub New() + End Sub +End Class" + + ' the update is not necessary and can be eliminated: + Dim edits = GetTopEdits(src1, src2) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) + End Sub + Public Sub Constructor_SharedModifier_Remove() ' Note that all tokens are aligned to avoid trivia edits. @@ -6358,8 +6478,8 @@ End Class Dim src2 = "Class C : End Class" Dim edits = GetTopEdits(src1, src2) - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "Class C", DeletedSymbolDisplay(FeaturesResources.constructor, "New()"))) + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -6476,8 +6596,8 @@ End Class Dim src2 = "Class C" & vbLf & visibility & " Sub New() : End Sub : End Class" Dim edits = GetTopEdits(src1, src2) - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, visibility & " Sub New()", FeaturesResources.constructor)) + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -6604,7 +6724,7 @@ End Class { DocumentResults(), DocumentResults( - diagnostics:={Diagnostic(RudeEditKind.ChangingAccessibility, "Public Sub New()", FeaturesResources.constructor)}) + semanticEdits:={SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), partialType:="C", preserveLocalVariables:=True)}) }) End Sub @@ -6741,7 +6861,7 @@ End Class {GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)}, { DocumentResults( - diagnostics:={Diagnostic(RudeEditKind.ChangingAccessibility, visibility & "Sub New()", FeaturesResources.constructor)}), + semanticEdits:={SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), partialType:="C", preserveLocalVariables:=True)}), DocumentResults() }) End Sub @@ -7463,10 +7583,50 @@ End Class #End Region #Region "Fields" + + + + + + Public Sub Field_Update_Modifiers_Accessibility_Significant(accessibility As String) + Dim src1 = " +Class C + " & accessibility & " _ + Dim F As Integer +End Class" + + Dim src2 = " +Class C + + Dim F As Integer +End Class" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) + End Sub + + + Public Sub Field_Update_Modifiers_Accessibility_Insignificant() + Dim src1 = " +Class C + Private _ + Dim F As Integer +End Class" + + Dim src2 = " +Class C + + Dim F As Integer +End Class" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifySemantics() + End Sub + - Public Sub Field_Modifiers_Update(oldModifiers As String, Optional newModifiers As String = "") + Public Sub Field_Update_Modifiers(oldModifiers As String, Optional newModifiers As String = "") If oldModifiers <> "" Then oldModifiers &= " " End If @@ -7489,7 +7649,7 @@ End Class End Sub - Public Sub FieldUpdate_Rename1() + Public Sub Field_Rename1() Dim src1 = "Class C : Dim a As Integer = 0 : End Class" Dim src2 = "Class C : Dim b As Integer = 0 : End Class" Dim edits = GetTopEdits(src1, src2) @@ -7502,7 +7662,7 @@ End Class End Sub - Public Sub FieldUpdate_Rename2() + Public Sub Field_Rename2() Dim src1 = "Class C : Dim a1(), b1? As Integer, c1(1,2) As New D() : End Class" Dim src2 = "Class C : Dim a2(), b2? As Integer, c2(1,2) As New D() : End Class" Dim edits = GetTopEdits(src1, src2) @@ -7519,7 +7679,7 @@ End Class End Sub - Public Sub Field_TypeUpdate1() + Public Sub Field_Update_Type1() Dim src1 = "Class C : Dim a As Integer : End Class" Dim src2 = "Class C : Dim a As Boolean : End Class" Dim edits = GetTopEdits(src1, src2) @@ -8311,6 +8471,153 @@ End Class #End Region #Region "Properties" + + + + + + Public Sub Property_Update_Modifiers_Accessibility_Significant(accessibility As String) + Dim src1 = " +Class C + " & accessibility & " _ + Property P As Integer +End Class" + + Dim src2 = " +Class C + + Property P As Integer +End Class" + + Dim edits = GetTopEdits(src1, src2) + + ' update of the property itself is not necessary and could be eliminated: + edits.VerifySemantics({ + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.P")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.get_P")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.set_P"))}) + End Sub + + + Public Sub Property_Update_Modifiers_Accessibility_Insignificant() + Dim src1 = " +Class C + Public _ + Property P As Integer +End Class" + + Dim src2 = " +Class C + + Property P As Integer +End Class" + + Dim edits = GetTopEdits(src1, src2) + + edits.VerifySemantics() + End Sub + + + + + + + Public Sub Property_Update_Modifiers_Accessibility_Custom_Significant(accessibility As String) + Dim src1 = " +Class C + " & accessibility & " _ + Property P As Integer + Get + End Get + Set + End Set + End Property +End Class" + + Dim src2 = " +Class C + + Property P As Integer + Get + End Get + Set + End Set + End Property +End Class" + + Dim edits = GetTopEdits(src1, src2) + + ' update of the property itself is not necessary and could be eliminated: + edits.VerifySemantics({ + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.P")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.get_P")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.set_P"))}) + End Sub + + + Public Sub Property_Update_Modifiers_Accessibility_Custom_Insignificant() + Dim src1 = " +Class C + Public _ + Property P As Integer + Get + End Get + Set + End Set + End Property +End Class" + + Dim src2 = " +Class C + + Property P As Integer + Get + End Get + Set + End Set + End Property +End Class" + + Dim edits = GetTopEdits(src1, src2) + + edits.VerifySemantics() + End Sub + + + Public Sub Property_Update_Modifiers_Accessibility_Custom_Mix() + Dim src1 = " +Class C + Public _ + Property P As Integer + Protected _ + Get + End Get + Set + End Set + End Property +End Class" + + Dim src2 = " +Class C + Protected _ + Property P As Integer + + Get + End Get + Set + End Set + End Property +End Class" + + Dim edits = GetTopEdits(src1, src2) + + ' update C.get_P is not necessary and could be eliminated: + edits.VerifySemantics({ + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.P")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.get_P")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.set_P"))}) + End Sub + @@ -8454,7 +8761,7 @@ End Class" ' Note that all tokens are aligned to avoid trivia edits. Dim src1 = " Class C - Public Property F As Integer + Public Property P As Integer Friend _ Get Return Nothing @@ -8465,7 +8772,7 @@ Class C End Class" Dim src2 = " Class C - Public Property F As Integer + Public Property P As Integer Private _ Get Return Nothing @@ -8476,11 +8783,8 @@ Class C End Class" Dim edits = GetTopEdits(src1, src2) - Dim decl = "Private _ - Get" - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, decl, FeaturesResources.property_accessor)) + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.get_P"))}) End Sub @@ -8488,7 +8792,7 @@ End Class" ' Note that all tokens are aligned to avoid trivia edits. Dim src1 = " Class C - Public Property F As Integer + Public Property P As Integer Get Return Nothing End Get @@ -8499,7 +8803,7 @@ Class C End Class" Dim src2 = " Class C - Public Property F As Integer + Public Property P As Integer Get Return Nothing End Get @@ -8510,11 +8814,8 @@ Class C End Class" Dim edits = GetTopEdits(src1, src2) - Dim decl = "Private _ - Set" - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, decl, FeaturesResources.property_accessor)) + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.set_P"))}) End Sub @@ -9137,8 +9438,8 @@ End Class Dim src2 = "Class C : Dim a As Integer = 0 : End Class" Dim edits = GetTopEdits(src1, src2) - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "Class C", DeletedSymbolDisplay(FeaturesResources.constructor, "New()"))) + edits.VerifySemantics(ActiveStatementsDescription.Empty, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -9147,8 +9448,8 @@ End Class Dim src2 = "Class C : Property a As Integer = 0 : End Class" Dim edits = GetTopEdits(src1, src2) - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.ChangingAccessibility, "Class C", DeletedSymbolDisplay(FeaturesResources.constructor, "New()"))) + edits.VerifySemantics(ActiveStatementsDescription.Empty, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -10710,10 +11011,82 @@ End Class #End Region #Region "Events" + + + + + + Public Sub Event_Update_Modifiers_Accessibility_Significant(accessibility As String) + Dim src1 = " +Imports System +Class C + " & accessibility & " _ + Event E As Action +End Class" + + Dim src2 = " +Imports System +Class C + + Event E As Action +End Class" + + Dim edits = GetTopEdits(src1, src2) + + ' update of the event itself is not necessary and could be eliminated: + edits.VerifySemantics({ + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.E")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.add_E")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.remove_E"))}) + End Sub + + + + + + + Public Sub Event_Update_Modifiers_Accessibility_Custom_Significant(accessibility As String) + Dim src1 = " +Imports System +Class C + " & accessibility & " _ + Custom Event E As Action + AddHandler(value As Action) + End AddHandler + RemoveHandler(value As Action) + End RemoveHandler + RaiseEvent() + End RaiseEvent + End Event +End Class" + + Dim src2 = " +Imports System +Class C + + Custom Event E As Action + AddHandler(value As Action) + End AddHandler + RemoveHandler(value As Action) + End RemoveHandler + RaiseEvent() + End RaiseEvent + End Event +End Class" + + Dim edits = GetTopEdits(src1, src2) + + ' Update of the event itself is not necessary and could be eliminated. + ' Note: raise event isn't updated - it's accessibility is always "private". + edits.VerifySemantics({ + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.E")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.add_E")), + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.remove_E"))}) + End Sub - Public Sub Event_Modifiers_Update(oldModifiers As String, Optional newModifiers As String = "") + Public Sub Event_Update_Modifiers(oldModifiers As String, Optional newModifiers As String = "") If oldModifiers <> "" Then oldModifiers &= " " End If @@ -10724,7 +11097,8 @@ End Class Dim src1 = " Class C - " & oldModifiers & " Custom Event E As Action + " & oldModifiers & " _ + Custom Event E As Action AddHandler(value As Action) End AddHandler RemoveHandler(value As Action) @@ -10736,7 +11110,8 @@ End Class" Dim src2 = " Class C - " & newModifiers & " Custom Event E As Action + " & newModifiers & " _ + Custom Event E As Action AddHandler(value As Action) End AddHandler RemoveHandler(value As Action) @@ -10753,7 +11128,7 @@ End Class" End Sub - Public Sub Event_Accessor_Attribute_Update() + Public Sub Event_Update_Accessor_Attribute() Dim srcAttribute = " Class A Inherits Attribute