Skip to content

Commit

Permalink
Make EnC service a MEF service instead of a workspace service
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat committed Apr 20, 2023
1 parent 3b400f4 commit 96e7fe5
Show file tree
Hide file tree
Showing 16 changed files with 72 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ public EditAndContinueWorkspaceServiceTests()
};
}

private TestWorkspace CreateWorkspace(out Solution solution, out EditAndContinueWorkspaceService service, Type[] additionalParts = null)
private TestWorkspace CreateWorkspace(out Solution solution, out EditAndContinueService service, Type[] additionalParts = null)
{
var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features.AddParts(additionalParts), solutionTelemetryId: s_solutionTelemetryId);
solution = workspace.CurrentSolution;
service = GetEditAndContinueService(workspace);
return workspace;
}

private TestWorkspace CreateEditorWorkspace(out Solution solution, out EditAndContinueWorkspaceService service, out EditAndContinueLanguageService languageService, Type[] additionalParts = null)
private TestWorkspace CreateEditorWorkspace(out Solution solution, out EditAndContinueService service, out EditAndContinueLanguageService languageService, Type[] additionalParts = null)
{
var composition = EditorTestCompositions.EditorFeatures
.RemoveParts(typeof(MockWorkspaceEventListenerProvider))
Expand Down Expand Up @@ -161,16 +161,16 @@ private static Solution AddDefaultTestProject(
return document.Project.Solution;
}

private EditAndContinueWorkspaceService GetEditAndContinueService(Workspace workspace)
private EditAndContinueService GetEditAndContinueService(TestWorkspace workspace)
{
var service = (EditAndContinueWorkspaceService)workspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>();
var service = (EditAndContinueService)workspace.GetService<IEditAndContinueService>();
var accessor = service.GetTestAccessor();
accessor.SetOutputProvider(project => _mockCompilationOutputsProvider(project));
return service;
}

private async Task<DebuggingSession> StartDebuggingSessionAsync(
EditAndContinueWorkspaceService service,
EditAndContinueService service,
Solution solution,
CommittedSolution.DocumentState initialState = CommittedSolution.DocumentState.MatchesBuildOutput,
IPdbMatchingSourceTextProvider sourceTextProvider = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ public async Task Proxy(TestHost testHost)

if (testHost == TestHost.InProcess)
{
localComposition = localComposition.AddParts(typeof(MockEditAndContinueWorkspaceService));
localComposition = localComposition
.AddExcludedPartTypes(typeof(EditAndContinueService))
.AddParts(typeof(MockEditAndContinueWorkspaceService));
}

using var localWorkspace = new TestWorkspace(composition: localComposition);
Expand All @@ -63,16 +65,17 @@ public async Task Proxy(TestHost testHost)
{
Assert.Null(clientProvider);

mockEncService = (MockEditAndContinueWorkspaceService)localWorkspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>();
mockEncService = (MockEditAndContinueWorkspaceService)localWorkspace.GetService<IEditAndContinueService>();
}
else
{
Assert.NotNull(clientProvider);
clientProvider!.AdditionalRemoteParts = new[] { typeof(MockEditAndContinueWorkspaceService) };
clientProvider!.ExcludedRemoteParts = new[] { typeof(EditAndContinueService) };

var client = await InProcRemoteHostClient.GetTestClientAsync(localWorkspace);
var remoteWorkspace = client.TestData.WorkspaceManager.GetWorkspace();
mockEncService = (MockEditAndContinueWorkspaceService)remoteWorkspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>();
mockEncService = (MockEditAndContinueWorkspaceService)remoteWorkspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>().Service;
}

var projectId = ProjectId.CreateNewId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests
internal delegate void ActionOut<TArg1>(out TArg1 arg);
internal delegate void ActionOut<TArg1, TArg2>(TArg1 arg1, out TArg2 arg2);

[ExportWorkspaceService(typeof(IEditAndContinueWorkspaceService), ServiceLayer.Test), Shared]
internal class MockEditAndContinueWorkspaceService : IEditAndContinueWorkspaceService
[Export(typeof(IEditAndContinueService)), Shared]
internal class MockEditAndContinueWorkspaceService : IEditAndContinueService
{
public Func<Solution, ImmutableArray<DocumentId>, ImmutableArray<ImmutableArray<ActiveStatementSpan>>>? GetBaseActiveStatementSpansImpl;
public Func<Solution, ActiveStatementSpanProvider, ManagedInstructionId, LinePositionSpan?>? GetCurrentActiveStatementPositionImpl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ protected AbstractEditAndContinueAnalyzer(Action<SyntaxNode>? testFaultInjector)
}

private static TraceLog Log
=> EditAndContinueWorkspaceService.AnalysisLog;
=> EditAndContinueService.AnalysisLog;

internal abstract bool ExperimentalFeaturesEnabled(SyntaxTree tree);

Expand Down
14 changes: 7 additions & 7 deletions src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,14 +414,14 @@ await TryGetMatchingSourceTextAsync(sourceText, sourceFilePath, currentDocument:

if (debugInfoReaderProvider == null)
{
EditAndContinueWorkspaceService.Log.Write("Source file of project '{0}' doesn't match output PDB: PDB '{1}' (assembly: '{2}') not found", projectName, compilationOutputs.PdbDisplayPath, compilationOutputs.AssemblyDisplayPath);
EditAndContinueService.Log.Write("Source file of project '{0}' doesn't match output PDB: PDB '{1}' (assembly: '{2}') not found", projectName, compilationOutputs.PdbDisplayPath, compilationOutputs.AssemblyDisplayPath);
}

return debugInfoReaderProvider;
}
catch (Exception e)
{
EditAndContinueWorkspaceService.Log.Write("Source file of project '{0}' doesn't match output PDB: error opening PDB '{1}' (assembly: '{2}'): {3}", projectName, compilationOutputs.PdbDisplayPath, compilationOutputs.AssemblyDisplayPath, e.Message);
EditAndContinueService.Log.Write("Source file of project '{0}' doesn't match output PDB: error opening PDB '{1}' (assembly: '{2}'): {3}", projectName, compilationOutputs.PdbDisplayPath, compilationOutputs.AssemblyDisplayPath, e.Message);
return null;
}
}
Expand Down Expand Up @@ -454,14 +454,14 @@ private static bool IsMatchingSourceText(SourceText sourceText, ImmutableArray<b
return sourceText;
}

EditAndContinueWorkspaceService.Log.Write("Checksum differs for source file '{0}'", sourceFilePath);
EditAndContinueService.Log.Write("Checksum differs for source file '{0}'", sourceFilePath);

// does not match:
return null;
}
catch (Exception e)
{
EditAndContinueWorkspaceService.Log.Write("Error calculating checksum for source file '{0}': '{1}'", sourceFilePath, e.Message);
EditAndContinueService.Log.Write("Error calculating checksum for source file '{0}': '{1}'", sourceFilePath, e.Message);

// unable to determine:
return default;
Expand Down Expand Up @@ -501,22 +501,22 @@ private static bool IsMatchingSourceText(SourceText sourceText, ImmutableArray<b
{
if (!debugInfoReader.TryGetDocumentChecksum(sourceFilePath, out checksum, out var algorithmId))
{
EditAndContinueWorkspaceService.Log.Write("Source '{0}' doesn't match output PDB: no document", sourceFilePath);
EditAndContinueService.Log.Write("Source '{0}' doesn't match output PDB: no document", sourceFilePath);
return false;
}

algorithm = SourceHashAlgorithms.GetSourceHashAlgorithm(algorithmId);
if (algorithm == SourceHashAlgorithm.None)
{
// This can only happen if the PDB was post-processed by a misbehaving tool.
EditAndContinueWorkspaceService.Log.Write("Source '{0}' doesn't match PDB: unknown checksum alg", sourceFilePath);
EditAndContinueService.Log.Write("Source '{0}' doesn't match PDB: unknown checksum alg", sourceFilePath);
}

return true;
}
catch (Exception e)
{
EditAndContinueWorkspaceService.Log.Write("Source '{0}' doesn't match output PDB: error reading symbols: {1}", sourceFilePath, e.Message);
EditAndContinueService.Log.Write("Source '{0}' doesn't match output PDB: error reading symbols: {1}", sourceFilePath, e.Message);
}

// unable to determine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ private static unsafe bool TryCreateInitialBaseline(
}
catch (Exception e)
{
EditAndContinueWorkspaceService.Log.Write("Failed to create baseline for '{0}': {1}", projectId, e.Message);
EditAndContinueService.Log.Write("Failed to create baseline for '{0}': {1}", projectId, e.Message);

var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ErrorReadingFile);
diagnostics = ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None, new[] { fileBeingRead, e.Message }));
Expand Down Expand Up @@ -545,7 +545,7 @@ public async ValueTask<EmitSolutionUpdateResults> EmitSolutionUpdateAsync(

private void LogSolutionUpdate(SolutionUpdate update, UpdateId updateId)
{
var log = EditAndContinueWorkspaceService.Log;
var log = EditAndContinueService.Log;

log.Write("Solution update {0}.{1} status: {2}", updateId.SessionId.Ordinal, updateId.Ordinal, update.ModuleUpdates.Status);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,20 @@ namespace Microsoft.CodeAnalysis.EditAndContinue
/// <summary>
/// Implements core of Edit and Continue orchestration: management of edit sessions and connecting EnC related services.
/// </summary>
[ExportWorkspaceService(typeof(IEditAndContinueWorkspaceService)), Shared]
internal sealed class EditAndContinueWorkspaceService : IEditAndContinueWorkspaceService
[Export(typeof(IEditAndContinueService)), Shared]
internal sealed class EditAndContinueService : IEditAndContinueService
{
[ExportWorkspaceService(typeof(IEditAndContinueWorkspaceService)), Shared]
internal sealed class WorkspaceService : IEditAndContinueWorkspaceService
{
public IEditAndContinueService Service { get; }

[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public WorkspaceService(IEditAndContinueService service)
=> Service = service;
}

internal static readonly TraceLog Log;
internal static readonly TraceLog AnalysisLog;

Expand All @@ -39,12 +50,12 @@ internal sealed class EditAndContinueWorkspaceService : IEditAndContinueWorkspac

[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public EditAndContinueWorkspaceService()
public EditAndContinueService()
{
_compilationOutputsProvider = GetCompilationOutputs;
}

static EditAndContinueWorkspaceService()
static EditAndContinueService()
{
Log = new(2048, "EnC", "Trace.log");
AnalysisLog = new(1024, "EnC", "Analysis.log");
Expand Down Expand Up @@ -278,9 +289,9 @@ internal TestAccessor GetTestAccessor()

internal readonly struct TestAccessor
{
private readonly EditAndContinueWorkspaceService _service;
private readonly EditAndContinueService _service;

public TestAccessor(EditAndContinueWorkspaceService service)
public TestAccessor(EditAndContinueService service)
{
_service = service;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Features/Core/Portable/EditAndContinue/EditSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ public async ValueTask<SolutionUpdate> EmitSolutionUpdateAsync(Solution solution
{
try
{
var log = EditAndContinueWorkspaceService.Log;
var log = EditAndContinueService.Log;

log.Write("EmitSolutionUpdate {0}.{1}: '{2}'", updateId.SessionId.Ordinal, updateId.Ordinal, solution.FilePath);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
namespace Microsoft.CodeAnalysis.EditAndContinue
{
internal interface IEditAndContinueWorkspaceService : IWorkspaceService
{
IEditAndContinueService Service { get; }
}

internal interface IEditAndContinueService
{
ValueTask<ImmutableArray<Diagnostic>> GetDocumentDiagnosticsAsync(Document document, ActiveStatementSpanProvider activeStatementSpanProvider, CancellationToken cancellationToken);
ValueTask<EmitSolutionUpdateResults> EmitSolutionUpdateAsync(DebuggingSessionId sessionId, Solution solution, ActiveStatementSpanProvider activeStatementSpanProvider, CancellationToken cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public void Dispose()
_connection?.Dispose();
}

private IEditAndContinueWorkspaceService GetLocalService()
=> _workspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>();
private IEditAndContinueService GetLocalService()
=> _workspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>().Service;

public async ValueTask BreakStateOrCapabilitiesChangedAsync(IDiagnosticAnalyzerService diagnosticService, EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource, bool? inBreakState, CancellationToken cancellationToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ public RemoteEditAndContinueServiceProxy(Workspace workspace)
Workspace = workspace;
}

private IEditAndContinueWorkspaceService GetLocalService()
=> Workspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>();
private IEditAndContinueService GetLocalService()
=> Workspace.Services.GetRequiredService<IEditAndContinueWorkspaceService>().Service;

public async ValueTask<RemoteDebuggingSessionProxy?> StartDebuggingSessionAsync(
Solution solution,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ public Update(
private static readonly ImmutableArray<Update> EmptyUpdate = ImmutableArray.Create<Update>();
private static readonly ImmutableArray<Diagnostic> EmptyDiagnostic = ImmutableArray.Create<Diagnostic>();

private readonly IEditAndContinueWorkspaceService _encService;
private readonly IEditAndContinueService _encService;
private DebuggingSessionId _sessionId;

public UnitTestingHotReloadService(HostWorkspaceServices services)
=> _encService = services.GetRequiredService<IEditAndContinueWorkspaceService>();
=> _encService = services.GetRequiredService<IEditAndContinueWorkspaceService>().Service;

/// <summary>
/// Starts the watcher.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ internal Update(Guid moduleId, ImmutableArray<byte> ilDelta, ImmutableArray<byte
private static readonly ActiveStatementSpanProvider s_solutionActiveStatementSpanProvider =
(_, _, _) => ValueTaskFactory.FromResult(ImmutableArray<ActiveStatementSpan>.Empty);

private readonly IEditAndContinueWorkspaceService _encService;
private readonly IEditAndContinueService _encService;
private DebuggingSessionId _sessionId;
private readonly ImmutableArray<string> _capabilities;

public WatchHotReloadService(HostWorkspaceServices services, ImmutableArray<string> capabilities)
=> (_encService, _capabilities) = (services.GetRequiredService<IEditAndContinueWorkspaceService>(), capabilities);
=> (_encService, _capabilities) = (services.GetRequiredService<IEditAndContinueWorkspaceService>().Service, capabilities);

/// <summary>
/// Starts the watcher.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ internal sealed class GlassTestsHotReloadService

private readonly IManagedHotReloadService _debuggerService;

private readonly IEditAndContinueWorkspaceService _encService;
private readonly IEditAndContinueService _encService;
private DebuggingSessionId _sessionId;

public GlassTestsHotReloadService(HostWorkspaceServices services, IManagedHotReloadService debuggerService)
{
_encService = services.GetRequiredService<IEditAndContinueWorkspaceService>();
_encService = services.GetRequiredService<IEditAndContinueWorkspaceService>().Service;
_debuggerService = debuggerService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,22 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)

private sealed class WorkspaceManager : RemoteWorkspaceManager
{
public WorkspaceManager(Func<RemoteWorkspace, SolutionAssetCache> createAssetStorage, ConcurrentDictionary<Guid, TestGeneratorReference> sharedTestGeneratorReferences, Type[]? additionalRemoteParts)
: base(createAssetStorage, CreateRemoteWorkspace(sharedTestGeneratorReferences, additionalRemoteParts))
public WorkspaceManager(
Func<RemoteWorkspace, SolutionAssetCache> createAssetStorage,
ConcurrentDictionary<Guid, TestGeneratorReference> sharedTestGeneratorReferences,
Type[]? additionalRemoteParts,
Type[]? excludedRemoteParts)
: base(createAssetStorage, CreateRemoteWorkspace(sharedTestGeneratorReferences, additionalRemoteParts, excludedRemoteParts))
{
}
}

private static RemoteWorkspace CreateRemoteWorkspace(ConcurrentDictionary<Guid, TestGeneratorReference> sharedTestGeneratorReferences, Type[]? additionalRemoteParts)
private static RemoteWorkspace CreateRemoteWorkspace(
ConcurrentDictionary<Guid, TestGeneratorReference> sharedTestGeneratorReferences,
Type[]? additionalRemoteParts,
Type[]? excludedRemoteParts)
{
var hostServices = FeaturesTestCompositions.RemoteHost.AddParts(additionalRemoteParts).GetHostServices();
var hostServices = FeaturesTestCompositions.RemoteHost.AddParts(additionalRemoteParts).AddExcludedPartTypes(excludedRemoteParts).GetHostServices();

// We want to allow references to source generators to be shared between the "in proc" and "remote" workspaces and
// MEF compositions, so tell the serializer service to use the same map for this "remote" workspace as the in-proc one.
Expand All @@ -56,6 +63,7 @@ private static RemoteWorkspace CreateRemoteWorkspace(ConcurrentDictionary<Guid,
private readonly Lazy<RemoteHostClient> _lazyClient;

public Type[]? AdditionalRemoteParts { get; set; }
public Type[]? ExcludedRemoteParts { get; set; }
public TraceListener? TraceListener { get; set; }

public InProcRemoteHostClientProvider(SolutionServices services, RemoteServiceCallbackDispatcherRegistry callbackDispatchers)
Expand All @@ -68,7 +76,8 @@ public InProcRemoteHostClientProvider(SolutionServices services, RemoteServiceCa
() => new WorkspaceManager(
_ => new SolutionAssetCache(),
testSerializerServiceFactory.SharedTestGeneratorReferences,
AdditionalRemoteParts));
AdditionalRemoteParts,
ExcludedRemoteParts));
_lazyClient = new Lazy<RemoteHostClient>(
() => InProcRemoteHostClient.Create(
_services,
Expand Down
Loading

0 comments on commit 96e7fe5

Please sign in to comment.