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