From f4c0c0f234741e738c38ddde9417e02b7e862474 Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Thu, 2 Dec 2021 13:01:33 -0800 Subject: [PATCH 1/8] Add external access to stacktrace APIs for Unit Testing --- .../API/UnitTestingStackTraceService.cs | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs new file mode 100644 index 0000000000000..ad80d17239e29 --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.StackTraceExplorer; +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.API +{ + internal sealed class UnitTestingStackTraceService + { + private readonly IStackTraceExplorerService _stackTraceService; + + public UnitTestingStackTraceService(HostWorkspaceServices services) + => _stackTraceService = services.GetRequiredService(); + + public async Task> ParseAsync(string input, CancellationToken cancellationToken) + { + var result = await StackTraceAnalyzer.AnalyzeAsync(input, cancellationToken).ConfigureAwait(false); + return result.ParsedFrames.SelectAsArray(p => new Frame(p, _stackTraceService)); + } + + public readonly struct Frame + { + private readonly ParsedFrame _parsedFrame; + private readonly IStackTraceExplorerService _stackTraceService; + + public Frame(ParsedFrame parsedFrame, IStackTraceExplorerService service) + { + _parsedFrame = parsedFrame; + _stackTraceService = service; + } + + public (Document? document, int lineNumber) TryGetDocumentAndLine(Solution solution) + => _stackTraceService.GetDocumentAndLine(solution, _parsedFrame); + + public async Task TryFindMethodDefinitionAsync(Solution solution, CancellationToken cancellationToken) + { + var definition = await _stackTraceService.TryFindDefinitionAsync(solution, _parsedFrame, StackFrameSymbolPart.Method, cancellationToken).ConfigureAwait(false); + if (definition == null) + { + return null; + } + + return new Definition(definition); + } + } + + public readonly struct Definition + { + private readonly FindUsages.DefinitionItem _definition; + + public Definition(FindUsages.DefinitionItem definition) + { + _definition = definition; + } + + public async Task TryNavigateToAsync(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) + { + var canNavigate = await _definition.CanNavigateToAsync(workspace, cancellationToken).ConfigureAwait(false); + if (canNavigate) + { + return await _definition.TryNavigateToAsync(workspace, showInPreviewTab, activateTab, cancellationToken).ConfigureAwait(false); + } + + return false; + } + } + } +} From 4fbc6c49b4a005dc57790eb17237ce2d6cc739ea Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Thu, 2 Dec 2021 13:06:15 -0800 Subject: [PATCH 2/8] Switch to a single line parsing and frame --- .../UnitTesting/API/UnitTestingStackTraceService.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs index ad80d17239e29..5921c7c2c02fa 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs @@ -7,6 +7,8 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.StackTraceExplorer; using System.Collections.Immutable; +using System; +using System.Linq; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.API { @@ -17,10 +19,15 @@ internal sealed class UnitTestingStackTraceService public UnitTestingStackTraceService(HostWorkspaceServices services) => _stackTraceService = services.GetRequiredService(); - public async Task> ParseAsync(string input, CancellationToken cancellationToken) + public async Task ParseAsync(string line, CancellationToken cancellationToken) { - var result = await StackTraceAnalyzer.AnalyzeAsync(input, cancellationToken).ConfigureAwait(false); - return result.ParsedFrames.SelectAsArray(p => new Frame(p, _stackTraceService)); + var result = await StackTraceAnalyzer.AnalyzeAsync(line, cancellationToken).ConfigureAwait(false); + if (result.ParsedFrames.Length > 1) + { + throw new InvalidOperationException(); + } + + return new Frame(result.ParsedFrames.Single(), _stackTraceService); } public readonly struct Frame From eca50ada4be2f0c23b3917913d079e89c7b9c38d Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Thu, 2 Dec 2021 13:07:08 -0800 Subject: [PATCH 3/8] Handle cases where no frames are parsed --- .../UnitTesting/API/UnitTestingStackTraceService.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs index 5921c7c2c02fa..59dcfeb6bffdd 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs @@ -19,9 +19,15 @@ internal sealed class UnitTestingStackTraceService public UnitTestingStackTraceService(HostWorkspaceServices services) => _stackTraceService = services.GetRequiredService(); - public async Task ParseAsync(string line, CancellationToken cancellationToken) + public async Task TryParseAsync(string line, CancellationToken cancellationToken) { var result = await StackTraceAnalyzer.AnalyzeAsync(line, cancellationToken).ConfigureAwait(false); + + if (result.ParsedFrames.Length == 0) + { + return null; + } + if (result.ParsedFrames.Length > 1) { throw new InvalidOperationException(); @@ -41,7 +47,7 @@ public Frame(ParsedFrame parsedFrame, IStackTraceExplorerService service) _stackTraceService = service; } - public (Document? document, int lineNumber) TryGetDocumentAndLine(Solution solution) + public (Document? document, int lineNumber) TryGetDocumentAndLine(Solution solution) => _stackTraceService.GetDocumentAndLine(solution, _parsedFrame); public async Task TryFindMethodDefinitionAsync(Solution solution, CancellationToken cancellationToken) From 89b56833a3a8e7e980c4290148ba9e08291c6004 Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Sat, 4 Dec 2021 01:38:03 -0800 Subject: [PATCH 4/8] Change to return all frames instead of single --- .../API/UnitTestingStackTraceService.cs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs index 59dcfeb6bffdd..e1906541002d4 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs @@ -7,8 +7,6 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.StackTraceExplorer; using System.Collections.Immutable; -using System; -using System.Linq; namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.API { @@ -19,21 +17,10 @@ internal sealed class UnitTestingStackTraceService public UnitTestingStackTraceService(HostWorkspaceServices services) => _stackTraceService = services.GetRequiredService(); - public async Task TryParseAsync(string line, CancellationToken cancellationToken) + public async Task> TryParseAsync(string input, CancellationToken cancellationToken) { - var result = await StackTraceAnalyzer.AnalyzeAsync(line, cancellationToken).ConfigureAwait(false); - - if (result.ParsedFrames.Length == 0) - { - return null; - } - - if (result.ParsedFrames.Length > 1) - { - throw new InvalidOperationException(); - } - - return new Frame(result.ParsedFrames.Single(), _stackTraceService); + var result = await StackTraceAnalyzer.AnalyzeAsync(input, cancellationToken).ConfigureAwait(false); + return result.ParsedFrames.SelectAsArray(p => new Frame(p, _stackTraceService)); } public readonly struct Frame From d1a108303913cf64161fabaf776249abad13c568 Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Sat, 4 Dec 2021 01:38:39 -0800 Subject: [PATCH 5/8] Use Workspace in constructor --- .../UnitTesting/API/UnitTestingStackTraceService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs index e1906541002d4..61962c110edfc 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs @@ -14,8 +14,8 @@ internal sealed class UnitTestingStackTraceService { private readonly IStackTraceExplorerService _stackTraceService; - public UnitTestingStackTraceService(HostWorkspaceServices services) - => _stackTraceService = services.GetRequiredService(); + public UnitTestingStackTraceService(Workspace workspace) + => _stackTraceService = workspace.Services.GetRequiredService(); public async Task> TryParseAsync(string input, CancellationToken cancellationToken) { From 0de304c707ca1db6ae2a56429ab104f2c57be0a4 Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Mon, 6 Dec 2021 17:34:12 -0800 Subject: [PATCH 6/8] Update to hold onto workspace --- .../API/UnitTestingStackTraceService.cs | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs index 61962c110edfc..dadbb0f0048c4 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs @@ -12,58 +12,66 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.API { internal sealed class UnitTestingStackTraceService { + private readonly Workspace _workspace; private readonly IStackTraceExplorerService _stackTraceService; public UnitTestingStackTraceService(Workspace workspace) - => _stackTraceService = workspace.Services.GetRequiredService(); + { + _workspace = workspace; + _stackTraceService = workspace.Services.GetRequiredService(); + } public async Task> TryParseAsync(string input, CancellationToken cancellationToken) { var result = await StackTraceAnalyzer.AnalyzeAsync(input, cancellationToken).ConfigureAwait(false); - return result.ParsedFrames.SelectAsArray(p => new Frame(p, _stackTraceService)); + return result.ParsedFrames.SelectAsArray(p => new Frame(p, _stackTraceService, _workspace)); } public readonly struct Frame { private readonly ParsedFrame _parsedFrame; private readonly IStackTraceExplorerService _stackTraceService; + private readonly Workspace _workspace; - public Frame(ParsedFrame parsedFrame, IStackTraceExplorerService service) + public Frame(ParsedFrame parsedFrame, IStackTraceExplorerService service, Workspace workspace) { _parsedFrame = parsedFrame; _stackTraceService = service; + _workspace = workspace; } - public (Document? document, int lineNumber) TryGetDocumentAndLine(Solution solution) - => _stackTraceService.GetDocumentAndLine(solution, _parsedFrame); + public (Document? document, int lineNumber) TryGetDocumentAndLine() + => _stackTraceService.GetDocumentAndLine(_workspace.CurrentSolution, _parsedFrame); - public async Task TryFindMethodDefinitionAsync(Solution solution, CancellationToken cancellationToken) + public async Task TryFindMethodDefinitionAsync(CancellationToken cancellationToken) { - var definition = await _stackTraceService.TryFindDefinitionAsync(solution, _parsedFrame, StackFrameSymbolPart.Method, cancellationToken).ConfigureAwait(false); + var definition = await _stackTraceService.TryFindDefinitionAsync(_workspace.CurrentSolution, _parsedFrame, StackFrameSymbolPart.Method, cancellationToken).ConfigureAwait(false); if (definition == null) { return null; } - return new Definition(definition); + return new Definition(definition, _workspace); } } public readonly struct Definition { private readonly FindUsages.DefinitionItem _definition; + private readonly Workspace _workspace; - public Definition(FindUsages.DefinitionItem definition) + public Definition(FindUsages.DefinitionItem definition, Workspace workspace) { _definition = definition; + _workspace = workspace; } - public async Task TryNavigateToAsync(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) + public async Task TryNavigateToAsync(bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) { - var canNavigate = await _definition.CanNavigateToAsync(workspace, cancellationToken).ConfigureAwait(false); + var canNavigate = await _definition.CanNavigateToAsync(_workspace, cancellationToken).ConfigureAwait(false); if (canNavigate) { - return await _definition.TryNavigateToAsync(workspace, showInPreviewTab, activateTab, cancellationToken).ConfigureAwait(false); + return await _definition.TryNavigateToAsync(_workspace, showInPreviewTab, activateTab, cancellationToken).ConfigureAwait(false); } return false; From 8034b5194aa6a7a5e4f156a87c9557b98679fd08 Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Tue, 4 Jan 2022 16:37:59 -0800 Subject: [PATCH 7/8] Use interface accessor and factory --- .../IUnitTestingStackTraceServiceAccessor.cs | 19 +++++ .../API/UnitTestingStackTraceService.cs | 81 ------------------- .../UnitTestingDefinitionItemWrapper.cs | 16 ++++ .../UnitTestingParsedFrameWrapper.cs | 18 +++++ .../UnitTestingStackTraceServiceAccessor.cs | 46 +++++++++++ ...TestingStackTraceServiceAccessorFactory.cs | 32 ++++++++ 6 files changed, 131 insertions(+), 81 deletions(-) create mode 100644 src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs delete mode 100644 src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs create mode 100644 src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingDefinitionItemWrapper.cs create mode 100644 src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingParsedFrameWrapper.cs create mode 100644 src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs create mode 100644 src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs new file mode 100644 index 0000000000000..daed2fdca3eba --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/IUnitTestingStackTraceServiceAccessor.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api +{ + internal interface IUnitTestingStackTraceServiceAccessor : IWorkspaceService + { + Task> TryParseAsync(string input, Workspace workspace, CancellationToken cancellationToken); + Task TryFindMethodDefinitionAsync(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame, CancellationToken cancellationToken); + (Document? document, int lineNumber) GetDocumentAndLine(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame); + Task TryNavigateToAsync(Workspace workspace, UnitTestingDefinitionItemWrapper definitionItem, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken); + } +} diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs deleted file mode 100644 index dadbb0f0048c4..0000000000000 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingStackTraceService.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.StackTraceExplorer; -using System.Collections.Immutable; - -namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.API -{ - internal sealed class UnitTestingStackTraceService - { - private readonly Workspace _workspace; - private readonly IStackTraceExplorerService _stackTraceService; - - public UnitTestingStackTraceService(Workspace workspace) - { - _workspace = workspace; - _stackTraceService = workspace.Services.GetRequiredService(); - } - - public async Task> TryParseAsync(string input, CancellationToken cancellationToken) - { - var result = await StackTraceAnalyzer.AnalyzeAsync(input, cancellationToken).ConfigureAwait(false); - return result.ParsedFrames.SelectAsArray(p => new Frame(p, _stackTraceService, _workspace)); - } - - public readonly struct Frame - { - private readonly ParsedFrame _parsedFrame; - private readonly IStackTraceExplorerService _stackTraceService; - private readonly Workspace _workspace; - - public Frame(ParsedFrame parsedFrame, IStackTraceExplorerService service, Workspace workspace) - { - _parsedFrame = parsedFrame; - _stackTraceService = service; - _workspace = workspace; - } - - public (Document? document, int lineNumber) TryGetDocumentAndLine() - => _stackTraceService.GetDocumentAndLine(_workspace.CurrentSolution, _parsedFrame); - - public async Task TryFindMethodDefinitionAsync(CancellationToken cancellationToken) - { - var definition = await _stackTraceService.TryFindDefinitionAsync(_workspace.CurrentSolution, _parsedFrame, StackFrameSymbolPart.Method, cancellationToken).ConfigureAwait(false); - if (definition == null) - { - return null; - } - - return new Definition(definition, _workspace); - } - } - - public readonly struct Definition - { - private readonly FindUsages.DefinitionItem _definition; - private readonly Workspace _workspace; - - public Definition(FindUsages.DefinitionItem definition, Workspace workspace) - { - _definition = definition; - _workspace = workspace; - } - - public async Task TryNavigateToAsync(bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) - { - var canNavigate = await _definition.CanNavigateToAsync(_workspace, cancellationToken).ConfigureAwait(false); - if (canNavigate) - { - return await _definition.TryNavigateToAsync(_workspace, showInPreviewTab, activateTab, cancellationToken).ConfigureAwait(false); - } - - return false; - } - } - } -} diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingDefinitionItemWrapper.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingDefinitionItemWrapper.cs new file mode 100644 index 0000000000000..6e7045ae4af07 --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingDefinitionItemWrapper.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting +{ + internal readonly struct UnitTestingDefinitionItemWrapper + { + internal FindUsages.DefinitionItem UnderlyingObject { get; } + + public UnitTestingDefinitionItemWrapper(FindUsages.DefinitionItem definition) + { + UnderlyingObject = definition; + } + } +} diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingParsedFrameWrapper.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingParsedFrameWrapper.cs new file mode 100644 index 0000000000000..b26b52b9da7b1 --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingParsedFrameWrapper.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.StackTraceExplorer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting +{ + internal readonly struct UnitTestingParsedFrameWrapper + { + internal ParsedFrame UnderlyingObject { get; } + + public UnitTestingParsedFrameWrapper(ParsedFrame parsedFrame) + { + UnderlyingObject = parsedFrame; + } + } +} diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs new file mode 100644 index 0000000000000..cc74dbe801c29 --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.StackTraceExplorer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting +{ + internal class UnitTestingStackTraceServiceAccessor : IUnitTestingStackTraceServiceAccessor + { + private readonly IStackTraceExplorerService _stackTraceExplorerService; + + [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] + public UnitTestingStackTraceServiceAccessor( + IStackTraceExplorerService stackTraceExplorerService) + { + _stackTraceExplorerService = stackTraceExplorerService; + } + + public (Document? document, int lineNumber) GetDocumentAndLine(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame) + => _stackTraceExplorerService.GetDocumentAndLine(workspace.CurrentSolution, parsedFrame.UnderlyingObject); + + public async Task TryFindMethodDefinitionAsync(Workspace workspace, UnitTestingParsedFrameWrapper parsedFrame, CancellationToken cancellationToken) + { + var definition = await _stackTraceExplorerService.TryFindDefinitionAsync(workspace.CurrentSolution, parsedFrame.UnderlyingObject, StackFrameSymbolPart.Method, cancellationToken).ConfigureAwait(false); + return definition is null + ? null + : new UnitTestingDefinitionItemWrapper(definition); + } + + public async Task> TryParseAsync(string input, Workspace workspace, CancellationToken cancellationToken) + { + var result = await StackTraceAnalyzer.AnalyzeAsync(input, cancellationToken).ConfigureAwait(false); + return result.ParsedFrames.SelectAsArray(p => new UnitTestingParsedFrameWrapper(p)); + } + + public Task TryNavigateToAsync(Workspace workspace, UnitTestingDefinitionItemWrapper definitionItem, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) + => definitionItem.UnderlyingObject.TryNavigateToAsync(workspace, showInPreviewTab, activateTab, cancellationToken); + } +} diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs new file mode 100644 index 0000000000000..6f439c85d209f --- /dev/null +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.StackTraceExplorer; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting +{ + [ExportWorkspaceServiceFactory(typeof(IUnitTestingStackTraceServiceAccessor))] + [Shared] + + internal class UnitTestingStackTraceServiceAccessorFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public UnitTestingStackTraceServiceAccessorFactory() + { + } + + [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + { + var stackTraceExplorerService = workspaceServices.GetRequiredService(); + return new UnitTestingStackTraceServiceAccessor(stackTraceExplorerService); + } + } +} From ddafc8a3c303111e6e0cc2f514fc0d7ad309ffc0 Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Fri, 14 Jan 2022 14:16:54 -0800 Subject: [PATCH 8/8] Move Api exposed wrappers to Api namespace --- .../UnitTesting/{ => API}/UnitTestingDefinitionItemWrapper.cs | 2 +- .../UnitTesting/{ => API}/UnitTestingParsedFrameWrapper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/Features/Core/Portable/ExternalAccess/UnitTesting/{ => API}/UnitTestingDefinitionItemWrapper.cs (88%) rename src/Features/Core/Portable/ExternalAccess/UnitTesting/{ => API}/UnitTestingParsedFrameWrapper.cs (89%) diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingDefinitionItemWrapper.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingDefinitionItemWrapper.cs similarity index 88% rename from src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingDefinitionItemWrapper.cs rename to src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingDefinitionItemWrapper.cs index 6e7045ae4af07..5a066d48da9d5 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingDefinitionItemWrapper.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingDefinitionItemWrapper.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api { internal readonly struct UnitTestingDefinitionItemWrapper { diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingParsedFrameWrapper.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingParsedFrameWrapper.cs similarity index 89% rename from src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingParsedFrameWrapper.cs rename to src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingParsedFrameWrapper.cs index b26b52b9da7b1..5159b778f2448 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingParsedFrameWrapper.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingParsedFrameWrapper.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis.StackTraceExplorer; -namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api { internal readonly struct UnitTestingParsedFrameWrapper {