未验证 提交 104692ce 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #34117 from sharwell/single-streaming-presenter

Require exactly one export of IStreamingFindUsagesPresenter when used
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using Microsoft.CodeAnalysis.Editor.GoToDefinition;
using Microsoft.CodeAnalysis.Editor.Host;
......@@ -13,9 +11,8 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.GoToDefinition
internal class CSharpGoToDefinitionService : AbstractGoToDefinitionService
{
[ImportingConstructor]
public CSharpGoToDefinitionService(
[ImportMany]IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters)
: base(streamingPresenters)
public CSharpGoToDefinitionService(IStreamingFindUsagesPresenter streamingPresenter)
: base(streamingPresenter)
{
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
......@@ -30,7 +24,7 @@ namespace Microsoft.CodeAnalysis.Editor.FindReferences
[Name(PredefinedCommandHandlerNames.FindReferences)]
internal class FindReferencesCommandHandler : VSCommanding.ICommandHandler<FindReferencesCommandArgs>
{
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IStreamingFindUsagesPresenter _streamingPresenter;
private readonly IAsynchronousOperationListener _asyncListener;
......@@ -38,13 +32,12 @@ internal class FindReferencesCommandHandler : VSCommanding.ICommandHandler<FindR
[ImportingConstructor]
public FindReferencesCommandHandler(
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
IStreamingFindUsagesPresenter streamingPresenter,
IAsynchronousOperationListenerProvider listenerProvider)
{
Contract.ThrowIfNull(streamingPresenters);
Contract.ThrowIfNull(listenerProvider);
_streamingPresenters = streamingPresenters;
_streamingPresenter = streamingPresenter;
_asyncListener = listenerProvider.GetListener(FeatureAttribute.FindReferences);
}
......@@ -84,32 +77,19 @@ public bool ExecuteCommand(FindReferencesCommandArgs args, CommandExecutionConte
private bool TryExecuteCommand(int caretPosition, Document document, CommandExecutionContext context)
{
var streamingService = document.GetLanguageService<IFindUsagesService>();
var streamingPresenter = GetStreamingPresenter();
// See if we're running on a host that can provide streaming results.
// We'll both need a FAR service that can stream results to us, and
// a presenter that can accept streamed results.
if (streamingService != null && streamingPresenter != null)
if (streamingService != null && _streamingPresenter != null)
{
_ = StreamingFindReferencesAsync(document, caretPosition, streamingService, streamingPresenter);
_ = StreamingFindReferencesAsync(document, caretPosition, streamingService, _streamingPresenter);
return true;
}
return false;
}
private IStreamingFindUsagesPresenter GetStreamingPresenter()
{
try
{
return _streamingPresenters.FirstOrDefault()?.Value;
}
catch
{
return null;
}
}
private async Task StreamingFindReferencesAsync(
Document document, int caretPosition,
IFindUsagesService findUsagesService,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
......@@ -16,12 +15,11 @@ namespace Microsoft.CodeAnalysis.Editor.GoToDefinition
// GoToDefinition
internal abstract class AbstractGoToDefinitionService : IGoToDefinitionService
{
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IStreamingFindUsagesPresenter _streamingPresenter;
protected AbstractGoToDefinitionService(
IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters)
protected AbstractGoToDefinitionService(IStreamingFindUsagesPresenter streamingPresenter)
{
_streamingPresenters = streamingPresenters;
_streamingPresenter = streamingPresenter;
}
public async Task<IEnumerable<INavigableItem>> FindDefinitionsAsync(
......@@ -54,7 +52,7 @@ public bool TryGoToDefinition(Document document, int position, CancellationToken
return GoToDefinitionHelpers.TryGoToDefinition(symbol,
document.Project,
_streamingPresenters,
_streamingPresenter,
thirdPartyNavigationAllowed: isThirdPartyNavigationAllowed,
throwOnHiddenDefinition: true,
cancellationToken: cancellationToken);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
......@@ -96,18 +95,17 @@ internal static class GoToDefinitionHelpers
public static bool TryGoToDefinition(
ISymbol symbol,
Project project,
IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
IStreamingFindUsagesPresenter streamingPresenter,
CancellationToken cancellationToken,
bool thirdPartyNavigationAllowed = true,
bool throwOnHiddenDefinition = false)
{
var definitions = GetDefinitions(symbol, project, thirdPartyNavigationAllowed, cancellationToken);
var presenter = streamingPresenters.FirstOrDefault()?.Value;
var title = string.Format(EditorFeaturesResources._0_declarations,
FindUsagesHelpers.GetDisplayName(symbol));
return presenter.TryNavigateToOrPresentItemsAsync(
return streamingPresenter.TryNavigateToOrPresentItemsAsync(
project.Solution.Workspace, title, definitions).WaitAndGetResult(cancellationToken);
}
......@@ -115,7 +113,7 @@ internal static class GoToDefinitionHelpers
ImmutableArray<DefinitionItem> definitions,
Project project,
string title,
IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
IStreamingFindUsagesPresenter streamingPresenter,
CancellationToken cancellationToken)
{
if (definitions.IsDefaultOrEmpty)
......@@ -123,9 +121,7 @@ internal static class GoToDefinitionHelpers
return false;
}
var presenter = streamingPresenters.FirstOrDefault()?.Value;
return presenter.TryNavigateToOrPresentItemsAsync(
return streamingPresenter.TryNavigateToOrPresentItemsAsync(
project.Solution.Workspace, title, definitions).WaitAndGetResult(cancellationToken);
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Editor.Commanding.Commands;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;
using VSCommanding = Microsoft.VisualStudio.Commanding;
......@@ -26,13 +24,13 @@ namespace Microsoft.CodeAnalysis.Editor.GoToImplementation
[Name(PredefinedCommandHandlerNames.GoToImplementation)]
internal partial class GoToImplementationCommandHandler : VSCommanding.ICommandHandler<GoToImplementationCommandArgs>
{
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IStreamingFindUsagesPresenter _streamingPresenter;
[ImportingConstructor]
public GoToImplementationCommandHandler(
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters)
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public GoToImplementationCommandHandler(IStreamingFindUsagesPresenter streamingPresenter)
{
_streamingPresenters = streamingPresenters;
_streamingPresenter = streamingPresenter;
}
public string DisplayName => EditorFeaturesResources.Go_To_Implementation;
......@@ -82,8 +80,6 @@ public bool ExecuteCommand(GoToImplementationCommandArgs args, CommandExecutionC
IFindUsagesService streamingService,
CommandExecutionContext context)
{
var streamingPresenter = GetStreamingPresenter();
if (streamingService != null)
{
// We have all the cheap stuff, so let's do expensive stuff now
......@@ -94,7 +90,7 @@ public bool ExecuteCommand(GoToImplementationCommandArgs args, CommandExecutionC
{
StreamingGoToImplementation(
document, caretPosition,
streamingService, streamingPresenter,
streamingService, _streamingPresenter,
userCancellationToken, out messageToShow);
}
......@@ -139,17 +135,5 @@ public bool ExecuteCommand(GoToImplementationCommandArgs args, CommandExecutionC
streamingPresenter.TryNavigateToOrPresentItemsAsync(
document.Project.Solution.Workspace, goToImplContext.SearchTitle, definitionItems).Wait(cancellationToken);
}
private IStreamingFindUsagesPresenter GetStreamingPresenter()
{
try
{
return _streamingPresenters.FirstOrDefault()?.Value;
}
catch
{
return null;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Editor.GoToDefinition;
......@@ -19,14 +18,14 @@ private class NavigableSymbol : INavigableSymbol
private readonly ImmutableArray<DefinitionItem> _definitions;
private readonly SnapshotSpan _span;
private readonly Document _document;
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _presenters;
private readonly IStreamingFindUsagesPresenter _presenter;
private readonly IWaitIndicator _waitIndicator;
public NavigableSymbol(
ImmutableArray<DefinitionItem> definitions,
SnapshotSpan span,
Document document,
IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
IStreamingFindUsagesPresenter streamingPresenter,
IWaitIndicator waitIndicator)
{
Contract.ThrowIfFalse(definitions.Length > 0);
......@@ -34,7 +33,7 @@ private class NavigableSymbol : INavigableSymbol
_definitions = definitions;
_span = span;
_document = document;
_presenters = streamingPresenters;
_presenter = streamingPresenter;
_waitIndicator = waitIndicator;
}
......@@ -53,7 +52,7 @@ private class NavigableSymbol : INavigableSymbol
_definitions,
_document.Project,
_definitions[0].NameDisplayParts.GetFullText(),
_presenters,
_presenter,
context.CancellationToken)
);
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.GoToDefinition;
......@@ -13,7 +10,6 @@
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.CodeAnalysis.Editor.NavigableSymbols
{
......@@ -21,16 +17,16 @@ internal partial class NavigableSymbolService
{
private partial class NavigableSymbolSource : INavigableSymbolSource
{
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _presenters;
private readonly IStreamingFindUsagesPresenter _presenter;
private readonly IWaitIndicator _waitIndicator;
private bool _disposed;
public NavigableSymbolSource(
IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
IStreamingFindUsagesPresenter streamingPresenter,
IWaitIndicator waitIndicator)
{
_presenters = streamingPresenters;
_presenter = streamingPresenter;
_waitIndicator = waitIndicator;
}
......@@ -70,7 +66,7 @@ public async Task<INavigableSymbol> GetNavigableSymbolAsync(SnapshotSpan trigger
}
var snapshotSpan = new SnapshotSpan(snapshot, context.Span.ToSpan());
return new NavigableSymbol(definitions.ToImmutableArray(), snapshotSpan, document, _presenters, _waitIndicator);
return new NavigableSymbol(definitions.ToImmutableArray(), snapshotSpan, document, _presenter, _waitIndicator);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
......@@ -18,22 +16,22 @@ namespace Microsoft.CodeAnalysis.Editor.NavigableSymbols
internal partial class NavigableSymbolService : INavigableSymbolSourceProvider
{
private static readonly object s_key = new object();
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IStreamingFindUsagesPresenter _streamingPresenter;
private readonly IWaitIndicator _waitIndicator;
[ImportingConstructor]
public NavigableSymbolService(
IWaitIndicator waitIndicator,
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters)
IStreamingFindUsagesPresenter streamingPresenter)
{
_waitIndicator = waitIndicator;
_streamingPresenters = streamingPresenters;
_streamingPresenter = streamingPresenter;
}
public INavigableSymbolSource TryCreateNavigableSymbolSource(ITextView textView, ITextBuffer buffer)
{
return textView.GetOrCreatePerSubjectBufferProperty(buffer, s_key,
(v, b) => new NavigableSymbolSource(_streamingPresenters, _waitIndicator));
(v, b) => new NavigableSymbolSource(_streamingPresenter, _waitIndicator));
}
}
}
......@@ -65,7 +65,7 @@ public async Task TestFindReferencesAsynchronousCall()
var listenerProvider = workspace.ExportProvider.GetExportedValue<IAsynchronousOperationListenerProvider>();
var handler = new FindReferencesCommandHandler(
SpecializedCollections.SingletonEnumerable(new Lazy<IStreamingFindUsagesPresenter>(() => presenter)),
presenter,
listenerProvider);
var textView = workspace.Documents[0].GetTextView();
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.Editor.FindReferences
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
......@@ -38,7 +37,7 @@ class C
Dim context = New FindReferencesTests.TestContext()
Dim commandHandler = New FindReferencesCommandHandler(
{New Lazy(Of IStreamingFindUsagesPresenter)(Function() New MockStreamingFindReferencesPresenter(context))},
New MockStreamingFindReferencesPresenter(context),
listenerProvider)
Dim document = workspace.CurrentSolution.GetDocument(testDocument.Id)
......
......@@ -96,12 +96,11 @@ class C
Dim navigatedTo = False
Dim presenter = New MockStreamingFindUsagesPresenter(Sub() navigatedTo = True)
Dim presenters = {New Lazy(Of IStreamingFindUsagesPresenter)(Function() presenter)}
Dim cursorBuffer = cursorDocument.TextBuffer
Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id)
Dim goToDefService = New CSharpGoToDefinitionService(presenters)
Dim goToDefService = New CSharpGoToDefinitionService(presenter)
Dim waitContext = New TestUIThreadOperationContext(updatesBeforeCancel)
Dim commandHandler = New GoToDefinitionCommandHandler()
......
......@@ -14,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition
Public Class GoToDefinitionTests
Friend Sub Test(workspaceDefinition As XElement,
expectedResult As Boolean,
executeOnDocument As Func(Of Document, Integer, IEnumerable(Of Lazy(Of IStreamingFindUsagesPresenter)), Boolean))
executeOnDocument As Func(Of Document, Integer, IStreamingFindUsagesPresenter, Boolean))
Using workspace = TestWorkspace.Create(
workspaceDefinition, exportProvider:=GoToTestHelpers.ExportProviderFactory.CreateExportProvider())
Dim solution = workspace.CurrentSolution
......@@ -38,8 +38,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition
Dim presenterCalled As Boolean = False
Dim presenter = New MockStreamingFindUsagesPresenter(Sub() presenterCalled = True)
Dim presenters = {New Lazy(Of IStreamingFindUsagesPresenter)(Function() presenter)}
Dim actualResult = executeOnDocument(document, cursorPosition, presenters)
Dim actualResult = executeOnDocument(document, cursorPosition, presenter)
Assert.Equal(expectedResult, actualResult)
......@@ -104,10 +103,10 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition
Private Sub Test(workspaceDefinition As XElement, Optional expectedResult As Boolean = True)
Test(workspaceDefinition, expectedResult,
Function(document As Document, cursorPosition As Integer, presenters As IEnumerable(Of Lazy(Of IStreamingFindUsagesPresenter)))
Function(document As Document, cursorPosition As Integer, presenter As IStreamingFindUsagesPresenter)
Dim goToDefService = If(document.Project.Language = LanguageNames.CSharp,
DirectCast(New CSharpGoToDefinitionService(presenters), IGoToDefinitionService),
New VisualBasicGoToDefinitionService(presenters))
DirectCast(New CSharpGoToDefinitionService(presenter), IGoToDefinitionService),
New VisualBasicGoToDefinitionService(presenter))
Return goToDefService.TryGoToDefinition(document, cursorPosition, CancellationToken.None)
End Function)
......
......@@ -116,7 +116,7 @@ End Class"
End Function
Private Function ExtractSymbol(workspace As TestWorkspace, position As Integer, spans As IDictionary(Of String, ImmutableArray(Of TextSpan))) As Task(Of INavigableSymbol)
Dim presenter = {New Lazy(Of IStreamingFindUsagesPresenter)(Function() New MockStreamingFindUsagesPresenter(Sub() Return))}
Dim presenter = New MockStreamingFindUsagesPresenter(Sub() Return)
Dim service = New NavigableSymbolService(TestWaitIndicator.Default, presenter)
Dim view = workspace.Documents.First().GetTextView()
Dim buffer = workspace.Documents.First().GetTextBuffer()
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities;
using Microsoft.CodeAnalysis.SymbolMapping;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities.ExperimentationService;
using Microsoft.CodeAnalysis.UnitTests.Fakes;
using Microsoft.VisualStudio.Composition;
namespace Microsoft.CodeAnalysis.Editor.UnitTests
......@@ -91,5 +90,11 @@ public static ComposableCatalog GetEditorAssemblyCatalog()
return ExportProviderCache.GetOrCreateAssemblyCatalog(assemblies, ExportProviderCache.CreateResolver())
.WithPart(typeof(TestExperimentationServiceInternal));
}
public static ComposableCatalog WithDefaultFakes(this ComposableCatalog catalog)
{
return catalog
.WithPart(typeof(StubStreamingFindUsagesPresenter));
}
}
}
......@@ -35,7 +35,8 @@ public static ExportProvider ExportProviderWithCSharpAndVisualBasic
private static Lazy<ComposableCatalog> s_lazyMinimumCatalogWithCSharpAndVisualBasic =
new Lazy<ComposableCatalog>(() => ExportProviderCache.CreateTypeCatalog(GetNeutralAndCSharpAndVisualBasicTypes())
.WithParts(MinimalTestExportProvider.GetEditorAssemblyCatalog()));
.WithParts(MinimalTestExportProvider.GetEditorAssemblyCatalog())
.WithDefaultFakes());
private static Lazy<IExportProviderFactory> s_lazyMinimumExportProviderFactoryWithCSharpAndVisualBasic =
new Lazy<IExportProviderFactory>(() => ExportProviderCache.GetOrCreateExportProviderFactory(MinimumCatalogWithCSharpAndVisualBasic));
......@@ -120,7 +121,8 @@ public static ComposableCatalog GetCSharpAndVisualBasicAssemblyCatalog()
{
return ExportProviderCache.GetOrCreateAssemblyCatalog(
GetNeutralAndCSharpAndVisualBasicTypes().Select(t => t.Assembly).Distinct(), ExportProviderCache.CreateResolver())
.WithParts(MinimalTestExportProvider.GetEditorAssemblyCatalog());
.WithParts(MinimalTestExportProvider.GetEditorAssemblyCatalog())
.WithDefaultFakes();
}
}
}
......@@ -4,7 +4,6 @@ Imports System.Composition
Imports Microsoft.CodeAnalysis.Editor.GoToDefinition
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.VisualBasic.Utilities
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.GoToDefinition
<ExportLanguageService(GetType(IGoToDefinitionService), LanguageNames.VisualBasic), [Shared]>
......@@ -12,8 +11,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.GoToDefinition
Inherits AbstractGoToDefinitionService
<ImportingConstructor>
Public Sub New(<ImportMany> streamingPresenters As IEnumerable(Of Lazy(Of IStreamingFindUsagesPresenter)))
MyBase.New(streamingPresenters)
Public Sub New(streamingPresenter As IStreamingFindUsagesPresenter)
MyBase.New(streamingPresenter)
End Sub
End Class
End Namespace
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
......@@ -42,7 +40,7 @@ internal abstract partial class AbstractObjectBrowserLibraryManager : AbstractLi
private AbstractListItemFactory _listItemFactory;
private object _classMemberGate = new object();
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IStreamingFindUsagesPresenter _streamingPresenter;
private readonly IThreadingContext _threadingContext;
protected AbstractObjectBrowserLibraryManager(
......@@ -62,7 +60,7 @@ internal abstract partial class AbstractObjectBrowserLibraryManager : AbstractLi
Workspace.WorkspaceChanged += OnWorkspaceChanged;
_libraryService = new Lazy<ILibraryService>(() => Workspace.Services.GetLanguageServices(_languageName).GetService<ILibraryService>());
_streamingPresenters = componentModel.DefaultExportProvider.GetExports<IStreamingFindUsagesPresenter>();
_streamingPresenter = componentModel.DefaultExportProvider.GetExportedValue<IStreamingFindUsagesPresenter>();
_threadingContext = componentModel.DefaultExportProvider.GetExportedValue<IThreadingContext>();
}
......@@ -502,10 +500,8 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
switch (commandId)
{
case (uint)VSConstants.VSStd97CmdID.FindReferences:
var streamingPresenter = _streamingPresenters.FirstOrDefault()?.Value;
var symbolListItem = _activeListItem as SymbolListItem;
if (streamingPresenter != null && symbolListItem?.ProjectId != null)
if (symbolListItem?.ProjectId != null)
{
var project = this.Workspace.CurrentSolution.GetProject(symbolListItem.ProjectId);
if (project != null)
......@@ -515,7 +511,7 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
// and the references will be asynchronously added to the FindReferences
// window as they are computed. The user also knows something is happening
// as the window, with the progress-banner will pop up immediately.
var task = FindReferencesAsync(streamingPresenter, symbolListItem, project);
var task = FindReferencesAsync(_streamingPresenter, symbolListItem, project);
return true;
}
}
......
......@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Undo;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.Composition;
......@@ -18,7 +19,6 @@
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider;
......@@ -28,17 +28,22 @@ namespace Microsoft.VisualStudio.LanguageServices
[Export(typeof(VisualStudioWorkspaceImpl))]
internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl
{
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
/// <remarks>
/// Must be lazily constructed since the <see cref="IStreamingFindUsagesPresenter"/> implementation imports a
/// backreference to <see cref="VisualStudioWorkspace"/>.
/// </remarks>
private readonly Lazy<IStreamingFindUsagesPresenter> _streamingPresenter;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public RoslynVisualStudioWorkspace(
ExportProvider exportProvider,
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
Lazy<IStreamingFindUsagesPresenter> streamingPresenter,
[ImportMany] IEnumerable<IDocumentOptionsProviderFactory> documentOptionsProviderFactories,
[Import(typeof(SVsServiceProvider))] IAsyncServiceProvider asyncServiceProvider)
: base(exportProvider, asyncServiceProvider)
{
_streamingPresenters = streamingPresenters;
_streamingPresenter = streamingPresenter;
foreach (var providerFactory in documentOptionsProviderFactories)
{
......@@ -107,11 +112,6 @@ private static bool TryResolveSymbol(ISymbol symbol, Project project, Cancellati
public override bool TryGoToDefinition(
ISymbol symbol, Project project, CancellationToken cancellationToken)
{
if (!_streamingPresenters.Any())
{
return false;
}
if (!TryResolveSymbol(symbol, project, cancellationToken,
out var searchSymbol, out var searchProject))
{
......@@ -120,7 +120,7 @@ private static bool TryResolveSymbol(ISymbol symbol, Project project, Cancellati
return GoToDefinitionHelpers.TryGoToDefinition(
searchSymbol, searchProject,
_streamingPresenters, cancellationToken);
_streamingPresenter.Value, cancellationToken);
}
public override bool TryFindAllReferences(ISymbol symbol, Project project, CancellationToken cancellationToken)
......
......@@ -3,7 +3,6 @@
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.GoToDefinition
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Test.Utilities
......@@ -42,7 +41,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.GoToDefinition
WpfTestRunner.RequireWpfFact($"{NameOf(GoToDefinitionHelpers)}.{NameOf(GoToDefinitionHelpers.TryGoToDefinition)} assumes it's on the UI thread with a {NameOf(TaskExtensions.WaitAndGetResult)} call")
Dim success = GoToDefinitionHelpers.TryGoToDefinition(
symbolInfo.Symbol, document.Project,
{New Lazy(Of IStreamingFindUsagesPresenter)(Function() presenter)},
presenter,
thirdPartyNavigationAllowed:=True, throwOnHiddenDefinition:=False,
cancellationToken:=CancellationToken.None)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using System.Threading;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.UnitTests.Fakes
{
[Export(typeof(IStreamingFindUsagesPresenter))]
[Shared]
[PartNotDiscoverable]
internal class StubStreamingFindUsagesPresenter : IStreamingFindUsagesPresenter
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public StubStreamingFindUsagesPresenter()
{
}
public virtual void ClearAll()
{
}
public virtual FindUsagesContext StartSearch(string title, bool supportsReferences)
{
return new SimpleFindUsagesContext(CancellationToken.None);
}
}
}
......@@ -11,6 +11,7 @@
using Microsoft.CodeAnalysis.Remote;
using Microsoft.VisualStudio.Composition;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Test.Utilities
{
......@@ -171,17 +172,19 @@ private static IExportProviderFactory CreateExportProviderFactory(ComposableCata
var configuration = CompositionConfiguration.Create(catalog.WithCompositionService());
var runtimeComposition = RuntimeComposition.CreateRuntimeComposition(configuration);
var exportProviderFactory = runtimeComposition.CreateExportProviderFactory();
return new SingleExportProviderFactory(catalog, exportProviderFactory);
return new SingleExportProviderFactory(catalog, configuration, exportProviderFactory);
}
private class SingleExportProviderFactory : IExportProviderFactory
{
private readonly ComposableCatalog _catalog;
private readonly CompositionConfiguration _configuration;
private readonly IExportProviderFactory _exportProviderFactory;
public SingleExportProviderFactory(ComposableCatalog catalog, IExportProviderFactory exportProviderFactory)
public SingleExportProviderFactory(ComposableCatalog catalog, CompositionConfiguration configuration, IExportProviderFactory exportProviderFactory)
{
_catalog = catalog;
_configuration = configuration;
_exportProviderFactory = exportProviderFactory;
}
......@@ -200,6 +203,35 @@ public ExportProvider GetOrCreateExportProvider()
var expected = _expectedProviderForCatalog;
if (expected == null)
{
foreach (var errorCollection in _configuration.CompositionErrors)
{
foreach (var error in errorCollection)
{
foreach (var part in error.Parts)
{
foreach (var (importBinding, exportBindings) in part.SatisfyingExports)
{
if (exportBindings.Count <= 1)
{
// Ignore composition errors for missing parts
continue;
}
if (importBinding.ImportDefinition.Cardinality != ImportCardinality.ZeroOrMore)
{
// This failure occurs when a binding fails because multiple exports were
// provided but only a single one (at most) is expected. This typically occurs
// when a test ExportProvider is created with a mock implementation without
// first removing a value provided by default.
throw new InvalidOperationException(
"Failed to construct the MEF catalog for testing. Multiple exports were found for a part for which only one export is expected:" + Environment.NewLine
+ error.Message);
}
}
}
}
}
expected = _exportProviderFactory.CreateExportProvider();
expected = Interlocked.CompareExchange(ref _expectedProviderForCatalog, expected, null) ?? expected;
Interlocked.CompareExchange(ref _currentExportProvider, expected, null);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册