Skip to content

Commit

Permalink
Allow reordering parameters, and fix inserting, and deleting them
Browse files Browse the repository at this point in the history
  • Loading branch information
davidwengier committed Oct 10, 2022
1 parent 8664540 commit fcb7bd3
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15698,6 +15698,138 @@ .maxstack 8
.Verify();
}

[Fact]
public void Method_InsertAndDeleteParameter()
{
using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20)
.AddGeneration(
source: $$"""
class C
{
void M(int someInt) { someInt.ToString(); }
}
""",
validator: g =>
{
g.VerifyTypeDefNames("<Module>", "C");
g.VerifyMethodDefNames("M", ".ctor");
})
.AddGeneration(
source: $$"""
class C
{
void M(int someInt, bool someBool) { someInt.ToString(); }
}
""",
edits: new[] {
Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, newSymbolProvider: c=>c.GetMember("C")),
Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol),
},
validator: g =>
{
g.VerifyTypeDefNames();
g.VerifyMethodDefNames("M", "M");
g.VerifyDeletedMembers("C: {M}");

g.VerifyEncLogDefinitions(new[]
{
Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default),
Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod),
Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default),
Row(1, TableIndex.Param, EditAndContinueOperation.Default),
Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter),
Row(2, TableIndex.Param, EditAndContinueOperation.Default),
Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter),
Row(3, TableIndex.Param, EditAndContinueOperation.Default)
});
g.VerifyEncMapDefinitions(new[]
{
Handle(1, TableIndex.MethodDef),
Handle(3, TableIndex.MethodDef),
Handle(1, TableIndex.Param),
Handle(2, TableIndex.Param),
Handle(3, TableIndex.Param)
});

var expectedIL = """
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj 0x0A000006
IL_0005: throw
}
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: nop
IL_0001: ldarga.s V_1
IL_0003: call 0x0A000007
IL_0008: pop
IL_0009: ret
}
""";

// Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations
g.VerifyIL(expectedIL);
})
.AddGeneration(
source: $$"""
class C
{
void M(int someInt) { someInt.ToString(); }
}
""",
edits: new[] {
Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol, newSymbolProvider: c=>c.GetMember("C")),
Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol),
},
validator: g =>
{
g.VerifyTypeDefNames();
g.VerifyMethodDefNames("M", "M");
g.VerifyDeletedMembers("C: {M}");

g.VerifyEncLogDefinitions(new[]
{
Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default),
Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default),
Row(1, TableIndex.Param, EditAndContinueOperation.Default),
Row(2, TableIndex.Param, EditAndContinueOperation.Default),
Row(3, TableIndex.Param, EditAndContinueOperation.Default)
});
g.VerifyEncMapDefinitions(new[]
{
Handle(1, TableIndex.MethodDef),
Handle(3, TableIndex.MethodDef),
Handle(1, TableIndex.Param),
Handle(2, TableIndex.Param),
Handle(3, TableIndex.Param)
});

var expectedIL = """
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: nop
IL_0001: ldarga.s V_1
IL_0003: call 0x0A000008
IL_0008: pop
IL_0009: ret
}
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj 0x0A000009
IL_0005: throw
}
""";

// Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations
g.VerifyIL(expectedIL);
})
.Verify();
}

[Fact]
public void FileTypes_01()
{
Expand Down
156 changes: 153 additions & 3 deletions src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2823,7 +2823,9 @@ protected C(C other)
new[]
{
Diagnostic(RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, "protected virtual bool PrintMembers(System.Text.StringBuilder sb)", "PrintMembers(System.Text.StringBuilder builder)"),
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "System.Text.StringBuilder sb", FeaturesResources.parameter),
Diagnostic(RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, "public virtual bool Equals(C rhs)", "Equals(C other)"),
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "C rhs", FeaturesResources.parameter),
Diagnostic(RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, "protected C(C other)", "C(C original)")
},
capabilities: EditAndContinueCapabilities.Baseline);
Expand Down Expand Up @@ -6907,6 +6909,27 @@ public void Method_ReturnType_Update_RuntimeTypeChanged(string oldType, string n
capabilities: EditAndContinueCapabilities.Baseline);
}

[Fact]
public void Method_ReturnType_Update_AndBodyChange()
{
var src1 = "class C { int M() => 1; }";
var src2 = "class C { char M() => 'a'; }";

var edits = GetTopEdits(src1, src2);

edits.VerifySemantics(
new[]
{
SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.M"), deletedSymbolContainerProvider: c => c.GetMember("C")),
SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.M"))
},
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);

edits.VerifySemanticDiagnostics(
new[] { Diagnostic(RudeEditKind.ChangingTypeNotSupportedByRuntime, "char M()", FeaturesResources.method) },
capabilities: EditAndContinueCapabilities.Baseline);
}

[Fact]
public void Method_Update()
{
Expand Down Expand Up @@ -16606,12 +16629,23 @@ event Action F { add {} remove {} }
[Fact]
public void ParameterRename_Method1()
{
var src1 = @"class C { public void M(int a) {} }";
var src2 = @"class C { public void M(int b) {} } ";
var src1 = @"class C { public void M(int a) { a.ToString(); } }";
var src2 = @"class C { public void M(int b) { b.ToString(); } } ";

var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [public void M(int a) { a.ToString(); }]@10 -> [public void M(int b) { b.ToString(); }]@10",
"Update [int a]@24 -> [int b]@24");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
},
capabilities: EditAndContinueCapabilities.UpdateParameters);

