diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index a51026ed55351..8959add27efdf 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -3352,7 +3352,6 @@ internal override EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, - ICollection updatedMethods, CompilationTestData? testData, CancellationToken cancellationToken) { @@ -3364,7 +3363,6 @@ internal override EmitDifferenceResult EmitDifference( metadataStream, ilStream, pdbStream, - updatedMethods, testData, cancellationToken); } diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs index f687ff4e4f4cb..80b467c126c93 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs @@ -10,6 +10,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Emit @@ -24,7 +25,6 @@ internal static EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, - ICollection updatedMethods, CompilationTestData? testData, CancellationToken cancellationToken) { @@ -35,6 +35,9 @@ internal static EmitDifferenceResult EmitDifference( var serializationProperties = compilation.ConstructModuleSerializationProperties(emitOptions, runtimeMDVersion, baseline.ModuleVersionId); var manifestResources = SpecializedCollections.EmptyEnumerable(); + var updatedMethods = ArrayBuilder.GetInstance(); + var updatedTypes = ArrayBuilder.GetInstance(); + PEDeltaAssemblyBuilder moduleBeingBuilt; try { @@ -52,7 +55,7 @@ internal static EmitDifferenceResult EmitDifference( { // TODO: https://github.com/dotnet/roslyn/issues/9004 diagnostics.Add(ErrorCode.ERR_ModuleEmitFailure, NoLocation.Singleton, compilation.AssemblyName, e.Message); - return new EmitDifferenceResult(success: false, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: null); + return new EmitDifferenceResult(success: false, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: null, updatedMethods: updatedMethods.ToImmutableAndFree(), updatedTypes: updatedTypes.ToImmutableAndFree()); } if (testData != null) @@ -87,6 +90,7 @@ internal static EmitDifferenceResult EmitDifference( ilStream, pdbStream, updatedMethods, + updatedTypes, diagnostics, testData?.SymWriterFactory, emitOptions.PdbFilePath, @@ -96,7 +100,9 @@ internal static EmitDifferenceResult EmitDifference( return new EmitDifferenceResult( success: newBaseline != null, diagnostics: diagnostics.ToReadOnlyAndFree(), - baseline: newBaseline); + baseline: newBaseline, + updatedMethods: updatedMethods.ToImmutableAndFree(), + updatedTypes: updatedTypes.ToImmutableAndFree()); } /// diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs index 9fe24387baf54..068ba6382dc68 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs @@ -81,7 +81,7 @@ class C c2.GlobalNamespace.GetMember("C").GetMember("Main")) }; - c2.EmitDifference(baseline, edits, mdStream, ilStream, pdbStream, updatedMethods); + c2.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream); var actualIL = ImmutableArray.Create(ilStream.ToArray()).GetMethodIL(); var expectedIL = @" @@ -152,7 +152,7 @@ class C c2.GlobalNamespace.GetMember("C").GetMember("Main")) }; - c2.EmitDifference(baseline, edits, mdStream, ilStream, pdbStream, updatedMethods); + c2.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream); var actualIL = ImmutableArray.Create(ilStream.ToArray()).GetMethodIL(); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index cc9e92b89a723..7dae6013bdcab 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -58,6 +58,8 @@ static IEnumerable G() using var md1 = diff1.GetMetadata(); var reader1 = md1.Reader; + diff1.VerifyUpdatedTypes("0x02000002"); + CheckEncLog(reader1, Row(2, TableIndex.AssemblyRef, EditAndContinueOperation.Default), Row(17, TableIndex.MemberRef, EditAndContinueOperation.Default), @@ -860,6 +862,8 @@ static async Task F() // only methods with sequence points should be listed in UpdatedMethods: diff1.VerifyUpdatedMethods("0x06000004"); + diff1.VerifyUpdatedTypes("0x02000002", "0x02000003"); + using (var md1 = diff1.GetMetadata()) { // Verify that no new TypeDefs, FieldDefs or MethodDefs were added, @@ -3321,6 +3325,8 @@ .locals init (int V_0) ImmutableArray.Create( SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + diff1.VerifyUpdatedTypes("0x02000003", "0x02000004"); + diff1.VerifySynthesizedMembers( "C: {d__0}", "C.d__0: {<>1__state, <>2__current, <>l__initialThreadId, <>4__this, 5__1, System.IDisposable.Dispose, MoveNext, System.Collections.Generic.IEnumerator.get_Current, System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current, System.Collections.Generic.IEnumerable.GetEnumerator, System.Collections.IEnumerable.GetEnumerator, System.Collections.Generic.IEnumerator.Current, System.Collections.IEnumerator.Current}", @@ -3333,6 +3339,8 @@ .locals init (int V_0) ImmutableArray.Create( SemanticEdit.Create(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true))); + diff2.VerifyUpdatedTypes("0x02000003", "0x02000004"); + diff2.VerifySynthesizedMembers( "C: {d__0}", "C.d__0: {<>1__state, <>2__current, <>l__initialThreadId, <>4__this, 5__1, System.IDisposable.Dispose, MoveNext, System.Collections.Generic.IEnumerator.get_Current, System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current, System.Collections.Generic.IEnumerable.GetEnumerator, System.Collections.IEnumerable.GetEnumerator, System.Collections.Generic.IEnumerator.Current, System.Collections.IEnumerator.Current}", diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs index a3306c748750b..0652a0d96bc13 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs @@ -863,6 +863,10 @@ public void AddField() var reader1 = md1.Reader; var readers = new[] { reader0, reader1 }; + diff1.VerifyUpdatedTypes("0x02000002"); + + CheckNames(readers, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "C"); + CheckNames(readers, reader1.GetTypeDefNames()); CheckNames(readers, reader1.GetFieldDefNames(), "G"); CheckNames(readers, reader1.GetMethodDefNames(), ".ctor"); @@ -1615,6 +1619,10 @@ static object F() var reader1 = md1.Reader; var readers = new[] { reader0, reader1 }; + diff1.VerifyUpdatedTypes("0x02000002", "0x02000003"); + + CheckNames(readers, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "A", "B`1"); + CheckNames(readers, reader1.GetTypeDefNames(), "C`1"); Assert.Equal(1, reader1.GetTableRowCount(TableIndex.NestedClass)); @@ -2046,6 +2054,10 @@ interface J { } var reader1 = md1.Reader; var readers = new[] { reader0, reader1 }; + diff1.VerifyUpdatedTypes("0x02000002"); + + CheckNames(readers, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "I"); + CheckNames(readers, reader1.GetTypeDefNames(), "J"); CheckNames(readers, reader1.GetFieldDefNames(), "X", "Y"); CheckNames(readers, reader1.GetMethodDefNames(), "add_Y", "remove_Y", "M", "N", "get_P", "set_P", "get_Q", "set_Q", "add_E", "remove_E", "add_F", "remove_F", ".cctor"); @@ -2071,6 +2083,10 @@ interface J { } var reader2 = md2.Reader; readers = new[] { reader0, reader1, reader2 }; + diff2.VerifyUpdatedTypes("0x02000002"); + + CheckNames(readers, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "I"); + CheckNames(readers, reader2.GetTypeDefNames()); CheckNames(readers, reader2.GetFieldDefNames(), "X"); CheckNames(readers, reader2.GetMethodDefNames(), "M", "N", "get_P", "set_P", "get_Q", "set_Q", "add_E", "remove_E", "add_F", "remove_F", ".cctor"); @@ -2207,6 +2223,10 @@ [B] static void M2<[A]T>() { } var reader1 = md1.Reader; var readers = new[] { reader0, reader1 }; + diff1.VerifyUpdatedTypes("0x02000004"); + + CheckNames(readers, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "C"); + CheckNames(readers, reader1.GetTypeDefNames()); CheckNames(readers, reader1.GetMethodDefNames(), "M2", "get_P2", "add_E2", "remove_E2"); @@ -2352,6 +2372,11 @@ static void M() // Verify delta metadata contains expected rows. using var md1 = diff1.GetMetadata(); var readers = new[] { reader0, md1.Reader }; + + diff1.VerifyUpdatedTypes("0x02000002"); + + CheckNames(readers, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "C"); + CheckNames(readers, md1.Reader.GetTypeDefNames()); CheckNames(readers, md1.Reader.GetMethodDefNames(), "M"); CheckEncLog(md1.Reader, @@ -2422,6 +2447,11 @@ void M() using var md1 = diff1.GetMetadata(); var reader1 = md1.Reader; var readers = new[] { reader0, reader1 }; + + diff1.VerifyUpdatedTypes("0x02000003"); + + CheckNames(readers, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "C"); + CheckNames(readers, reader1.GetTypeDefNames()); CheckNames(readers, reader1.GetEventDefNames()); CheckNames(readers, reader1.GetFieldDefNames()); @@ -2453,6 +2483,8 @@ static void M() var testData0 = new CompilationTestData(); var bytes0 = compilation0.EmitToArray(testData: testData0); + using var md0 = ModuleMetadata.CreateFromImage(bytes0); + var reader0 = md0.MetadataReader; var generation0 = EmitBaseline.CreateInitialBaseline( ModuleMetadata.CreateFromImage(bytes0), @@ -2465,6 +2497,10 @@ static void M() var md1 = diff1.GetMetadata(); var reader1 = md1.Reader; + diff1.VerifyUpdatedTypes("0x02000002"); + + CheckNames(reader0, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "C"); + CheckEncLog(reader1, Row(2, TableIndex.AssemblyRef, EditAndContinueOperation.Default), Row(12, TableIndex.TypeRef, EditAndContinueOperation.Default), @@ -2554,11 +2590,17 @@ class C var compilation1 = compilation0.WithSource(source1); var bytes0 = compilation0.EmitToArray(); var generation0 = EmitBaseline.CreateInitialBaseline(ModuleMetadata.CreateFromImage(bytes0), EmptyLocalsProvider); + using var md0 = ModuleMetadata.CreateFromImage(bytes0); var diff1 = compilation1.EmitDifference( generation0, ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Insert, null, compilation1.GetMember("C.puts")))); + diff1.VerifyUpdatedTypes("0x02000002"); + + var reader0 = md0.MetadataReader; + CheckNames(reader0, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "C"); + using var md1 = diff1.GetMetadata(); var reader1 = md1.Reader; CheckEncLog(reader1, @@ -6178,7 +6220,7 @@ .locals init ([unchanged] V_0, IL_0021: br.s IL_0023 -IL_0023: ldloc.s V_6 IL_0025: ret -}", methodToken: diff1.UpdatedMethods.Single()); +}", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } /// @@ -7381,7 +7423,6 @@ static string F() var method1F = compilation1.GetMember("C.F"); using MemoryStream mdStream = new MemoryStream(), ilStream = new MemoryStream(), pdbStream = new MemoryStream(); - var updatedMethods = new List(); var isAddedSymbol = new Func(s => false); var badStream = new BrokenStream(); @@ -7394,7 +7435,6 @@ static string F() badStream, ilStream, pdbStream, - updatedMethods, new CompilationTestData(), default); Assert.False(result.Success); @@ -7410,7 +7450,6 @@ static string F() mdStream, badStream, pdbStream, - updatedMethods, new CompilationTestData(), default); Assert.False(result.Success); @@ -7426,7 +7465,6 @@ static string F() mdStream, ilStream, badStream, - updatedMethods, new CompilationTestData(), default); Assert.False(result.Success); @@ -7470,7 +7508,6 @@ static string F() var method1F = compilation1.GetMember("C.F"); using MemoryStream mdStream = new MemoryStream(), ilStream = new MemoryStream(), pdbStream = new MemoryStream(); - var updatedMethods = new List(); var isAddedSymbol = new Func(s => false); var badStream = new BrokenStream(); @@ -7483,7 +7520,6 @@ static string F() mdStream, ilStream, badStream, - updatedMethods, new CompilationTestData(), default); Assert.False(result.Success); @@ -9380,6 +9416,11 @@ .maxstack 2 ImmutableArray.Create( SemanticEdit.Create(SemanticEditKind.Update, ctor0, ctor1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + diff1.VerifyUpdatedTypes("0x02000002", "0x02000004"); + + var reader0 = md0.MetadataReader; + CheckNames(reader0, reader0.GetUpdatedTypeDefNames(diff1.EmitResult), "C", "<>c__DisplayClass0_0"); + diff1.VerifySynthesizedMembers( "C: {<>c__DisplayClass0_0}", "C.<>c__DisplayClass0_0: {x, <.ctor>b__0}"); @@ -9423,6 +9464,10 @@ .maxstack 2 ImmutableArray.Create( SemanticEdit.Create(SemanticEditKind.Update, ctor1, ctor2, GetSyntaxMapFromMarkers(source1, source0), preserveLocalVariables: true))); + diff2.VerifyUpdatedTypes("0x02000002", "0x02000004"); + + CheckNames(reader0, reader0.GetUpdatedTypeDefNames(diff2.EmitResult), "C", "<>c__DisplayClass0_0"); + diff2.VerifySynthesizedMembers( "C: {<>c__DisplayClass0_0}", "C.<>c__DisplayClass0_0: {x, <.ctor>b__0}"); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs index 257498198dd53..21b020ad0cdb1 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs @@ -594,7 +594,7 @@ .locals init (object V_0, } -IL_0041: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } /// @@ -1296,7 +1296,7 @@ .locals init (double[,,] V_0, IL_006c: ble.s IL_0027 -IL_006e: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -1765,7 +1765,7 @@ .locals init (string[] V_0, //arr IL_002b: conv.i4 IL_002c: blt.s IL_0017 -IL_002e: ret -}", methodToken: diff1.UpdatedMethods.Single()); +}", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -2035,7 +2035,7 @@ .locals init (object V_0, IL_0055: callvirt ""int string.Length.get"" IL_005a: blt.s IL_0044 -IL_005c: ret -}", methodToken: diff2.UpdatedMethods.Single()); +}", methodToken: diff2.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -2426,7 +2426,7 @@ .locals init (string V_0, IL_0036: nop -IL_0037: br.s IL_0039 -IL_0039: ret -}", methodToken: diff1.UpdatedMethods.Single()); +}", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -3270,7 +3270,7 @@ .locals init (object V_0, ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true))); diff1.VerifyIL("C.b__0", @" -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); #endif } @@ -3529,7 +3529,7 @@ .locals init (int V_0) ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true))); diff1.VerifyIL("?", @" -{", methodToken: diff1.UpdatedMethods.Single()); +{", methodToken: diff1.EmitResult.UpdatedMethods.Single()); #endif } @@ -3689,7 +3689,7 @@ .locals init (int V_0, ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true))); diff1.VerifyIL("?", @" -{", methodToken: diff1.UpdatedMethods.Single()); +{", methodToken: diff1.EmitResult.UpdatedMethods.Single()); #endif } @@ -3738,7 +3738,7 @@ .locals init (int V_0, //x -IL_0011: ldloc.3 IL_0012: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -3794,7 +3794,7 @@ .locals init (int V_0, //i IL_001f: br.s IL_0021 -IL_0021: ldloc.3 IL_0022: ret -}", methodToken: diff1.UpdatedMethods.Single()); +}", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -3849,7 +3849,7 @@ .locals init (System.ValueTuple> V_0, //x -IL_0031: ldloc.2 IL_0032: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -3901,7 +3901,7 @@ .locals init (int V_0, //x -IL_0010: ldloc.s V_4 IL_0012: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -3957,7 +3957,7 @@ .locals init (int V_0, //i IL_001f: br.s IL_0021 -IL_0021: ldloc.3 IL_0022: ret -}", methodToken: diff1.UpdatedMethods.Single()); +}", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -4017,7 +4017,7 @@ .locals init (bool V_0, IL_002b: br.s IL_002d -IL_002d: ldloc.2 IL_002e: ret -}", methodToken: diff1.UpdatedMethods.Single()); +}", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -4095,7 +4095,7 @@ .locals init (int V_0, //a -IL_003b: ldloc.s V_5 IL_003d: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -4186,7 +4186,7 @@ .locals init (int V_0, //i -IL_0049: ldloc.s V_6 IL_004b: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -4251,7 +4251,7 @@ .locals init (C.d__0 V_0) IL_0032: call ""System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task.get"" IL_0037: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -4311,7 +4311,7 @@ .locals init (C.d__0 V_0) IL_0032: call ""System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task.get"" IL_0037: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -4401,7 +4401,7 @@ .locals init (int V_0, //x -IL_0046: ldloc.s V_8 IL_0048: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] @@ -4485,7 +4485,7 @@ .locals init ([unchanged] V_0, IL_004b: blt.s IL_000e -IL_004d: ret } -", methodToken: diff1.UpdatedMethods.Single()); +", methodToken: diff1.EmitResult.UpdatedMethods.Single()); } [Fact] diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index b25ae0de6417c..767b815c8fb16 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -973,7 +973,6 @@ public IPointerTypeSymbol CreatePointerTypeSymbol(ITypeSymbol pointedAtType) protected abstract IPointerTypeSymbol CommonCreatePointerTypeSymbol(ITypeSymbol elementType); - /// /// Returns a new IFunctionPointerTypeSymbol representing a function pointer type tied to types in this /// Compilation. @@ -2699,6 +2698,7 @@ internal EmitResult Emit( return new EmitResult(success, diagnostics.ToReadOnlyAndFree()); } +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters /// /// Emit the differences between the compilation and the previous generation /// for Edit and Continue. The differences are expressed as added and changed @@ -2706,6 +2706,7 @@ internal EmitResult Emit( /// of the current compilation is returned as an EmitBaseline for use in a /// subsequent Edit and Continue. /// + [Obsolete("UpdatedMethods is now part of EmitDifferenceResult, so you should use an overload that doesn't take it.")] public EmitDifferenceResult EmitDifference( EmitBaseline baseline, IEnumerable edits, @@ -2725,6 +2726,7 @@ public EmitDifferenceResult EmitDifference( /// of the current compilation is returned as an EmitBaseline for use in a /// subsequent Edit and Continue. /// + [Obsolete("UpdatedMethods is now part of EmitDifferenceResult, so you should use an overload that doesn't take it.")] public EmitDifferenceResult EmitDifference( EmitBaseline baseline, IEnumerable edits, @@ -2734,6 +2736,32 @@ public EmitDifferenceResult EmitDifference( Stream pdbStream, ICollection updatedMethods, CancellationToken cancellationToken = default(CancellationToken)) + { + var diff = EmitDifference(baseline, edits, isAddedSymbol, metadataStream, ilStream, pdbStream, cancellationToken); + + foreach (var token in diff.UpdatedMethods) + { + updatedMethods.Add(token); + } + + return diff; + } + + /// + /// Emit the differences between the compilation and the previous generation + /// for Edit and Continue. The differences are expressed as added and changed + /// symbols, and are emitted as metadata, IL, and PDB deltas. A representation + /// of the current compilation is returned as an EmitBaseline for use in a + /// subsequent Edit and Continue. + /// + public EmitDifferenceResult EmitDifference( + EmitBaseline baseline, + IEnumerable edits, + Func isAddedSymbol, + Stream metadataStream, + Stream ilStream, + Stream pdbStream, + CancellationToken cancellationToken = default(CancellationToken)) { if (baseline == null) { @@ -2768,8 +2796,9 @@ public EmitDifferenceResult EmitDifference( throw new ArgumentNullException(nameof(pdbStream)); } - return this.EmitDifference(baseline, edits, isAddedSymbol, metadataStream, ilStream, pdbStream, updatedMethods, testData: null, cancellationToken); + return this.EmitDifference(baseline, edits, isAddedSymbol, metadataStream, ilStream, pdbStream, testData: null, cancellationToken); } +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters internal abstract EmitDifferenceResult EmitDifference( EmitBaseline baseline, @@ -2778,7 +2807,6 @@ internal abstract EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, - ICollection updatedMethodHandles, CompilationTestData? testData, CancellationToken cancellationToken); @@ -3067,7 +3095,8 @@ internal static bool SerializePeToStream( Stream metadataStream, Stream ilStream, Stream pdbStream, - ICollection updatedMethods, + ArrayBuilder updatedMethods, + ArrayBuilder updatedTypes, DiagnosticBag diagnostics, Func? testSymWriterFactory, string? pdbFilePath, @@ -3102,7 +3131,9 @@ internal static bool SerializePeToStream( (nativePdbWriter == null) ? pdbStream : null, out MetadataSizes metadataSizes); - writer.GetMethodTokens(updatedMethods); + writer.GetUpdatedMethodTokens(updatedMethods); + + writer.GetUpdatedTypeTokens(updatedTypes); nativePdbWriter?.WriteTo(pdbStream); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 8b0536a6bdbaf..353c61b7f2e88 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -25,6 +25,7 @@ internal sealed class DeltaMetadataWriter : MetadataWriter private readonly DefinitionMap _definitionMap; private readonly SymbolChanges _changes; + private readonly List _updatedTypeDefs; private readonly DefinitionIndex _typeDefs; private readonly DefinitionIndex _eventDefs; private readonly DefinitionIndex _fieldDefs; @@ -76,6 +77,7 @@ public DeltaMetadataWriter( var sizes = previousGeneration.TableSizes; + _updatedTypeDefs = new List(); _typeDefs = new DefinitionIndex(this.TryGetExistingTypeDefIndex, sizes[(int)TableIndex.TypeDef]); _eventDefs = new DefinitionIndex(this.TryGetExistingEventDefIndex, sizes[(int)TableIndex.Event]); _fieldDefs = new DefinitionIndex(this.TryGetExistingFieldDefIndex, sizes[(int)TableIndex.Field]); @@ -216,7 +218,7 @@ private static IReadOnlyDictionary AddRange(IReadOnlyDictionary /// Return tokens for all modified debuggable methods. /// - public void GetMethodTokens(ICollection methods) + public void GetUpdatedMethodTokens(ArrayBuilder methods) { foreach (var def in _methodDefs.GetRows()) { @@ -228,6 +230,17 @@ public void GetMethodTokens(ICollection methods) } } + /// + /// Return tokens for all modified debuggable types. + /// + public void GetUpdatedTypeTokens(ArrayBuilder types) + { + foreach (var def in _updatedTypeDefs) + { + types.Add(MetadataTokens.TypeDefinitionHandle(_typeDefs[def])); + } + } + protected override ushort Generation { get { return (ushort)(_previousGeneration.Ordinal + 1); } @@ -444,10 +457,15 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) case SymbolChange.Updated: _typeDefs.AddUpdated(typeDef); + _updatedTypeDefs.Add(typeDef); break; case SymbolChange.ContainsChanges: // Members changed. + // We keep this list separately because we don't want to output duplicate typedef entries in the EnC log, + // which uses _typeDefs, but it's simpler to let the members output those rows for the updated typedefs + // with the right update type. + _updatedTypeDefs.Add(typeDef); break; case SymbolChange.None: diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitDifferenceResult.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitDifferenceResult.cs index 40af43efb470d..02e8e74297ab4 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitDifferenceResult.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitDifferenceResult.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Reflection.Metadata; namespace Microsoft.CodeAnalysis.Emit { @@ -10,10 +11,16 @@ public sealed class EmitDifferenceResult : EmitResult { public EmitBaseline? Baseline { get; } - internal EmitDifferenceResult(bool success, ImmutableArray diagnostics, EmitBaseline? baseline) : - base(success, diagnostics) + public ImmutableArray UpdatedMethods { get; } + + public ImmutableArray UpdatedTypes { get; } + + internal EmitDifferenceResult(bool success, ImmutableArray diagnostics, EmitBaseline? baseline, ImmutableArray updatedMethods, ImmutableArray updatedTypes) + : base(success, diagnostics) { Baseline = baseline; + UpdatedMethods = updatedMethods; + UpdatedTypes = updatedTypes; } } } diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 2150bf83007de..9a671f5f41145 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,5 +1,8 @@ *REMOVED*Microsoft.CodeAnalysis.SyntaxNode.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxNode! other) -> bool const Microsoft.CodeAnalysis.WellKnownMemberNames.PrintMembersMethodName = "PrintMembers" -> string! +Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! +Microsoft.CodeAnalysis.Emit.EmitDifferenceResult.UpdatedMethods.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.Emit.EmitDifferenceResult.UpdatedTypes.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.GeneratorAttribute.GeneratorAttribute(string! firstLanguage, params string![]! additionalLanguages) -> void Microsoft.CodeAnalysis.GeneratorAttribute.Languages.get -> string![]! Microsoft.CodeAnalysis.IFieldSymbol.IsExplicitlyNamedTupleElement.get -> bool diff --git a/src/Compilers/Test/Core/Compilation/CompilationDifference.cs b/src/Compilers/Test/Core/Compilation/CompilationDifference.cs index 9afdbbf5c5442..cf8e61bad5444 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationDifference.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationDifference.cs @@ -28,22 +28,19 @@ public sealed class CompilationDifference public readonly ImmutableArray PdbDelta; internal readonly CompilationTestData TestData; public readonly EmitDifferenceResult EmitResult; - public readonly ImmutableArray UpdatedMethods; internal CompilationDifference( ImmutableArray metadata, ImmutableArray il, ImmutableArray pdb, CompilationTestData testData, - EmitDifferenceResult result, - ImmutableArray methodHandles) + EmitDifferenceResult result) { MetadataDelta = metadata; ILDelta = il; PdbDelta = pdb; TestData = testData; EmitResult = result; - UpdatedMethods = methodHandles; } public EmitBaseline NextGeneration @@ -150,7 +147,14 @@ public void VerifyUpdatedMethods(params string[] expectedMethodTokens) { AssertEx.Equal( expectedMethodTokens, - UpdatedMethods.Select(methodHandle => $"0x{MetadataTokens.GetToken(methodHandle):X8}")); + EmitResult.UpdatedMethods.Select(methodHandle => $"0x{MetadataTokens.GetToken(methodHandle):X8}")); + } + + public void VerifyUpdatedTypes(params string[] expectedTypeTokens) + { + AssertEx.Equal( + expectedTypeTokens, + EmitResult.UpdatedTypes.Select(typeHandle => $"0x{MetadataTokens.GetToken(typeHandle):X8}")); } } } diff --git a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs index d9323306c5c56..b32953150b1a8 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs @@ -145,8 +145,6 @@ internal static CompilationDifference EmitDifference( using var ilStream = new MemoryStream(); using var pdbStream = new MemoryStream(); - var updatedMethods = new List(); - var result = compilation.EmitDifference( baseline, edits, @@ -154,7 +152,6 @@ internal static CompilationDifference EmitDifference( mdStream, ilStream, pdbStream, - updatedMethods, testData, CancellationToken.None); @@ -163,8 +160,7 @@ internal static CompilationDifference EmitDifference( ilStream.ToImmutable(), pdbStream.ToImmutable(), testData, - result, - updatedMethods.ToImmutableArray()); + result); } internal static void VerifyAssemblyVersionsAndAliases(this Compilation compilation, params string[] expectedAssembliesAndAliases) diff --git a/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs b/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs index 298889f6004fa..51f5c91a89bad 100644 --- a/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs +++ b/src/Compilers/Test/Core/Metadata/MetadataReaderUtils.cs @@ -7,18 +7,17 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; +using System.IO.Compression; using System.Linq; -using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; -using Microsoft.CodeAnalysis; -using Roslyn.Utilities; using Microsoft.CodeAnalysis.Debugging; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using System.IO; -using System.IO.Compression; +using Roslyn.Utilities; namespace Roslyn.Test.Utilities { @@ -110,6 +109,11 @@ public static Guid GetModuleVersionId(this MetadataReader reader) return reader.GetGuid(reader.GetModuleDefinition().Mvid); } + public static StringHandle[] GetUpdatedTypeDefNames(this MetadataReader reader, EmitDifferenceResult emitResult) + { + return emitResult.UpdatedTypes.Select(handle => reader.GetTypeDefinition(handle).Name).ToArray(); + } + public static StringHandle[] GetAssemblyRefNames(this MetadataReader reader) { return reader.AssemblyReferences.Select(handle => reader.GetAssemblyReference(handle).Name).ToArray(); diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index d15ac350b8b58..d445d7b3c6cf7 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -2554,7 +2554,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic metadataStream As Stream, ilStream As Stream, pdbStream As Stream, - updatedMethods As ICollection(Of MethodDefinitionHandle), testData As CompilationTestData, cancellationToken As CancellationToken) As EmitDifferenceResult @@ -2566,7 +2565,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic metadataStream, ilStream, pdbStream, - updatedMethods, testData, cancellationToken) End Function diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb index f15985b0d51a2..659acb689b99e 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.Emit +Imports Microsoft.CodeAnalysis.PooledObjects Namespace Microsoft.CodeAnalysis.VisualBasic.Emit @@ -22,7 +23,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit metadataStream As Stream, ilStream As Stream, pdbStream As Stream, - updatedMethods As ICollection(Of MethodDefinitionHandle), testData As CompilationTestData, cancellationToken As CancellationToken) As EmitDifferenceResult @@ -34,6 +34,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Dim serializationProperties = compilation.ConstructModuleSerializationProperties(emitOpts, runtimeMDVersion, baseline.ModuleVersionId) Dim manifestResources = SpecializedCollections.EmptyEnumerable(Of ResourceDescription)() + Dim updatedMethods = ArrayBuilder(Of MethodDefinitionHandle).GetInstance() + Dim updatedTypes = ArrayBuilder(Of TypeDefinitionHandle).GetInstance() + Dim moduleBeingBuilt As PEDeltaAssemblyBuilder Try moduleBeingBuilt = New PEDeltaAssemblyBuilder( @@ -48,7 +51,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Catch e As NotSupportedException ' TODO: https://github.com/dotnet/roslyn/issues/9004 diagnostics.Add(ERRID.ERR_ModuleEmitFailure, NoLocation.Singleton, compilation.AssemblyName, e.Message) - Return New EmitDifferenceResult(success:=False, diagnostics:=diagnostics.ToReadOnlyAndFree(), baseline:=Nothing) + Return New EmitDifferenceResult(success:=False, diagnostics:=diagnostics.ToReadOnlyAndFree(), baseline:=Nothing, updatedMethods:=updatedMethods.ToImmutableAndFree(), updatedTypes:=updatedTypes.ToImmutableAndFree()) End Try If testData IsNot Nothing Then @@ -81,6 +84,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ilStream, pdbStream, updatedMethods, + updatedTypes, diagnostics, testData?.SymWriterFactory, emitOpts.PdbFilePath, @@ -90,7 +94,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return New EmitDifferenceResult( success:=newBaseline IsNot Nothing, diagnostics:=diagnostics.ToReadOnlyAndFree(), - baseline:=newBaseline) + baseline:=newBaseline, + updatedMethods:=updatedMethods.ToImmutableAndFree(), + updatedTypes:=updatedTypes.ToImmutableAndFree()) End Function Friend Function MapToCompilation( diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 6d1adc2be1962..bdf4c555bd603 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -882,8 +882,6 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol using var metadataStream = SerializableBytes.CreateWritableStream(); using var ilStream = SerializableBytes.CreateWritableStream(); - var updatedMethods = ImmutableArray.CreateBuilder(); - // project must support compilations since it supports EnC Contract.ThrowIfNull(newCompilation); @@ -894,14 +892,15 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol metadataStream, ilStream, pdbStream, - updatedMethods, cancellationToken); if (emitResult.Success) { Contract.ThrowIfNull(emitResult.Baseline); - var updatedMethodTokens = updatedMethods.SelectAsArray(h => MetadataTokens.GetToken(h)); + // TODO: Pass these to ManagedModuleUpdate in the new debugger contracts API + var updatedMethodTokens = emitResult.UpdatedMethods.SelectAsArray(h => MetadataTokens.GetToken(h)); + var updatedTypeTokens = emitResult.UpdatedTypes.SelectAsArray(h => MetadataTokens.GetToken(h)); // Determine all active statements whose span changed and exception region span deltas. GetActiveStatementAndExceptionRegionSpans(