Skip to content

Commit

Permalink
Implement capabilities changed handler (#56584)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat authored Sep 21, 2021
1 parent 1d81d6a commit 0f60b3e
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue;
using Microsoft.VisualStudio.Debugger.Contracts.HotReload;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.Implementation.EditAndContinue
Expand All @@ -22,6 +23,7 @@ internal sealed class EditAndContinueLanguageService : IEditAndContinueSolutionP
private static readonly ActiveStatementSpanProvider s_noActiveStatementSpanProvider =
(_, _, _) => ValueTaskFactory.FromResult(ImmutableArray<ActiveStatementSpan>.Empty);

private readonly Lazy<IManagedEditAndContinueDebuggerService> _debuggerService;
private readonly IDiagnosticAnalyzerService _diagnosticService;
private readonly EditAndContinueDiagnosticUpdateSource _diagnosticUpdateSource;

Expand All @@ -41,10 +43,12 @@ internal sealed class EditAndContinueLanguageService : IEditAndContinueSolutionP
/// </summary>
public EditAndContinueLanguageService(
Lazy<IHostWorkspaceProvider> workspaceProvider,
Lazy<IManagedEditAndContinueDebuggerService> debuggerService,
IDiagnosticAnalyzerService diagnosticService,
EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource)
{
WorkspaceProvider = workspaceProvider;
_debuggerService = debuggerService;
_diagnosticService = diagnosticService;
_diagnosticUpdateSource = diagnosticUpdateSource;
}
Expand All @@ -71,7 +75,7 @@ internal void Disable()
/// <summary>
/// Called by the debugger when a debugging session starts and managed debugging is being used.
/// </summary>
public async ValueTask StartSessionAsync(IManagedEditAndContinueDebuggerService debugger, CancellationToken cancellationToken)
public async ValueTask StartSessionAsync(CancellationToken cancellationToken)
{
IsSessionActive = true;

Expand All @@ -89,7 +93,7 @@ public async ValueTask StartSessionAsync(IManagedEditAndContinueDebuggerService

_debuggingSession = await proxy.StartDebuggingSessionAsync(
solution,
debugger,
_debuggerService.Value,
captureMatchingDocuments: openedDocumentIds,
captureAllMatchingDocuments: false,
reportDiagnostics: true,
Expand All @@ -115,7 +119,7 @@ public async ValueTask EnterBreakStateAsync(CancellationToken cancellationToken)

try
{
await session.BreakStateChangedAsync(_diagnosticService, inBreakState: true, cancellationToken).ConfigureAwait(false);
await session.BreakStateOrCapabilitiesChangedAsync(_diagnosticService, inBreakState: true, cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
{
Expand All @@ -139,7 +143,7 @@ public async ValueTask ExitBreakStateAsync(CancellationToken cancellationToken)

try
{
await session.BreakStateChangedAsync(_diagnosticService, inBreakState: false, cancellationToken).ConfigureAwait(false);
await session.BreakStateOrCapabilitiesChangedAsync(_diagnosticService, inBreakState: false, cancellationToken).ConfigureAwait(false);
GetActiveStatementTrackingService().EndTracking();
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
Expand All @@ -149,6 +153,23 @@ public async ValueTask ExitBreakStateAsync(CancellationToken cancellationToken)
}
}

public async ValueTask OnCapabilitiesChangedAsync(CancellationToken cancellationToken)
{
if (_disabled)
{
return;
}

try
{
await GetDebuggingSession().BreakStateOrCapabilitiesChangedAsync(_diagnosticService, inBreakState: null, cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
{
_disabled = true;
}
}

public async ValueTask CommitUpdatesAsync(CancellationToken cancellationToken)
{
try
Expand Down Expand Up @@ -239,26 +260,40 @@ public async ValueTask<bool> HasChangesAsync(string? sourceFilePath, Cancellatio
}
}

public async ValueTask<(ManagedModuleUpdates updates, ImmutableArray<DiagnosticData> diagnostics, ImmutableArray<(DocumentId DocumentId, ImmutableArray<RudeEditDiagnostic> Diagnostics)> rudeEdits, DiagnosticData? syntaxError, Solution? solution)>
GetUpdatesAsync(bool trackActiveStatements, CancellationToken cancellationToken)
public async ValueTask<ManagedModuleUpdates> GetEditAndContinueUpdatesAsync(CancellationToken cancellationToken)
{
if (_disabled)
{
return (new ManagedModuleUpdates(ManagedModuleUpdateStatus.None, ImmutableArray<ManagedModuleUpdate>.Empty),
ImmutableArray<DiagnosticData>.Empty,
ImmutableArray<(DocumentId DocumentId, ImmutableArray<RudeEditDiagnostic> Diagnostics)>.Empty,
syntaxError: null,
solution: null);
return new ManagedModuleUpdates(ManagedModuleUpdateStatus.None, ImmutableArray<ManagedModuleUpdate>.Empty);
}

var solution = GetCurrentCompileTimeSolution();
var activeStatementSpanProvider = trackActiveStatements ? GetActiveStatementSpanProvider(solution) : s_noActiveStatementSpanProvider;
var (updates, diagnostics, rudeEdits, syntaxError) = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, _diagnosticService, _diagnosticUpdateSource, cancellationToken).ConfigureAwait(false);
var activeStatementSpanProvider = GetActiveStatementSpanProvider(solution);
var (updates, _, _, _) = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, _diagnosticService, _diagnosticUpdateSource, cancellationToken).ConfigureAwait(false);
_pendingUpdatedSolution = solution;
return (updates, diagnostics, rudeEdits, syntaxError, solution);
return updates;
}

public async ValueTask<ManagedHotReloadUpdates> GetHotReloadUpdatesAsync(CancellationToken cancellationToken)
{
if (_disabled)
{
return new ManagedHotReloadUpdates(ImmutableArray<ManagedHotReloadUpdate>.Empty, ImmutableArray<ManagedHotReloadDiagnostic>.Empty);
}

var solution = GetCurrentCompileTimeSolution();
var (moduleUpdates, diagnosticData, rudeEdits, syntaxError) = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, s_noActiveStatementSpanProvider, _diagnosticService, _diagnosticUpdateSource, cancellationToken).ConfigureAwait(false);
_pendingUpdatedSolution = solution;

var updates = moduleUpdates.Updates.SelectAsArray(
update => new ManagedHotReloadUpdate(update.Module, update.ILDelta, update.MetadataDelta));

var diagnostics = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, cancellationToken).ConfigureAwait(false);

return new ManagedHotReloadUpdates(updates, diagnostics);
}

public async Task<SourceSpan?> GetCurrentActiveStatementPositionAsync(ManagedInstructionId instruction, CancellationToken cancellationToken)
public async ValueTask<SourceSpan?> GetCurrentActiveStatementPositionAsync(ManagedInstructionId instruction, CancellationToken cancellationToken)
{
try
{
Expand All @@ -277,7 +312,7 @@ public async ValueTask<bool> HasChangesAsync(string? sourceFilePath, Cancellatio
}
}

public async Task<bool?> IsActiveStatementInExceptionRegionAsync(ManagedInstructionId instruction, CancellationToken cancellationToken)
public async ValueTask<bool?> IsActiveStatementInExceptionRegionAsync(ManagedInstructionId instruction, CancellationToken cancellationToken)
{
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.EditAndContinue
[ExportMetadata("UIContext", EditAndContinueUIContext.EncCapableProjectExistsInWorkspaceUIContextString)]
internal sealed class ManagedEditAndContinueLanguageService : IManagedEditAndContinueLanguageService, IEditAndContinueSolutionProvider
{
private readonly Lazy<IManagedEditAndContinueDebuggerService> _debuggerService;
private readonly EditAndContinueLanguageService _encService;

/// <summary>
Expand All @@ -37,8 +36,7 @@ public ManagedEditAndContinueLanguageService(
EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource,
Lazy<IManagedEditAndContinueDebuggerService> debuggerService)
{
_encService = new EditAndContinueLanguageService(workspaceProvider, diagnosticService, diagnosticUpdateSource);
_debuggerService = debuggerService;
_encService = new EditAndContinueLanguageService(workspaceProvider, debuggerService, diagnosticService, diagnosticUpdateSource);
}

public EditAndContinueLanguageService Service => _encService;
Expand All @@ -54,7 +52,7 @@ public Task StartDebuggingAsync(DebugSessionFlags flags, CancellationToken cance
return Task.CompletedTask;
}

return _encService.StartSessionAsync(_debuggerService.Value, cancellationToken).AsTask();
return _encService.StartSessionAsync(cancellationToken).AsTask();
}

public Task EnterBreakStateAsync(CancellationToken cancellationToken)
Expand All @@ -75,14 +73,14 @@ public Task StopDebuggingAsync(CancellationToken cancellationToken)
public Task<bool> HasChangesAsync(string? sourceFilePath, CancellationToken cancellationToken)
=> _encService.HasChangesAsync(sourceFilePath, cancellationToken).AsTask();

public async Task<ManagedModuleUpdates> GetManagedModuleUpdatesAsync(CancellationToken cancellationToken)
=> (await _encService.GetUpdatesAsync(trackActiveStatements: true, cancellationToken).ConfigureAwait(false)).updates;
public Task<ManagedModuleUpdates> GetManagedModuleUpdatesAsync(CancellationToken cancellationToken)
=> _encService.GetEditAndContinueUpdatesAsync(cancellationToken).AsTask();

public Task<SourceSpan?> GetCurrentActiveStatementPositionAsync(ManagedInstructionId instruction, CancellationToken cancellationToken)
=> _encService.GetCurrentActiveStatementPositionAsync(instruction, cancellationToken);
=> _encService.GetCurrentActiveStatementPositionAsync(instruction, cancellationToken).AsTask();

public Task<bool?> IsActiveStatementInExceptionRegionAsync(ManagedInstructionId instruction, CancellationToken cancellationToken)
=> _encService.IsActiveStatementInExceptionRegionAsync(instruction, cancellationToken);
=> _encService.IsActiveStatementInExceptionRegionAsync(instruction, cancellationToken).AsTask();

public event Action<Solution> SolutionCommitted
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public Task PrepareModuleForUpdateAsync(Guid module, CancellationToken cancellat
}

private readonly EditAndContinueLanguageService _encService;
private readonly DebuggerService _debuggerService;

/// <summary>
/// Import <see cref="IHostWorkspaceProvider"/> and <see cref="IManagedHotReloadService"/> lazily so that the host does not need to implement them
Expand All @@ -61,29 +60,16 @@ public ManagedHotReloadLanguageService(
EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource,
Lazy<IManagedHotReloadService> hotReloadService)
{
_encService = new EditAndContinueLanguageService(workspaceProvider, diagnosticService, diagnosticUpdateSource);
_debuggerService = new DebuggerService(hotReloadService);
_encService = new EditAndContinueLanguageService(workspaceProvider, new Lazy<IManagedEditAndContinueDebuggerService>(() => new DebuggerService(hotReloadService)), diagnosticService, diagnosticUpdateSource);
}

public EditAndContinueLanguageService Service => _encService;

public ValueTask StartSessionAsync(CancellationToken cancellationToken)
=> _encService.StartSessionAsync(_debuggerService, cancellationToken);
=> _encService.StartSessionAsync(cancellationToken);

public async ValueTask<ManagedHotReloadUpdates> GetUpdatesAsync(CancellationToken cancellationToken)
{
var (moduleUpdates, diagnosticData, rudeEdits, syntaxError, solution) = await _encService.GetUpdatesAsync(trackActiveStatements: false, cancellationToken).ConfigureAwait(false);
if (solution == null)
{
return new ManagedHotReloadUpdates(ImmutableArray<ManagedHotReloadUpdate>.Empty, ImmutableArray<ManagedHotReloadDiagnostic>.Empty);
}

var updates = moduleUpdates.Updates.SelectAsArray(
update => new ManagedHotReloadUpdate(update.Module, update.ILDelta, update.MetadataDelta));
var diagnostics = await EmitSolutionUpdateResults.GetHotReloadDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, cancellationToken).ConfigureAwait(false);

return new ManagedHotReloadUpdates(updates, diagnostics);
}
public ValueTask<ManagedHotReloadUpdates> GetUpdatesAsync(CancellationToken cancellationToken)
=> _encService.GetHotReloadUpdatesAsync(cancellationToken);

public ValueTask CommitUpdatesAsync(CancellationToken cancellationToken)
=> _encService.CommitUpdatesAsync(cancellationToken);
Expand Down
Loading

0 comments on commit 0f60b3e

Please sign in to comment.