Skip to content

Commit fcb7bd3

Browse files
committed
Allow reordering parameters, and fix inserting, and deleting them
1 parent 8664540 commit fcb7bd3

File tree

6 files changed

+378
-27
lines changed

6 files changed

+378
-27
lines changed

src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15698,6 +15698,138 @@ .maxstack 8
1569815698
.Verify();
1569915699
}
1570015700

15701+
[Fact]
15702+
public void Method_InsertAndDeleteParameter()
15703+
{
15704+
using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20)
15705+
.AddGeneration(
15706+
source: $$"""
15707+
class C
15708+
{
15709+
void M(int someInt) { someInt.ToString(); }
15710+
}
15711+
""",
15712+
validator: g =>
15713+
{
15714+
g.VerifyTypeDefNames("<Module>", "C");
15715+
g.VerifyMethodDefNames("M", ".ctor");
15716+
})
15717+
.AddGeneration(
15718+
source: $$"""
15719+
class C
15720+
{
15721+
void M(int someInt, bool someBool) { someInt.ToString(); }
15722+
}
15723+
""",
15724+
edits: new[] {
15725+
Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, newSymbolProvider: c=>c.GetMember("C")),
15726+
Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol),
15727+
},
15728+
validator: g =>
15729+
{
15730+
g.VerifyTypeDefNames();
15731+
g.VerifyMethodDefNames("M", "M");
15732+
g.VerifyDeletedMembers("C: {M}");
15733+
15734+
g.VerifyEncLogDefinitions(new[]
15735+
{
15736+
Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default),
15737+
Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod),
15738+
Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default),
15739+
Row(1, TableIndex.Param, EditAndContinueOperation.Default),
15740+
Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter),
15741+
Row(2, TableIndex.Param, EditAndContinueOperation.Default),
15742+
Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter),
15743+
Row(3, TableIndex.Param, EditAndContinueOperation.Default)
15744+
});
15745+
g.VerifyEncMapDefinitions(new[]
15746+
{
15747+
Handle(1, TableIndex.MethodDef),
15748+
Handle(3, TableIndex.MethodDef),
15749+
Handle(1, TableIndex.Param),
15750+
Handle(2, TableIndex.Param),
15751+
Handle(3, TableIndex.Param)
15752+
});
15753+
15754+
var expectedIL = """
15755+
{
15756+
// Code size 6 (0x6)
15757+
.maxstack 8
15758+
IL_0000: newobj 0x0A000006
15759+
IL_0005: throw
15760+
}
15761+
{
15762+
// Code size 10 (0xa)
15763+
.maxstack 8
15764+
IL_0000: nop
15765+
IL_0001: ldarga.s V_1
15766+
IL_0003: call 0x0A000007
15767+
IL_0008: pop
15768+
IL_0009: ret
15769+
}
15770+
""";
15771+
15772+
// Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations
15773+
g.VerifyIL(expectedIL);
15774+
})
15775+
.AddGeneration(
15776+
source: $$"""
15777+
class C
15778+
{
15779+
void M(int someInt) { someInt.ToString(); }
15780+
}
15781+
""",
15782+
edits: new[] {
15783+
Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol, newSymbolProvider: c=>c.GetMember("C")),
15784+
Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol),
15785+
},
15786+
validator: g =>
15787+
{
15788+
g.VerifyTypeDefNames();
15789+
g.VerifyMethodDefNames("M", "M");
15790+
g.VerifyDeletedMembers("C: {M}");
15791+
15792+
g.VerifyEncLogDefinitions(new[]
15793+
{
15794+
Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default),
15795+
Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default),
15796+
Row(1, TableIndex.Param, EditAndContinueOperation.Default),
15797+
Row(2, TableIndex.Param, EditAndContinueOperation.Default),
15798+
Row(3, TableIndex.Param, EditAndContinueOperation.Default)
15799+
});
15800+
g.VerifyEncMapDefinitions(new[]
15801+
{
15802+
Handle(1, TableIndex.MethodDef),
15803+
Handle(3, TableIndex.MethodDef),
15804+
Handle(1, TableIndex.Param),
15805+
Handle(2, TableIndex.Param),
15806+
Handle(3, TableIndex.Param)
15807+
});
15808+
15809+
var expectedIL = """
15810+
{
15811+
// Code size 10 (0xa)
15812+
.maxstack 8
15813+
IL_0000: nop
15814+
IL_0001: ldarga.s V_1
15815+
IL_0003: call 0x0A000008
15816+
IL_0008: pop
15817+
IL_0009: ret
15818+
}
15819+
{
15820+
// Code size 6 (0x6)
15821+
.maxstack 8
15822+
IL_0000: newobj 0x0A000009
15823+
IL_0005: throw
15824+
}
15825+
""";
15826+
15827+
// Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations
15828+
g.VerifyIL(expectedIL);
15829+
})
15830+
.Verify();
15831+
}
15832+
1570115833
[Fact]
1570215834
public void FileTypes_01()
1570315835
{

src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs

Lines changed: 153 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,7 +2823,9 @@ protected C(C other)
28232823
new[]
28242824
{
28252825
Diagnostic(RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, "protected virtual bool PrintMembers(System.Text.StringBuilder sb)", "PrintMembers(System.Text.StringBuilder builder)"),
2826+
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "System.Text.StringBuilder sb", FeaturesResources.parameter),
28262827
Diagnostic(RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, "public virtual bool Equals(C rhs)", "Equals(C other)"),
2828+
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "C rhs", FeaturesResources.parameter),
28272829
Diagnostic(RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, "protected C(C other)", "C(C original)")
28282830
},
28292831
capabilities: EditAndContinueCapabilities.Baseline);
@@ -6907,6 +6909,27 @@ public void Method_ReturnType_Update_RuntimeTypeChanged(string oldType, string n
69076909
capabilities: EditAndContinueCapabilities.Baseline);
69086910
}
69096911

