From 386a08414753dc1873d0c074772b3f57e3bd0671 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 4 Apr 2017 17:03:39 -0700 Subject: [PATCH 1/2] More work organizing code related to finding symbols. --- .../Core/Portable/FindSymbols/SearchKind.cs | 31 +++++++ .../Core/Portable/FindSymbols/SearchQuery.cs | 71 +++++++++++++++ .../FindSymbols/SymbolFinder_Declarations.cs | 89 ------------------- ... => SymbolFinder_FindLiteralReferences.cs} | 64 ------------- .../SymbolFinder_FindReferences_Current.cs | 84 +++++++++++++++++ ... => SymbolFinder_FindReferences_Legacy.cs} | 28 ++---- .../SymbolFinder_FindRenamableReferences.cs | 39 ++++++++ .../Core/Portable/Workspaces.csproj | 8 +- 8 files changed, 236 insertions(+), 178 deletions(-) create mode 100644 src/Workspaces/Core/Portable/FindSymbols/SearchKind.cs create mode 100644 src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs rename src/Workspaces/Core/Portable/FindSymbols/{SymbolFinder_Remote.cs => SymbolFinder_FindLiteralReferences.cs} (55%) create mode 100644 src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs rename src/Workspaces/Core/Portable/FindSymbols/{SymbolFinder_References.cs => SymbolFinder_FindReferences_Legacy.cs} (79%) create mode 100644 src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindRenamableReferences.cs diff --git a/src/Workspaces/Core/Portable/FindSymbols/SearchKind.cs b/src/Workspaces/Core/Portable/FindSymbols/SearchKind.cs new file mode 100644 index 0000000000000..e198dee6a2623 --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/SearchKind.cs @@ -0,0 +1,31 @@ +// 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 Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.FindSymbols +{ + internal enum SearchKind + { + /// + /// Use an case-sensitive comparison when searching for matching items. + /// + Exact, + + /// + /// Use a case-insensitive comparison when searching for matching items. + /// + ExactIgnoreCase, + + /// + /// Use a fuzzy comparison when searching for matching items. Fuzzy matching allows for + /// a certain amount of misspellings, missing words, etc. See for + /// more details. + /// + Fuzzy, + + /// + /// Search term is matched in a custom manner (i.e. with a user provided predicate). + /// + Custom + } +} \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs b/src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs new file mode 100644 index 0000000000000..0941f1abd8cb4 --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs @@ -0,0 +1,71 @@ +// 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 Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.FindSymbols +{ + internal class SearchQuery + { + /// The name being searched for. Is null in the case of custom predicate searching.. But + /// can be used for faster index based searching when it is available. + public readonly string Name; + + ///The kind of search this is. Faster index-based searching can be used if the + /// SearchKind is not . + public readonly SearchKind Kind; + + ///The predicate to fall back on if faster index searching is not possible. + private readonly Func _predicate; + + private SearchQuery(string name, SearchKind kind) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + Kind = kind; + + switch (kind) + { + case SearchKind.Exact: + _predicate = s => StringComparer.Ordinal.Equals(name, s); + break; + case SearchKind.ExactIgnoreCase: + _predicate = s => CaseInsensitiveComparison.Comparer.Equals(name, s); + break; + case SearchKind.Fuzzy: + // Create a single WordSimilarityChecker and capture a delegate reference to + // its 'AreSimilar' method. That way we only create the WordSimilarityChecker + // once and it can cache all the information it needs while it does the AreSimilar + // check against all the possible candidates. + var editDistance = new WordSimilarityChecker(name, substringsAreSimilar: false); + _predicate = editDistance.AreSimilar; + break; + } + } + + private SearchQuery(Func predicate) + { + Kind = SearchKind.Custom; + _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); + } + + public static SearchQuery Create(string name, bool ignoreCase) + { + return new SearchQuery(name, ignoreCase ? SearchKind.ExactIgnoreCase : SearchKind.Exact); + } + + public static SearchQuery CreateFuzzy(string name) + { + return new SearchQuery(name, SearchKind.Fuzzy); + } + + public static SearchQuery CreateCustom(Func predicate) + { + return new SearchQuery(predicate); + } + + public Func GetPredicate() + { + return _predicate; + } + } +} \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs index f11165bc5035a..9d5de2ab54c15 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs @@ -14,95 +14,6 @@ namespace Microsoft.CodeAnalysis.FindSymbols { - internal enum SearchKind - { - /// - /// Use an case-sensitive comparison when searching for matching items. - /// - Exact, - - /// - /// Use a case-insensitive comparison when searching for matching items. - /// - ExactIgnoreCase, - - /// - /// Use a fuzzy comparison when searching for matching items. Fuzzy matching allows for - /// a certain amount of misspellings, missing words, etc. See for - /// more details. - /// - Fuzzy, - - /// - /// Search term is matched in a custom manner (i.e. with a user provided predicate). - /// - Custom - } - - internal class SearchQuery - { - /// The name being searched for. Is null in the case of custom predicate searching.. But - /// can be used for faster index based searching when it is available. - public readonly string Name; - - ///The kind of search this is. Faster index-based searching can be used if the - /// SearchKind is not . - public readonly SearchKind Kind; - - ///The predicate to fall back on if faster index searching is not possible. - private readonly Func _predicate; - - private SearchQuery(string name, SearchKind kind) - { - Name = name ?? throw new ArgumentNullException(nameof(name)); - Kind = kind; - - switch (kind) - { - case SearchKind.Exact: - _predicate = s => StringComparer.Ordinal.Equals(name, s); - break; - case SearchKind.ExactIgnoreCase: - _predicate = s => CaseInsensitiveComparison.Comparer.Equals(name, s); - break; - case SearchKind.Fuzzy: - // Create a single WordSimilarityChecker and capture a delegate reference to - // its 'AreSimilar' method. That way we only create the WordSimilarityChecker - // once and it can cache all the information it needs while it does the AreSimilar - // check against all the possible candidates. - var editDistance = new WordSimilarityChecker(name, substringsAreSimilar: false); - _predicate = editDistance.AreSimilar; - break; - } - } - - private SearchQuery(Func predicate) - { - Kind = SearchKind.Custom; - _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); - } - - public static SearchQuery Create(string name, bool ignoreCase) - { - return new SearchQuery(name, ignoreCase ? SearchKind.ExactIgnoreCase : SearchKind.Exact); - } - - public static SearchQuery CreateFuzzy(string name) - { - return new SearchQuery(name, SearchKind.Fuzzy); - } - - public static SearchQuery CreateCustom(Func predicate) - { - return new SearchQuery(predicate); - } - - public Func GetPredicate() - { - return _predicate; - } - } - public static partial class SymbolFinder { /// diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Remote.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs similarity index 55% rename from src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Remote.cs rename to src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs index 3af943376df79..ce3592f5134d5 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Remote.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs @@ -12,31 +12,6 @@ namespace Microsoft.CodeAnalysis.FindSymbols { public static partial class SymbolFinder { - internal static async Task FindReferencesAsync( - SymbolAndProjectId symbolAndProjectId, - Solution solution, - IStreamingFindReferencesProgress progress, - IImmutableSet documents, - CancellationToken cancellationToken) - { - using (Logger.LogBlock(FunctionId.FindReference, cancellationToken)) - { - var outOfProcessAllowed = solution.Workspace.Options.GetOption(SymbolFinderOptions.OutOfProcessAllowed); - if (symbolAndProjectId.ProjectId == null || !outOfProcessAllowed) - { - // This is a call through our old public API. We don't have the necessary - // data to effectively run the call out of proc. - await FindReferencesInCurrentProcessAsync( - symbolAndProjectId, solution, progress, documents, cancellationToken).ConfigureAwait(false); - } - else - { - await FindReferencesInServiceProcessAsync( - symbolAndProjectId, solution, progress, documents, cancellationToken).ConfigureAwait(false); - } - } - } - internal static async Task FindLiteralReferencesAsync( object value, Solution solution, @@ -61,45 +36,6 @@ await FindLiteralReferencesInServiceProcessOrFallBackToLocalProcessAsync( } } - internal static Task FindReferencesInCurrentProcessAsync( - SymbolAndProjectId symbolAndProjectId, Solution solution, - IStreamingFindReferencesProgress progress, IImmutableSet documents, - CancellationToken cancellationToken) - { - var finders = ReferenceFinders.DefaultReferenceFinders; - progress = progress ?? StreamingFindReferencesProgress.Instance; - var engine = new FindReferencesSearchEngine( - solution, documents, finders, progress, cancellationToken); - return engine.FindReferencesAsync(symbolAndProjectId); - } - - private static async Task FindReferencesInServiceProcessAsync( - SymbolAndProjectId symbolAndProjectId, - Solution solution, - IStreamingFindReferencesProgress progress, - IImmutableSet documents, - CancellationToken cancellationToken) - { - var client = await solution.Workspace.TryGetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); - if (client == null) - { - await FindReferencesInCurrentProcessAsync( - symbolAndProjectId, solution, progress, documents, cancellationToken).ConfigureAwait(false); - return; - } - - // Create a callback that we can pass to the server process to hear about the - // results as it finds them. When we hear about results we'll forward them to - // the 'progress' parameter which will then update the UI. - var serverCallback = new FindReferencesServerCallback(solution, progress, cancellationToken); - - await client.RunCodeAnalysisServiceOnRemoteHostAsync( - solution, serverCallback, - nameof(IRemoteSymbolFinder.FindReferencesAsync), - new object[] { SerializableSymbolAndProjectId.Dehydrate(symbolAndProjectId), documents?.Select(d => d.Id).ToArray() }, - cancellationToken).ConfigureAwait(false); - } - internal static Task FindLiteralReferencesInCurrentProcessAsync( object value, Solution solution, IStreamingFindLiteralReferencesProgress progress, diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs new file mode 100644 index 0000000000000..798ed271ad359 --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs @@ -0,0 +1,84 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindSymbols.Finders; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Remote; + +namespace Microsoft.CodeAnalysis.FindSymbols +{ + // This file contains the current FindReferences APIs. The current APIs allow for OOP + // implementation and will defer to the oop server if it is available. If not, it will + // compute the results in process. + + public static partial class SymbolFinder + { + internal static async Task FindReferencesAsync( + SymbolAndProjectId symbolAndProjectId, + Solution solution, + IStreamingFindReferencesProgress progress, + IImmutableSet documents, + CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.FindReference, cancellationToken)) + { + var outOfProcessAllowed = solution.Workspace.Options.GetOption(SymbolFinderOptions.OutOfProcessAllowed); + if (symbolAndProjectId.ProjectId == null || !outOfProcessAllowed) + { + // This is a call through our old public API. We don't have the necessary + // data to effectively run the call out of proc. + await FindReferencesInCurrentProcessAsync( + symbolAndProjectId, solution, progress, documents, cancellationToken).ConfigureAwait(false); + } + else + { + await FindReferencesInServiceProcessAsync( + symbolAndProjectId, solution, progress, documents, cancellationToken).ConfigureAwait(false); + } + } + } + + internal static Task FindReferencesInCurrentProcessAsync( + SymbolAndProjectId symbolAndProjectId, Solution solution, + IStreamingFindReferencesProgress progress, IImmutableSet documents, + CancellationToken cancellationToken) + { + var finders = ReferenceFinders.DefaultReferenceFinders; + progress = progress ?? StreamingFindReferencesProgress.Instance; + var engine = new FindReferencesSearchEngine( + solution, documents, finders, progress, cancellationToken); + return engine.FindReferencesAsync(symbolAndProjectId); + } + + private static async Task FindReferencesInServiceProcessAsync( + SymbolAndProjectId symbolAndProjectId, + Solution solution, + IStreamingFindReferencesProgress progress, + IImmutableSet documents, + CancellationToken cancellationToken) + { + var client = await solution.Workspace.TryGetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); + if (client == null) + { + await FindReferencesInCurrentProcessAsync( + symbolAndProjectId, solution, progress, documents, cancellationToken).ConfigureAwait(false); + return; + } + + // Create a callback that we can pass to the server process to hear about the + // results as it finds them. When we hear about results we'll forward them to + // the 'progress' parameter which will then update the UI. + var serverCallback = new FindReferencesServerCallback(solution, progress, cancellationToken); + + await client.RunCodeAnalysisServiceOnRemoteHostAsync( + solution, serverCallback, + nameof(IRemoteSymbolFinder.FindReferencesAsync), + new object[] { SerializableSymbolAndProjectId.Dehydrate(symbolAndProjectId), documents?.Select(d => d.Id).ToArray() }, + cancellationToken).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_References.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Legacy.cs similarity index 79% rename from src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_References.cs rename to src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Legacy.cs index 603e351483f1f..32d1fb9c7cbec 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_References.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Legacy.cs @@ -11,6 +11,11 @@ namespace Microsoft.CodeAnalysis.FindSymbols { + // This file contains the legacy FindReferences APIs. The APIs are legacy because they + // do not contain enough information for us to effectively remote them over to the OOP + // process to do the work. Specifically, they lack the "current project context" necessary + // to be able to effectively serialize symbols to/from the remote process. + public static partial class SymbolFinder { /// @@ -72,28 +77,5 @@ await FindReferencesAsync( solution, streamingProgress, documents, cancellationToken).ConfigureAwait(false); return streamingProgress.GetReferencedSymbols(); } - - internal static async Task> FindRenamableReferencesAsync( - SymbolAndProjectId symbolAndProjectId, - Solution solution, - CancellationToken cancellationToken) - { - using (Logger.LogBlock(FunctionId.FindReference_Rename, cancellationToken)) - { - var streamingProgress = new StreamingProgressCollector( - StreamingFindReferencesProgress.Instance); - - IImmutableSet documents = null; - var engine = new FindReferencesSearchEngine( - solution, - documents, - ReferenceFinders.DefaultRenameReferenceFinders, - streamingProgress, - cancellationToken); - - await engine.FindReferencesAsync(symbolAndProjectId).ConfigureAwait(false); - return streamingProgress.GetReferencedSymbols(); - } - } } } \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindRenamableReferences.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindRenamableReferences.cs new file mode 100644 index 0000000000000..3f575a056332e --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindRenamableReferences.cs @@ -0,0 +1,39 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindSymbols.Finders; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Remote; + +namespace Microsoft.CodeAnalysis.FindSymbols +{ + public static partial class SymbolFinder + { + internal static async Task> FindRenamableReferencesAsync( + SymbolAndProjectId symbolAndProjectId, + Solution solution, + CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.FindReference_Rename, cancellationToken)) + { + var streamingProgress = new StreamingProgressCollector( + StreamingFindReferencesProgress.Instance); + + IImmutableSet documents = null; + var engine = new FindReferencesSearchEngine( + solution, + documents, + ReferenceFinders.DefaultRenameReferenceFinders, + streamingProgress, + cancellationToken); + + await engine.FindReferencesAsync(symbolAndProjectId).ConfigureAwait(false); + return streamingProgress.GetReferencedSymbols(); + } + } + } +} \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj index 3033263ea6acb..dc39b70a321cb 100644 --- a/src/Workspaces/Core/Portable/Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Workspaces.csproj @@ -368,7 +368,11 @@ + + + + @@ -441,7 +445,7 @@ - + @@ -683,7 +687,7 @@ - + From 77f7f07c25483a47f3a86506a3ca32fa7eb7dcea Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 4 Apr 2017 17:13:23 -0700 Subject: [PATCH 2/2] Make methods private. --- .../Core/Portable/FindSymbols/SymbolFinder_Declarations.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs index 9d5de2ab54c15..c8957e4867977 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs @@ -343,7 +343,7 @@ public static async Task> FindSourceDeclarationsAsync( solution, SearchQuery.CreateCustom(predicate), filter, cancellationToken).ConfigureAwait(false); } - internal static async Task> FindSourceDeclarationsAsync( + private static async Task> FindSourceDeclarationsAsync( Solution solution, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken) { if (solution == null) @@ -388,7 +388,7 @@ public static async Task> FindSourceDeclarationsAsync( project, SearchQuery.CreateCustom(predicate), filter, cancellationToken).ConfigureAwait(false); } - internal static async Task> FindSourceDeclarationsAsync( + private static async Task> FindSourceDeclarationsAsync( Project project, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken) { if (project == null)