Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move part of the SymbolFinder out of proc. #18562

Merged
merged 7 commits into from
Apr 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,18 @@ private async Task<ImmutableArray<SymbolResult>> GetMatchingTypesAsync(
var syntaxFacts = project.LanguageServices.GetService<ISyntaxFactsService>();
syntaxFacts.GetNameAndArityOfSimpleName(node, out var name, out var arity);

var symbolAndProjectIds = await DeclarationFinder.FindAllDeclarationsAsync(
project, name, this.IgnoreCase, SymbolFilter.Type, cancellationToken).ConfigureAwait(false);
var symbolAndProjectIds = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name, this.IgnoreCase),
SymbolFilter.Type, cancellationToken).ConfigureAwait(false);
var symbols = symbolAndProjectIds.SelectAsArray(t => t.Symbol);

// also lookup type symbols with the "Attribute" suffix.
var inAttributeContext = syntaxFacts.IsAttributeName(node);
if (inAttributeContext)
{
var attributeSymbolAndProjectIds = await DeclarationFinder.FindAllDeclarationsAsync(
project, name + "Attribute", this.IgnoreCase, SymbolFilter.Type, cancellationToken).ConfigureAwait(false);
var attributeSymbolAndProjectIds = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name + "Attribute", this.IgnoreCase),
SymbolFilter.Type, cancellationToken).ConfigureAwait(false);
symbols = symbols.Concat(attributeSymbolAndProjectIds.SelectAsArray(t => t.Symbol));
}

Expand Down Expand Up @@ -189,8 +191,9 @@ private async Task<ImmutableArray<SymbolResult>> GetMatchingNamespacesAsync(
return ImmutableArray<SymbolResult>.Empty;
}

var symbolAndProjectIds = await DeclarationFinder.FindAllDeclarationsAsync(
project, name, this.IgnoreCase, SymbolFilter.Namespace, cancellationToken).ConfigureAwait(false);
var symbolAndProjectIds = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name, this.IgnoreCase),
SymbolFilter.Namespace, cancellationToken).ConfigureAwait(false);

var symbols = symbolAndProjectIds.SelectAsArray(t => t.Symbol);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent
Dim syntaxFactService = document.Project.Solution.Workspace.Services.GetLanguageServices(targetType.Language).GetService(Of ISyntaxFactsService)

