From fefb0595b6b340af1c6317a5081b1098e96458c5 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 3 May 2021 12:14:51 -0700 Subject: [PATCH] Dispose workspaces at the end of RunAsync Fixes #805 --- .../AnalyzerTest`1.cs | 34 +++++++++++++++++-- .../PublicAPI.Unshipped.txt | 6 ++-- .../CodeFixTest`1.cs | 2 +- .../PublicAPI.Unshipped.txt | 2 +- .../CodeRefactoringTest`1.cs | 2 +- .../PublicAPI.Unshipped.txt | 2 +- .../PublicAPI.Unshipped.txt | 2 +- .../SourceGeneratorTest`1.cs | 2 +- 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs index 770326c4f..e17ac7b5d 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -165,12 +166,34 @@ public string TestCode /// protected TimeSpan MatchDiagnosticsTimeout { get; set; } = TimeSpan.FromSeconds(2); + private readonly ConcurrentBag _workspaces = new ConcurrentBag(); + /// /// Runs the test. /// /// The that the operation will observe. /// A representing the asynchronous operation. - public virtual async Task RunAsync(CancellationToken cancellationToken = default) + public async Task RunAsync(CancellationToken cancellationToken = default) + { + try + { + await RunImplAsync(cancellationToken); + } + finally + { + while (_workspaces.TryTake(out var workspace)) + { + workspace.Dispose(); + } + } + } + + /// + /// Runs the test. + /// + /// The that the operation will observe. + /// A representing the asynchronous operation. + protected virtual async Task RunImplAsync(CancellationToken cancellationToken) { Verify.NotEmpty($"{nameof(TestState)}.{nameof(SolutionState.Sources)}", TestState.Sources); @@ -1310,7 +1333,14 @@ protected virtual Project ApplyCompilationOptions(Project project) return solution.GetProject(project.Id); } - public virtual AdhocWorkspace CreateWorkspace() + public Workspace CreateWorkspace() + { + var workspace = CreateWorkspaceImpl(); + _workspaces.Add(workspace); + return workspace; + } + + protected virtual Workspace CreateWorkspaceImpl() { var exportProvider = ExportProviderFactory.Value.CreateExportProvider(); var host = MefHostServices.Create(exportProvider.AsCompositionContext()); diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt index cd1037a9e..2ab84d52f 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt @@ -3,6 +3,7 @@ Microsoft.CodeAnalysis.Testing.AnalyzerTest.AnalyzerTest() -> void Microsoft.CodeAnalysis.Testing.AnalyzerTest.CompilerDiagnostics.get -> Microsoft.CodeAnalysis.Testing.CompilerDiagnostics Microsoft.CodeAnalysis.Testing.AnalyzerTest.CompilerDiagnostics.set -> void Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateProjectAsync(Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState primaryProject, System.Collections.Immutable.ImmutableArray additionalProjects, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateWorkspace() -> Microsoft.CodeAnalysis.Workspace Microsoft.CodeAnalysis.Testing.AnalyzerTest.DiagnosticVerifier.get -> System.Action Microsoft.CodeAnalysis.Testing.AnalyzerTest.DiagnosticVerifier.set -> void Microsoft.CodeAnalysis.Testing.AnalyzerTest.DisabledDiagnostics.get -> System.Collections.Generic.List @@ -16,6 +17,7 @@ Microsoft.CodeAnalysis.Testing.AnalyzerTest.MatchDiagnosticsTimeout.s Microsoft.CodeAnalysis.Testing.AnalyzerTest.OptionsTransforms.get -> System.Collections.Generic.List> Microsoft.CodeAnalysis.Testing.AnalyzerTest.ReferenceAssemblies.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies Microsoft.CodeAnalysis.Testing.AnalyzerTest.ReferenceAssemblies.set -> void +Microsoft.CodeAnalysis.Testing.AnalyzerTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task Microsoft.CodeAnalysis.Testing.AnalyzerTest.SolutionTransforms.get -> System.Collections.Generic.List> Microsoft.CodeAnalysis.Testing.AnalyzerTest.TestBehaviors.get -> Microsoft.CodeAnalysis.Testing.TestBehaviors Microsoft.CodeAnalysis.Testing.AnalyzerTest.TestBehaviors.set -> void @@ -320,7 +322,7 @@ static readonly Microsoft.CodeAnalysis.Testing.DiagnosticResult.EmptyDiagnosticR virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.ApplyCompilationOptions(Microsoft.CodeAnalysis.Project project) -> Microsoft.CodeAnalysis.Project virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateProjectImplAsync(Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState primaryProject, System.Collections.Immutable.ImmutableArray additionalProjects, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateSolutionAsync(Microsoft.CodeAnalysis.ProjectId projectId, Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState projectState, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task -virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateWorkspace() -> Microsoft.CodeAnalysis.AdhocWorkspace +virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateWorkspaceImpl() -> Microsoft.CodeAnalysis.Workspace virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.DefaultFilePath.get -> string virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.DefaultFilePathPrefix.get -> string virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.DefaultTestProjectName.get -> string @@ -328,7 +330,7 @@ virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetAnalyzerOption virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetDefaultDiagnostic(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer[] analyzers) -> Microsoft.CodeAnalysis.DiagnosticDescriptor virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetProjectCompilationAsync(Microsoft.CodeAnalysis.Project project, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.IsCompilerDiagnosticIncluded(Microsoft.CodeAnalysis.Diagnostic diagnostic, Microsoft.CodeAnalysis.Testing.CompilerDiagnostics compilerDiagnostics) -> bool -virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual Microsoft.CodeAnalysis.Testing.CodeActionTest.FilterCodeActions(System.Collections.Immutable.ImmutableArray actions) -> System.Collections.Immutable.ImmutableArray virtual Microsoft.CodeAnalysis.Testing.DefaultVerifier.CreateMessage(string message) -> string virtual Microsoft.CodeAnalysis.Testing.DefaultVerifier.Empty(string collectionName, System.Collections.Generic.IEnumerable collection) -> void diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs index 0ee162819..c207545c8 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs @@ -216,7 +216,7 @@ bool CodeFixProvidersHandleDiagnostic(Diagnostic localDiagnostic) } } - public override async Task RunAsync(CancellationToken cancellationToken = default) + protected override async Task RunImplAsync(CancellationToken cancellationToken) { Verify.NotEmpty($"{nameof(TestState)}.{nameof(SolutionState.Sources)}", TestState.Sources); diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt index 6ec73c7a2..6e09256b2 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt @@ -36,7 +36,7 @@ Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider.EmptyCodeFixProvider() -> void abstract Microsoft.CodeAnalysis.Testing.CodeFixTest.GetCodeFixProviders() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.CodeFixTest.IsCompilerDiagnosticIncluded(Microsoft.CodeAnalysis.Diagnostic diagnostic, Microsoft.CodeAnalysis.Testing.CompilerDiagnostics compilerDiagnostics) -> bool -override Microsoft.CodeAnalysis.Testing.CodeFixTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.CodeFixTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task override Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider.FixableDiagnosticIds.get -> System.Collections.Immutable.ImmutableArray override Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider.RegisterCodeFixesAsync(Microsoft.CodeAnalysis.CodeFixes.CodeFixContext context) -> System.Threading.Tasks.Task static Microsoft.CodeAnalysis.Testing.CodeFixVerifier.Diagnostic() -> Microsoft.CodeAnalysis.Testing.DiagnosticResult diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs index 441845d59..3b2e0def1 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs @@ -64,7 +64,7 @@ protected override IEnumerable GetDiagnosticAnalyzers() /// The to be used. protected abstract IEnumerable GetCodeRefactoringProviders(); - public override async Task RunAsync(CancellationToken cancellationToken = default) + protected override async Task RunImplAsync(CancellationToken cancellationToken) { Verify.NotEmpty($"{nameof(TestState)}.{nameof(SolutionState.Sources)}", TestState.Sources); diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt index 74ed5b386..f2aaec429 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt @@ -12,7 +12,7 @@ Microsoft.CodeAnalysis.Testing.EmptyCodeRefactoringProvider.EmptyCodeRefactoring abstract Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.GetCodeRefactoringProviders() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.GetDefaultDiagnostic(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer[] analyzers) -> Microsoft.CodeAnalysis.DiagnosticDescriptor override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.GetDiagnosticAnalyzers() -> System.Collections.Generic.IEnumerable -override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task override Microsoft.CodeAnalysis.Testing.EmptyCodeRefactoringProvider.ComputeRefactoringsAsync(Microsoft.CodeAnalysis.CodeRefactorings.CodeRefactoringContext context) -> System.Threading.Tasks.Task static Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.TriggerSpanDescriptor.get -> Microsoft.CodeAnalysis.DiagnosticDescriptor static Microsoft.CodeAnalysis.Testing.CodeRefactoringVerifier.VerifyRefactoringAsync(string source, Microsoft.CodeAnalysis.Testing.DiagnosticResult expected, string fixedSource) -> System.Threading.Tasks.Task diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt index c5004ff9d..09cd1e21f 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt @@ -11,4 +11,4 @@ abstract Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.CreateGen abstract Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetSourceGenerators() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetDiagnosticAnalyzers() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetProjectCompilationAsync(Microsoft.CodeAnalysis.Project project, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task -override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs index f7ac4fb3f..394b9bae3 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs @@ -33,7 +33,7 @@ protected override IEnumerable GetDiagnosticAnalyzers() protected abstract GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators); - public override async Task RunAsync(CancellationToken cancellationToken = default) + protected override async Task RunImplAsync(CancellationToken cancellationToken) { var analyzers = GetDiagnosticAnalyzers().ToArray(); var defaultDiagnostic = GetDefaultDiagnostic(analyzers);