Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow reordering parameters, inserting, and deleting parameters #64596

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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