Dim eventHandlerName As String = actualEventName + "Handler"
Dim existingSymbolAndProjectIds = Await DeclarationFinder.FindSourceDeclarationsWithNormalQueryInLocalProcessAsync(
Dim existingSymbolAndProjectIds = Await DeclarationFinder.FindSourceDeclarationsWithNormalQueryAsync(
document.Project.Solution, eventHandlerName, Not syntaxFactService.IsCaseSensitive, SymbolFilter.Type, cancellationToken).ConfigureAwait(False)

Dim existingSymbols = existingSymbolAndProjectIds.SelectAsArray(Function(t) t.Symbol)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.FindSymbols
{
Expand All @@ -16,7 +17,7 @@ private static Task AddCompilationDeclarationsWithNormalQueryAsync(
Project project, SearchQuery query, SymbolFilter filter,
ArrayBuilder<SymbolAndProjectId> list, CancellationToken cancellationToken)
{
Debug.Assert(query.Kind != SearchKind.Custom);
Contract.ThrowIfTrue(query.Kind == SearchKind.Custom, "Custom queries are not supported in this API");
return AddCompilationDeclarationsWithNormalQueryAsync(
project, query, filter, list,
startingCompilation: null,
Expand All @@ -33,7 +34,7 @@ private static async Task AddCompilationDeclarationsWithNormalQueryAsync(
IAssemblySymbol startingAssembly,
CancellationToken cancellationToken)
{
Debug.Assert(query.Kind != SearchKind.Custom);
Contract.ThrowIfTrue(query.Kind == SearchKind.Custom, "Custom queries are not supported in this API");

using (Logger.LogBlock(FunctionId.SymbolFinder_Project_AddDeclarationsAsync, cancellationToken))
{
Expand Down Expand Up @@ -67,7 +68,7 @@ private static async Task AddMetadataDeclarationsWithNormalQueryAsync(
{
// All entrypoints to this function are Find functions that are only searching
// for specific strings (i.e. they never do a custom search).
Debug.Assert(query.Kind != SearchKind.Custom);
Contract.ThrowIfTrue(query.Kind == SearchKind.Custom, "Custom queries are not supported in this API");

using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// 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.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;

Expand All @@ -17,63 +16,38 @@ namespace Microsoft.CodeAnalysis.FindSymbols

internal static partial class DeclarationFinder
{
/// <summary>
/// Find the declared symbols from either source, referenced projects or metadata assemblies with the specified name.
/// </summary>
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindAllDeclarationsAsync(
Project project, string name, bool ignoreCase, CancellationToken cancellationToken)
public static async Task<ImmutableArray<SymbolAndProjectId>> FindAllDeclarationsWithNormalQueryAsync(
Project project, SearchQuery query, SymbolFilter criteria, CancellationToken cancellationToken)
{
if (name == null)
// All entrypoints to this function are Find functions that are only searching
// for specific strings (i.e. they never do a custom search).
Contract.ThrowIfTrue(query.Kind == SearchKind.Custom, "Custom queries are not supported in this API");

if (project == null)
{
throw new ArgumentNullException(nameof(name));
throw new ArgumentNullException(nameof(project));
}

if (string.IsNullOrWhiteSpace(name))
if (query.Name != null && string.IsNullOrWhiteSpace(query.Name))
{
return ImmutableArray<SymbolAndProjectId>.Empty;
}

return await FindAllDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name, ignoreCase), SymbolFilter.All, cancellationToken: cancellationToken).ConfigureAwait(false);
}
var (succeeded, results) = await TryFindAllDeclarationsWithNormalQueryInRemoteProcessAsync(
project, query, criteria, cancellationToken).ConfigureAwait(false);

/// <summary>
/// Find the declared symbols from either source, referenced projects or metadata assemblies with the specified name.
/// </summary>
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindAllDeclarationsAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
if (name == null)
if (succeeded)
{
throw new ArgumentNullException(nameof(name));
return results;
}

if (string.IsNullOrWhiteSpace(name))
{
return ImmutableArray<SymbolAndProjectId>.Empty;
}

return await FindAllDeclarationsWithNormalQueryAsync(
project, SearchQuery.Create(name, ignoreCase), filter, cancellationToken: cancellationToken).ConfigureAwait(false);
return await FindAllDeclarationsWithNormalQueryInCurrentProcessAsync(
project, query, criteria, cancellationToken).ConfigureAwait(false);
}

internal static async Task<ImmutableArray<SymbolAndProjectId>> FindAllDeclarationsWithNormalQueryAsync(
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindAllDeclarationsWithNormalQueryInCurrentProcessAsync(
Project project, SearchQuery query, SymbolFilter criteria, CancellationToken cancellationToken)
{
// All entrypoints to this function are Find functions that are only searching
// for specific strings (i.e. they never do a custom search).
Debug.Assert(query.Kind != SearchKind.Custom);

if (project == null)
{
throw new ArgumentNullException(nameof(project));
}

if (query.Name != null && string.IsNullOrWhiteSpace(query.Name))
{
return ImmutableArray<SymbolAndProjectId>.Empty;
}

var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

var list = ArrayBuilder<SymbolAndProjectId>.GetInstance();
Expand Down Expand Up @@ -115,5 +89,40 @@ await AddMetadataDeclarationsWithNormalQueryAsync(

return list.ToImmutableAndFree();
}

private static async Task<(bool, ImmutableArray<SymbolAndProjectId>)> TryFindAllDeclarationsWithNormalQueryInRemoteProcessAsync(
Project project, SearchQuery query, SymbolFilter criteria, CancellationToken cancellationToken)
{
var session = await SymbolFinder.TryGetRemoteSessionAsync(
project.Solution, cancellationToken).ConfigureAwait(false);
if (session != null)
{
var result = await session.InvokeAsync<SerializableSymbolAndProjectId[]>(
nameof(IRemoteSymbolFinder.FindAllDeclarationsWithNormalQueryAsync),
project.Id, query.Name, query.Kind, criteria).ConfigureAwait(false);

var rehydrated = await RehydrateAsync(
project.Solution, result, cancellationToken).ConfigureAwait(false);

return (true, rehydrated);
}

return (false, ImmutableArray<SymbolAndProjectId>.Empty);
}

private static async Task<ImmutableArray<SymbolAndProjectId>> RehydrateAsync(
Solution solution, SerializableSymbolAndProjectId[] array, CancellationToken cancellationToken)
{
var result = ArrayBuilder<SymbolAndProjectId>.GetInstance();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to pre-allocate the size, given array.Length?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.


foreach (var dehydrated in array)
{
cancellationToken.ThrowIfCancellationRequested();
var rehydrated = await dehydrated.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
result.Add(rehydrated);
}

return result.ToImmutableAndFree();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Remote;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.FindSymbols
Expand All @@ -16,8 +17,13 @@ namespace Microsoft.CodeAnalysis.FindSymbols

internal static partial class DeclarationFinder
{
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithNormalQueryInLocalProcessAsync(
Solution solution, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken)
#region Dispatch Members

// These are the public entrypoints to finding source declarations. They will attempt to
// remove the query to the OOP process, and will fallback to local processing if they can't.

public static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithNormalQueryAsync(
Solution solution, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
if (solution == null)
{
Expand All @@ -34,20 +40,20 @@ internal static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclara
return ImmutableArray<SymbolAndProjectId>.Empty;
}

var query = SearchQuery.Create(name, ignoreCase);
var result = ArrayBuilder<SymbolAndProjectId>.GetInstance();
foreach (var projectId in solution.ProjectIds)
var (succeded, results) = await TryFindSourceDeclarationsWithNormalQueryInRemoteProcessAsync(
solution, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false);

if (succeded)
{
var project = solution.GetProject(projectId);
await AddCompilationDeclarationsWithNormalQueryAsync(
project, query, filter, result, cancellationToken).ConfigureAwait(false);
return results;
}

return result.ToImmutableAndFree();
return await FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
solution, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false);
}

public static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsithNormalQueryInLocalProcessAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken)
public static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarationsWithNormalQueryAsync(
Project project, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
if (project == null)
{
Expand All @@ -64,11 +70,95 @@ public static async Task<ImmutableArray<SymbolAndProjectId>> FindSourceDeclarati
return ImmutableArray<SymbolAndProjectId>.Empty;
}

var (succeded, results) = await TryFindSourceDeclarationsWithNormalQueryInRemoteProcessAsync(
project, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false);

if (succeded)
{
return results;
}

return await FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
project, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false);
}

#endregion

#region Remote Dispatch

// These are the members that actually try to send the request to the remote process.

private static async Task<(bool, ImmutableArray<SymbolAndProjectId>)> TryFindSourceDeclarationsWithNormalQueryInRemoteProcessAsync(
Solution solution, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
var session = await SymbolFinder.TryGetRemoteSessionAsync(solution, cancellationToken).ConfigureAwait(false);
if (session != null)
{
var result = await session.InvokeAsync<SerializableSymbolAndProjectId[]>(
nameof(IRemoteSymbolFinder.FindSolutionSourceDeclarationsWithNormalQuery),
name, ignoreCase, criteria).ConfigureAwait(false);

var rehydrated = await RehydrateAsync(
solution, result, cancellationToken).ConfigureAwait(false);

return (true, rehydrated);
}

return (false, ImmutableArray<SymbolAndProjectId>.Empty);
}

private static async Task<(bool, ImmutableArray<SymbolAndProjectId>)> TryFindSourceDeclarationsWithNormalQueryInRemoteProcessAsync(
Project project, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
var session = await SymbolFinder.TryGetRemoteSessionAsync(project.Solution, cancellationToken).ConfigureAwait(false);
if (session != null)
{
var result = await session.InvokeAsync<SerializableSymbolAndProjectId[]>(
nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithNormalQuery),
project.Id, name, ignoreCase, criteria).ConfigureAwait(false);

var rehydrated = await RehydrateAsync(
project.Solution, result, cancellationToken).ConfigureAwait(false);

return (true, rehydrated);
}

return (false, ImmutableArray<SymbolAndProjectId>.Empty);
}

#endregion

#region Local processing

// These are the members that have the core logic that does the actual finding. They will
// be called 'in proc' in the remote process if we are able to remote the request. Or they
// will be called 'in proc' from within VS if we are not able to remote the request.

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)
{
var project = solution.GetProject(projectId);
await AddCompilationDeclarationsWithNormalQueryAsync(
project, query, criteria, result, cancellationToken).ConfigureAwait(false);
}

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();
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,14 @@ internal interface IRemoteSymbolFinder
{
Task FindReferencesAsync(SerializableSymbolAndProjectId symbolAndProjectIdArg, DocumentId[] documentArgs);
Task FindLiteralReferencesAsync(object value);

Task<SerializableSymbolAndProjectId[]> FindAllDeclarationsWithNormalQueryAsync(
ProjectId projectId, string name, SearchKind searchKind, SymbolFilter criteria);

Task<SerializableSymbolAndProjectId[]> FindSolutionSourceDeclarationsWithNormalQuery(
string name, bool ignoreCase, SymbolFilter criteria);

Task<SerializableSymbolAndProjectId[]> FindProjectSourceDeclarationsWithNormalQuery(
ProjectId projectId, string name, bool ignoreCase, SymbolFilter criteria);
}
}
Loading