6912+
[Fact]
6913+
public void Method_ReturnType_Update_AndBodyChange()
6914+
{
6915+
var src1 = "class C { int M() => 1; }";
6916+
var src2 = "class C { char M() => 'a'; }";
6917+
6918+
var edits = GetTopEdits(src1, src2);
6919+
6920+
edits.VerifySemantics(
6921+
new[]
6922+
{
6923+
SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.M"), deletedSymbolContainerProvider: c => c.GetMember("C")),
6924+
SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.M"))
6925+
},
6926+
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
6927+
6928+
edits.VerifySemanticDiagnostics(
6929+
new[] { Diagnostic(RudeEditKind.ChangingTypeNotSupportedByRuntime, "char M()", FeaturesResources.method) },
6930+
capabilities: EditAndContinueCapabilities.Baseline);
6931+
}
6932+
69106933
[Fact]
69116934
public void Method_Update()
69126935
{
@@ -16606,12 +16629,23 @@ event Action F { add {} remove {} }
1660616629
[Fact]
1660716630
public void ParameterRename_Method1()
1660816631
{
16609-
var src1 = @"class C { public void M(int a) {} }";
16610-
var src2 = @"class C { public void M(int b) {} } ";
16632+
var src1 = @"class C { public void M(int a) { a.ToString(); } }";
16633+
var src2 = @"class C { public void M(int b) { b.ToString(); } } ";
1661116634

1661216635
var edits = GetTopEdits(src1, src2);
1661316636
edits.VerifyEdits(
16637+
"Update [public void M(int a) { a.ToString(); }]@10 -> [public void M(int b) { b.ToString(); }]@10",
1661416638
"Update [int a]@24 -> [int b]@24");
16639+
16640+
edits.VerifySemantics(
16641+
new[] {
16642+
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
16643+
},
16644+
capabilities: EditAndContinueCapabilities.UpdateParameters);
16645+
16646+
edits.VerifySemanticDiagnostics(
16647+
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
16648+
capabilities: EditAndContinueCapabilities.Baseline);
1661516649
}
1661616650

1661716651
[Fact]
@@ -16662,11 +16696,19 @@ public void ParameterRename_Indexer2()
1666216696
public void ParameterInsert1()
1666316697
{
1666416698
var src1 = @"class C { public void M() {} }";
16665-
var src2 = @"class C { public void M(int a) {} } ";
16699+
var src2 = @"class C { public void M(int a) { a.ToString(); } } ";
1666616700

1666716701
var edits = GetTopEdits(src1, src2);
1666816702
edits.VerifyEdits(
16703+
"Update [public void M() {}]@10 -> [public void M(int a) { a.ToString(); }]@10",
1666916704
"Insert [int a]@24");
16705+
16706+
edits.VerifySemantics(
16707+
new[] {
16708+
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
16709+
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol)
16710+
},
16711+
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
1667016712
}
1667116713

1667216714
[Fact]
@@ -16679,6 +16721,32 @@ public void ParameterInsert2()
1667916721
edits.VerifyEdits(
1668016722
"Update [(int a)]@23 -> [(int a, ref int b)]@23",
1668116723
"Insert [ref int b]@31");
16724+
16725+
edits.VerifySemantics(
16726+
new[] {
16727+
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
16728+
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol)
16729+
},
16730+
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
16731+
}
16732+
16733+
[Fact]
16734+
public void ParameterInsert3()
16735+
{
16736+
var src1 = @"class C { public void M() {} }";
16737+
var src2 = @"class C { public int M(int a) { return a; } } ";
16738+
16739+
var edits = GetTopEdits(src1, src2);
16740+
edits.VerifyEdits(
16741+
"Update [public void M() {}]@10 -> [public int M(int a) { return a; }]@10",
16742+
"Insert [int a]@23");
16743+
16744+
edits.VerifySemantics(
16745+
new[] {
16746+
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
16747+
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol)
16748+
},
16749+
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
1668216750
}
1668316751

1668416752
[Fact]
@@ -16690,6 +16758,13 @@ public void ParameterDelete1()
1669016758
var edits = GetTopEdits(src1, src2);
1669116759
edits.VerifyEdits(
1669216760
"Delete [int a]@24");
16761+
16762+
edits.VerifySemantics(
16763+
new[] {
16764+
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
16765+
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol)
16766+
},
16767+
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
1669316768
}
1669416769

