Remove AdhocWorkspaceFactory from DI, and make it fully own the workspace it creates

This commit is contained in:
David Wengier 2024-09-16 15:00:12 +10:00
Родитель c1f8fd5d6b
Коммит c128730081
13 изменённых файлов: 60 добавлений и 96 удалений

Просмотреть файл

@ -29,7 +29,7 @@ internal sealed class InlineCompletionEndpoint(
IDocumentMappingService documentMappingService,
IClientConnection clientConnection,
IFormattingCodeDocumentProvider formattingCodeDocumentProvider,
IAdhocWorkspaceFactory adhocWorkspaceFactory,
IHostServicesProvider hostServicesProvider,
RazorLSPOptionsMonitor optionsMonitor,
ILoggerFactory loggerFactory)
: IRazorRequestHandler<VSInternalInlineCompletionRequest, VSInternalInlineCompletionList?>, ICapabilitiesProvider
@ -39,10 +39,10 @@ internal sealed class InlineCompletionEndpoint(
"if", "indexer", "interface", "invoke", "iterator", "iterindex", "lock", "mbox", "namespace", "#if", "#region", "prop",
"propfull", "propg", "sim", "struct", "svm", "switch", "try", "tryf", "unchecked", "unsafe", "using", "while");
private readonly IDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService));
private readonly IClientConnection _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection));
private readonly IDocumentMappingService _documentMappingService = documentMappingService;
private readonly IClientConnection _clientConnection = clientConnection;
private readonly IFormattingCodeDocumentProvider _formattingCodeDocumentProvider = formattingCodeDocumentProvider;
private readonly IAdhocWorkspaceFactory _adhocWorkspaceFactory = adhocWorkspaceFactory ?? throw new ArgumentNullException(nameof(adhocWorkspaceFactory));
private readonly IHostServicesProvider _hostServicesProvider = hostServicesProvider;
private readonly RazorLSPOptionsMonitor _optionsMonitor = optionsMonitor;
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<InlineCompletionEndpoint>();
@ -128,13 +128,14 @@ internal sealed class InlineCompletionEndpoint(
}
var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine);
using var formattingContext = FormattingContext.Create(
using var adhocWorkspaceFactory = new AdhocWorkspaceFactory(_hostServicesProvider);
var formattingContext = FormattingContext.Create(
request.TextDocument.Uri,
documentContext.Snapshot,
codeDocument,
options,
_formattingCodeDocumentProvider,
_adhocWorkspaceFactory);
adhocWorkspaceFactory);
if (!TryGetSnippetWithAdjustedIndentation(formattingContext, item.Text, hostDocumentIndex, out var newSnippetText))
{
continue;

Просмотреть файл

@ -7,11 +7,10 @@ using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal sealed class LspWorkspaceProvider(IAdhocWorkspaceFactory workspaceFactory) : IWorkspaceProvider, IDisposable
internal sealed class LspWorkspaceProvider(IHostServicesProvider hostServicesProvider) : IWorkspaceProvider, IDisposable
{
private readonly IAdhocWorkspaceFactory _workspaceFactory = workspaceFactory;
private readonly AdhocWorkspaceFactory _workspaceFactory = new AdhocWorkspaceFactory(hostServicesProvider);
private Workspace? _workspace;
private bool _disposed;
void IDisposable.Dispose()
@ -21,7 +20,7 @@ internal sealed class LspWorkspaceProvider(IAdhocWorkspaceFactory workspaceFacto
return;
}
_workspace?.Dispose();
_workspaceFactory.Dispose();
_disposed = true;
}
@ -32,6 +31,6 @@ internal sealed class LspWorkspaceProvider(IAdhocWorkspaceFactory workspaceFacto
throw new ObjectDisposedException(nameof(LspWorkspaceProvider));
}
return _workspace ??= _workspaceFactory.Create();
return _workspaceFactory.GetOrCreate();
}
}

Просмотреть файл

