提交 1d1a5c96 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #15385 from CyrusNajmabadi/consolidateGoToDef2

Remove the synchronous GoToImplementation path for C#/VB.
......@@ -75,4 +75,4 @@ internal void AdjustStack(int count)
}
}
}
}
}
\ No newline at end of file
......@@ -120,7 +120,6 @@
<Compile Include="Formatting\Indentation\WhitespaceExtensions.cs" />
<Compile Include="Formatting\CSharpEditorFormattingService.PasteFormattingRule.cs" />
<Compile Include="GoToDefinition\CSharpGoToDefinitionService.cs" />
<Compile Include="GoToImplementation\CSharpGoToImplementationService.cs" />
<Compile Include="Highlighting\KeywordHighlighters\AbstractAsyncHighlighter.cs" />
<Compile Include="Highlighting\KeywordHighlighters\AsyncAnonymousMethodHighlighter.cs" />
<Compile Include="Highlighting\KeywordHighlighters\AsyncMethodHighlighter.cs" />
......
// 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.GoToImplementation;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Editor.CSharp.GoToImplementation
{
[ExportLanguageService(typeof(IGoToImplementationService), LanguageNames.CSharp), Shared]
internal sealed class CSharpGoToImplementationService : AbstractGoToImplementationService
{
[ImportingConstructor]
public CSharpGoToImplementationService(
[ImportMany]IEnumerable<Lazy<INavigableItemsPresenter>> presenters)
: base(presenters)
{
}
}
}
\ No newline at end of file
......@@ -261,7 +261,6 @@
<Compile Include="Implementation\Diagnostics\SuggestionAdornmentManagerProvider.cs" />
<Compile Include="Implementation\Diagnostics\SuggestionTag.cs" />
<Compile Include="FindUsages\AbstractFindUsagesService.ProgressAdapter.cs" />
<Compile Include="GoToImplementation\AbstractGoToImplementationService.cs" />
<Compile Include="GoToImplementation\IGoToImplementationService.cs" />
<Compile Include="Implementation\Intellisense\Completion\BraceCompletionMetadata.cs" />
<Compile Include="Implementation\Intellisense\Completion\OptionSetExtensions.cs" />
......
// 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.FindUsages;
using Microsoft.CodeAnalysis.Editor.GoToDefinition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.GoToImplementation
{
internal abstract class AbstractGoToImplementationService : IGoToImplementationService
{
private readonly IEnumerable<Lazy<INavigableItemsPresenter>> _navigableItemPresenters;
public AbstractGoToImplementationService(
IEnumerable<Lazy<INavigableItemsPresenter>> navigableItemPresenters)
{
_navigableItemPresenters = navigableItemPresenters;
}
public bool TryGoToImplementation(Document document, int position, CancellationToken cancellationToken, out string message)
{
var result = FindUsagesHelpers.FindImplementationsAsync(document, position, cancellationToken).WaitAndGetResult(cancellationToken);
if (result == null)
{
message = EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret;
return false;
}
if (result.Value.message != null)
{
message = result.Value.message;
return false;
}
return TryGoToImplementations(
result.Value.symbol, result.Value.project,
result.Value.implementations, cancellationToken, out message);
}
private bool TryGoToImplementations(
ISymbol symbol, Project project, ImmutableArray<ISymbol> implementations, CancellationToken cancellationToken, out string message)
{
if (implementations.Length == 0)
{
message = EditorFeaturesResources.The_symbol_has_no_implementations;
return false;
}
else if (implementations.Length == 1)
{
GoToDefinitionHelpers.TryGoToDefinition(
implementations.Single(), project, _navigableItemPresenters,
SpecializedCollections.EmptyEnumerable<Lazy<IStreamingFindUsagesPresenter>>(),
cancellationToken);
message = null;
return true;
}
else
{
return TryPresentInNavigableItemsPresenter(symbol, project, implementations, out message);
}
}
private bool TryPresentInNavigableItemsPresenter(
ISymbol symbol, Project project, ImmutableArray<ISymbol> implementations, out string message)
{
// We have multiple symbols, so we'll build a list of all preferred locations for all the symbols
var navigableItems = implementations.SelectMany(
implementation => CreateItemsForImplementation(implementation, project.Solution));
var presenter = _navigableItemPresenters.First();
var taggedParts = NavigableItemFactory.GetSymbolDisplayTaggedParts(project, symbol);
presenter.Value.DisplayResult(taggedParts.JoinText(), navigableItems);
message = null;
return true;
}
private static IEnumerable<INavigableItem> CreateItemsForImplementation(ISymbol implementation, Solution solution)
{
var symbolDisplayService = solution.Workspace.Services.GetLanguageServices(implementation.Language).GetRequiredService<ISymbolDisplayService>();
return NavigableItemFactory.GetItemsFromPreferredSourceLocations(
solution,
implementation,
displayTaggedParts: symbolDisplayService.ToDisplayParts(implementation).ToTaggedText());
}
}
}
\ No newline at end of file
......@@ -62,11 +62,8 @@ private void ExecuteCommand(Document document, int caretPosition)
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.
var streamingEnabled = document.Project.Solution.Workspace.Options.GetOption(FeatureOnOffOptions.StreamingGoToImplementation, document.Project.Language);
var canUseStreamingWindow = streamingEnabled && streamingService != null && streamingPresenter != null;
var canUseStreamingWindow = streamingEnabled && streamingService != null;
var canUseSynchronousWindow = synchronousService != null;
if (canUseStreamingWindow || canUseSynchronousWindow)
......
' 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
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.Editor.CSharp.GoToDefinition
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.GoToDefinition
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.GoToDefinition
Imports Microsoft.CodeAnalysis.Navigation
Imports Microsoft.VisualStudio.Composition
Imports Microsoft.VisualStudio.Text
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition
Public Class GoToDefinitionTests
Friend Async Function TestAsync(workspaceDefinition As XElement,
expectedResult As Boolean,
executeOnDocument As Func(Of Document, Integer, IEnumerable(Of Lazy(Of INavigableItemsPresenter)), Boolean)) As System.Threading.Tasks.Task
Using workspace = Await TestWorkspace.CreateAsync(
workspaceDefinition, exportProvider:=GoToTestHelpers.ExportProvider)
Dim solution = workspace.CurrentSolution
Dim cursorDocument = workspace.Documents.First(Function(d) d.CursorPosition.HasValue)
Dim cursorPosition = cursorDocument.CursorPosition.Value
Dim items As IList(Of INavigableItem) = Nothing
' Set up mocks. The IDocumentNavigationService should be called if there is one,
' location and the INavigableItemsPresenter should be called if there are
' multiple locations.
' prepare a notification listener
Dim textView = cursorDocument.GetTextView()
Dim textBuffer = textView.TextBuffer
textView.Caret.MoveTo(New SnapshotPoint(textBuffer.CurrentSnapshot, cursorPosition))
Dim cursorBuffer = cursorDocument.TextBuffer
Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id)
Dim mockDocumentNavigationService = DirectCast(workspace.Services.GetService(Of IDocumentNavigationService)(), MockDocumentNavigationService)
Dim presenter = New MockNavigableItemsPresenter(Sub(i) items = i)
Dim presenters = {New Lazy(Of INavigableItemsPresenter)(Function() presenter)}
Dim actualResult = executeOnDocument(document, cursorPosition, presenters)
Assert.Equal(expectedResult, actualResult)
Dim expectedLocations As New List(Of FilePathAndSpan)
For Each testDocument In workspace.Documents
For Each selectedSpan In testDocument.SelectedSpans
expectedLocations.Add(New FilePathAndSpan(testDocument.FilePath, selectedSpan))
Next
Next
expectedLocations.Sort()
If expectedResult Then
If mockDocumentNavigationService._triedNavigationToSpan Then
Dim definitionDocument = workspace.GetTestDocument(mockDocumentNavigationService._documentId)
Assert.Single(definitionDocument.SelectedSpans)
Assert.Equal(definitionDocument.SelectedSpans.Single(), mockDocumentNavigationService._span)
' The INavigableItemsPresenter should not have been called
Assert.Null(items)
Else
Assert.False(mockDocumentNavigationService._triedNavigationToPosition)
Assert.False(mockDocumentNavigationService._triedNavigationToLineAndOffset)
Assert.NotEmpty(items)
Dim actualLocations As New List(Of FilePathAndSpan)
For Each location In items
actualLocations.Add(New FilePathAndSpan(location.Document.FilePath, location.SourceSpan))
Next
actualLocations.Sort()
Assert.Equal(expectedLocations, actualLocations)
' The IDocumentNavigationService should not have been called
Assert.Null(mockDocumentNavigationService._documentId)
End If
Else
Assert.Null(mockDocumentNavigationService._documentId)
Assert.True(items Is Nothing OrElse items.Count = 0)
End If
End Using
End Function
Private Function TestAsync(workspaceDefinition As XElement, Optional expectedResult As Boolean = True) As Tasks.Task
Return GoToTestHelpers.TestAsync(workspaceDefinition, expectedResult,
Return TestAsync(workspaceDefinition, expectedResult,
Function(document As Document, cursorPosition As Integer, presenters As IEnumerable(Of Lazy(Of INavigableItemsPresenter)))
Dim goToDefService = If(document.Project.Language = LanguageNames.CSharp,
DirectCast(New CSharpGoToDefinitionService(presenters, {}), IGoToDefinitionService),
......
......@@ -2,23 +2,48 @@
Imports System.Threading
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.Editor.CSharp.GoToImplementation
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Editor.FindUsages
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.GoToImplementation
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToImplementation
Public Class GoToImplementationTests
Private Function TestAsync(workspaceDefinition As XElement, Optional shouldSucceed As Boolean = True) As Tasks.Task
Return GoToTestHelpers.TestAsync(workspaceDefinition, shouldSucceed,
Function(document As Document, cursorPosition As Integer, presenters As IEnumerable(Of Lazy(Of INavigableItemsPresenter)))
Dim service = If(document.Project.Language = LanguageNames.CSharp,
DirectCast(New CSharpGoToImplementationService(presenters), IGoToImplementationService),
New VisualBasicGoToImplementationService(presenters))
Dim message As String = Nothing
Return service.TryGoToImplementation(document, cursorPosition, CancellationToken.None, message)
End Function)
Private Async Function TestAsync(workspaceDefinition As XElement, Optional shouldSucceed As Boolean = True) As Tasks.Task
Using workspace = Await TestWorkspace.CreateAsync(workspaceDefinition)
Dim documentWithCursor = workspace.DocumentWithCursor
Dim position = documentWithCursor.CursorPosition.Value
Dim document = workspace.CurrentSolution.GetDocument(documentWithCursor.Id)
Dim findUsagesService = document.GetLanguageService(Of IFindUsagesService)
Dim context = New SimpleFindUsagesContext(CancellationToken.None)
Await findUsagesService.FindImplementationsAsync(document, position, context)
If Not shouldSucceed Then
Assert.NotNull(context.Message)
Else
Dim actualDefinitions = context.GetDefinitions().
SelectMany(Function(d) d.SourceSpans).
Select(Function(ss) New FilePathAndSpan(ss.Document.FilePath, ss.SourceSpan)).
ToList()
actualDefinitions.Sort()
Dim expectedDefinitions = workspace.Documents.SelectMany(
Function(d) d.SelectedSpans.Select(Function(ss) New FilePathAndSpan(d.FilePath, ss))).ToList()
expectedDefinitions.Sort()
Assert.Equal(actualDefinitions.Count, expectedDefinitions.Count)
For i = 0 To actualDefinitions.Count - 1
Dim actual = actualDefinitions(i)
Dim expected = expectedDefinitions(i)
Assert.True(actual.CompareTo(expected) = 0,
$"Expected: ({expected}) but got: ({actual})")
Next
End If
End Using
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.GoToImplementation)>
......
......@@ -93,7 +93,8 @@ protected internal override bool PartialSemanticsEnabled
get { return _backgroundCompiler != null; }
}
public TestHostDocument DocumentWithCursor { get { return Documents.Single(d => d.CursorPosition.HasValue && !d.IsLinkFile); } }
public TestHostDocument DocumentWithCursor
=> Documents.Single(d => d.CursorPosition.HasValue && !d.IsLinkFile);
protected override void OnDocumentTextChanged(Document document)
{
......
......@@ -17,100 +17,32 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers
Public ReadOnly ExportProvider As ExportProvider = MinimalTestExportProvider.CreateExportProvider(Catalog)
Public Async Function TestAsync(workspaceDefinition As XElement, expectedResult As Boolean, executeOnDocument As Func(Of Document, Integer, IEnumerable(Of Lazy(Of INavigableItemsPresenter)), Boolean)) As System.Threading.Tasks.Task
Using workspace = Await TestWorkspace.CreateAsync(workspaceDefinition, exportProvider:=ExportProvider)
Dim solution = workspace.CurrentSolution
Dim cursorDocument = workspace.Documents.First(Function(d) d.CursorPosition.HasValue)
Dim cursorPosition = cursorDocument.CursorPosition.Value
Dim items As IList(Of INavigableItem) = Nothing
' Set up mocks. The IDocumentNavigationService should be called if there is one,
' location and the INavigableItemsPresenter should be called if there are
' multiple locations.
' prepare a notification listener
Dim textView = cursorDocument.GetTextView()
Dim textBuffer = textView.TextBuffer
textView.Caret.MoveTo(New SnapshotPoint(textBuffer.CurrentSnapshot, cursorPosition))
Dim cursorBuffer = cursorDocument.TextBuffer
Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id)
Dim mockDocumentNavigationService = DirectCast(workspace.Services.GetService(Of IDocumentNavigationService)(), MockDocumentNavigationService)
Dim presenter = New MockNavigableItemsPresenter(Sub(i) items = i)
Dim presenters = {New Lazy(Of INavigableItemsPresenter)(Function() presenter)}
Dim actualResult = executeOnDocument(document, cursorPosition, presenters)
Assert.Equal(expectedResult, actualResult)
Dim expectedLocations As New List(Of FilePathAndSpan)
For Each testDocument In workspace.Documents
For Each selectedSpan In testDocument.SelectedSpans
expectedLocations.Add(New FilePathAndSpan(testDocument.FilePath, selectedSpan))
Next
Next
expectedLocations.Sort()
End Module
If expectedResult Then
If mockDocumentNavigationService._triedNavigationToSpan Then
Dim definitionDocument = workspace.GetTestDocument(mockDocumentNavigationService._documentId)
Assert.Single(definitionDocument.SelectedSpans)
Assert.Equal(definitionDocument.SelectedSpans.Single(), mockDocumentNavigationService._span)
Friend Structure FilePathAndSpan
Implements IComparable(Of FilePathAndSpan)
' The INavigableItemsPresenter should not have been called
Assert.Null(items)
Else
Assert.False(mockDocumentNavigationService._triedNavigationToPosition)
Assert.False(mockDocumentNavigationService._triedNavigationToLineAndOffset)
Assert.NotEmpty(items)
Public ReadOnly Property FilePath As String
Public ReadOnly Property Span As TextSpan
Dim actualLocations As New List(Of FilePathAndSpan)
Public Sub New(filePath As String, span As TextSpan)
Me.FilePath = filePath
Me.Span = span
End Sub
For Each location In items
actualLocations.Add(New FilePathAndSpan(location.Document.FilePath, location.SourceSpan))
Next
Public Function CompareTo(other As FilePathAndSpan) As Integer Implements IComparable(Of FilePathAndSpan).CompareTo
Dim result = String.CompareOrdinal(FilePath, other.FilePath)
actualLocations.Sort()
Assert.Equal(expectedLocations, actualLocations)
If result <> 0 Then
Return result
End If
' The IDocumentNavigationService should not have been called
Assert.Null(mockDocumentNavigationService._documentId)
End If
Else
Assert.Null(mockDocumentNavigationService._documentId)
Assert.True(items Is Nothing OrElse items.Count = 0)
End If
End Using
Return Span.CompareTo(other.Span)
End Function
Private Structure FilePathAndSpan
Implements IComparable(Of FilePathAndSpan)
Public ReadOnly Property FilePath As String
Public ReadOnly Property Span As TextSpan
Public Sub New(filePath As String, span As TextSpan)
Me.FilePath = filePath
Me.Span = span
End Sub
Public Function CompareTo(other As FilePathAndSpan) As Integer Implements IComparable(Of FilePathAndSpan).CompareTo
Dim result = String.CompareOrdinal(FilePath, other.FilePath)
If result <> 0 Then
Return result
End If
Return Span.CompareTo(other.Span)
End Function
Public Overrides Function ToString() As String
Return $"{FilePath}, {Span}"
End Function
End Structure
Public Overrides Function ToString() As String
Return $"{FilePath}, {Span}"
End Function
End Structure
End Module
End Namespace
\ No newline at end of file
......@@ -106,7 +106,6 @@
<Compile Include="Formatting\Indentation\SpecialFormattingOperation.vb" />
<Compile Include="Formatting\Indentation\VisualBasicIndentationService.Indenter.vb" />
<Compile Include="Formatting\Indentation\VisualBasicIndentationService.vb" />
<Compile Include="GoToImplementation\VisualBasicGoToImplementationService.vb" />
<Compile Include="GoToDefinition\VisualBasicGoToDefinitionService.vb" />
<Compile Include="Highlighting\KeywordHighlighters\AccessorDeclarationHighlighter.vb" />
<Compile Include="Highlighting\KeywordHighlighters\ConditionalPreprocessorHighlighter.vb" />
......
' 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.Composition
Imports Microsoft.CodeAnalysis.Editor.GoToImplementation
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.GoToImplementation
<ExportLanguageService(GetType(IGoToImplementationService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicGoToImplementationService
Inherits AbstractGoToImplementationService
<ImportingConstructor>
Public Sub New(<ImportMany> presenters As IEnumerable(Of Lazy(Of INavigableItemsPresenter)))
MyBase.New(presenters)
End Sub
End Class
End Namespace
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册