Restoring usage of LocateOwner in legacy-only completion scenarios (#9877)

* Restoring usage of LocateOwner in legacy-only scenarios

We want to continue using LocateOwner for legacy code as the logic in FindInnermostNode isn't finding the correct node here.

* Adding unit test
This commit is contained in:
Alex Gavrilov 2024-01-30 00:11:35 -08:00
Родитель df383360c3
Коммит 0784964473
3 изменённых файлов: 23 добавлений и 7 удалений

Просмотреть файл

@ -4,14 +4,15 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.CodeAnalysis.Razor.Tooltip;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.VisualStudio.Core.Imaging;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion;
@ -64,6 +65,8 @@ internal class RazorDirectiveAttributeCompletionSource : IAsyncCompletionSource
{
try
{
Debug.Assert(triggerLocation.Snapshot.TextBuffer.IsLegacyCoreRazorBuffer());
var codeDocument = await _parser.GetLatestCodeDocumentAsync(triggerLocation.Snapshot, token);
if (codeDocument is null)
{
@ -74,7 +77,10 @@ internal class RazorDirectiveAttributeCompletionSource : IAsyncCompletionSource
var syntaxTree = codeDocument.GetSyntaxTree();
var tagHelperDocumentContext = codeDocument.GetTagHelperContext();
var absoluteIndex = triggerLocation.Position;
var owner = syntaxTree.Root.FindInnermostNode(absoluteIndex, includeWhitespace: true, walkMarkersBack: true);
var queryableChange = new SourceChange(absoluteIndex, length: 0, newText: string.Empty);
#pragma warning disable CS0618 // Type or member is obsolete, will be removed in an upcoming change
var owner = syntaxTree.Root.LocateOwner(queryableChange);
#pragma warning restore CS0618 // Type or member is obsolete
var razorCompletionContext = new RazorCompletionContext(absoluteIndex, owner, syntaxTree, tagHelperDocumentContext);
var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext);

Просмотреть файл

@ -3,12 +3,13 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.VisualStudio.Core.Imaging;
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion;
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data;
@ -62,6 +63,8 @@ internal class RazorDirectiveCompletionSource : IAsyncCompletionSource
{
try
{
Debug.Assert(triggerLocation.Snapshot.TextBuffer.IsLegacyCoreRazorBuffer());
var codeDocument = await Parser.GetLatestCodeDocumentAsync(triggerLocation.Snapshot, token);
if (codeDocument is null)
{
@ -72,7 +75,10 @@ internal class RazorDirectiveCompletionSource : IAsyncCompletionSource
var syntaxTree = codeDocument.GetSyntaxTree();
var tagHelperDocumentContext = codeDocument.GetTagHelperContext();
var absoluteIndex = triggerLocation.Position;
var owner = syntaxTree.Root.FindInnermostNode(absoluteIndex, includeWhitespace: true, walkMarkersBack: true);
var queryableChange = new SourceChange(absoluteIndex, length: 0, newText: string.Empty);
#pragma warning disable CS0618 // Type or member is obsolete, will be removed in an upcoming change
var owner = syntaxTree.Root.LocateOwner(queryableChange);
#pragma warning restore CS0618 // Type or member is obsolete
var razorCompletionContext = new RazorCompletionContext(absoluteIndex, owner, syntaxTree, tagHelperDocumentContext);
var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext);

Просмотреть файл

@ -53,6 +53,7 @@ public class RazorDirectiveCompletionSourceTest : ProjectSnapshotManagerDispatch
.ReturnsAsync(value: null); // CodeDocument will be null faking a parser without a parse.
var completionSource = new RazorDirectiveCompletionSource(parser.Object, _completionFactsService);
var documentSnapshot = new StringTextSnapshot(text);
var textBuffer = new TestTextBuffer(documentSnapshot, new LegacyCoreContentType());
var triggerLocation = new SnapshotPoint(documentSnapshot, 4);
var applicableSpan = new SnapshotSpan(documentSnapshot, new Span(1, text.Length - 1 /* validCompletion */));
@ -77,6 +78,7 @@ public class RazorDirectiveCompletionSourceTest : ProjectSnapshotManagerDispatch
var parser = CreateParser(text);
var completionSource = new RazorDirectiveCompletionSource(parser, _completionFactsService);
var documentSnapshot = new StringTextSnapshot(text);
var textBuffer = new TestTextBuffer(documentSnapshot, new LegacyCoreContentType());
var triggerLocation = new SnapshotPoint(documentSnapshot, 4);
var applicableSpan = new SnapshotSpan(documentSnapshot, new Span(2, text.Length - 3 /* @() */));
@ -94,15 +96,17 @@ public class RazorDirectiveCompletionSourceTest : ProjectSnapshotManagerDispatch
}
// This is more of an integration level test validating the end-to-end completion flow.
[UIFact]
[UITheory]
[InlineData("@")]
[InlineData("@\r\n")]
[WorkItem("https://github.com/dotnet/razor-tooling/issues/4547")]
public async Task GetCompletionContextAsync_ProvidesCompletionsWhenAtCompletionPoint()
public async Task GetCompletionContextAsync_ProvidesCompletionsWhenAtCompletionPoint(string text)
{
// Arrange
var text = "@";
var parser = CreateParser(text, SectionDirective.Directive);
var completionSource = new RazorDirectiveCompletionSource(parser, _completionFactsService);
var documentSnapshot = new StringTextSnapshot(text);
var textBuffer = new TestTextBuffer(documentSnapshot, new LegacyCoreContentType());
var triggerLocation = new SnapshotPoint(documentSnapshot, 1);
var applicableSpan = new SnapshotSpan(documentSnapshot, new Span(1, 0));