@ -119,7 +119,6 @@ internal partial class RazorLanguageServer : SystemTextJsonLanguageServer<RazorR
// Add the logger as a service in case anything in CLaSP pulls it out to do logging
services.AddSingleton<ILspLogger>(Logger);
services.AddSingleton<IAdhocWorkspaceFactory, AdhocWorkspaceFactory>();
services.AddSingleton<IWorkspaceProvider, LspWorkspaceProvider>();
services.AddSingleton<IFormattingCodeDocumentProvider, LspFormattingCodeDocumentProvider>();

Просмотреть файл

@ -1,11 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
namespace Microsoft.CodeAnalysis.Razor.Workspaces;
internal class AdhocWorkspaceFactory(IHostServicesProvider hostServicesProvider) : IAdhocWorkspaceFactory
internal sealed class AdhocWorkspaceFactory(IHostServicesProvider hostServicesProvider) : IDisposable
{
public AdhocWorkspace Create()
private readonly Lazy<AdhocWorkspace> _lazyWorkspace = new(() => CreateWorkspace(hostServicesProvider));
private static AdhocWorkspace CreateWorkspace(IHostServicesProvider hostServicesProvider)
{
var fallbackServices = hostServicesProvider.GetServices();
var services = AdhocServices.Create(
@ -15,4 +19,17 @@ internal class AdhocWorkspaceFactory(IHostServicesProvider hostServicesProvider)
return new AdhocWorkspace(services);
}
public AdhocWorkspace GetOrCreate()
{
return _lazyWorkspace.Value;
}
public void Dispose()
{
if (_lazyWorkspace.IsValueCreated)
{
_lazyWorkspace.Value.Dispose();
}
}
}

Просмотреть файл

@ -18,20 +18,19 @@ using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.Razor.Formatting;
internal sealed class FormattingContext : IDisposable
internal sealed class FormattingContext
{
private readonly IAdhocWorkspaceFactory _workspaceFactory;
private readonly AdhocWorkspaceFactory _workspaceFactory;
private readonly IFormattingCodeDocumentProvider _codeDocumentProvider;
private Document? _csharpWorkspaceDocument;
private AdhocWorkspace? _csharpWorkspace;
private IReadOnlyList<FormattingSpan>? _formattingSpans;
private IReadOnlyDictionary<int, IndentationContext>? _indentations;
private FormattingContext(
IFormattingCodeDocumentProvider codeDocumentProvider,
IAdhocWorkspaceFactory workspaceFactory,
AdhocWorkspaceFactory workspaceFactory,
Uri uri,
IDocumentSnapshot originalSnapshot,
RazorCodeDocument codeDocument,
@ -83,7 +82,7 @@ internal sealed class FormattingContext : IDisposable
}
}
public AdhocWorkspace CSharpWorkspace => _csharpWorkspace ??= _workspaceFactory.Create();
public AdhocWorkspace CSharpWorkspace => _workspaceFactory.GetOrCreate();
/// <summary>A Dictionary of int (line number) to IndentationContext.</summary>
/// <remarks>
@ -252,15 +251,6 @@ internal sealed class FormattingContext : IDisposable
return false;
}
public void Dispose()
{
_csharpWorkspace?.Dispose();
if (_csharpWorkspaceDocument != null)
{
_csharpWorkspaceDocument = null;
}
}
public async Task<FormattingContext> WithTextAsync(SourceText changedText)
{
var changedSnapshot = OriginalSnapshot.WithText(changedText);
@ -307,7 +297,7 @@ internal sealed class FormattingContext : IDisposable
RazorCodeDocument codeDocument,
RazorFormattingOptions options,
IFormattingCodeDocumentProvider codeDocumentProvider,
IAdhocWorkspaceFactory workspaceFactory,
AdhocWorkspaceFactory workspaceFactory,
bool automaticallyAddUsings,
int hostDocumentIndex,
char triggerCharacter)
@ -330,7 +320,7 @@ internal sealed class FormattingContext : IDisposable
RazorCodeDocument codeDocument,
RazorFormattingOptions options,
IFormattingCodeDocumentProvider codeDocumentProvider,
IAdhocWorkspaceFactory workspaceFactory)
AdhocWorkspaceFactory workspaceFactory)
{
return new FormattingContext(
codeDocumentProvider,

Просмотреть файл

@ -30,7 +30,7 @@ internal class RazorFormattingService : IRazorFormattingService
private static readonly FrozenSet<string> s_htmlTriggerCharacterSet = FrozenSet.ToFrozenSet(["\n", "{", "}", ";"], StringComparer.Ordinal);
private readonly IFormattingCodeDocumentProvider _codeDocumentProvider;
private readonly IAdhocWorkspaceFactory _workspaceFactory;
private readonly IHostServicesProvider _hostServicesProvider;
private readonly ImmutableArray<IFormattingPass> _documentFormattingPasses;
private readonly ImmutableArray<IFormattingPass> _validationPasses;
@ -40,11 +40,11 @@ internal class RazorFormattingService : IRazorFormattingService
public RazorFormattingService(
IFormattingCodeDocumentProvider codeDocumentProvider,
IDocumentMappingService documentMappingService,
IAdhocWorkspaceFactory workspaceFactory,
IHostServicesProvider hostServicesProvider,
ILoggerFactory loggerFactory)
{
_codeDocumentProvider = codeDocumentProvider;
_workspaceFactory = workspaceFactory;
_hostServicesProvider = hostServicesProvider;
_htmlOnTypeFormattingPass = new HtmlOnTypeFormattingPass(loggerFactory);
_csharpOnTypeFormattingPass = new CSharpOnTypeFormattingPass(documentMappingService, loggerFactory);
@ -97,13 +97,14 @@ internal class RazorFormattingService : IRazorFormattingService
var uri = documentContext.Uri;
var documentSnapshot = documentContext.Snapshot;
var hostDocumentVersion = documentContext.Snapshot.Version;
using var context = FormattingContext.Create(
using var adhocWorkspaceFactory = new AdhocWorkspaceFactory(_hostServicesProvider);
var context = FormattingContext.Create(
uri,
documentSnapshot,
codeDocument,
options,
_codeDocumentProvider,
_workspaceFactory);
adhocWorkspaceFactory);
var originalText = context.SourceText;
var result = htmlChanges;
@ -225,14 +226,15 @@ internal class RazorFormattingService : IRazorFormattingService
var documentSnapshot = documentContext.Snapshot;
var uri = documentContext.Uri;
var codeDocument = await _codeDocumentProvider.GetCodeDocumentAsync(documentSnapshot).ConfigureAwait(false);
using var context = FormattingContext.CreateForOnTypeFormatting(
using var adhocWorkspaceFactory = new AdhocWorkspaceFactory(_hostServicesProvider);
var context = FormattingContext.CreateForOnTypeFormatting(
uri,
documentSnapshot,
codeDocument,
options,
_codeDocumentProvider,
_workspaceFactory,
automaticallyAddUsings: automaticallyAddUsings,
adhocWorkspaceFactory,
automaticallyAddUsings,
hostDocumentIndex,
triggerCharacter);
var result = generatedDocumentChanges;

Просмотреть файл

@ -1,9 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Razor.Workspaces;
internal interface IAdhocWorkspaceFactory
{
AdhocWorkspace Create();
}

Просмотреть файл

@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.Formatting;
[Export(typeof(IRazorFormattingService)), Shared]
[method: ImportingConstructor]
internal sealed class RemoteRazorFormattingService(IFormattingCodeDocumentProvider codeDocumentProvider, IDocumentMappingService documentMappingService, IAdhocWorkspaceFactory adhocWorkspaceFactory, ILoggerFactory loggerFactory)
: RazorFormattingService(codeDocumentProvider, documentMappingService, adhocWorkspaceFactory, loggerFactory)
internal sealed class RemoteRazorFormattingService(IFormattingCodeDocumentProvider codeDocumentProvider, IDocumentMappingService documentMappingService, IHostServicesProvider hostServicesProvider, ILoggerFactory loggerFactory)
: RazorFormattingService(codeDocumentProvider, documentMappingService, hostServicesProvider, loggerFactory)
{
}

Просмотреть файл

@ -1,12 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.CodeAnalysis.Remote.Razor;
[Export(typeof(IAdhocWorkspaceFactory)), Shared]
internal sealed class RemoteAdhocWorkspaceFactory(IHostServicesProvider hostServicesProvider) : AdhocWorkspaceFactory(hostServicesProvider)
{
}

Просмотреть файл

@ -6,13 +6,12 @@ using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer.Test;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer;
using Microsoft.CodeAnalysis.Razor.Formatting;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Moq;
using Xunit;
using Xunit.Abstractions;
@ -30,7 +29,7 @@ public class FormattingContentValidationPassTest(ITestOutputHelper testOutput) :
[||]public class Foo { }
}
""";
using var context = CreateFormattingContext(source);
var context = CreateFormattingContext(source);
var edits = ImmutableArray.Create(new TextChange(source.Span, " "));
var input = edits;
var pass = GetPass();
@ -51,7 +50,7 @@ public class FormattingContentValidationPassTest(ITestOutputHelper testOutput) :
[|public class Foo { }
|]}
""";
using var context = CreateFormattingContext(source);
var context = CreateFormattingContext(source);
var edits = ImmutableArray.Create(new TextChange(source.Span, " "));
var input = edits;
var pass = GetPass();
@ -85,13 +84,14 @@ public class FormattingContentValidationPassTest(ITestOutputHelper testOutput) :
InsertSpaces = insertSpaces,
};
using var adhocWorkspaceFactory = new AdhocWorkspaceFactory(new DefaultHostServicesProvider());
var context = FormattingContext.Create(
uri,
documentSnapshot,
codeDocument,
options,
new LspFormattingCodeDocumentProvider(),
TestAdhocWorkspaceFactory.Instance);
adhocWorkspaceFactory);
return context;
}

