提交 c59d11e9 编写于 作者: S Sam Harwell

Implement INavigateToItemProvider2 with filtering

Fixes #27850
上级 98a1eabb
// 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;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.NavigateTo;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Language.NavigateTo.Interfaces;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.PatternMatching;
using Roslyn.Utilities;
......@@ -26,6 +25,7 @@ private class Searcher
private readonly INavigateToCallback _callback;
private readonly string _searchPattern;
private readonly bool _searchCurrentDocument;
private readonly ISet<string> _kinds;
private readonly Document _currentDocument;
private readonly ProgressTracker _progress;
private readonly IAsynchronousOperationListener _asyncListener;
......@@ -38,6 +38,7 @@ private class Searcher
INavigateToCallback callback,
string searchPattern,
bool searchCurrentDocument,
ISet<string> kinds,
CancellationToken cancellationToken)
{
_solution = solution;
......@@ -45,6 +46,7 @@ private class Searcher
_callback = callback;
_searchPattern = searchPattern;
_searchCurrentDocument = searchCurrentDocument;
_kinds = kinds;
_cancellationToken = cancellationToken;
_progress = new ProgressTracker(callback.ReportProgress);
_asyncListener = asyncListener;
......@@ -110,8 +112,8 @@ private async Task SearchAsyncWorker(Project project)
if (service != null)
{
var searchTask = _currentDocument != null
? service.SearchDocumentAsync(_currentDocument, _searchPattern, _cancellationToken)
: service.SearchProjectAsync(project, _searchPattern, _cancellationToken);
? service.SearchDocumentAsync(_currentDocument, _searchPattern, _kinds, _cancellationToken)
: service.SearchProjectAsync(project, _searchPattern, _kinds, _cancellationToken);
var results = await searchTask.ConfigureAwait(false);
if (results != null)
......@@ -126,7 +128,6 @@ private async Task SearchAsyncWorker(Project project)
}
}
#pragma warning disable CS0618 // MatchKind is obsolete
private void ReportMatchResult(Project project, INavigateToSearchResult result)
{
var matchedSpans = result.NameMatchSpans.SelectAsArray(t => t.ToSpan());
......@@ -163,7 +164,6 @@ private PatternMatchKind GetPatternMatchKind(NavigateToMatchKind matchKind)
default: throw ExceptionUtilities.UnexpectedValue(matchKind);
}
}
#pragma warning restore CS0618 // MatchKind is obsolete
/// <summary>
/// Returns the name for the language used by the old Navigate To providers.
......
......@@ -3,16 +3,14 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Language.NavigateTo.Interfaces;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.NavigateTo
{
internal partial class NavigateToItemProvider : INavigateToItemProvider
internal partial class NavigateToItemProvider : INavigateToItemProvider2
{
private readonly Workspace _workspace;
private readonly IAsynchronousOperationListener _asyncListener;
......@@ -32,6 +30,22 @@ internal partial class NavigateToItemProvider : INavigateToItemProvider
_displayFactory = new NavigateToItemDisplayFactory();
}
public ISet<string> KindsProvided { get; } = ImmutableHashSet.Create(
NavigateToItemKind.Class,
NavigateToItemKind.Constant,
NavigateToItemKind.Delegate,
NavigateToItemKind.Enum,
NavigateToItemKind.EnumItem,
NavigateToItemKind.Event,
NavigateToItemKind.Field,
NavigateToItemKind.Interface,
NavigateToItemKind.Method,
NavigateToItemKind.Module,
NavigateToItemKind.Property,
NavigateToItemKind.Structure);
public bool CanFilter => true;
public void StopSearch()
{
_cancellationTokenSource.Cancel();
......@@ -46,25 +60,7 @@ public void Dispose()
public void StartSearch(INavigateToCallback callback, string searchValue)
{
this.StopSearch();
if (string.IsNullOrWhiteSpace(searchValue))
{
callback.Done();
return;
}
var searchCurrentDocument = GetSearchCurrentDocumentOption(callback);
var searcher = new Searcher(
_workspace.CurrentSolution,
_asyncListener,
_displayFactory,
callback,
searchValue,
searchCurrentDocument,
_cancellationTokenSource.Token);
searcher.Search();
StartSearch(callback, searchValue, KindsProvided);
}
private bool GetSearchCurrentDocumentOption(INavigateToCallback callback)
......@@ -88,5 +84,34 @@ private bool GetSearchCurrentDocumentOptionWorker(INavigateToCallback callback)
var options2 = callback.Options as INavigateToOptions2;
return options2?.SearchCurrentDocument ?? false;
}
public void StartSearch(INavigateToCallback callback, string searchValue, INavigateToFilterParameters filter)
{
StartSearch(callback, searchValue, filter.Kinds);
}
private void StartSearch(INavigateToCallback callback, string searchValue, ISet<string> kinds)
{
this.StopSearch();
if (string.IsNullOrWhiteSpace(searchValue))
{
callback.Done();
return;
}
var searchCurrentDocument = GetSearchCurrentDocumentOption(callback);
var searcher = new Searcher(
_workspace.CurrentSolution,
_asyncListener,
_displayFactory,
callback,
searchValue,
searchCurrentDocument,
kinds,
_cancellationTokenSource.Token);
searcher.Search();
}
}
}
// 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.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
......@@ -22,21 +22,21 @@ internal abstract partial class AbstractNavigateToSearchService
new ConditionalWeakTable<Project, Tuple<string, ImmutableArray<SearchResult>>>();
public static Task<ImmutableArray<INavigateToSearchResult>> SearchProjectInCurrentProcessAsync(
Project project, string searchPattern, CancellationToken cancellationToken)
Project project, string searchPattern, ISet<string> kinds, CancellationToken cancellationToken)
{
return FindSearchResultsAsync(
project, searchDocument: null, pattern: searchPattern, cancellationToken: cancellationToken);
project, searchDocument: null, pattern: searchPattern, kinds, cancellationToken: cancellationToken);
}
public static Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentInCurrentProcessAsync(
Document document, string searchPattern, CancellationToken cancellationToken)
Document document, string searchPattern, ISet<string> kinds, CancellationToken cancellationToken)
{
return FindSearchResultsAsync(
document.Project, document, searchPattern, cancellationToken);
document.Project, document, searchPattern, kinds, cancellationToken);
}
private static async Task<ImmutableArray<INavigateToSearchResult>> FindSearchResultsAsync(
Project project, Document searchDocument, string pattern, CancellationToken cancellationToken)
Project project, Document searchDocument, string pattern, ISet<string> kinds, CancellationToken cancellationToken)
{
// If the user created a dotted pattern then we'll grab the last part of the name
var (patternName, patternContainerOpt) = PatternMatcher.GetNameAndContainer(pattern);
......@@ -63,10 +63,10 @@ internal abstract partial class AbstractNavigateToSearchService
// scratch.
#if true
var task = searchDocument != null
? ComputeSearchResultsAsync(project, searchDocument, nameMatcher, containerMatcherOpt, nameMatches, containerMatches, cancellationToken)
: TryFilterPreviousSearchResultsAsync(project, searchDocument, pattern, nameMatcher, containerMatcherOpt, nameMatches, containerMatches, cancellationToken);
? ComputeSearchResultsAsync(project, searchDocument, nameMatcher, containerMatcherOpt, kinds, nameMatches, containerMatches, cancellationToken)
: TryFilterPreviousSearchResultsAsync(project, searchDocument, pattern, nameMatcher, containerMatcherOpt, kinds, nameMatches, containerMatches, cancellationToken);
#else
var task = ComputeSearchResultsAsync(project, searchDocument, nameMatcher, containerMatcherOpt, nameMatches, containerMatches, cancellationToken);
var task = ComputeSearchResultsAsync(project, searchDocument, nameMatcher, containerMatcherOpt, kinds, nameMatches, containerMatches, cancellationToken);
#endif
var searchResults = await task.ConfigureAwait(false);
......@@ -83,6 +83,7 @@ internal abstract partial class AbstractNavigateToSearchService
private static async Task<ImmutableArray<SearchResult>> TryFilterPreviousSearchResultsAsync(
Project project, Document searchDocument, string pattern,
PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt,
ISet<string> kinds,
ArrayBuilder<PatternMatch> nameMatches, ArrayBuilder<PatternMatch> containerMatches,
CancellationToken cancellationToken)
{
......@@ -99,6 +100,7 @@ internal abstract partial class AbstractNavigateToSearchService
searchResults = FilterPreviousResults(
previousResult.Item2,
nameMatcher, containerMatcherOpt,
kinds,
nameMatches, containerMatches, cancellationToken);
}
else
......@@ -108,6 +110,7 @@ internal abstract partial class AbstractNavigateToSearchService
searchResults = await ComputeSearchResultsAsync(
project, searchDocument,
nameMatcher, containerMatcherOpt,
kinds,
nameMatches, containerMatches, cancellationToken).ConfigureAwait(false);
}
......@@ -126,6 +129,7 @@ internal abstract partial class AbstractNavigateToSearchService
private static ImmutableArray<SearchResult> FilterPreviousResults(
ImmutableArray<SearchResult> previousResults,
PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt,
ISet<string> kinds,
ArrayBuilder<PatternMatch> nameMatches, ArrayBuilder<PatternMatch> containerMatches,
CancellationToken cancellationToken)
{
......@@ -137,7 +141,7 @@ internal abstract partial class AbstractNavigateToSearchService
var info = previousResult.DeclaredSymbolInfo;
AddResultIfMatch(
document, info, nameMatcher, containerMatcherOpt,
document, info, nameMatcher, containerMatcherOpt, kinds,
nameMatches, containerMatches, result, cancellationToken);
}
......@@ -147,6 +151,7 @@ internal abstract partial class AbstractNavigateToSearchService
private static async Task<ImmutableArray<SearchResult>> ComputeSearchResultsAsync(
Project project, Document searchDocument,
PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt,
ISet<string> kinds,
ArrayBuilder<PatternMatch> nameMatches, ArrayBuilder<PatternMatch> containerMatches,
CancellationToken cancellationToken)
{
......@@ -165,7 +170,8 @@ internal abstract partial class AbstractNavigateToSearchService
{
AddResultIfMatch(
document, declaredSymbolInfo,
nameMatcher, containerMatcherOpt,
nameMatcher, containerMatcherOpt,
kinds,
nameMatches, containerMatches,
result, cancellationToken);
}
......@@ -177,6 +183,7 @@ internal abstract partial class AbstractNavigateToSearchService
private static void AddResultIfMatch(
Document document, DeclaredSymbolInfo declaredSymbolInfo,
PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt,
ISet<string> kinds,
ArrayBuilder<PatternMatch> nameMatches, ArrayBuilder<PatternMatch> containerMatches,
ArrayBuilder<SearchResult> result, CancellationToken cancellationToken)
{
......@@ -184,7 +191,8 @@ internal abstract partial class AbstractNavigateToSearchService
containerMatches.Clear();
cancellationToken.ThrowIfCancellationRequested();
if (nameMatcher.AddMatches(declaredSymbolInfo.Name, nameMatches) &&
if (kinds.Contains(GetItemKind(declaredSymbolInfo)) &&
nameMatcher.AddMatches(declaredSymbolInfo.Name, nameMatches) &&
containerMatcherOpt?.AddMatches(declaredSymbolInfo.FullyQualifiedContainerName, containerMatches) != false)
{
result.Add(ConvertResult(
......
// 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.Experiments;
using Microsoft.CodeAnalysis.Remote;
using Roslyn.Utilities;
......@@ -15,25 +12,25 @@ namespace Microsoft.CodeAnalysis.NavigateTo
internal abstract partial class AbstractNavigateToSearchService
{
private async Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentInRemoteProcessAsync(
RemoteHostClient client, Document document, string searchPattern, CancellationToken cancellationToken)
RemoteHostClient client, Document document, string searchPattern, ISet<string> kinds, CancellationToken cancellationToken)
{
var solution = document.Project.Solution;
var serializableResults = await client.TryRunCodeAnalysisRemoteAsync<IList<SerializableNavigateToSearchResult>>(
solution, nameof(IRemoteNavigateToSearchService.SearchDocumentAsync),
new object[] { document.Id, searchPattern }, cancellationToken).ConfigureAwait(false);
new object[] { document.Id, searchPattern, kinds }, cancellationToken).ConfigureAwait(false);
return serializableResults.SelectAsArray(r => r.Rehydrate(solution));
}
private async Task<ImmutableArray<INavigateToSearchResult>> SearchProjectInRemoteProcessAsync(
RemoteHostClient client, Project project, string searchPattern, CancellationToken cancellationToken)
RemoteHostClient client, Project project, string searchPattern, ISet<string> kinds, CancellationToken cancellationToken)
{
var solution = project.Solution;
var serializableResults = await client.TryRunCodeAnalysisRemoteAsync<IList<SerializableNavigateToSearchResult>>(
solution, nameof(IRemoteNavigateToSearchService.SearchProjectAsync),
new object[] { project.Id, searchPattern }, cancellationToken).ConfigureAwait(false);
new object[] { project.Id, searchPattern, kinds }, cancellationToken).ConfigureAwait(false);
return serializableResults.SelectAsArray(r => r.Rehydrate(solution));
}
......
// 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.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
......@@ -9,34 +10,34 @@ namespace Microsoft.CodeAnalysis.NavigateTo
internal abstract partial class AbstractNavigateToSearchService : INavigateToSearchService
{
public async Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentAsync(
Document document, string searchPattern, CancellationToken cancellationToken)
Document document, string searchPattern, ISet<string> kinds, CancellationToken cancellationToken)
{
var client = await TryGetRemoteHostClientAsync(document.Project, cancellationToken).ConfigureAwait(false);
if (client == null)
{
return await SearchDocumentInCurrentProcessAsync(
document, searchPattern, cancellationToken).ConfigureAwait(false);
document, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
}
else
{
return await SearchDocumentInRemoteProcessAsync(
client, document, searchPattern, cancellationToken).ConfigureAwait(false);
client, document, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
}
}
public async Task<ImmutableArray<INavigateToSearchResult>> SearchProjectAsync(
Project project, string searchPattern, CancellationToken cancellationToken)
Project project, string searchPattern, ISet<string> kinds, CancellationToken cancellationToken)
{
var client = await TryGetRemoteHostClientAsync(project, cancellationToken).ConfigureAwait(false);
if (client == null)
{
return await SearchProjectInCurrentProcessAsync(
project, searchPattern, cancellationToken).ConfigureAwait(false);
project, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
}
else
{
return await SearchProjectInRemoteProcessAsync(
client, project, searchPattern, cancellationToken).ConfigureAwait(false);
client, project, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
}
}
}
......
// 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.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
......@@ -9,7 +10,7 @@ namespace Microsoft.CodeAnalysis.NavigateTo
{
internal interface INavigateToSearchService : ILanguageService
{
Task<ImmutableArray<INavigateToSearchResult>> SearchProjectAsync(Project project, string searchPattern, CancellationToken cancellationToken);
Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentAsync(Document document, string searchPattern, CancellationToken cancellationToken);
Task<ImmutableArray<INavigateToSearchResult>> SearchProjectAsync(Project project, string searchPattern, ISet<string> kinds, CancellationToken cancellationToken);
Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentAsync(Document document, string searchPattern, ISet<string> kinds, 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.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
......@@ -10,7 +9,7 @@ namespace Microsoft.CodeAnalysis.NavigateTo
{
internal interface IRemoteNavigateToSearchService
{
Task<IList<SerializableNavigateToSearchResult>> SearchDocumentAsync(DocumentId documentId, string searchPattern, CancellationToken cancellationToken);
Task<IList<SerializableNavigateToSearchResult>> SearchProjectAsync(ProjectId projectId, string searchPattern, CancellationToken cancellationToken);
Task<IList<SerializableNavigateToSearchResult>> SearchDocumentAsync(DocumentId documentId, string searchPattern, string[] kinds, CancellationToken cancellationToken);
Task<IList<SerializableNavigateToSearchResult>> SearchProjectAsync(ProjectId projectId, string searchPattern, string[] kinds, CancellationToken cancellationToken);
}
}
......@@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Remote
internal partial class CodeAnalysisService : IRemoteNavigateToSearchService
{
public Task<IList<SerializableNavigateToSearchResult>> SearchDocumentAsync(
DocumentId documentId, string searchPattern, CancellationToken cancellationToken)
DocumentId documentId, string searchPattern, string[] kinds, CancellationToken cancellationToken)
{
return RunServiceAsync(async token =>
{
......@@ -21,7 +21,7 @@ internal partial class CodeAnalysisService : IRemoteNavigateToSearchService
var project = solution.GetDocument(documentId);
var result = await AbstractNavigateToSearchService.SearchDocumentInCurrentProcessAsync(
project, searchPattern, token).ConfigureAwait(false);
project, searchPattern, kinds.ToImmutableHashSet(), token).ConfigureAwait(false);
return Convert(result);
}
......@@ -29,7 +29,7 @@ internal partial class CodeAnalysisService : IRemoteNavigateToSearchService
}
public Task<IList<SerializableNavigateToSearchResult>> SearchProjectAsync(
ProjectId projectId, string searchPattern, CancellationToken cancellationToken)
ProjectId projectId, string searchPattern, string[] kinds, CancellationToken cancellationToken)
{
return RunServiceAsync(async token =>
{
......@@ -39,7 +39,7 @@ internal partial class CodeAnalysisService : IRemoteNavigateToSearchService
var project = solution.GetProject(projectId);
var result = await AbstractNavigateToSearchService.SearchProjectInCurrentProcessAsync(
project, searchPattern, token).ConfigureAwait(false);
project, searchPattern, kinds.ToImmutableHashSet(), token).ConfigureAwait(false);
return Convert(result);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册