1669516770
[Fact]
@@ -16702,6 +16777,13 @@ public void ParameterDelete2()
1670216777
edits.VerifyEdits(
1670316778
"Update [(int a, int b)]@23 -> [(int b)]@23",
1670416779
"Delete [int a]@24");
16780+
16781+
edits.VerifySemantics(
16782+
new[] {
16783+
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
16784+
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol)
16785+
},
16786+
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
1670516787
}
1670616788

1670716789
[Fact]
@@ -16724,10 +16806,65 @@ public void ParameterReorder()
1672416806
var edits = GetTopEdits(src1, src2);
1672516807
edits.VerifyEdits(
1672616808
"Reorder [int b]@31 -> @24");
16809+
16810+
edits.VerifySemantics(
16811+
new[] {
16812+
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
16813+
},
16814+
capabilities: EditAndContinueCapabilities.UpdateParameters);
16815+
16816+
edits.VerifySemanticDiagnostics(
16817+
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
16818+
capabilities: EditAndContinueCapabilities.Baseline);
1672716819
}
1672816820

1672916821
[Fact]
1673016822
public void ParameterReorderAndUpdate()
16823+
{
16824+
var src1 = @"class C { public void M(int a, int b) { a.ToString(); } }";
16825+
var src2 = @"class C { public void M(int b, int a) { b.ToString(); } } ";
16826+
16827+
var edits = GetTopEdits(src1, src2);
16828+
edits.VerifyEdits(
16829+
"Update [public void M(int a, int b) { a.ToString(); }]@10 -> [public void M(int b, int a) { b.ToString(); }]@10",
16830+
"Reorder [int b]@31 -> @24");
16831+
16832+
edits.VerifySemantics(
16833+
new[] {
16834+
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
16835+
},
16836+
capabilities: EditAndContinueCapabilities.UpdateParameters);
16837+
16838+
edits.VerifySemanticDiagnostics(
16839+
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
16840+
capabilities: EditAndContinueCapabilities.Baseline);
16841+
}
16842+
16843+
[Fact]
16844+
public void ParameterReorderAndChangeTypes()
16845+
{
16846+
var src1 = @"class C { public void M(string a, int b) { a.ToString(); } }";
16847+
var src2 = @"class C { public void M(int b, string a) { b.ToString(); } } ";
16848+
16849+
var edits = GetTopEdits(src1, src2);
16850+
edits.VerifyEdits(
16851+
"Update [public void M(string a, int b) { a.ToString(); }]@10 -> [public void M(int b, string a) { b.ToString(); }]@10",
16852+
"Reorder [int b]@34 -> @24");
16853+
16854+
edits.VerifySemantics(
16855+
new[] {
16856+
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_String)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
16857+
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Int32)?.ISymbol)
16858+
},
16859+
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
16860+
16861+
edits.VerifySemanticDiagnostics(
16862+
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
16863+
capabilities: EditAndContinueCapabilities.Baseline);
16864+
}
16865+
16866+
[Fact]
16867+
public void ParameterReorderAndRename()
1673116868
{
1673216869
var src1 = @"class C { public void M(int a, int b) {} }";
1673316870
var src2 = @"class C { public void M(int b, int c) {} } ";
@@ -16736,6 +16873,19 @@ public void ParameterReorderAndUpdate()
1673616873
edits.VerifyEdits(
1673716874
"Reorder [int b]@31 -> @24",
1673816875
"Update [int a]@24 -> [int c]@31");
16876+
16877+
edits.VerifySemantics(
16878+
new[] {
16879+
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
16880+
},
16881+
capabilities: EditAndContinueCapabilities.UpdateParameters);
16882+
16883+
edits.VerifySemanticDiagnostics(
16884+
new[] {
16885+
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter),
16886+
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int c", FeaturesResources.parameter)
16887+
},
16888+
capabilities: EditAndContinueCapabilities.Baseline);
1673916889
}
1674016890