Просмотреть файл

@ -5,11 +5,11 @@ using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer.Test;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer;
using Microsoft.CodeAnalysis.Razor.Formatting;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Text;
using Xunit;
using Xunit.Abstractions;
@ -27,7 +27,7 @@ public class FormattingDiagnosticValidationPassTest(ITestOutputHelper testOutput
[||]public class Foo { }
}
""";
using var context = CreateFormattingContext(source);
var context = CreateFormattingContext(source);
var edits = ImmutableArray.Create(new TextChange(source.Span, " "));
var input = edits;
var pass = GetPass();
@ -49,7 +49,7 @@ public class FormattingDiagnosticValidationPassTest(ITestOutputHelper testOutput
public class Foo { }
}
""";
using var context = CreateFormattingContext(source);
var context = CreateFormattingContext(source);
var badEdit = new TextChange(source.Span, "@ "); // Creates a diagnostic
var pass = GetPass();
@ -82,13 +82,14 @@ public class FormattingDiagnosticValidationPassTest(ITestOutputHelper testOutput
InsertSpaces = insertSpaces,
};
using var adhocWorkspaceFactory = new AdhocWorkspaceFactory(new DefaultHostServicesProvider());
var context = FormattingContext.Create(
uri,
documentSnapshot,
codeDocument,
options,
new LspFormattingCodeDocumentProvider(),
TestAdhocWorkspaceFactory.Instance);
adhocWorkspaceFactory);
return context;
}

Просмотреть файл

@ -5,7 +5,6 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
using Microsoft.AspNetCore.Razor.LanguageServer.Test;
using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Razor.Formatting;
@ -40,7 +39,8 @@ internal static class TestRazorFormattingService
}
var formattingCodeDocumentProvider = new LspFormattingCodeDocumentProvider();
var hostServicesProvider = new DefaultHostServicesProvider();
return new RazorFormattingService(formattingCodeDocumentProvider, mappingService, TestAdhocWorkspaceFactory.Instance, loggerFactory);
return new RazorFormattingService(formattingCodeDocumentProvider, mappingService, hostServicesProvider, loggerFactory);
}
}

Просмотреть файл

@ -1,24 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Test;
internal class TestAdhocWorkspaceFactory : IAdhocWorkspaceFactory
{
public static readonly TestAdhocWorkspaceFactory Instance = new();
private TestAdhocWorkspaceFactory()
{
}
public AdhocWorkspace Create()
{
var services = TestServices.Create(workspaceServices: [], razorLanguageServices: []);
var workspace = TestWorkspace.Create(services);
return workspace;
}
}