edits.VerifySemanticDiagnostics(
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
capabilities: EditAndContinueCapabilities.Baseline);
}

[Fact]
Expand Down Expand Up @@ -16662,11 +16696,19 @@ public void ParameterRename_Indexer2()
public void ParameterInsert1()
{
var src1 = @"class C { public void M() {} }";
var src2 = @"class C { public void M(int a) {} } ";
var src2 = @"class C { public void M(int a) { a.ToString(); } } ";

var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [public void M() {}]@10 -> [public void M(int a) { a.ToString(); }]@10",
"Insert [int a]@24");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol)
},
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
}

[Fact]
Expand All @@ -16679,6 +16721,32 @@ public void ParameterInsert2()
edits.VerifyEdits(
"Update [(int a)]@23 -> [(int a, ref int b)]@23",
"Insert [ref int b]@31");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol)
},
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
}

[Fact]
public void ParameterInsert3()
{
var src1 = @"class C { public void M() {} }";
var src2 = @"class C { public int M(int a) { return a; } } ";

var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [public void M() {}]@10 -> [public int M(int a) { return a; }]@10",
"Insert [int a]@23");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol)
},
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
}

[Fact]
Expand All @@ -16690,6 +16758,13 @@ public void ParameterDelete1()
var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Delete [int a]@24");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 0)?.ISymbol)
},
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
}

[Fact]
Expand All @@ -16702,6 +16777,13 @@ public void ParameterDelete2()
edits.VerifyEdits(
"Update [(int a, int b)]@23 -> [(int b)]@23",
"Delete [int a]@24");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 2)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterCount() == 1)?.ISymbol)
},
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);
}

[Fact]
Expand All @@ -16724,10 +16806,65 @@ public void ParameterReorder()
var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Reorder [int b]@31 -> @24");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
},
capabilities: EditAndContinueCapabilities.UpdateParameters);

edits.VerifySemanticDiagnostics(
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
capabilities: EditAndContinueCapabilities.Baseline);
}

[Fact]
public void ParameterReorderAndUpdate()
{
var src1 = @"class C { public void M(int a, int b) { a.ToString(); } }";
var src2 = @"class C { public void M(int b, int a) { b.ToString(); } } ";

var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [public void M(int a, int b) { a.ToString(); }]@10 -> [public void M(int b, int a) { b.ToString(); }]@10",
"Reorder [int b]@31 -> @24");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
},
capabilities: EditAndContinueCapabilities.UpdateParameters);

edits.VerifySemanticDiagnostics(
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
capabilities: EditAndContinueCapabilities.Baseline);
}

[Fact]
public void ParameterReorderAndChangeTypes()
{
var src1 = @"class C { public void M(string a, int b) { a.ToString(); } }";
var src2 = @"class C { public void M(int b, string a) { b.ToString(); } } ";

var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [public void M(string a, int b) { a.ToString(); }]@10 -> [public void M(int b, string a) { b.ToString(); }]@10",
"Reorder [int b]@34 -> @24");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Delete, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_String)?.ISymbol, deletedSymbolContainerProvider: c => c.GetMember("C")),
SemanticEdit(SemanticEditKind.Insert, c => c.GetMembers("C.M").FirstOrDefault(m => m.GetParameterTypes()[0].SpecialType == SpecialType.System_Int32)?.ISymbol)
},
capabilities: EditAndContinueCapabilities.AddMethodToExistingType);

edits.VerifySemanticDiagnostics(
new[] { Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter) },
capabilities: EditAndContinueCapabilities.Baseline);
}

[Fact]
public void ParameterReorderAndRename()
{
var src1 = @"class C { public void M(int a, int b) {} }";
var src2 = @"class C { public void M(int b, int c) {} } ";
Expand All @@ -16736,6 +16873,19 @@ public void ParameterReorderAndUpdate()
edits.VerifyEdits(
"Reorder [int b]@31 -> @24",
"Update [int a]@24 -> [int c]@31");

edits.VerifySemantics(
new[] {
SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))
},
capabilities: EditAndContinueCapabilities.UpdateParameters);

edits.VerifySemanticDiagnostics(
new[] {
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter),
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int c", FeaturesResources.parameter)
},
capabilities: EditAndContinueCapabilities.Baseline);
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10760,8 +10760,16 @@ End Class
edits.VerifyEdits(
"Reorder [b As Integer]@38 -> @24")

edits.VerifySemantics(
semanticEdits:=
{
SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.M"))
},
capabilities:=EditAndContinueCapabilities.UpdateParameters)

edits.VerifySemanticDiagnostics(
Diagnostic(RudeEditKind.Move, "b As Integer", FeaturesResources.parameter))
{Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "b As Integer", FeaturesResources.parameter)},
capabilities:=EditAndContinueCapabilities.Baseline)
End Sub

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

edits.VerifySemanticDiagnostics(
{Diagnostic(RudeEditKind.Move, "b As Integer", FeaturesResources.parameter),
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "c", FeaturesResources.parameter)},
{Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "b As Integer", FeaturesResources.parameter),
Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "c", FeaturesResources.parameter)},
capabilities:=EditAndContinueCapabilities.Baseline)
End Sub

Expand Down
Loading

0 comments on commit fcb7bd3

Please sign in to comment.