diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.cs index 631a347e2793e..a618d8dcb2e43 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.cs @@ -67,6 +67,7 @@ static object F(object o) Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(1, TableIndex.NestedClass, EditAndContinueOperation.Default)); } @@ -185,7 +186,8 @@ int F(object o) CheckEncLogDefinitions(reader1, Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -257,7 +259,8 @@ int F(object o) Row(4, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -532,6 +535,7 @@ int F(int a) Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } @@ -586,6 +590,7 @@ int F(int a) Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } @@ -641,7 +646,8 @@ int F(int a) CheckEncLogDefinitions(reader1, Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -786,6 +792,7 @@ int F(int a) Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } @@ -866,7 +873,9 @@ class C : D Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -990,7 +999,14 @@ void F() Row(18, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(19, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(20, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(21, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(21, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), + Row(7, TableIndex.Param, EditAndContinueOperation.Default), + Row(8, TableIndex.Param, EditAndContinueOperation.Default), + Row(9, TableIndex.Param, EditAndContinueOperation.Default), + Row(10, TableIndex.Param, EditAndContinueOperation.Default), + Row(11, TableIndex.Param, EditAndContinueOperation.Default), + Row(12, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -1076,6 +1092,12 @@ void F() Row(18, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(19, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(20, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), + Row(7, TableIndex.Param, EditAndContinueOperation.Default), + Row(8, TableIndex.Param, EditAndContinueOperation.Default), + Row(9, TableIndex.Param, EditAndContinueOperation.Default), + Row(10, TableIndex.Param, EditAndContinueOperation.Default), Row(15, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(16, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } @@ -1153,6 +1175,8 @@ void F() Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(15, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), Row(14, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } @@ -1240,6 +1264,10 @@ public void F() Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); @@ -1322,6 +1350,10 @@ public void F() Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } @@ -1399,6 +1431,8 @@ public void F() Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } @@ -2635,7 +2669,9 @@ static object F() Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -4235,7 +4271,8 @@ .maxstack 2 Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -4323,7 +4360,8 @@ .maxstack 2 Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -4429,7 +4467,8 @@ .maxstack 2 Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); } [Fact] @@ -4478,7 +4517,8 @@ public void TopLevelStatement_Closure() CheckEncLogDefinitions(reader1, Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); } } } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index d0cf473e1e686..7e8adb0b172ed 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -637,6 +637,9 @@ static async Task F(int a) Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(2, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), @@ -1107,6 +1110,7 @@ static IEnumerable F(int p) Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); @@ -1211,6 +1215,7 @@ static IEnumerable F(int p) Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); @@ -1322,6 +1327,7 @@ static IEnumerable F(int p) Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs index 429fe7ebad6c4..2edb50bd5a7f4 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs @@ -1101,6 +1101,221 @@ static void Main() { } Handle(2, TableIndex.AssemblyRef)); } + [Fact] + public void ModifyMethod_ParameterAttributes() + { + var source0 = +@"class C +{ + static void Main() { } + static string F(string input, int a) { return input; } +}"; + var source1 = +@"class C +{ + static void Main() { } + static string F([System.ComponentModel.Description(""input"")]string input, int a) { return input; } + static void G(string input) { } +}"; + var source2 = +@"class C +{ + static void Main() { } + static string F([System.ComponentModel.Description(""input"")]string input, int a) { return input; } + static void G([System.ComponentModel.Description(""input"")]string input) { } +}"; + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugExe, targetFramework: TargetFramework.NetStandard20); + var compilation1 = compilation0.WithSource(source1); + var compilation2 = compilation1.WithSource(source2); + + var methodF0 = compilation0.GetMember("C.F"); + var methodF1 = compilation1.GetMember("C.F"); + var methodG1 = compilation1.GetMember("C.G"); + var methodG2 = compilation2.GetMember("C.G"); + + // Verify full metadata contains expected rows. + var bytes0 = compilation0.EmitToArray(); + using var md0 = ModuleMetadata.CreateFromImage(bytes0); + var reader0 = md0.MetadataReader; + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C"); + CheckNames(reader0, reader0.GetMethodDefNames(), "Main", "F", ".ctor"); + CheckNames(reader0, reader0.GetMemberRefNames(), /*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); + CheckNames(reader0, reader0.GetParameterDefNames(), "input", "a"); + + CheckAttributes(reader0, + new CustomAttributeRow(Handle(1, TableIndex.Assembly), Handle(1, TableIndex.MemberRef)), + new CustomAttributeRow(Handle(1, TableIndex.Assembly), Handle(2, TableIndex.MemberRef)), + new CustomAttributeRow(Handle(1, TableIndex.Assembly), Handle(3, TableIndex.MemberRef))); + + var generation0 = EmitBaseline.CreateInitialBaseline( + md0, + EmptyLocalsProvider); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, methodF0, methodF1), + SemanticEdit.Create(SemanticEditKind.Insert, null, methodG1))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + var reader1 = md1.Reader; + var readers = new[] { reader0, reader1 }; + + EncValidation.VerifyModuleMvid(1, reader0, reader1); + + CheckNames(readers, reader1.GetTypeDefNames()); + CheckNames(readers, reader1.GetMethodDefNames(), "F", "G"); + CheckNames(readers, reader1.GetMemberRefNames(), /*DescriptionAttribute*/".ctor"); + CheckNames(readers, reader1.GetParameterDefNames(), "input", "a", "input"); + + CheckAttributes(reader1, + new CustomAttributeRow(Handle(1, TableIndex.Param), Handle(5, TableIndex.MemberRef))); + + CheckEncLog(reader1, + Row(2, TableIndex.AssemblyRef, EditAndContinueOperation.Default), + Row(5, TableIndex.MemberRef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), // New method, G + Row(1, TableIndex.Param, EditAndContinueOperation.Default), // Update existing param + Row(2, TableIndex.Param, EditAndContinueOperation.Default), // Update existing param + Row(4, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), // New param on method, G + Row(3, TableIndex.Param, EditAndContinueOperation.Default), // Support for the above + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + CheckEncMap(reader1, + Handle(6, TableIndex.TypeRef), + Handle(7, TableIndex.TypeRef), + Handle(2, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param), + Handle(3, TableIndex.Param), + Handle(5, TableIndex.MemberRef), + Handle(4, TableIndex.CustomAttribute), + Handle(2, TableIndex.StandAloneSig), + Handle(2, TableIndex.AssemblyRef)); + + var diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, methodG1, methodG2))); + + using var md2 = diff2.GetMetadata(); + var reader2 = md2.Reader; + readers = new[] { reader0, reader1, reader2 }; + + EncValidation.VerifyModuleMvid(2, reader1, reader2); + + CheckNames(readers, reader2.GetTypeDefNames()); + CheckNames(readers, reader2.GetMethodDefNames(), "G"); + CheckNames(readers, reader2.GetMemberRefNames(), /*DescriptionAttribute*/".ctor"); + CheckNames(readers, reader2.GetParameterDefNames(), "input"); + + CheckAttributes(reader2, + new CustomAttributeRow(Handle(3, TableIndex.Param), Handle(6, TableIndex.MemberRef))); + + CheckEncLog(reader2, + Row(3, TableIndex.AssemblyRef, EditAndContinueOperation.Default), + Row(6, TableIndex.MemberRef, EditAndContinueOperation.Default), + Row(8, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(9, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), // Update existing param, from the first delta + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + CheckEncMap(reader2, + Handle(8, TableIndex.TypeRef), + Handle(9, TableIndex.TypeRef), + Handle(4, TableIndex.MethodDef), + Handle(3, TableIndex.Param), + Handle(6, TableIndex.MemberRef), + Handle(5, TableIndex.CustomAttribute), + Handle(3, TableIndex.AssemblyRef)); + } + + [Fact] + public void ModifyDelegateInvokeMethod_AddAttributes() + { + var source0 = @" +class A : System.Attribute { } +delegate void D(int x); +"; + var source1 = @" +class A : System.Attribute { } +delegate void D([A]int x); +"; + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20); + var compilation1 = compilation0.WithSource(source1); + + var invoke0 = compilation0.GetMember("D.Invoke"); + var beginInvoke0 = compilation0.GetMember("D.BeginInvoke"); + var invoke1 = compilation1.GetMember("D.Invoke"); + var beginInvoke1 = compilation1.GetMember("D.BeginInvoke"); + + // Verify full metadata contains expected rows. + var bytes0 = compilation0.EmitToArray(); + using var md0 = ModuleMetadata.CreateFromImage(bytes0); + var reader0 = md0.MetadataReader; + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, invoke0, invoke1), + SemanticEdit.Create(SemanticEditKind.Update, beginInvoke0, beginInvoke1))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + var reader1 = md1.Reader; + var readers = new[] { reader0, reader1 }; + + CheckNames(readers, reader1.GetMethodDefNames(), "Invoke", "BeginInvoke"); + CheckNames(readers, reader1.GetParameterDefNames(), "x", "x", "callback", "object"); + + CheckAttributes(reader1, + new CustomAttributeRow(Handle(3, TableIndex.Param), Handle(1, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(4, TableIndex.Param), Handle(1, TableIndex.MethodDef))); + + CheckEncLog(reader1, + Row(2, TableIndex.AssemblyRef, EditAndContinueOperation.Default), + Row(10, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(11, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(12, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(13, TableIndex.TypeRef, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), // Updating existing parameter defs + Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), // Adding new custom attribute rows + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + CheckEncMap(reader1, + Handle(10, TableIndex.TypeRef), + Handle(11, TableIndex.TypeRef), + Handle(12, TableIndex.TypeRef), + Handle(13, TableIndex.TypeRef), + Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(3, TableIndex.Param), + Handle(4, TableIndex.Param), + Handle(5, TableIndex.Param), + Handle(6, TableIndex.Param), + Handle(4, TableIndex.CustomAttribute), + Handle(5, TableIndex.CustomAttribute), + Handle(2, TableIndex.AssemblyRef)); + } + /// /// Add a method that requires entries in the ParameterDefs table. /// Specifically, normal parameters or return types with attributes. @@ -1189,16 +1404,20 @@ class C EncValidation.VerifyModuleMvid(2, reader1, reader2); CheckNames(readers, reader2.GetTypeDefNames()); - CheckNames(readers, reader2.GetMethodDefNames(), "F"); - CheckNames(readers, reader2.GetParameterDefNames()); - CheckNames(readers, diff2.EmitResult.ChangedTypes, "C"); - CheckNames(readers, diff2.EmitResult.UpdatedMethods, "F"); CheckEncLogDefinitions(reader2, - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default)); // C.F + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), // C.F2 + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Constant, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); CheckEncMapDefinitions(reader2, - Handle(3, TableIndex.MethodDef)); + Handle(3, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param), + Handle(2, TableIndex.Constant), + Handle(4, TableIndex.CustomAttribute)); } [Fact] @@ -1423,8 +1642,10 @@ .maxstack 4 Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), Row(11, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(11, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(12, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(13, TableIndex.CustomAttribute, EditAndContinueOperation.Default), @@ -1451,10 +1672,12 @@ .maxstack 4 Handle(9, TableIndex.MethodDef), Handle(10, TableIndex.MethodDef), Handle(11, TableIndex.MethodDef), + Handle(3, TableIndex.Param), Handle(4, TableIndex.Param), Handle(7, TableIndex.MemberRef), Handle(8, TableIndex.MemberRef), Handle(9, TableIndex.MemberRef), + Handle(6, TableIndex.CustomAttribute), Handle(11, TableIndex.CustomAttribute), Handle(12, TableIndex.CustomAttribute), Handle(13, TableIndex.CustomAttribute), @@ -2158,11 +2381,15 @@ class C CheckEncLogDefinitions(reader3, Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); CheckEncMapDefinitions(reader3, Handle(4, TableIndex.TypeDef), Handle(5, TableIndex.MethodDef), + Handle(4, TableIndex.Param), + Handle(5, TableIndex.Param), Handle(4, TableIndex.CustomAttribute)); } @@ -2874,6 +3101,12 @@ interface J { } Row(13, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(1, TableIndex.Property, EditAndContinueOperation.Default), Row(2, TableIndex.Property, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), + Row(7, TableIndex.Param, EditAndContinueOperation.Default), + Row(8, TableIndex.Param, EditAndContinueOperation.Default), Row(11, TableIndex.MethodSemantics, EditAndContinueOperation.Default), Row(12, TableIndex.MethodSemantics, EditAndContinueOperation.Default), Row(13, TableIndex.MethodSemantics, EditAndContinueOperation.Default), @@ -11443,13 +11676,15 @@ protected virtual bool PrintMembers(System.Text.StringBuilder builder) Row(22, TableIndex.TypeRef, EditAndContinueOperation.Default), Row(4, TableIndex.TypeSpec, EditAndContinueOperation.Default), Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default)); // R.PrintMembers + Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), // R.PrintMembers + Row(3, TableIndex.Param, EditAndContinueOperation.Default)); CheckEncMap(reader1, Handle(20, TableIndex.TypeRef), Handle(21, TableIndex.TypeRef), Handle(22, TableIndex.TypeRef), Handle(10, TableIndex.MethodDef), + Handle(3, TableIndex.Param), Handle(3, TableIndex.StandAloneSig), Handle(4, TableIndex.TypeSpec), Handle(2, TableIndex.AssemblyRef)); @@ -11559,13 +11794,15 @@ public void TopLevelStatement_Update() Row(8, TableIndex.TypeRef, EditAndContinueOperation.Default), Row(9, TableIndex.TypeRef, EditAndContinueOperation.Default), Row(10, TableIndex.TypeRef, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default)); // Synthesized Main method + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), // Synthesized Main method + Row(1, TableIndex.Param, EditAndContinueOperation.Default)); CheckEncMap(reader1, Handle(8, TableIndex.TypeRef), Handle(9, TableIndex.TypeRef), Handle(10, TableIndex.TypeRef), Handle(1, TableIndex.MethodDef), + Handle(1, TableIndex.Param), Handle(6, TableIndex.MemberRef), Handle(7, TableIndex.MemberRef), Handle(2, TableIndex.AssemblyRef)); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index c25c01dfb5df4..fbaf49e743f14 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -35,8 +35,8 @@ internal sealed class DeltaMetadataWriter : MetadataWriter private readonly DefinitionIndex _fieldDefs; private readonly DefinitionIndex _methodDefs; private readonly DefinitionIndex _propertyDefs; - private readonly ParameterDefinitionIndex _parameterDefs; - private readonly List> _parameterDefList; + private readonly DefinitionIndex _parameterDefs; + private readonly Dictionary _parameterDefList; private readonly GenericParameterIndex _genericParameters; private readonly EventOrPropertyMapIndex _eventMap; private readonly EventOrPropertyMapIndex _propertyMap; @@ -46,14 +46,13 @@ internal sealed class DeltaMetadataWriter : MetadataWriter // correctly map the attributes to row numbers of existing attributes for that target private readonly Dictionary _customAttributeParentCounts; - // For the EncMap table we need to keep a list of exactly which rows in the CustomAttributes table are updated - // since we spread these out amongst existing rows, it's not just a contiguous set - private readonly List _customAttributeEncMapRows; - // Keep track of which CustomAttributes rows are added in this and previous deltas, over what is in the // original metadata private readonly Dictionary> _customAttributesAdded; + private readonly Dictionary _existingParameterDefs; + private readonly Dictionary _firstParamRowMap; + private readonly HeapOrReferenceIndex _assemblyRefIndex; private readonly HeapOrReferenceIndex _moduleRefIndex; private readonly InstanceAndStructuralReferenceIndex _memberRefIndex; @@ -99,17 +98,19 @@ public DeltaMetadataWriter( _fieldDefs = new DefinitionIndex(this.TryGetExistingFieldDefIndex, sizes[(int)TableIndex.Field]); _methodDefs = new DefinitionIndex(this.TryGetExistingMethodDefIndex, sizes[(int)TableIndex.MethodDef]); _propertyDefs = new DefinitionIndex(this.TryGetExistingPropertyDefIndex, sizes[(int)TableIndex.Property]); - _parameterDefs = new ParameterDefinitionIndex(sizes[(int)TableIndex.Param]); - _parameterDefList = new List>(); + _parameterDefs = new DefinitionIndex(this.TryGetExistingParameterDefIndex, sizes[(int)TableIndex.Param]); + _parameterDefList = new Dictionary(Cci.SymbolEquivalentEqualityComparer.Instance); _genericParameters = new GenericParameterIndex(sizes[(int)TableIndex.GenericParam]); _eventMap = new EventOrPropertyMapIndex(this.TryGetExistingEventMapIndex, sizes[(int)TableIndex.EventMap]); _propertyMap = new EventOrPropertyMapIndex(this.TryGetExistingPropertyMapIndex, sizes[(int)TableIndex.PropertyMap]); _methodImpls = new MethodImplIndex(this, sizes[(int)TableIndex.MethodImpl]); _customAttributeParentCounts = new Dictionary(); - _customAttributeEncMapRows = new List(); _customAttributesAdded = new Dictionary>(); + _firstParamRowMap = new Dictionary(); + _existingParameterDefs = new Dictionary(ReferenceEqualityComparer.Instance); + _assemblyRefIndex = new HeapOrReferenceIndex(this, lastRowId: sizes[(int)TableIndex.AssemblyRef]); _moduleRefIndex = new HeapOrReferenceIndex(this, lastRowId: sizes[(int)TableIndex.ModuleRef]); _memberRefIndex = new InstanceAndStructuralReferenceIndex(this, new MemberRefComparer(this), lastRowId: sizes[(int)TableIndex.MemberRef]); @@ -200,6 +201,7 @@ internal EmitBaseline GetDelta(Compilation compilation, Guid encId, MetadataSize eventsAdded: AddRange(_previousGeneration.EventsAdded, _eventDefs.GetAdded(), comparer: SymbolEquivalentEqualityComparer.Instance), fieldsAdded: AddRange(_previousGeneration.FieldsAdded, _fieldDefs.GetAdded(), comparer: SymbolEquivalentEqualityComparer.Instance), methodsAdded: AddRange(_previousGeneration.MethodsAdded, _methodDefs.GetAdded(), comparer: SymbolEquivalentEqualityComparer.Instance), + firstParamRowMap: AddRange(_previousGeneration.FirstParamRowMap, _firstParamRowMap), propertiesAdded: AddRange(_previousGeneration.PropertiesAdded, _propertyDefs.GetAdded(), comparer: SymbolEquivalentEqualityComparer.Instance), eventMapAdded: AddRange(_previousGeneration.EventMapAdded, _eventMap.GetAdded()), propertyMapAdded: AddRange(_previousGeneration.PropertyMapAdded, _propertyMap.GetAdded()), @@ -537,14 +539,38 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) foreach (var methodDef in typeDef.GetMethods(this.Context)) { - if (this.AddDefIfNecessary(_methodDefs, methodDef)) + this.AddDefIfNecessary(_methodDefs, methodDef); + var methodChange = _changes.GetChange(methodDef); + + if (methodChange == SymbolChange.Added) { + _firstParamRowMap.Add(GetMethodDefinitionHandle(methodDef), _parameterDefs.NextRowId); foreach (var paramDef in this.GetParametersToEmit(methodDef)) { _parameterDefs.Add(paramDef); - _parameterDefList.Add(KeyValuePairUtil.Create(methodDef, paramDef)); + _parameterDefList.Add(paramDef, methodDef); + } + } + else if (methodChange == SymbolChange.Updated) + { + // If we're re-emitting parameters for an existing method we need to find their original row numbers + // and reuse them so the EnCLog, EnCMap and CustomAttributes tables refer to the right rows + + // Unfortunately we have to check the original metadata and deltas separately as nothing tracks the aggregate data + // in a way that we can use + var handle = GetMethodDefinitionHandle(methodDef); + if (_previousGeneration.OriginalMetadata.MetadataReader.GetTableRowCount(TableIndex.MethodDef) >= MetadataTokens.GetRowNumber(handle)) + { + EmitParametersFromOriginalMetadata(methodDef, handle); + } + else + { + EmitParametersFromDelta(methodDef, handle); } + } + if (methodChange == SymbolChange.Added) + { if (methodDef.GenericParameterCount > 0) { foreach (var typeParameter in methodDef.GenericParameters) @@ -605,6 +631,36 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) implementingMethods.Free(); } + private void EmitParametersFromOriginalMetadata(IMethodDefinition methodDef, MethodDefinitionHandle handle) + { + var def = _previousGeneration.OriginalMetadata.MetadataReader.GetMethodDefinition(handle); + + var parameters = def.GetParameters(); + var paramDefinitions = this.GetParametersToEmit(methodDef); + int i = 0; + foreach (var param in parameters) + { + var paramDef = paramDefinitions[i]; + _parameterDefs.AddUpdated(paramDef); + _existingParameterDefs.Add(paramDef, MetadataTokens.GetRowNumber(param)); + _parameterDefList.Add(paramDef, methodDef); + i++; + } + } + + private void EmitParametersFromDelta(IMethodDefinition methodDef, MethodDefinitionHandle handle) + { + var ok = _previousGeneration.FirstParamRowMap.TryGetValue(handle, out var firstRowId); + Debug.Assert(ok); + + foreach (var paramDef in GetParametersToEmit(methodDef)) + { + _parameterDefs.AddUpdated(paramDef); + _existingParameterDefs.Add(paramDef, firstRowId++); + _parameterDefList.Add(paramDef, methodDef); + } + } + private bool AddDefIfNecessary(DefinitionIndex defIndex, T def) where T : class, IDefinition { @@ -737,7 +793,16 @@ protected override int AddCustomAttributesToTable(EntityHandle parentHandle, IEn return numAttributesEmitted; } - protected override void PopulateEncLogTableRows(ImmutableArray rowCounts) + public override void PopulateEncTables(ImmutableArray typeSystemRowCounts) + { + Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncLog] == 0); + Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncMap] == 0); + + PopulateEncLogTableRows(typeSystemRowCounts, out var customAttributeEncMapRows, out var paramEncMapRows); + PopulateEncMapTableRows(typeSystemRowCounts, customAttributeEncMapRows, paramEncMapRows); + } + + private void PopulateEncLogTableRows(ImmutableArray rowCounts, out List customAttributeEncMapRows, out List paramEncMapRows) { // The EncLog table is a log of all the operations needed // to update the previous metadata. That means all @@ -762,10 +827,10 @@ protected override void PopulateEncLogTableRows(ImmutableArray rowCounts) PopulateEncLogTableFieldsOrMethods(_methodDefs, TableIndex.MethodDef, EditAndContinueOperation.AddMethod); PopulateEncLogTableEventsOrProperties(_propertyDefs, TableIndex.Property, EditAndContinueOperation.AddProperty, _propertyMap, TableIndex.PropertyMap); - PopulateEncLogTableParameters(); + PopulateEncLogTableParameters(out paramEncMapRows); PopulateEncLogTableRows(TableIndex.Constant, previousSizes, deltaSizes); - PopulateEncLogTableCustomAttributes(); + PopulateEncLogTableCustomAttributes(out customAttributeEncMapRows); PopulateEncLogTableRows(TableIndex.DeclSecurity, previousSizes, deltaSizes); PopulateEncLogTableRows(TableIndex.ClassLayout, previousSizes, deltaSizes); PopulateEncLogTableRows(TableIndex.FieldLayout, previousSizes, deltaSizes); @@ -826,20 +891,38 @@ private void PopulateEncLogTableFieldsOrMethods( } } - private void PopulateEncLogTableParameters() + private void PopulateEncLogTableParameters(out List paramEncMapRows) { + paramEncMapRows = new List(); + var parameterFirstId = _parameterDefs.FirstRowId; - for (int i = 0; i < _parameterDefList.Count; i++) + int i = 0; + foreach (var paramDef in GetParameterDefs()) { - var methodDef = _parameterDefList[i].Key; + var methodDef = _parameterDefList[paramDef]; - metadata.AddEncLogEntry( - entity: MetadataTokens.MethodDefinitionHandle(_methodDefs.GetRowId(methodDef)), - code: EditAndContinueOperation.AddParameter); + if (_methodDefs.IsAddedNotChanged(methodDef)) + { + // For parameters on new methods we emit AddParameter rows for the method too + paramEncMapRows.Add(parameterFirstId + i); + metadata.AddEncLogEntry( + entity: MetadataTokens.MethodDefinitionHandle(_methodDefs.GetRowId(methodDef)), + code: EditAndContinueOperation.AddParameter); - metadata.AddEncLogEntry( - entity: MetadataTokens.ParameterHandle(parameterFirstId + i), - code: EditAndContinueOperation.Default); + metadata.AddEncLogEntry( + entity: MetadataTokens.ParameterHandle(parameterFirstId + i), + code: EditAndContinueOperation.Default); + i++; + } + else + { + // For previously emitted parameters we just update the Param row + var param = GetParameterHandle(paramDef); + paramEncMapRows.Add(MetadataTokens.GetRowNumber(param)); + metadata.AddEncLogEntry( + entity: param, + code: EditAndContinueOperation.Default); + } } } @@ -851,8 +934,10 @@ private void PopulateEncLogTableParameters() /// compilation or subsequent deltas, and only add more if we need to. The EncLog table is the thing that tells /// the runtime which row a CustomAttributes row is (ie, new or existing) /// - private void PopulateEncLogTableCustomAttributes() + private void PopulateEncLogTableCustomAttributes(out List customAttributeEncMapRows) { + customAttributeEncMapRows = new List(); + // List of attributes that need to be emitted to delete a previously emitted attribute var deletedAttributeRows = new List<(int parentRowId, HandleKind kind)>(); var customAttributesAdded = new Dictionary>(); @@ -878,7 +963,7 @@ private void PopulateEncLogTableCustomAttributes() foreach (var attributeHandle in existingCustomAttributes) { int rowId = MetadataTokens.GetRowNumber(attributeHandle); - AddLogEntryOrDelete(rowId, parent, add: index < count); + AddLogEntryOrDelete(rowId, parent, add: index < count, customAttributeEncMapRows); index++; } @@ -889,7 +974,7 @@ private void PopulateEncLogTableCustomAttributes() foreach (var rowId in rowIds) { TrackCustomAttributeAdded(rowId, parent); - AddLogEntryOrDelete(rowId, parent, add: index < count); + AddLogEntryOrDelete(rowId, parent, add: index < count, customAttributeEncMapRows); index++; } } @@ -899,7 +984,7 @@ private void PopulateEncLogTableCustomAttributes() { lastRowId++; TrackCustomAttributeAdded(lastRowId, parent); - AddEncLogEntry(lastRowId); + AddEncLogEntry(lastRowId, customAttributeEncMapRows); } } @@ -919,23 +1004,23 @@ private void PopulateEncLogTableCustomAttributes() } metadata.AddCustomAttribute(MetadataTokens.Handle(tableIndex, 0), MetadataTokens.EntityHandle(TableIndex.MemberRef, 0), value: default); - AddEncLogEntry(row.parentRowId); + AddEncLogEntry(row.parentRowId, customAttributeEncMapRows); } - void AddEncLogEntry(int rowId) + void AddEncLogEntry(int rowId, List customAttributeEncMapRows) { - _customAttributeEncMapRows.Add(rowId); + customAttributeEncMapRows.Add(rowId); metadata.AddEncLogEntry( entity: MetadataTokens.CustomAttributeHandle(rowId), code: EditAndContinueOperation.Default); } - void AddLogEntryOrDelete(int rowId, EntityHandle parent, bool add) + void AddLogEntryOrDelete(int rowId, EntityHandle parent, bool add, List customAttributeEncMapRows) { if (add) { // Update this row - AddEncLogEntry(rowId); + AddEncLogEntry(rowId, customAttributeEncMapRows); } else { @@ -981,7 +1066,7 @@ private void PopulateEncLogTableRows(TableIndex tableIndex, int firstRowId, int } } - protected override void PopulateEncMapTableRows(ImmutableArray rowCounts) + private void PopulateEncMapTableRows(ImmutableArray rowCounts, List customAttributeEncMapRows, List paramEncMapRows) { // The EncMap table maps from offset in each table in the delta // metadata to token. As such, the EncMap is a concatenated @@ -1005,9 +1090,9 @@ protected override void PopulateEncMapTableRows(ImmutableArray rowCounts) AddDefinitionTokens(tokens, _methodDefs, TableIndex.MethodDef); AddDefinitionTokens(tokens, _propertyDefs, TableIndex.Property); - AddReferencedTokens(tokens, TableIndex.Param, previousSizes, deltaSizes); + AddRowNumberTokens(tokens, paramEncMapRows, TableIndex.Param); AddReferencedTokens(tokens, TableIndex.Constant, previousSizes, deltaSizes); - AddRowNumberTokens(tokens, _customAttributeEncMapRows, TableIndex.CustomAttribute); + AddRowNumberTokens(tokens, customAttributeEncMapRows, TableIndex.CustomAttribute); AddReferencedTokens(tokens, TableIndex.DeclSecurity, previousSizes, deltaSizes); AddReferencedTokens(tokens, TableIndex.ClassLayout, previousSizes, deltaSizes); AddReferencedTokens(tokens, TableIndex.FieldLayout, previousSizes, deltaSizes); @@ -1410,6 +1495,11 @@ private bool TryGetExistingPropertyDefIndex(IPropertyDefinition item, out int in return false; } + private bool TryGetExistingParameterDefIndex(IParameterDefinition item, out int index) + { + return _existingParameterDefs.TryGetValue(item, out index); + } + private bool TryGetExistingEventMapIndex(int item, out int index) { if (_previousGeneration.EventMapAdded.TryGetValue(item, out index)) @@ -1458,28 +1548,6 @@ private bool TryGetExistingMethodImplIndex(MethodImplKey item, out int index) return false; } - private sealed class ParameterDefinitionIndex : DefinitionIndexBase - { - public ParameterDefinitionIndex(int lastRowId) - : base(lastRowId, ReferenceEqualityComparer.Instance) - { - } - - public override bool TryGetRowId(IParameterDefinition item, out int index) - { - return this.added.TryGetValue(item, out index); - } - - public void Add(IParameterDefinition item) - { - Debug.Assert(!this.IsFrozen); - - int index = this.NextRowId; - this.added.Add(item, index); - this.rows.Add(item); - } - } - private sealed class GenericParameterIndex : DefinitionIndexBase { public GenericParameterIndex(int lastRowId) diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs index ac37c774a1c30..fa7809a16fb33 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs @@ -209,6 +209,7 @@ public static EmitBaseline CreateInitialBaseline( eventsAdded: new Dictionary(), fieldsAdded: new Dictionary(), methodsAdded: new Dictionary(), + firstParamRowMap: new Dictionary(), propertiesAdded: new Dictionary(), eventMapAdded: new Dictionary(), propertyMapAdded: new Dictionary(), @@ -265,6 +266,7 @@ public static EmitBaseline CreateInitialBaseline( internal readonly IReadOnlyDictionary EventsAdded; internal readonly IReadOnlyDictionary FieldsAdded; internal readonly IReadOnlyDictionary MethodsAdded; + internal readonly IReadOnlyDictionary FirstParamRowMap; internal readonly IReadOnlyDictionary PropertiesAdded; internal readonly IReadOnlyDictionary EventMapAdded; internal readonly IReadOnlyDictionary PropertyMapAdded; @@ -322,6 +324,7 @@ private EmitBaseline( IReadOnlyDictionary eventsAdded, IReadOnlyDictionary fieldsAdded, IReadOnlyDictionary methodsAdded, + IReadOnlyDictionary firstParamRowMap, IReadOnlyDictionary propertiesAdded, IReadOnlyDictionary eventMapAdded, IReadOnlyDictionary propertyMapAdded, @@ -384,6 +387,7 @@ private EmitBaseline( EventsAdded = eventsAdded; FieldsAdded = fieldsAdded; MethodsAdded = methodsAdded; + FirstParamRowMap = firstParamRowMap; PropertiesAdded = propertiesAdded; EventMapAdded = eventMapAdded; PropertyMapAdded = propertyMapAdded; @@ -416,6 +420,7 @@ internal EmitBaseline With( IReadOnlyDictionary eventsAdded, IReadOnlyDictionary fieldsAdded, IReadOnlyDictionary methodsAdded, + IReadOnlyDictionary firstParamRowMap, IReadOnlyDictionary propertiesAdded, IReadOnlyDictionary eventMapAdded, IReadOnlyDictionary propertyMapAdded, @@ -449,6 +454,7 @@ internal EmitBaseline With( eventsAdded, fieldsAdded, methodsAdded, + firstParamRowMap, propertiesAdded, eventMapAdded, propertyMapAdded, diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs index 5da29a197116f..15ce2d0d8e0d1 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs @@ -49,6 +49,7 @@ public EmitBaseline MapBaselineToCompilation( eventsAdded, fieldsAdded, methodsAdded, + firstParamRowMap: baseline.FirstParamRowMap, propertiesAdded, eventMapAdded: baseline.EventMapAdded, propertyMapAdded: baseline.PropertyMapAdded, diff --git a/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs index 9aeb067d37667..b66d8e1dee847 100644 --- a/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs @@ -330,14 +330,6 @@ internal FullReferenceIndexer(MetadataWriter metadataWriter) } } - protected override void PopulateEncLogTableRows(ImmutableArray rowCounts) - { - } - - protected override void PopulateEncMapTableRows(ImmutableArray rowCounts) - { - } - protected override void PopulateEventMapTableRows() { ITypeDefinition? lastParent = null; diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index fbaa34f834fc5..bbb0c97aaeb42 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -404,16 +404,6 @@ private bool IsMinimalDelta /// protected abstract void PopulatePropertyMapTableRows(); - /// - /// Populate EncLog table. - /// - protected abstract void PopulateEncLogTableRows(ImmutableArray rowCounts); - - /// - /// Populate EncMap table. - /// - protected abstract void PopulateEncMapTableRows(ImmutableArray rowCounts); - protected abstract void ReportReferencesToAddedSymbols(); // If true, it is allowed to have methods not have bodies (for emitting metadata-only @@ -1120,8 +1110,7 @@ private BlobHandle GetMemberReferenceSignatureHandle(ITypeMemberReference member internal BlobHandle GetMethodSignatureHandle(IMethodReference methodReference) { - ImmutableArray signatureBlob; - return GetMethodSignatureHandleAndBlob(methodReference, out signatureBlob); + return GetMethodSignatureHandleAndBlob(methodReference, out _); } internal byte[] GetMethodSignature(IMethodReference methodReference) @@ -1729,6 +1718,8 @@ public void WriteMetadataAndIL(PdbWriter nativePdbWriterOpt, Stream metadataStre out Blob mvidStringFixup); var typeSystemRowCounts = metadata.GetRowCounts(); + Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncLog] == 0); + Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncMap] == 0); PopulateEncTables(typeSystemRowCounts); Debug.Assert(mappedFieldDataBuilder.Count == 0); @@ -1844,13 +1835,8 @@ public void BuildMetadataAndIL( PopulateTypeSystemTables(methodBodyOffsets, mappedFieldDataBuilder, managedResourceDataBuilder, dynamicAnalysisDataOpt, out mvidFixup); } - public void PopulateEncTables(ImmutableArray typeSystemRowCounts) + public virtual void PopulateEncTables(ImmutableArray typeSystemRowCounts) { - Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncLog] == 0); - Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncMap] == 0); - - PopulateEncLogTableRows(typeSystemRowCounts); - PopulateEncMapTableRows(typeSystemRowCounts); } public MetadataRootBuilder GetRootBuilder() diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb index d1a70a3446e3e..b174ddc922ccb 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb @@ -66,6 +66,7 @@ End Class Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(1, TableIndex.NestedClass, EditAndContinueOperation.Default)) End Using @@ -222,6 +223,7 @@ End Class Row(4, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) End Sub @@ -274,7 +276,8 @@ End Class Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(4, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default)) + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default)) End Sub @@ -358,7 +361,9 @@ End Class Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default)) + Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default)) End Sub @@ -435,6 +440,7 @@ End Module Row(7, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(14, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) @@ -705,7 +711,17 @@ End Class Row(31, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(32, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(33, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(34, TableIndex.MethodDef, EditAndContinueOperation.Default)) + Row(34, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(14, TableIndex.Param, EditAndContinueOperation.Default), + Row(15, TableIndex.Param, EditAndContinueOperation.Default), + Row(16, TableIndex.Param, EditAndContinueOperation.Default), + Row(17, TableIndex.Param, EditAndContinueOperation.Default), + Row(18, TableIndex.Param, EditAndContinueOperation.Default), + Row(19, TableIndex.Param, EditAndContinueOperation.Default), + Row(20, TableIndex.Param, EditAndContinueOperation.Default), + Row(21, TableIndex.Param, EditAndContinueOperation.Default), + Row(22, TableIndex.Param, EditAndContinueOperation.Default), + Row(23, TableIndex.Param, EditAndContinueOperation.Default)) End Sub @@ -761,7 +777,8 @@ End Class CheckEncLogDefinitions(reader1, Row(4, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default)) + Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default)) End Sub ''' @@ -824,7 +841,8 @@ End Class CheckEncLogDefinitions(reader1, Row(4, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default)) + Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default)) End Sub ''' @@ -891,7 +909,11 @@ End Class Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(13, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(14, TableIndex.MethodDef, EditAndContinueOperation.Default)) + Row(14, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.Param, EditAndContinueOperation.Default), + Row(7, TableIndex.Param, EditAndContinueOperation.Default), + Row(8, TableIndex.Param, EditAndContinueOperation.Default)) End Sub ' TODO: AggregateClauseCrossMatch diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb index fc4bd161e65f5..763c58165d500 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb @@ -1041,6 +1041,9 @@ End Class Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), @@ -1503,6 +1506,7 @@ End Class Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) @@ -1617,6 +1621,7 @@ End Class Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) @@ -1734,6 +1739,7 @@ End Class Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) @@ -2137,6 +2143,7 @@ End Class Row(4, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) @@ -2299,6 +2306,7 @@ End Class Row(7, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) @@ -2464,6 +2472,7 @@ End Class Row(7, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 20e6cbce4bf11..f1a2f3229de37 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -8292,6 +8292,43 @@ public void Operator_ReadOnlyRef_Parameter_Update() #region Constructor, Destructor + [Fact] + public void Constructor_Parameter_AddAttribute() + { + var src1 = @" +class C +{ + private int x = 1; + + public C(int a) + { + } +}"; + var src2 = @" +class C +{ + private int x = 2; + + public C([System.Obsolete]int a) + { + } +}"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + "Update [x = 1]@30 -> [x = 2]@30", + "Update [int a]@53 -> [[System.Obsolete]int a]@53"); + + edits.VerifySemantics( + ActiveStatementsDescription.Empty, + new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C..ctor")) + }, + capabilities: EditAndContinueTestHelpers.Net6RuntimeCapabilities); + } + [Fact] [WorkItem(2068, "https://github.com/dotnet/roslyn/issues/2068")] public void Constructor_ExternModifier_Add()