Skip to content

Commit 33e4c03

Browse files
authored
Merge pull request #47951 from sharwell/dispose-language-services
Dispose per-instance services created by factories
2 parents dabf0a7 + 607dab5 commit 33e4c03

23 files changed

+320
-52
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
1+
virtual Microsoft.CodeAnalysis.Host.HostLanguageServices.Dispose() -> void
2+
virtual Microsoft.CodeAnalysis.Host.HostWorkspaceServices.Dispose() -> void

src/Workspaces/Core/Portable/Workspace/Host/HostLanguageServices.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,23 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Diagnostics.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.Host.Mef;
68

79
namespace Microsoft.CodeAnalysis.Host;
810

911
/// <summary>
10-
/// Per language services provided by the host environment.
12+
/// Per-language services provided by the host environment.
1113
/// </summary>
12-
public abstract class HostLanguageServices
14+
/// <remarks>
15+
/// <para>Language services which implement <see cref="IDisposable"/> are considered ownable, in which case the
16+
/// owner is responsible for disposing of owned instances when they are no longer in use. The ownership rules are
17+
/// described in detail for <see cref="HostWorkspaceServices"/>. Instances of <see cref="ILanguageService"/> have
18+
/// the same ownership rules as <see cref="IWorkspaceService"/>, and instances of
19+
/// <see cref="ILanguageServiceFactory"/> have the same ownership rules as
20+
/// <see cref="IWorkspaceServiceFactory"/>.</para>
21+
/// </remarks>
22+
public abstract class HostLanguageServices : IDisposable
1323
{
1424
/// <summary>
1525
/// The <see cref="HostWorkspaceServices"/> that originated this language service.
@@ -40,6 +50,11 @@ protected HostLanguageServices()
4050
/// </summary>
4151
public abstract TLanguageService? GetService<TLanguageService>() where TLanguageService : ILanguageService;
4252

53+
[SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Derived types are not allowed to include a finalizer for this pattern.")]
54+
public virtual void Dispose()
55+
{
56+
}
57+
4358
/// <summary>
4459
/// Gets a language specific service provided by the host identified by the service type.
4560
/// If the host does not provide the service, this method returns throws <see cref="InvalidOperationException"/>.

src/Workspaces/Core/Portable/Workspace/Host/HostWorkspaceServices.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,44 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Collections.Immutable;
8+
using System.Diagnostics.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.Host.Mef;
810
using Microsoft.CodeAnalysis.Text;
911

1012
namespace Microsoft.CodeAnalysis.Host;
1113

1214
/// <summary>
1315
/// Per workspace services provided by the host environment.
1416
/// </summary>
15-
public abstract class HostWorkspaceServices
17+
/// <remarks>
18+
/// <para>Workspace services which implement <see cref="IDisposable"/> are considered ownable, in which case the
19+
/// owner is responsible for disposing of owned instances when they are no longer in use. When
20+
/// <see cref="IWorkspaceService"/> or <see cref="IWorkspaceServiceFactory"/> instances are provided directly to the
21+
/// <see cref="HostWorkspaceServices"/>, the owner of the instances is the type or container (e.g. a MEF export
22+
/// provider) which created the instances. For the specific case of ownable workspace services created by a factory
23+
/// (i.e. instances returned by <see cref="IWorkspaceServiceFactory.CreateService"/>), the <see cref="Workspace"/>
24+
/// is considered the owner of the resulting instance and is expected to be disposed during the call to
25+
/// <see cref="Dispose"/>.</para>
26+
///
27+
/// <para><strong>Summary of lifetime rules</strong></para>
28+
///
29+
/// <list type="bullet">
30+
/// <item><description>
31+
/// <strong><see cref="IWorkspaceService"/> instance constructed externally (e.g. MEF):</strong> Owned by the
32+
/// external source, and will not be automatically disposed when <see cref="Workspace"/> is disposed.
33+
/// </description></item>
34+
/// <item><description>
35+
/// <strong><see cref="IWorkspaceServiceFactory"/> instance constructed externally (e.g. MEF):</strong> Owned by
36+
/// the external source, and will not be automatically disposed when <see cref="Workspace"/> is disposed.
37+
/// </description></item>
38+
/// <item><description>
39+
/// <strong><see cref="IWorkspaceService"/> instance constructed by <see cref="IWorkspaceServiceFactory"/> within
40+
/// the context of <see cref="HostWorkspaceServices"/>:</strong> Owned by <see cref="Workspace"/>, and
41+
/// <strong>will</strong> be automatically disposed when <see cref="Workspace"/> is disposed.
42+
/// </description></item>
43+
/// </list>
44+
/// </remarks>
45+
public abstract class HostWorkspaceServices : IDisposable
1646
{
1747
/// <summary>
1848
/// The host services this workspace services originated from.
@@ -40,6 +70,11 @@ protected HostWorkspaceServices()
4070
#pragma warning restore
4171
}
4272

73+
[SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Derived types are not allowed to include a finalizer for this pattern.")]
74+
public virtual void Dispose()
75+
{
76+
}
77+
4378
/// <summary>
4479
/// Gets a workspace specific service provided by the host identified by the service type.
4580
/// If the host does not provide the service, this method throws <see cref="InvalidOperationException"/>.

src/Workspaces/Core/Portable/Workspace/Workspace.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
using Microsoft.CodeAnalysis.Internal.Log;
1818
using Microsoft.CodeAnalysis.Options;
1919
using Microsoft.CodeAnalysis.PooledObjects;
20-
using Microsoft.CodeAnalysis.Remote;
2120
using Microsoft.CodeAnalysis.Shared.Extensions;
2221
using Microsoft.CodeAnalysis.Shared.TestHooks;
22+
using Microsoft.CodeAnalysis.Shared.Utilities;
2323
using Microsoft.CodeAnalysis.Text;
2424
using Roslyn.Utilities;
2525

@@ -692,13 +692,9 @@ protected virtual void Dispose(bool finalize)
692692

693693
_legacyOptions.UnregisterWorkspace(this);
694694

695-
// Directly dispose IRemoteHostClientProvider if necessary. This is a test hook to ensure RemoteWorkspace
696-
// gets disposed in unit tests as soon as TestWorkspace gets disposed. This would be superseded by direct
697-
// support for IDisposable in https://github.com/dotnet/roslyn/pull/47951.
698-
if (Services.GetService<IRemoteHostClientProvider>() is IDisposable disposableService)
699-
{
700-
disposableService.Dispose();
701-
}
695+
// Dispose per-instance services created for this workspace (direct MEF exports, including factories, will
696+
// be disposed when the MEF catalog is disposed).
697+
Services.Dispose();
702698

703699
// We're disposing this workspace. Stop any work to update SG docs in the background.
704700
_updateSourceGeneratorsQueueTokenSource.Cancel();

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,4 +273,7 @@
273273
<data name="New_line_preferences" xml:space="preserve">
274274
<value>New line preferences</value>
275275
</data>
276+
<data name="Instantiated_parts_threw_exceptions_from_IDisposable_Dispose" xml:space="preserve">
277+
<value>Instantiated part(s) threw exception(s) from IDisposable.Dispose().</value>
278+
</data>
276279
</root>

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)