From d9e0900ec20843423e20f4a0a956e13f44c4fc7b Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 20 Aug 2021 15:51:02 -0700 Subject: [PATCH 1/3] Drop active statements when exiting break mode --- .../ManagedEditAndContinueLanguageService.cs | 23 ++- .../EditAndContinueWorkspaceServiceTests.cs | 158 ++++++++++++++---- .../RemoteEditAndContinueServiceTests.cs | 7 +- .../MockEditAndContinueWorkspaceService.cs | 9 +- .../EditAndContinue/DebuggingSession.cs | 4 +- .../EditAndContinueWorkspaceService.cs | 4 +- .../IEditAndContinueWorkspaceService.cs | 2 +- .../Remote/IRemoteEditAndContinueService.cs | 3 +- .../Remote/RemoteDebuggingSessionProxy.cs | 6 +- .../RemoteEditAndContinueService.cs | 5 +- 10 files changed, 166 insertions(+), 55 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs index 220b421d39a38..6a3b87151c1ae 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs @@ -122,7 +122,7 @@ public async Task EnterBreakStateAsync(CancellationToken cancellationToken) try { - await session.BreakStateEnteredAsync(_diagnosticService, cancellationToken).ConfigureAwait(false); + await session.BreakStateChangedAsync(_diagnosticService, inBreakState: true, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { @@ -135,16 +135,29 @@ public async Task EnterBreakStateAsync(CancellationToken cancellationToken) await GetActiveStatementTrackingService().StartTrackingAsync(solution, session, cancellationToken).ConfigureAwait(false); } - public Task ExitBreakStateAsync(CancellationToken cancellationToken) + public async Task ExitBreakStateAsync(CancellationToken cancellationToken) { GetDebuggingService().OnBeforeDebuggingStateChanged(DebuggingState.Break, DebuggingState.Run); - if (!_disabled) + if (_disabled) { - GetActiveStatementTrackingService().EndTracking(); + return; } - return Task.CompletedTask; + var session = GetDebuggingSession(); + + try + { + Contract.ThrowIfTrue(_disabled); + await session.BreakStateChangedAsync(_diagnosticService, inBreakState: false, cancellationToken).ConfigureAwait(false); + + GetActiveStatementTrackingService().EndTracking(); + } + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) + { + _disabled = true; + return; + } } public async Task CommitUpdatesAsync(CancellationToken cancellationToken) diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index 64dad861de24c..320f46661369d 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -171,13 +171,17 @@ private void EnterBreakState( ImmutableArray documentsWithRudeEdits = default) { _debuggerService.GetActiveStatementsImpl = () => activeStatements.NullToEmpty(); - session.BreakStateEntered(out var documentsToReanalyze); + session.BreakStateChanged(inBreakState: true, out var documentsToReanalyze); AssertEx.Equal(documentsWithRudeEdits.NullToEmpty(), documentsToReanalyze); } - private void ExitBreakState() + private void ExitBreakState( + DebuggingSession session, + ImmutableArray documentsWithRudeEdits = default) { _debuggerService.GetActiveStatementsImpl = () => ImmutableArray.Empty; + session.BreakStateChanged(inBreakState: false, out var documentsToReanalyze); + AssertEx.Equal(documentsWithRudeEdits.NullToEmpty(), documentsToReanalyze); } private static void CommitSolutionUpdate(DebuggingSession session, ImmutableArray documentsWithRudeEdits = default) @@ -838,7 +842,7 @@ public async Task ErrorReadingModuleFile(bool breakMode) if (breakMode) { - ExitBreakState(); + ExitBreakState(debuggingSession); } EndDebuggingSession(debuggingSession); @@ -847,7 +851,7 @@ public async Task ErrorReadingModuleFile(bool breakMode) { AssertEx.Equal(new[] { - "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", + "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC1001" }, _telemetryLog); @@ -1023,7 +1027,7 @@ public async Task FileAdded(bool breakMode) if (breakMode) { - ExitBreakState(); + ExitBreakState(debuggingSession); } EndDebuggingSession(debuggingSession); @@ -1032,7 +1036,7 @@ public async Task FileAdded(bool breakMode) { AssertEx.Equal(new[] { - "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", + "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=True" }, _telemetryLog); } @@ -1193,10 +1197,13 @@ public async Task RudeEdits(bool breakMode) if (breakMode) { - ExitBreakState(); + ExitBreakState(debuggingSession, documentsWithRudeEdits: ImmutableArray.Create(document2.Id)); + EndDebuggingSession(debuggingSession); + } + else + { + EndDebuggingSession(debuggingSession, documentsWithRudeEdits: ImmutableArray.Create(document2.Id)); } - - EndDebuggingSession(debuggingSession, documentsWithRudeEdits: ImmutableArray.Create(document2.Id)); AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); @@ -1204,7 +1211,7 @@ public async Task RudeEdits(bool breakMode) { AssertEx.Equal(new[] { - "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", + "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True", "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True" }, _telemetryLog); @@ -1334,10 +1341,13 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) if (breakMode) { - ExitBreakState(); + ExitBreakState(debuggingSession, documentsWithRudeEdits: ImmutableArray.Create(document2.Id)); + EndDebuggingSession(debuggingSession); + } + else + { + EndDebuggingSession(debuggingSession, documentsWithRudeEdits: ImmutableArray.Create(document2.Id)); } - - EndDebuggingSession(debuggingSession, documentsWithRudeEdits: ImmutableArray.Create(document2.Id)); AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); @@ -1345,7 +1355,7 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) { AssertEx.Equal(new[] { - "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", + "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True", "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True" }, _telemetryLog); @@ -1623,7 +1633,7 @@ public async Task Capabilities() AssertEx.Empty(diagnostics); // attach to additional processes - at least one process that does not allow updating custom attributes: - ExitBreakState(); + ExitBreakState(debuggingSession); _debuggerService.GetCapabilitiesImpl = () => ImmutableArray.Create("Baseline"); EnterBreakState(debuggingSession); @@ -1631,7 +1641,7 @@ public async Task Capabilities() AssertEx.Equal(new[] { "ENC0101: " + string.Format(FeaturesResources.Updating_the_attributes_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.class_) }, diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); - ExitBreakState(); + ExitBreakState(debuggingSession, documentsWithRudeEdits: ImmutableArray.Create(documentId)); diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetDocument(documentId), s_noActiveSpans, CancellationToken.None); AssertEx.Equal(new[] { "ENC0101: " + string.Format(FeaturesResources.Updating_the_attributes_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.class_) }, @@ -1645,7 +1655,7 @@ public async Task Capabilities() diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetDocument(documentId), s_noActiveSpans, CancellationToken.None); AssertEx.Empty(diagnostics); - ExitBreakState(); + ExitBreakState(debuggingSession); EndDebuggingSession(debuggingSession); } @@ -1762,7 +1772,7 @@ public async Task ValidSignificantChange_ApplyBeforeFileWatcherEvent(bool saveDo Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); CommitSolutionUpdate(debuggingSession); - ExitBreakState(); + ExitBreakState(debuggingSession); EnterBreakState(debuggingSession); @@ -1785,7 +1795,7 @@ public async Task ValidSignificantChange_ApplyBeforeFileWatcherEvent(bool saveDo Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); } - ExitBreakState(); + ExitBreakState(debuggingSession); EndDebuggingSession(debuggingSession); } @@ -2091,7 +2101,7 @@ void ValidateDelta(ManagedModuleUpdate delta) if (breakMode) { - ExitBreakState(); + ExitBreakState(debuggingSession); } EndDebuggingSession(debuggingSession); @@ -2105,7 +2115,7 @@ void ValidateDelta(ManagedModuleUpdate delta) { AssertEx.Equal(new[] { - $"Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount={(commitUpdate ? 2 : 1)}", + $"Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount={(commitUpdate ? 3 : 2)}", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=True", }, _telemetryLog); } @@ -2201,7 +2211,7 @@ public async Task ValidSignificantChange_EmitSuccessful_UpdateDeferred(bool comm // solution update status after committing an update: Assert.False(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); - ExitBreakState(); + ExitBreakState(debuggingSession); // make another update: EnterBreakState(debuggingSession); @@ -2222,7 +2232,7 @@ public async Task ValidSignificantChange_EmitSuccessful_UpdateDeferred(bool comm Assert.Null(debuggingSession.GetTestAccessor().GetPendingSolutionUpdate()); } - ExitBreakState(); + ExitBreakState(debuggingSession); EndDebuggingSession(debuggingSession); // open module readers should be disposed when the debugging session ends: @@ -2665,7 +2675,7 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() // solution update status after committing an update: Assert.False(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); - ExitBreakState(); + ExitBreakState(debuggingSession); EnterBreakState(debuggingSession); // @@ -2719,7 +2729,7 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() // solution update status after committing an update: Assert.False(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); - ExitBreakState(); + ExitBreakState(debuggingSession); EndDebuggingSession(debuggingSession); // open deferred module readers should be dispose when the debugging session ends: @@ -3268,6 +3278,94 @@ void F() EndDebuggingSession(debuggingSession); } + [Fact] + public async Task ActiveStatements_EncSessionFollowedByHotReload() + { + var markedSource1 = @" +class C +{ + int F() + { + try + { + return 0; + } + catch + { + return 1; + } + } +} +"; + var markedSource2 = @" +class C +{ + int F() + { + try + { + return 0; + } + catch + { + return 2; + } + } +} +"; + var source1 = ActiveStatementsDescription.ClearTags(markedSource1); + var source2 = ActiveStatementsDescription.ClearTags(markedSource2); + + using var _ = CreateWorkspace(out var solution, out var service); + (solution, var document) = AddDefaultTestProject(solution, source1); + + var moduleId = EmitLibrary(source1); + LoadLibraryToDebuggee(moduleId); + + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + + EnterBreakState(debuggingSession, GetActiveStatementDebugInfosCSharp( + new[] { markedSource1 }, + modules: new[] { moduleId }, + methodRowIds: new[] { 1 }, + methodVersions: new[] { 1 }, + flags: new[] + { + ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.IsLeafFrame + })); + + // change the source (rude edit) + solution = solution.WithDocumentText(document.Id, SourceText.From(source2, Encoding.UTF8)); + document = solution.GetDocument(document.Id); + + var diagnostics = await service.GetDocumentDiagnosticsAsync(document, s_noActiveSpans, CancellationToken.None); + AssertEx.Equal(new[] { "ENC0063: " + string.Format(FeaturesResources.Updating_a_0_around_an_active_statement_requires_restarting_the_application, CSharpFeaturesResources.catch_clause) }, + diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); + + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Empty(emitDiagnostics); + Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status); + + // undo the change + solution = solution.WithDocumentText(document.Id, SourceText.From(source1, Encoding.UTF8)); + document = solution.GetDocument(document.Id); + + ExitBreakState(debuggingSession, ImmutableArray.Create(document.Id)); + + // change the source (now a valid edit since there is no active statement) + solution = solution.WithDocumentText(document.Id, SourceText.From(source2, Encoding.UTF8)); + + diagnostics = await service.GetDocumentDiagnosticsAsync(document, s_noActiveSpans, CancellationToken.None); + Assert.Empty(diagnostics); + + // validate solution update status and emit (Hot Reload change): + (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Empty(emitDiagnostics); + Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + + EndDebuggingSession(debuggingSession); + } + /// /// Scenario: /// F5 a program that has function F that calls G. G has a long-running loop, which starts executing. @@ -3338,7 +3436,7 @@ static void F() $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) δ=1", }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); - ExitBreakState(); + ExitBreakState(debuggingSession); // Hot Reload update F v2 -> v3 @@ -3387,7 +3485,7 @@ static void F() $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) δ=5" }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); - ExitBreakState(); + ExitBreakState(debuggingSession); } /// @@ -3512,7 +3610,7 @@ static void F() $"0x06000003 v1 | AS {document.FilePath}: (7,14)-(7,18) δ=2", }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); - ExitBreakState(); + ExitBreakState(debuggingSession); } /// @@ -3598,7 +3696,7 @@ static void F() new ActiveStatementSpan(1, expectedSpanF1, ActiveStatementFlags.IsNonLeafFrame, unmappedDocumentId: null) }, spans); - ExitBreakState(); + ExitBreakState(debuggingSession); } [Fact] @@ -3670,7 +3768,7 @@ public async Task Disposal() await Assert.ThrowsAsync(async () => await debuggingSession.EmitSolutionUpdateAsync(solution, s_noActiveSpans, CancellationToken.None)); await Assert.ThrowsAsync(async () => await debuggingSession.GetCurrentActiveStatementPositionAsync(solution, s_noActiveSpans, instructionId: default, CancellationToken.None)); await Assert.ThrowsAsync(async () => await debuggingSession.IsActiveStatementInExceptionRegionAsync(solution, instructionId: default, CancellationToken.None)); - Assert.Throws(() => debuggingSession.BreakStateEntered(out _)); + Assert.Throws(() => debuggingSession.BreakStateChanged(inBreakState: true, out _)); Assert.Throws(() => debuggingSession.DiscardSolutionUpdate()); Assert.Throws(() => debuggingSession.CommitSolutionUpdate(out _)); Assert.Throws(() => debuggingSession.EndSession(out _, out _)); diff --git a/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs index 4b8bc8be8d173..b450c99aa6c9b 100644 --- a/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs @@ -160,14 +160,15 @@ void VerifyReanalyzeInvocation(ImmutableArray documentIds) Contract.ThrowIfNull(sessionProxy); - // BreakStateEntered + // BreakStateChanged - mockEncService.BreakStateEnteredImpl = (out ImmutableArray documentsToReanalyze) => + mockEncService.BreakStateChangesImpl = (bool inBreakState, out ImmutableArray documentsToReanalyze) => { + Assert.True(inBreakState); documentsToReanalyze = ImmutableArray.Create(document.Id); }; - await sessionProxy.BreakStateEnteredAsync(mockDiagnosticService, CancellationToken.None).ConfigureAwait(false); + await sessionProxy.BreakStateChangedAsync(mockDiagnosticService, inBreakState: true, CancellationToken.None).ConfigureAwait(false); VerifyReanalyzeInvocation(ImmutableArray.Create(document.Id)); var activeStatement = (await remoteDebuggeeModuleMetadataProvider!.GetActiveStatementsAsync(CancellationToken.None).ConfigureAwait(false)).Single(); diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/MockEditAndContinueWorkspaceService.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/MockEditAndContinueWorkspaceService.cs index be25d9f98bb7e..e57ef93a99bfb 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/MockEditAndContinueWorkspaceService.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/MockEditAndContinueWorkspaceService.cs @@ -11,7 +11,8 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { - internal delegate void ActionOut(out T arg); + internal delegate void ActionOut(out TArg1 arg); + internal delegate void ActionOut(TArg1 arg1, out TArg2 arg2); internal class MockEditAndContinueWorkspaceService : IEditAndContinueWorkspaceService { @@ -27,14 +28,14 @@ internal class MockEditAndContinueWorkspaceService : IEditAndContinueWorkspaceSe public Func? IsActiveStatementInExceptionRegionImpl; public Action? OnSourceFileUpdatedImpl; public ActionOut>? CommitSolutionUpdateImpl; - public ActionOut>? BreakStateEnteredImpl; + public ActionOut>? BreakStateChangesImpl; public Action? DiscardSolutionUpdateImpl; public Func>? GetDocumentDiagnosticsImpl; - public void BreakStateEntered(DebuggingSessionId sessionId, out ImmutableArray documentsToReanalyze) + public void BreakStateChanged(DebuggingSessionId sessionId, bool inBreakState, out ImmutableArray documentsToReanalyze) { documentsToReanalyze = ImmutableArray.Empty; - BreakStateEnteredImpl?.Invoke(out documentsToReanalyze); + BreakStateChangesImpl?.Invoke(inBreakState, out documentsToReanalyze); } public void CommitSolutionUpdate(DebuggingSessionId sessionId, out ImmutableArray documentsToReanalyze) diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 2f8415bcc90b4..3b005fa3d02d5 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -182,8 +182,8 @@ public void EndSession(out ImmutableArray documentsToReanalyze, out Dispose(); } - public void BreakStateEntered(out ImmutableArray documentsToReanalyze) - => RestartEditSession(nonRemappableRegions: null, inBreakState: true, out documentsToReanalyze); + public void BreakStateChanged(bool inBreakState, out ImmutableArray documentsToReanalyze) + => RestartEditSession(nonRemappableRegions: null, inBreakState, out documentsToReanalyze); internal void RestartEditSession(ImmutableDictionary>? nonRemappableRegions, bool inBreakState, out ImmutableArray documentsToReanalyze) { diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index ba055f97c2c5c..d65e24eb87612 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -157,11 +157,11 @@ public void EndDebuggingSession(DebuggingSessionId sessionId, out ImmutableArray debuggingSession.EndSession(out documentsToReanalyze, out var telemetryData); } - public void BreakStateEntered(DebuggingSessionId sessionId, out ImmutableArray documentsToReanalyze) + public void BreakStateChanged(DebuggingSessionId sessionId, bool inBreakState, out ImmutableArray documentsToReanalyze) { var debuggingSession = TryGetDebuggingSession(sessionId); Contract.ThrowIfNull(debuggingSession); - debuggingSession.BreakStateEntered(out documentsToReanalyze); + debuggingSession.BreakStateChanged(inBreakState, out documentsToReanalyze); } public ValueTask> GetDocumentDiagnosticsAsync(Document document, ActiveStatementSpanProvider activeStatementSpanProvider, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueWorkspaceService.cs index c827e14e9d30b..6c7491fbfd0e6 100644 --- a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueWorkspaceService.cs @@ -23,7 +23,7 @@ internal interface IEditAndContinueWorkspaceService : IWorkspaceService void OnSourceFileUpdated(Document document); ValueTask StartDebuggingSessionAsync(Solution solution, IManagedEditAndContinueDebuggerService debuggerService, ImmutableArray captureMatchingDocuments, bool captureAllMatchingDocuments, bool reportDiagnostics, CancellationToken cancellationToken); - void BreakStateEntered(DebuggingSessionId sessionId, out ImmutableArray documentsToReanalyze); + void BreakStateChanged(DebuggingSessionId sessionId, bool inBreakState, out ImmutableArray documentsToReanalyze); void EndDebuggingSession(DebuggingSessionId sessionId, out ImmutableArray documentsToReanalyze); ValueTask IsActiveStatementInExceptionRegionAsync(DebuggingSessionId sessionId, Solution solution, ManagedInstructionId instructionId, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/EditAndContinue/Remote/IRemoteEditAndContinueService.cs b/src/Features/Core/Portable/EditAndContinue/Remote/IRemoteEditAndContinueService.cs index ed5d7e5d6fa2b..10b13294f58ec 100644 --- a/src/Features/Core/Portable/EditAndContinue/Remote/IRemoteEditAndContinueService.cs +++ b/src/Features/Core/Portable/EditAndContinue/Remote/IRemoteEditAndContinueService.cs @@ -40,13 +40,12 @@ internal interface ICallback /// /// Returns ids of documents for which diagnostics need to be refreshed in-proc. /// - ValueTask> BreakStateEnteredAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken); + ValueTask> BreakStateChangedAsync(DebuggingSessionId sessionId, bool isBreakState, CancellationToken cancellationToken); /// /// Returns ids of documents for which diagnostics need to be refreshed in-proc. /// ValueTask> EndDebuggingSessionAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken); - ValueTask>> GetBaseActiveStatementSpansAsync(PinnedSolutionInfo solutionInfo, DebuggingSessionId sessionId, ImmutableArray documentIds, CancellationToken cancellationToken); ValueTask> GetAdjustedActiveStatementSpansAsync(PinnedSolutionInfo solutionInfo, RemoteServiceCallbackId callbackId, DebuggingSessionId sessionId, DocumentId documentId, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs index 21e7e09fb5fd6..dba7561a2d918 100644 --- a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs +++ b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs @@ -41,19 +41,19 @@ public void Dispose() private IEditAndContinueWorkspaceService GetLocalService() => _workspace.Services.GetRequiredService(); - public async ValueTask BreakStateEnteredAsync(IDiagnosticAnalyzerService diagnosticService, CancellationToken cancellationToken) + public async ValueTask BreakStateChangedAsync(IDiagnosticAnalyzerService diagnosticService, bool inBreakState, CancellationToken cancellationToken) { ImmutableArray documentsToReanalyze; var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); if (client == null) { - GetLocalService().BreakStateEntered(_sessionId, out documentsToReanalyze); + GetLocalService().BreakStateChanged(_sessionId, inBreakState, out documentsToReanalyze); } else { var documentsToReanalyzeOpt = await client.TryInvokeAsync>( - (service, cancallationToken) => service.BreakStateEnteredAsync(_sessionId, cancellationToken), + (service, cancallationToken) => service.BreakStateChangedAsync(_sessionId, inBreakState, cancellationToken), cancellationToken).ConfigureAwait(false); documentsToReanalyze = documentsToReanalyzeOpt.HasValue ? documentsToReanalyzeOpt.Value : ImmutableArray.Empty; diff --git a/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs b/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs index fed04f4b6d834..6592a195d614f 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue { @@ -81,11 +80,11 @@ public ValueTask StartDebuggingSessionAsync(PinnedSolutionIn /// /// Remote API. /// - public ValueTask> BreakStateEnteredAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken) + public ValueTask> BreakStateChangedAsync(DebuggingSessionId sessionId, bool inBreakState, CancellationToken cancellationToken) { return RunServiceAsync(cancellationToken => { - GetService().BreakStateEntered(sessionId, out var documentsToReanalyze); + GetService().BreakStateChanged(sessionId, inBreakState, out var documentsToReanalyze); return new ValueTask>(documentsToReanalyze); }, cancellationToken); } From 5b484a75d9969354ce363c75bb36f7217926e51f Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 20 Aug 2021 15:52:09 -0700 Subject: [PATCH 2/3] Add WorkItem --- .../Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index 320f46661369d..b53f1653e4ad5 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -3279,6 +3279,7 @@ void F() } [Fact] + [WorkItem(54347, "https://github.com/dotnet/roslyn/issues/54347")] public async Task ActiveStatements_EncSessionFollowedByHotReload() { var markedSource1 = @" From 08acf2eb5482fc1648717de3b3bba55f401212e8 Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 20 Aug 2021 15:54:06 -0700 Subject: [PATCH 3/3] Fix --- .../EditAndContinue/ManagedEditAndContinueLanguageService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs index 6a3b87151c1ae..d45f2b6eb0403 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/ManagedEditAndContinueLanguageService.cs @@ -148,9 +148,7 @@ public async Task ExitBreakStateAsync(CancellationToken cancellationToken) try { - Contract.ThrowIfTrue(_disabled); await session.BreakStateChangedAsync(_diagnosticService, inBreakState: false, cancellationToken).ConfigureAwait(false); - GetActiveStatementTrackingService().EndTracking(); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))