diff --git a/eng/Version.Details.props b/eng/Version.Details.props index c8afe919a46..6eba939dded 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,27 +6,27 @@ This file should be imported by eng/Versions.props - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 - 5.3.0-1.25530.6 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 + 5.3.0-2.25555.17 9.0.0-beta.25515.2 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 46db3ced2fa..24c5ecd1fd7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -2,89 +2,89 @@ - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef - + https://github.com/dotnet/roslyn - d9459428c3065525eeb740fa8cd7ce6b83c8b550 + b9d497daa87f8c902c451b0d960eaf70dfcda2ef diff --git a/eng/targets/Services.props b/eng/targets/Services.props index f9ece639103..bcc456f3a5e 100644 --- a/eng/targets/Services.props +++ b/eng/targets/Services.props @@ -44,5 +44,6 @@ + diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteDataTipRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteDataTipRangeService.cs new file mode 100644 index 00000000000..64e0b1ed722 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteDataTipRangeService.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; + +namespace Microsoft.CodeAnalysis.Razor.Remote; + +internal interface IRemoteDataTipRangeService : IRemoteJsonService +{ + ValueTask> GetDataTipRangeAsync( + JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, + JsonSerializableDocumentId razorDocumentId, + Position position, + CancellationToken cancellationToken); +} + diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs index fa25803fc2b..f08f7fc4882 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RazorServices.cs @@ -47,6 +47,7 @@ internal static class RazorServices (typeof(IRemoteFindAllReferencesService), null), (typeof(IRemoteMEFInitializationService), null), (typeof(IRemoteCodeLensService), null), + (typeof(IRemoteDataTipRangeService), null), ]; private const string ComponentName = "Razor"; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Debugging/RemoteDataTipRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Debugging/RemoteDataTipRangeService.cs new file mode 100644 index 00000000000..31ae4e5961a --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Debugging/RemoteDataTipRangeService.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; +using Microsoft.CodeAnalysis.Razor.DocumentMapping; +using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Text; +using static Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse; + +namespace Microsoft.CodeAnalysis.Remote.Razor; + +internal sealed class RemoteDataTipRangeService(in ServiceArgs args) : RazorDocumentServiceBase(in args), IRemoteDataTipRangeService +{ + internal sealed class Factory : FactoryBase + { + protected override IRemoteDataTipRangeService CreateService(in ServiceArgs args) + => new RemoteDataTipRangeService(in args); + } + + private readonly IDocumentMappingService _documentMappingService = args.ExportProvider.GetExportedValue(); + + public ValueTask> GetDataTipRangeAsync( + JsonSerializableRazorPinnedSolutionInfoWrapper solutionInfo, + JsonSerializableDocumentId documentId, + Position position, + CancellationToken cancellationToken) + { + return RunServiceAsync( + solutionInfo, + documentId, + context => GetDataTipRangeAsync(context, position, cancellationToken), + cancellationToken); + } + + private async ValueTask> GetDataTipRangeAsync( + RemoteDocumentContext context, + Position position, + CancellationToken cancellationToken) + { + var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); + var razorIndex = codeDocument.Source.Text.GetRequiredAbsoluteIndex(position); + var csharpDocument = codeDocument.GetRequiredCSharpDocument(); + + if (!_documentMappingService.TryMapToCSharpDocumentPosition(csharpDocument, razorIndex, out var csharpPosition, out _)) + { + return NoFurtherHandling; + } + + var generatedDocument = await context.Snapshot.GetGeneratedDocumentAsync(cancellationToken).ConfigureAwait(false); + + var csharpResult = await ExternalAccess.Razor.Cohost.Handlers.DataTipRange.GetDataTipRangeAsync(generatedDocument, csharpPosition, cancellationToken).ConfigureAwait(false); + if (csharpResult?.ExpressionRange is null) + { + return NoFurtherHandling; + } + + if (!DocumentMappingService.TryMapToRazorDocumentRange(csharpDocument, csharpResult.HoverRange, out var razorHoverRange) + || !DocumentMappingService.TryMapToRazorDocumentRange(csharpDocument, csharpResult.ExpressionRange, out var razorExpressionRange)) + { + return NoFurtherHandling; + } + + var razorResult = new VSInternalDataTip() + { + HoverRange = razorHoverRange, + ExpressionRange = razorExpressionRange, + DataTipTags = csharpResult.DataTipTags, + }; + + return Results(razorResult); + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDataTipRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDataTipRangeEndpoint.cs new file mode 100644 index 00000000000..e1e372fb883 --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDataTipRangeEndpoint.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; +using Microsoft.CodeAnalysis.Razor.Cohost; +using Microsoft.CodeAnalysis.Razor.Remote; + +namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; + +#pragma warning disable RS0030 // Do not use banned APIs +[Shared] +[CohostEndpoint(VSInternalMethods.TextDocumentDataTipRangeName)] +[Export(typeof(IDynamicRegistrationProvider))] +[ExportRazorStatelessLspService(typeof(CohostDataTipRangeEndpoint))] +[method: ImportingConstructor] +#pragma warning restore RS0030 // Do not use banned APIs +internal sealed class CohostDataTipRangeEndpoint( + IIncompatibleProjectService incompatibleProjectService, + IRemoteServiceInvoker remoteServiceInvoker) + : AbstractCohostDocumentEndpoint(incompatibleProjectService), IDynamicRegistrationProvider +{ + private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker; + + protected override bool MutatesSolutionState => false; + + protected override bool RequiresLSPSolution => true; + + public ImmutableArray GetRegistrations(VSInternalClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext) + { + return [new Registration + { + Method = VSInternalMethods.TextDocumentDataTipRangeName, + RegisterOptions = new TextDocumentRegistrationOptions() + }]; + } + + protected override RazorTextDocumentIdentifier? GetRazorTextDocumentIdentifier(TextDocumentPositionParams request) + => request.TextDocument.ToRazorTextDocumentIdentifier(); + + protected override Task HandleRequestAsync(TextDocumentPositionParams request, TextDocument razorDocument, CancellationToken cancellationToken) + => HandleRequestAsync(razorDocument, request.Position, cancellationToken); + + private async Task HandleRequestAsync(TextDocument razorDocument, Position position, CancellationToken cancellationToken) + { + var data = await _remoteServiceInvoker.TryInvokeAsync>( + razorDocument.Project.Solution, + (service, solutionInfo, cancellationToken) => service.GetDataTipRangeAsync(solutionInfo, razorDocument.Id, position, cancellationToken), + cancellationToken).ConfigureAwait(false); + + return data.Result; + } + + internal TestAccessor GetTestAccessor() => new(this); + + internal readonly struct TestAccessor(CohostDataTipRangeEndpoint instance) + { + public Task HandleRequestAsync(TextDocument razorDocument, Position position, CancellationToken cancellationToken) + => instance.HandleRequestAsync(razorDocument, position, cancellationToken); + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FindAllReferences.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FindAllReferences.cs index 3b7d921bad0..c90d2da645d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FindAllReferences.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FindAllReferences.cs @@ -27,7 +27,10 @@ internal partial class RazorCustomMessageTarget ProjectContext = null, }, Position = request.ProjectedPosition, - Context = new ReferenceContext(), + Context = new ReferenceContext() + { + IncludeDeclaration = true + }, }; var response = await _requestInvoker.ReinvokeRequestOnServerAsync( diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/DataTipRangeHandlerEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/DataTipRangeHandlerEndpointTest.cs index 76079879557..3ed38060bde 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/DataTipRangeHandlerEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/DataTipRangeHandlerEndpointTest.cs @@ -2,11 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; -using Microsoft.CodeAnalysis.Testing; +using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Text; using Xunit; using Xunit.Abstractions; @@ -19,10 +18,10 @@ public sealed class DataTipRangeHandlerEndpointTest(ITestOutputHelper testOutput public async Task Handle_CSharpInHtml_DataTipRange_FirstExpression() { var input = """ - @{ - {|expression:{|hover:a$$aa|}|}.bbb.ccc; - } - """; + @{ + {|expression:{|hover:a$$aa|}|}.bbb.ccc; + } + """; await VerifyDataTipRangeAsync(input); } @@ -31,10 +30,10 @@ public async Task Handle_CSharpInHtml_DataTipRange_FirstExpression() public async Task Handle_CSharpInHtml_DataTipRange_SecondExpression() { var input = """ - @{ - {|expression:{|hover:aaa.b$$bb|}|}.ccc; - } - """; + @{ + {|expression:{|hover:aaa.b$$bb|}|}.ccc; + } + """; await VerifyDataTipRangeAsync(input); } @@ -43,10 +42,10 @@ public async Task Handle_CSharpInHtml_DataTipRange_SecondExpression() public async Task Handle_CSharpInHtml_DataTipRange_LastExpression() { var input = """ - @{ - {|expression:{|hover:aaa.bbb.c$$cc|}|}; - } - """; + @{ + {|expression:{|hover:aaa.bbb.c$$cc|}|}; + } + """; await VerifyDataTipRangeAsync(input); } @@ -55,41 +54,36 @@ public async Task Handle_CSharpInHtml_DataTipRange_LastExpression() public async Task Handle_CSharpInHtml_DataTipRange_LinqExpression() { var input = """ - @using System.Linq; + @using System.Linq; - @{ - int[] args; - var v = {|expression:{|hover:args.Se$$lect|}(a => a.ToString())|}.Where(a => a.Length >= 0); - } - """; + @{ + int[] args; + var v = {|expression:{|hover:args.Se$$lect|}(a => a.ToString())|}.Where(a => a.Length >= 0); + } + """; await VerifyDataTipRangeAsync(input, VSInternalDataTipTags.LinqExpression); } - private async Task VerifyDataTipRangeAsync(string input, VSInternalDataTipTags dataTipTags = 0) + private async Task VerifyDataTipRangeAsync(TestCode input, VSInternalDataTipTags dataTipTags = 0) { // Arrange - TestFileMarkupParser.GetPositionAndSpans(input, out var output, out int position, out ImmutableDictionary> spans); - - Assert.True(spans.TryGetValue("expression", out var expressionSpans), "Test authoring failure: Expected at least one span named 'expression'."); - Assert.True(expressionSpans.Length == 1, "Test authoring failure: Expected only one 'expression' span."); - Assert.True(spans.TryGetValue("hover", out var hoverSpans), "Test authoring failure: Expected at least one span named 'hover'."); - Assert.True(hoverSpans.Length == 1, "Test authoring failure: Expected only one 'hover' span."); - - var codeDocument = CreateCodeDocument(output); + var codeDocument = CreateCodeDocument(input.Text); var razorFilePath = "C:/path/to/file.razor"; // Act - var result = await GetDataTipRangeAsync(codeDocument, razorFilePath, position); + var result = await GetDataTipRangeAsync(codeDocument, razorFilePath, input.Position); // Assert - var expectedExpressionRange = codeDocument.Source.Text.GetRange(expressionSpans[0]); + var expectedExpressionSpan = input.GetNamedSpans("expression")[0]; + var expectedExpressionRange = codeDocument.Source.Text.GetRange(expectedExpressionSpan); Assert.Equal(expectedExpressionRange, result!.ExpressionRange); - var expectedHoverRange = codeDocument.Source.Text.GetRange(hoverSpans[0]); - Assert.Equal(expectedHoverRange, result!.HoverRange); + var expectedHoverSpan = input.GetNamedSpans("hover")[0]; + var expectedHoverRange = codeDocument.Source.Text.GetRange(expectedHoverSpan); + Assert.Equal(expectedHoverRange, result.HoverRange); - Assert.Equal(dataTipTags, result!.DataTipTags); + Assert.Equal(dataTipTags, result.DataTipTags); } private async Task GetDataTipRangeAsync(RazorCodeDocument codeDocument, string razorFilePath, int position) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs index 8b653606562..ca61a460e92 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs @@ -252,6 +252,9 @@ private Task HandleReferencesAsync(TParams @ }, Position = delegatedParams.ProjectedPosition, Context = new ReferenceContext() + { + IncludeDeclaration = true + }, }; return _csharpServer.ExecuteRequestAsync( diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDataTipRangeEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDataTipRangeEndpointTest.cs new file mode 100644 index 00000000000..09c0182726b --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDataTipRangeEndpointTest.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Test.Common; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; + +public sealed class CohostDataTipRangeEndpointTest(ITestOutputHelper testOutputHelper) : CohostEndpointTestBase(testOutputHelper) +{ + [Fact] + public async Task Handle_CSharpInHtml_DataTipRange_FirstExpression() + { + var input = """ + @{ + {|expression:{|hover:a$$aa|}|}.bbb.ccc; + } + """; + + await VerifyDataTipRangeAsync(input); + } + + [Fact] + public async Task Handle_CSharpInHtml_DataTipRange_SecondExpression() + { + var input = """ + @{ + {|expression:{|hover:aaa.b$$bb|}|}.ccc; + } + """; + + await VerifyDataTipRangeAsync(input); + } + + [Fact] + public async Task Handle_CSharpInHtml_DataTipRange_LastExpression() + { + var input = """ + @{ + {|expression:{|hover:aaa.bbb.c$$cc|}|}; + } + """; + + await VerifyDataTipRangeAsync(input); + } + + [Fact] + public async Task Handle_CSharpInHtml_DataTipRange_LinqExpression() + { + var input = """ + @using System.Linq; + + @{ + int[] args; + var v = {|expression:{|hover:args.Se$$lect|}(a => a.ToString())|}.Where(a => a.Length >= 0); + } + """; + + await VerifyDataTipRangeAsync(input, VSInternalDataTipTags.LinqExpression); + } + + private async Task VerifyDataTipRangeAsync(TestCode input, VSInternalDataTipTags dataTipTags = 0) + { + var document = CreateProjectAndRazorDocument(input.Text); + var inputText = await document.GetTextAsync(DisposalToken); + var position = inputText.GetPosition(input.Position); + + var endpoint = new CohostDataTipRangeEndpoint(IncompatibleProjectService, RemoteServiceInvoker); + + var result = await endpoint.GetTestAccessor().HandleRequestAsync(document, position, DisposalToken); + + Assumes.NotNull(result); + + var expectedExpressionSpan = input.GetNamedSpans("expression")[0]; + var expectedExpressionRange = inputText.GetRange(expectedExpressionSpan); + Assert.Equal(expectedExpressionRange, result.ExpressionRange); + + var expectedHoverSpan = input.GetNamedSpans("hover")[0]; + var expectedHoverRange = inputText.GetRange(expectedHoverSpan); + Assert.Equal(expectedHoverRange, result.HoverRange); + + Assert.Equal(dataTipTags, result.DataTipTags); + } +}