提交 f22ef943 编写于 作者: C CyrusNajmabadi

Initial impl of Add-Import actually running OOP.

上级 4878be21
......@@ -8,10 +8,12 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.CodeAnalysis.Text;
......@@ -56,6 +58,30 @@ protected AbstractAddImportFeatureService()
Document document, TextSpan span, string diagnosticId, ISymbolSearchService symbolSearchService,
bool searchReferenceAssemblies, ImmutableArray<PackageSource> packageSources,
CancellationToken cancellationToken)
{
var session = await document.Project.Solution.TryCreateCodeAnalysisServiceSessionAsync(
AddImportOptions.OutOfProcessAllowed, WellKnownExperimentNames.OutOfProcessAllowed,
new RemoteSymbolSearchService(symbolSearchService, cancellationToken), cancellationToken).ConfigureAwait(false);
using (session)
{
if (session == null)
{
return await GetFixesInCurrentProcessAsync(
document, span, diagnosticId, symbolSearchService,
searchReferenceAssemblies, packageSources, cancellationToken).ConfigureAwait(false);
}
else
{
return await GetFixesInRemoteProcessAsync(
session, document, span, diagnosticId,
searchReferenceAssemblies, packageSources).ConfigureAwait(false);
}
}
}
private async Task<ImmutableArray<AddImportFixData>> GetFixesInCurrentProcessAsync(
Document document, TextSpan span, string diagnosticId, ISymbolSearchService symbolSearchService,
bool searchReferenceAssemblies, ImmutableArray<PackageSource> packageSources, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var node = root.FindToken(span.Start, findInsideTrivia: true)
......
// 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.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Tags;
using Microsoft.CodeAnalysis.Text;
......@@ -129,5 +131,29 @@ public static AddImportFixData CreateForPackageSymbol(ImmutableArray<TextChange>
PackageVersionOpt = packageVersionOpt,
};
}
public SerializableAddImportFixData Dehydrate()
{
return new SerializableAddImportFixData
{
Kind = Kind,
TextChanges = TextChanges.ToArray(),
Title = Title,
Tags = Tags.NullToEmpty().ToArray(),
Priority = Priority,
ProjectReferenceToAdd = ProjectReferenceToAdd,
PortableExecutableReferenceProjectId = PortableExecutableReferenceProjectId,
PortableExecutableReferenceFilePathToAdd = PortableExecutableReferenceFilePathToAdd,
AssemblyReferenceAssemblyName = AssemblyReferenceAssemblyName,
AssemblyReferenceFullyQualifiedTypeName = AssemblyReferenceFullyQualifiedTypeName,
PackageSource = PackageSource,
PackageName = PackageName,
PackageVersionOpt = PackageVersionOpt
};
}
}
}
\ No newline at end of file
// 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.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.AddImport
{
internal abstract partial class AbstractAddImportFeatureService<TSimpleNameSyntax>
{
private async Task<ImmutableArray<AddImportFixData>> GetFixesInRemoteProcessAsync(
RemoteHostClient.Session session, Document document, TextSpan span, string diagnosticId,
bool searchReferenceAssemblies, ImmutableArray<PackageSource> packageSources)
{
var result = await session.InvokeAsync<SerializableAddImportFixData[]>(
nameof(IRemoteAddImportFeatureService.GetFixesAsync),
new object[] { document.Id, span, diagnosticId, searchReferenceAssemblies, packageSources.ToArray() }).ConfigureAwait(false);
return result.Select(d => d.Rehydrate()).ToImmutableArray();
}
/// <summary>
/// Used to supply the OOP server a callback that it can use to search for ReferenceAssemblies or
/// nuget packages. We can't necessarily do that search directly in the OOP server as our
/// 'SymbolSearchEngine' may actually be running in a *different* process (there is no guarantee
/// that all remote work happens in the same process).
///
/// This does mean, currently, that when we call over to OOP to do a search, it will bounce
/// back to VS, which will then bounce back out to OOP to perform the Nuget/ReferenceAssembly
/// portion of the search. Ideally we could keep this all OOP.
/// </summary>
private class RemoteSymbolSearchService : IRemoteSymbolSearchUpdateEngine
{
private readonly ISymbolSearchService _symbolSearchService;
private readonly CancellationToken _cancellationToken;
public RemoteSymbolSearchService(
ISymbolSearchService symbolSearchService,
CancellationToken cancellationToken)
{
_symbolSearchService = symbolSearchService;
_cancellationToken = cancellationToken;
}
public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory)
{
// Remote side should never call this.
throw new NotImplementedException();
}
public async Task<SerializablePackageWithTypeResult[]> FindPackagesWithTypeAsync(
string source, string name, int arity)
{
var result = await _symbolSearchService.FindPackagesWithTypeAsync(
source, name, arity, _cancellationToken).ConfigureAwait(false);
return result.Select(SerializablePackageWithTypeResult.Dehydrate).ToArray();
}
public async Task<SerializablePackageWithAssemblyResult[]> FindPackagesWithAssemblyAsync(
string source, string name)
{
var result = await _symbolSearchService.FindPackagesWithAssemblyAsync(
source, name, _cancellationToken).ConfigureAwait(false);
return result.Select(SerializablePackageWithAssemblyResult.Dehydrate).ToArray();
}
public async Task<SerializableReferenceAssemblyWithTypeResult[]> FindReferenceAssembliesWithTypeAsync(
string name, int arity)
{
var result = await _symbolSearchService.FindReferenceAssembliesWithTypeAsync(
name, arity, _cancellationToken).ConfigureAwait(false);
return result.Select(SerializableReferenceAssemblyWithTypeResult.Dehydrate).ToArray();
}
}
}
}
\ No newline at end of file
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.AddImport
{
internal interface IRemoteAddImportFeatureService
{
Task<SerializableAddImportFixData[]> GetFixesAsync(
DocumentId documentId, TextSpan span, string diagnosticId,
bool searchReferenceAssemblies, PackageSource[] packageSources);
}
}
\ No newline at end of file
// 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.Immutable;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
{
internal class SerializableAddImportFixData
{
public AddImportFixKind Kind;
/// <summary>
/// Text changes to make to the document. Usually just the import to add. May also
/// include a change to the name node the feature was invoked on to fix the casing of it.
/// May be empty for fixes that don't need to add an import and only do something like
/// add a project/metadata reference.
/// </summary>
public TextChange[] TextChanges;
/// <summary>
/// String to display in the lightbulb menu.
/// </summary>
public string Title;
/// <summary>
/// Tags that control what glyph is displayed in the lightbulb menu.
/// </summary>
public string[] Tags;
/// <summary>
/// The priority this item should have in the lightbulb list.
/// </summary>
public CodeActionPriority Priority;
#region When adding P2P refrences.
/// <summary>
/// The optional id for a <see cref="Project"/> we'd like to add a reference to.
/// </summary>
public ProjectId ProjectReferenceToAdd;
#endregion
#region When adding a metadata reference
/// <summary>
/// If we're adding <see cref="PortableExecutableReferenceFilePathToAdd"/> then this
/// is the id for the <see cref="Project"/> we can find that <see cref="PortableExecutableReference"/>
/// referenced from.
/// </summary>
public ProjectId PortableExecutableReferenceProjectId;
/// <summary>
/// If we want to add a <see cref="PortableExecutableReference"/> metadata reference, this
/// is the <see cref="PortableExecutableReference.FilePath"/> for it.
/// </summary>
public string PortableExecutableReferenceFilePathToAdd;
#endregion
#region When adding an assembly reference
public string AssemblyReferenceAssemblyName;
public string AssemblyReferenceFullyQualifiedTypeName;
#endregion
#region When adding a package reference
public string PackageSource;
public string PackageName;
public string PackageVersionOpt;
#endregion
public AddImportFixData Rehydrate()
{
switch (Kind)
{
case AddImportFixKind.ProjectSymbol:
return AddImportFixData.CreateForProjectSymbol(
TextChanges.ToImmutableArray(), Title, Tags.ToImmutableArray(),
Priority, ProjectReferenceToAdd);
case AddImportFixKind.MetadataSymbol:
return AddImportFixData.CreateForMetadataSymbol(
TextChanges.ToImmutableArray(), Title, Tags.ToImmutableArray(),
Priority, PortableExecutableReferenceProjectId, PortableExecutableReferenceFilePathToAdd);
case AddImportFixKind.PackageSymbol:
return AddImportFixData.CreateForPackageSymbol(
TextChanges.ToImmutableArray(), PackageSource, PackageName, PackageVersionOpt);
case AddImportFixKind.ReferenceAssemblySymbol:
return AddImportFixData.CreateForReferenceAssemblySymbol(
TextChanges.ToImmutableArray(), Title,
AssemblyReferenceAssemblyName, AssemblyReferenceFullyQualifiedTypeName);
}
throw ExceptionUtilities.Unreachable;
}
}
}
\ No newline at end of file
......@@ -100,6 +100,7 @@
<Link>Shared\Utilities\DesktopShim.cs</Link>
</Compile>
<Compile Include="AddImport\AbstractAddImportFeatureService.cs" />
<Compile Include="AddImport\Remote\AbstractAddImportFeatureService_Remote.cs" />
<Compile Include="AddImport\AddImportFixData.cs" />
<Compile Include="AddImport\AddImportFixKind.cs" />
<Compile Include="AddImport\AddImportOptions.cs" />
......@@ -108,6 +109,8 @@
<Compile Include="AddImport\CodeActions\MetadataSymbolReferenceCodeAction.cs" />
<Compile Include="AddImport\CodeActions\ProjectSymbolReferenceCodeAction.cs" />
<Compile Include="AddImport\IAddImportFeatureService.cs" />
<Compile Include="AddImport\Remote\SerializableAddImportFixData.cs" />
<Compile Include="AddImport\Remote\IRemoteAddImportFeatureService.cs" />
<Compile Include="AddImport\SearchScopes\AllSymbolsProjectSearchScope.cs" />
<Compile Include="AddImport\SearchScopes\MetadataSymbolsSearchScope.cs" />
<Compile Include="AddImport\SearchScopes\ProjectSearchScope.cs" />
......
......@@ -74,6 +74,7 @@
<Compile Include="Services\CodeAnalysisService_CodeLens.cs" />
<Compile Include="Services\CodeAnalysisService_DesignerAttributes.cs" />
<Compile Include="Services\CodeAnalysisService_DocumentHighlights.cs" />
<Compile Include="Services\CodeAnalysisService_AddImport.cs" />
<Compile Include="Services\CodeAnalysisService_TodoComments.cs" />
<Compile Include="Services\CodeAnalysisService_SymbolFinder.cs" />
<Compile Include="Services\RemoteSymbolSearchUpdateEngine.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.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.AddImport;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Remote
{
internal partial class CodeAnalysisService : IRemoteAddImportFeatureService
{
public async Task<SerializableAddImportFixData[]> GetFixesAsync(
DocumentId documentId, TextSpan span, string diagnosticId,
bool searchReferenceAssemblies, PackageSource[] packageSources)
{
using (UserOperationBooster.Boost())
{
var solution = await GetSolutionAsync().ConfigureAwait(false);
var document = solution.GetDocument(documentId);
var service = document.GetLanguageService<IAddImportFeatureService>();
var symbolSearchService = new SymbolSearchService(this);
var result = await service.GetFixesAsync(
document, span, diagnosticId, symbolSearchService, searchReferenceAssemblies,
packageSources.ToImmutableArray(), CancellationToken).ConfigureAwait(false);
return result.Select(d => d.Dehydrate()).ToArray();
}
}
/// <summary>
/// Provides an implementation of the ISymbolSearchService on the remote side so that
/// Add-Import can find results in nuget packages/reference assemblies. This works
/// by remoting *from* the OOP server back to the host, which can then forward this
/// appropriately to wherever the real ISymbolSearchService is running. This is necessary
/// because it's not guaranteed that the real ISymbolSearchService will be running in
/// the same process that is supplying the <see cref="CodeAnalysisService"/>.
///
/// Ideally we would not need to bounce back to the host for this.
/// </summary>
private class SymbolSearchService : ISymbolSearchService
{
private readonly CodeAnalysisService codeAnalysisService;
public SymbolSearchService(CodeAnalysisService codeAnalysisService)
{
this.codeAnalysisService = codeAnalysisService;
}
public async Task<ImmutableArray<PackageWithTypeResult>> FindPackagesWithTypeAsync(
string source, string name, int arity, CancellationToken cancellationToken)
{
var result = await codeAnalysisService.Rpc.InvokeAsync<SerializablePackageWithTypeResult[]>(
nameof(FindPackagesWithTypeAsync), source, name, arity).ConfigureAwait(false);
return result.Select(r => r.Rehydrate()).ToImmutableArray();
}
public async Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAssemblyAsync(
string source, string assemblyName, CancellationToken cancellationToken)
{
var result = await codeAnalysisService.Rpc.InvokeAsync<SerializablePackageWithAssemblyResult[]>(
nameof(FindPackagesWithAssemblyAsync), source, assemblyName).ConfigureAwait(false);
return result.Select(r => r.Rehydrate()).ToImmutableArray();
}
public async Task<ImmutableArray<ReferenceAssemblyWithTypeResult>> FindReferenceAssembliesWithTypeAsync(
string name, int arity, CancellationToken cancellationToken)
{
var result = await codeAnalysisService.Rpc.InvokeAsync<SerializableReferenceAssemblyWithTypeResult[]>(
nameof(FindReferenceAssembliesWithTypeAsync), name, arity).ConfigureAwait(false);
return result.Select(r => r.Rehydrate()).ToImmutableArray();
}
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册