1674116891
[Theory]

src/EditorFeatures/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10760,8 +10760,16 @@ End Class
1076010760
edits.VerifyEdits(
1076110761
"Reorder [b As Integer]@38 -> @24")
1076210762

10763+
edits.VerifySemantics(
10764+
semanticEdits:=
10765+
{
10766+
SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.M"))
10767+
},
10768+
capabilities:=EditAndContinueCapabilities.UpdateParameters)
10769+
1076310770
edits.VerifySemanticDiagnostics(
10764-
Diagnostic(RudeEditKind.Move, "b As Integer", FeaturesResources.parameter))
10771+
{Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "b As Integer", FeaturesResources.parameter)},
10772+
capabilities:=EditAndContinueCapabilities.Baseline)
1076510773
End Sub
1076610774

1076710775
<Fact>
@@ -10775,8 +10783,8 @@ End Class
1077510783
"Update [a]@24 -> [c]@38")
1077610784

1077710785
edits.VerifySemanticDiagnostics(
10778-
{Diagnostic(RudeEditKind.Move, "b As Integer", FeaturesResources.parameter),
10779-
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "c", FeaturesResources.parameter)},
10786+
{Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "b As Integer", FeaturesResources.parameter),
10787+
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "c", FeaturesResources.parameter)},
1078010788
capabilities:=EditAndContinueCapabilities.Baseline)
1078110789
End Sub
1078210790

0 commit comments

Comments
 (0)