提交 de1b70df 编写于 作者: C CyrusNajmabadi

Release resources after a query is executed.

上级 1c77d9c0
......@@ -42,33 +42,35 @@ protected SearchScope(AbstractAddImportCodeFixProvider<TSimpleNameSyntax> provid
return ImmutableArray<SymbolResult<ISymbol>>.Empty;
}
var query = this.Exact ? SearchQuery.Create(name, ignoreCase: true) : SearchQuery.CreateFuzzy(name);
var symbols = await FindDeclarationsAsync(name, filter, query).ConfigureAwait(false);
if (Exact)
using (var query = this.Exact ? SearchQuery.Create(name, ignoreCase: true) : SearchQuery.CreateFuzzy(name))
{
// We did an exact, case insensitive, search. Case sensitive matches should
// be preferred though over insensitive ones.
return symbols.SelectAsArray(s =>
SymbolResult.Create(s.Name, nameNode, s, weight: s.Name == name ? 0 : 1));
}
var symbols = await FindDeclarationsAsync(name, filter, query).ConfigureAwait(false);
// TODO(cyrusn): It's a shame we have to compute this twice. However, there's no
// great way to store the original value we compute because it happens deep in the
// compiler bowels when we call FindDeclarations.
var similarityChecker = WordSimilarityChecker.Allocate(name, substringsAreSimilar: false);
if (Exact)
{
// We did an exact, case insensitive, search. Case sensitive matches should
// be preferred though over insensitive ones.
return symbols.SelectAsArray(s =>
SymbolResult.Create(s.Name, nameNode, s, weight: s.Name == name ? 0 : 1));
}
var result = symbols.SelectAsArray(s =>
{
var areSimilar = similarityChecker.AreSimilar(s.Name, out var matchCost);
// TODO(cyrusn): It's a shame we have to compute this twice. However, there's no
// great way to store the original value we compute because it happens deep in the
// compiler bowels when we call FindDeclarations.
var similarityChecker = WordSimilarityChecker.Allocate(name, substringsAreSimilar: false);
Debug.Assert(areSimilar);
return SymbolResult.Create(s.Name, nameNode, s, matchCost);
});
var result = symbols.SelectAsArray(s =>
{
var areSimilar = similarityChecker.AreSimilar(s.Name, out var matchCost);
similarityChecker.Free();
Debug.Assert(areSimilar);
return SymbolResult.Create(s.Name, nameNode, s, matchCost);
});
return result;
similarityChecker.Free();
return result;
}
}
}
}
......
......@@ -183,26 +183,31 @@ internal static partial class DeclarationFinder
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
Solution solution, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
var query = SearchQuery.Create(name, ignoreCase);
var result = ArrayBuilder<SymbolAndProjectId>.GetInstance();
foreach (var projectId in solution.ProjectIds)
using (var query = SearchQuery.Create(name, ignoreCase))
{
var project = solution.GetProject(projectId);
await AddCompilationDeclarationsWithNormalQueryAsync(
project, query, criteria, result, cancellationToken).ConfigureAwait(false);
}
var result = ArrayBuilder<SymbolAndProjectId>.GetInstance();
foreach (var projectId in solution.ProjectIds)
{
var project = solution.GetProject(projectId);
await AddCompilationDeclarationsWithNormalQueryAsync(
project, query, criteria, result, cancellationToken).ConfigureAwait(false);
}
return result.ToImmutableAndFree();
return result.ToImmutableAndFree();
}
}
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken)
{
var list = ArrayBuilder<SymbolAndProjectId>.GetInstance();
await AddCompilationDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name, ignoreCase),
filter, list, cancellationToken).ConfigureAwait(false);
return list.ToImmutableAndFree();
using (var query = SearchQuery.Create(name, ignoreCase))
{
await AddCompilationDeclarationsWithNormalQueryAsync(
project, query, filter, list, cancellationToken).ConfigureAwait(false);
return list.ToImmutableAndFree();
}
}
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithPatternInCurrentProcessAsync(
......@@ -215,36 +220,38 @@ internal static partial class DeclarationFinder
// we only want to check the 'WL' portion. Then, after we get all the candidate symbols
// we'll check if the full name matches the full pattern.
var patternMatcher = new PatternMatcher(pattern);
var query = SearchQuery.CreateCustom(
k => !patternMatcher.GetMatchesForLastSegmentOfPattern(k).IsDefaultOrEmpty);
var symbolAndProjectIds = await SymbolFinder.FindSourceDeclarationsWithCustomQueryAsync(
project, query, criteria, cancellationToken).ConfigureAwait(false);
var result = ArrayBuilder<SymbolAndProjectId>.GetInstance();
// Now see if the symbols the compiler returned actually match the full pattern.
foreach (var symbolAndProjectId in symbolAndProjectIds)
using (var query = SearchQuery.CreateCustom(
k => !patternMatcher.GetMatchesForLastSegmentOfPattern(k).IsDefaultOrEmpty))
{
var symbol = symbolAndProjectId.Symbol;
// As an optimization, don't bother getting the container for this symbol if this
// isn't a dotted pattern. Getting the container could cause lots of string
// allocations that we don't if we're never going to check it.
var matches = !patternMatcher.IsDottedPattern
? new PatternMatches(patternMatcher.GetMatches(GetSearchName(symbol)))
: patternMatcher.GetMatches(GetSearchName(symbol), GetContainer(symbol));
var symbolAndProjectIds = await SymbolFinder.FindSourceDeclarationsWithCustomQueryAsync(
project, query, criteria, cancellationToken).ConfigureAwait(false);
var result = ArrayBuilder<SymbolAndProjectId>.GetInstance();
if (matches.IsEmpty)
// Now see if the symbols the compiler returned actually match the full pattern.
foreach (var symbolAndProjectId in symbolAndProjectIds)
{
// Didn't actually match the full pattern, ignore it.
continue;
var symbol = symbolAndProjectId.Symbol;
// As an optimization, don't bother getting the container for this symbol if this
// isn't a dotted pattern. Getting the container could cause lots of string
// allocations that we don't if we're never going to check it.
var matches = !patternMatcher.IsDottedPattern
? new PatternMatches(patternMatcher.GetMatches(GetSearchName(symbol)))
: patternMatcher.GetMatches(GetSearchName(symbol), GetContainer(symbol));
if (matches.IsEmpty)
{
// Didn't actually match the full pattern, ignore it.
continue;
}
result.Add(symbolAndProjectId);
}
result.Add(symbolAndProjectId);
return result.ToImmutableAndFree();
}
return result.ToImmutableAndFree();
}
private static string GetSearchName(ISymbol symbol)
......
......@@ -5,7 +5,7 @@
namespace Microsoft.CodeAnalysis.FindSymbols
{
internal class SearchQuery
internal class SearchQuery : IDisposable
{
/// <summary>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.</summary>
......@@ -18,6 +18,8 @@ internal class SearchQuery
///<summary>The predicate to fall back on if faster index searching is not possible.</summary>
private readonly Func<string, bool> _predicate;
private readonly WordSimilarityChecker _wordSimilarityChecker;
private SearchQuery(string name, SearchKind kind)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
......@@ -36,8 +38,8 @@ private SearchQuery(string name, SearchKind kind)
// 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 = WordSimilarityChecker.Allocate(name, substringsAreSimilar: false);
_predicate = editDistance.AreSimilar;
_wordSimilarityChecker = WordSimilarityChecker.Allocate(name, substringsAreSimilar: false);
_predicate = _wordSimilarityChecker.AreSimilar;
break;
default:
throw ExceptionUtilities.UnexpectedValue(kind);
......@@ -50,6 +52,11 @@ private SearchQuery(Func<string, bool> predicate)
_predicate = predicate ?? throw new ArgumentNullException(nameof(predicate));
}
public void Dispose()
{
_wordSimilarityChecker?.Free();
}
public static SearchQuery Create(string name, SearchKind kind)
=> new SearchQuery(name, kind);
......
......@@ -14,9 +14,12 @@ public static partial class SymbolFinder
public static async Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, CancellationToken cancellationToken = default(CancellationToken))
{
var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name, ignoreCase), SymbolFilter.All, cancellationToken).ConfigureAwait(false);
return declarations.SelectAsArray(t => t.Symbol);
using (var query = SearchQuery.Create(name, ignoreCase))
{
var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
project, query, SymbolFilter.All, cancellationToken).ConfigureAwait(false);
return declarations.SelectAsArray(t => t.Symbol);
}
}
/// <summary>
......@@ -25,9 +28,12 @@ public static partial class SymbolFinder
public static async Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name, ignoreCase), filter, cancellationToken).ConfigureAwait(false);
return declarations.SelectAsArray(t => t.Symbol);
using (var query = SearchQuery.Create(name, ignoreCase))
{
var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
project, query, filter, cancellationToken).ConfigureAwait(false);
return declarations.SelectAsArray(t => t.Symbol);
}
}
}
}
\ No newline at end of file
......@@ -30,10 +30,13 @@ public static Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Solution so
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Solution solution, Func<string, bool> predicate, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
solution, SearchQuery.CreateCustom(predicate), filter, cancellationToken).ConfigureAwait(false);
using (var query = SearchQuery.CreateCustom(predicate))
{
var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
solution, query, filter, cancellationToken).ConfigureAwait(false);
return declarations.SelectAsArray(d => d.Symbol);
return declarations.SelectAsArray(d => d.Symbol);
}
}
private static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithCustomQueryAsync(
......@@ -74,10 +77,13 @@ public static Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Project pro
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Project project, Func<string, bool> predicate, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
project, SearchQuery.CreateCustom(predicate), filter, cancellationToken).ConfigureAwait(false);
using (var query = SearchQuery.CreateCustom(predicate))
{
var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
project, query, filter, cancellationToken).ConfigureAwait(false);
return declarations.SelectAsArray(d => d.Symbol);
return declarations.SelectAsArray(d => d.Symbol);
}
}
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithCustomQueryAsync(
......
......@@ -50,10 +50,13 @@ public async Task FindLiteralReferencesAsync(object value)
var solution = await GetSolutionAsync().ConfigureAwait(false);
var project = solution.GetProject(projectId);
var result = await DeclarationFinder.FindAllDeclarationsWithNormalQueryInCurrentProcessAsync(
project, SearchQuery.Create(name, searchKind), criteria, this.CancellationToken).ConfigureAwait(false);
using (var query = SearchQuery.Create(name, searchKind))
{
var result = await DeclarationFinder.FindAllDeclarationsWithNormalQueryInCurrentProcessAsync(
project, query, criteria, this.CancellationToken).ConfigureAwait(false);
return result.Select(SerializableSymbolAndProjectId.Dehydrate).ToArray();
return result.Select(SerializableSymbolAndProjectId.Dehydrate).ToArray();
}
}
public async Task<SerializableSymbolAndProjectId[]> FindSolutionSourceDeclarationsWithNormalQueryAsync(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册