提交 068594d0 编写于 作者: P Paul Vick 提交者: Heejae Chang

Merge pull request #13779 from panopticoncentral/codelens

Add out of proc CodeLens processing
上级 26899dfc
......@@ -28,7 +28,7 @@ protected static async Task RunCountTest(XElement input, int cap = 0)
foreach (var span in annotatedSpan.Value)
{
var declarationSyntaxNode = syntaxNode.FindNode(span);
var result = await new CodeLensReferenceService().GetReferenceCountAsync(workspace.CurrentSolution, annotatedDocument.Id,
var result = await new CodeLensReferencesService().GetReferenceCountAsync(workspace.CurrentSolution, annotatedDocument.Id,
declarationSyntaxNode, cap, CancellationToken.None);
Assert.NotNull(result);
Assert.Equal(expected, result.Count);
......@@ -59,7 +59,7 @@ protected static async Task RunReferenceTest(XElement input)
foreach (var span in annotatedSpan.Value)
{
var declarationSyntaxNode = syntaxNode.FindNode(span);
var result = await new CodeLensReferenceService().FindReferenceLocationsAsync(workspace.CurrentSolution,
var result = await new CodeLensReferencesService().FindReferenceLocationsAsync(workspace.CurrentSolution,
annotatedDocument.Id, declarationSyntaxNode, CancellationToken.None);
var count = result.Count();
Assert.Equal(expected, count);
......@@ -89,7 +89,7 @@ protected static async Task RunMethodReferenceTest(XElement input)
foreach (var span in annotatedSpan.Value)
{
var declarationSyntaxNode = syntaxNode.FindNode(span);
var result = await new CodeLensReferenceService().FindReferenceMethodsAsync(workspace.CurrentSolution,
var result = await new CodeLensReferencesService().FindReferenceMethodsAsync(workspace.CurrentSolution,
annotatedDocument.Id, declarationSyntaxNode, CancellationToken.None);
var count = result.Count();
Assert.Equal(expected, count);
......
......@@ -2,21 +2,18 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CodeLens
{
[ExportWorkspaceService(typeof(ICodeLensReferencesService)), Shared]
internal sealed class CodeLensReferenceService : ICodeLensReferencesService
internal sealed class CodeLensReferencesService : ICodeLensReferencesService
{
private static readonly SymbolDisplayFormat MethodDisplayFormat =
new SymbolDisplayFormat(
......
// 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.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.CodeLens
{
[ExportWorkspaceServiceFactory(typeof(ICodeLensReferencesService)), Shared]
internal sealed class CodeLensReferencesServiceFactory : IWorkspaceServiceFactory
{
public static readonly ICodeLensReferencesService Instance = new CodeLensReferencesService();
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return Instance;
}
}
}
......@@ -81,5 +81,23 @@ public ReferenceLocationDescriptor(string longDescription, string language, Glyp
AfterReferenceText1 = afterReferenceText1;
AfterReferenceText2 = afterReferenceText2;
}
public ReferenceLocationDescriptor(string longDescription, string language, Glyph? glyph, int lineNumber, int columnNumber, DocumentId documentId, string referenceLineText, int referenceStart, int referenceLength, string beforeReferenceText1, string beforeReferenceText2, string afterReferenceText1, string afterReferenceText2)
{
LongDescription = longDescription;
Language = language;
Glyph = glyph;
LineNumber = lineNumber;
ColumnNumber = columnNumber;
// We want to keep track of the location's document if it comes from a file in your solution.
DocumentId = documentId;
ReferenceLineText = referenceLineText;
ReferenceStart = referenceStart;
ReferenceLength = referenceLength;
BeforeReferenceText1 = beforeReferenceText1;
BeforeReferenceText2 = beforeReferenceText2;
AfterReferenceText1 = afterReferenceText1;
AfterReferenceText2 = afterReferenceText2;
}
}
}
......@@ -10,16 +10,16 @@ internal sealed class ReferenceMethodDescriptor
/// <summary>
/// Describe a caller method of a callee
/// </summary>
/// <param name="methodFullName">Method's fully qualified name</param>
/// <param name="methodFilePath">Method full path</param>
/// <param name="fullName">Method's fully qualified name</param>
/// <param name="filePath">Method full path</param>
/// <remarks>
/// Method full name is expected to be in the .NET full name type convention. That is,
/// namespace/type is delimited by '.' and nested type is delimited by '+'
/// </remarks>
public ReferenceMethodDescriptor(string methodFullName, string methodFilePath)
public ReferenceMethodDescriptor(string fullName, string filePath)
{
FullName = methodFullName;
FilePath = methodFilePath;
FullName = fullName;
FilePath = filePath;
}
/// <summary>
......
......@@ -45,6 +45,7 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.ExternalDependencyServices" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.VisualBasic" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Xaml" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Remote.ServiceHub" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.TestImpact.Orchestrator" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.VisualBasic.EditorFeatures" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.VisualBasic.Features" />
......@@ -91,6 +92,7 @@
</Compile>
<Compile Include="AddMissingReference\AbstractAddMissingReferenceCodeFixProvider.cs" />
<Compile Include="AddMissingReference\CodeAction.cs" />
<Compile Include="CodeLens\CodeLensReferencesServiceFactory.cs" />
<Compile Include="Structure\Syntax\BlockStructureExtensions.cs" />
<Compile Include="Structure\Syntax\AbstractBlockStructureProvider.cs" />
<Compile Include="Structure\BlockSpan.cs" />
......@@ -161,7 +163,7 @@
<Compile Include="CodeFixes\Suppression\ExportSuppressionFixProviderAttribute.cs" />
<Compile Include="CodeFixes\Suppression\WrapperCodeFixProvider.cs" />
<Compile Include="CodeFixes\Suppression\AbstractSuppressionCodeFixProvider.cs" />
<Compile Include="CodeLens\CodeLensReferenceService.cs" />
<Compile Include="CodeLens\CodeLensReferencesService.cs" />
<Compile Include="CodeLens\CodeLensFindReferenceProgress.cs" />
<Compile Include="CodeLens\ICodeLensReferencesService.cs" />
<Compile Include="CodeLens\ICodeLensDisplayInfoService.cs" />
......@@ -671,4 +673,4 @@
<ItemGroup />
<Import Project="..\..\..\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems" Label="Shared" />
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</Project>
</Project>
\ 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.Generic;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeLens;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
using Microsoft.VisualStudio.LanguageServices.Remote;
namespace Microsoft.VisualStudio.LanguageServices.CodeLens
{
[ExportWorkspaceService(typeof(ICodeLensReferencesService), layer: ServiceLayer.Host), Shared]
internal sealed class RemoteCodeLensReferencesService : ICodeLensReferencesService
{
public async Task<ReferenceCount> GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, int maxSearchResults,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync(solution, documentId, syntaxNode, maxSearchResults, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<ReferenceCount>(WellKnownServiceHubServices.CodeAnalysisService_GetReferenceCountAsync, new CodeLensArguments(documentId, syntaxNode), maxSearchResults).ConfigureAwait(false);
}
}
public async Task<IEnumerable<ReferenceLocationDescriptor>> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.FindReferenceLocationsAsync(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<IEnumerable<ReferenceLocationDescriptor>>(WellKnownServiceHubServices.CodeAnalysisService_FindReferenceLocationsAsync, new CodeLensArguments(documentId, syntaxNode)).ConfigureAwait(false);
}
}
public async Task<IEnumerable<ReferenceMethodDescriptor>> FindReferenceMethodsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<IEnumerable<ReferenceMethodDescriptor>>(WellKnownServiceHubServices.CodeAnalysisService_FindReferenceMethodsAsync, new CodeLensArguments(documentId, syntaxNode)).ConfigureAwait(false);
}
}
public async Task<string> GetFullyQualifiedName(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedName(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<string>(WellKnownServiceHubServices.CodeAnalysisService_GetFullyQualifiedName, new CodeLensArguments(documentId, syntaxNode)).ConfigureAwait(false);
}
}
}
}
......@@ -74,6 +74,9 @@
<PublicAPI Include="PublicAPI.Unshipped.txt" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Workspaces\Remote\ServiceHub\CodeLens\CodeLensArguments.cs">
<Link>CodeLens\CodeLensArguments.cs</Link>
</Compile>
<Compile Include="..\..\Workspaces\Remote\ServiceHub\Diagnostics\DiagnosticArguments.cs">
<Link>Diagnostics\DiagnosticArguments.cs</Link>
</Compile>
......@@ -92,6 +95,7 @@
<Compile Include="..\..\Workspaces\Remote\ServiceHub\Shared\WellKnownServiceHubServices.cs">
<Link>Shared\WellKnownServiceHubServices.cs</Link>
</Compile>
<Compile Include="CodeLens\RemoteCodeLensReferencesService.cs" />
<Compile Include="Diagnostics\OutOfProcDiagnosticAnalyzerExecutor.cs" />
<Compile Include="Extensions\RemoteHostClientExtensions.cs" />
<Compile Include="FindReferences\FindReferencesTableControlEventProcessorProvider.cs" />
......
......@@ -351,5 +351,9 @@ internal enum FunctionId
AssetService_SynchronizeSolutionAssetsAsync,
SolutionChecksumServiceFactory_GetChecksumObjects,
ChecksumTreeNode_GetOrCreateChecksumObject,
CodeAnalysisService_GetReferenceCountAsync,
CodeAnalysisService_FindReferenceLocationsAsync,
CodeAnalysisService_FindReferenceMethodsAsync,
CodeAnalysisService_GetFullyQualifiedName,
}
}
// 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 Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Remote.Diagnostics
{
/// <summary>
/// helper type to package diagnostic arguments to pass around between remote hosts
/// </summary>
internal class CodeLensArguments
{
public Guid ProjectIdGuid;
public string ProjectIdDebugName;
public Guid DocumentIdGuid;
public string DocumentIdDebugName;
public int Start;
public int Length;
public CodeLensArguments()
{
}
public CodeLensArguments(DocumentId documentId, SyntaxNode syntaxNode)
{
ProjectIdGuid = documentId.ProjectId.Id;
ProjectIdDebugName = documentId.ProjectId.DebugName;
DocumentIdGuid = documentId.Id;
DocumentIdDebugName = documentId.DebugName;
Start = syntaxNode.Span.Start;
Length = syntaxNode.Span.Length;
}
public DocumentId GetDocumentId()
=>
DocumentId.CreateFromSerialized(ProjectId.CreateFromSerialized(ProjectIdGuid, ProjectIdDebugName),
DocumentIdGuid, DocumentIdDebugName);
public TextSpan GetTextSpan() => new TextSpan(Start, Length);
}
}
\ No newline at end of file
......@@ -19,6 +19,10 @@
<Project>{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}</Project>
<Name>CodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Features\Core\Portable\Features.csproj">
<Project>{edc68a0e-c68d-4a74-91b7-bf38ec909888}</Project>
<Name>Features</Name>
</ProjectReference>
<ProjectReference Include="..\..\Core\Desktop\Workspaces.Desktop.csproj">
<Project>{2e87fa96-50bb-4607-8676-46521599f998}</Project>
<Name>Workspaces.Desktop</Name>
......@@ -45,6 +49,8 @@
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
<Compile Include="CodeLens\CodeLensArguments.cs" />
<Compile Include="Services\CodeAnalysisService_CodeLens.cs" />
<Compile Include="Services\SnapshotService.JsonRpcAssetSource.cs" />
<PublicAPI Include="PublicAPI.Shipped.txt" />
<PublicAPI Include="PublicAPI.Unshipped.txt" />
......
// 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.IO;
using Microsoft.CodeAnalysis.CodeLens;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Remote
{
internal partial class CodeAnalysisService
{
public async Task<ReferenceCount> GetReferenceCountAsync(CodeLensArguments arguments, int maxResultCount, byte[] solutionChecksum)
{
try
{
var documentId = arguments.GetDocumentId();
var textSpan = arguments.GetTextSpan();
using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_GetReferenceCountAsync, documentId.ProjectId.DebugName, CancellationToken))
{
var solution = await RoslynServices.SolutionService.GetSolutionAsync(new Checksum(solutionChecksum), CancellationToken).ConfigureAwait(false);
var syntaxNode = (await solution.GetDocument(documentId).GetSyntaxRootAsync().ConfigureAwait(false)).FindNode(textSpan);
return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync(solution, documentId,
syntaxNode, maxResultCount, CancellationToken).ConfigureAwait(false);
}
}
catch (IOException)
{
// stream to send over result has closed before we
// had chance to check cancellation
}
catch (OperationCanceledException)
{
// rpc connection has closed.
// this can happen if client side cancelled the
// operation
}
return null;
}
public async Task<IEnumerable<ReferenceLocationDescriptor>> FindReferenceLocationsAsync(CodeLensArguments arguments, byte[] solutionChecksum)
{
try
{
var documentId = arguments.GetDocumentId();
var textSpan = arguments.GetTextSpan();
using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceLocationsAsync, documentId.ProjectId.DebugName, CancellationToken))
{
var solution = await RoslynServices.SolutionService.GetSolutionAsync(new Checksum(solutionChecksum), CancellationToken).ConfigureAwait(false);
var syntaxNode = (await solution.GetDocument(documentId).GetSyntaxRootAsync().ConfigureAwait(false)).FindNode(textSpan);
return await CodeLensReferencesServiceFactory.Instance.FindReferenceLocationsAsync(solution, documentId,
syntaxNode, CancellationToken).ConfigureAwait(false);
}
}
catch (IOException)
{
// stream to send over result has closed before we
// had chance to check cancellation
}
catch (OperationCanceledException)
{
// rpc connection has closed.
// this can happen if client side cancelled the
// operation
}
return null;
}
public async Task<IEnumerable<ReferenceMethodDescriptor>> FindReferenceMethodsAsync(CodeLensArguments arguments, byte[] solutionChecksum)
{
try
{
var documentId = arguments.GetDocumentId();
var textSpan = arguments.GetTextSpan();
using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceMethodsAsync, documentId.ProjectId.DebugName, CancellationToken))
{
var solution = await RoslynServices.SolutionService.GetSolutionAsync(new Checksum(solutionChecksum), CancellationToken).ConfigureAwait(false);
var syntaxNode = (await solution.GetDocument(documentId).GetSyntaxRootAsync().ConfigureAwait(false)).FindNode(textSpan);
return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync(solution, documentId,
syntaxNode, CancellationToken).ConfigureAwait(false);
}
}
catch (IOException)
{
// stream to send over result has closed before we
// had chance to check cancellation
}
catch (OperationCanceledException)
{
// rpc connection has closed.
// this can happen if client side cancelled the
// operation
}
return null;
}
public async Task<string> GetFullyQualifiedName(CodeLensArguments arguments, byte[] solutionChecksum)
{
try
{
var documentId = arguments.GetDocumentId();
var textSpan = arguments.GetTextSpan();
using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_GetFullyQualifiedName, documentId.ProjectId.DebugName, CancellationToken))
{
var solution = await RoslynServices.SolutionService.GetSolutionAsync(new Checksum(solutionChecksum), CancellationToken).ConfigureAwait(false);
var syntaxNode = (await solution.GetDocument(documentId).GetSyntaxRootAsync().ConfigureAwait(false)).FindNode(textSpan);
return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedName(solution, documentId,
syntaxNode, CancellationToken).ConfigureAwait(false);
}
}
catch (IOException)
{
// stream to send over result has closed before we
// had chance to check cancellation
}
catch (OperationCanceledException)
{
// rpc connection has closed.
// this can happen if client side cancelled the
// operation
}
return null;
}
}
}
......@@ -9,6 +9,10 @@ internal static class WellKnownServiceHubServices
public const string CodeAnalysisService = "codeAnalysisService";
public const string CodeAnalysisService_CalculateDiagnosticsAsync = "CalculateDiagnosticsAsync";
public const string CodeAnalysisService_GetReferenceCountAsync = "GetReferenceCountAsync";
public const string CodeAnalysisService_FindReferenceLocationsAsync = "FindReferenceLocationsAsync";
public const string CodeAnalysisService_FindReferenceMethodsAsync = "FindReferenceMethodsAsync";
public const string CodeAnalysisService_GetFullyQualifiedName = "GetFullyQualifiedName";
public const string AssetService_RequestAssetAsync = "RequestAssetAsync";
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册