Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't use project engines directly in the language server #9836

Merged
merged 5 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,12 @@ public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? res
result = _codeDocument;
return result is not null;
}

public IDocumentSnapshot WithText(SourceText text)
{
var id = _textDocument.Id;
var newDocument = _textDocument.Project.Solution.WithAdditionalDocumentText(id, text).GetAdditionalDocument(id).AssumeNotNull();

return new CohostDocumentSnapshot(newDocument, _projectSnapshot);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
Expand All @@ -27,8 +26,6 @@ internal class FormattingContext : IDisposable

private IReadOnlyList<FormattingSpan>? _formattingSpans;
private IReadOnlyDictionary<int, IndentationContext>? _indentations;
private RazorProjectEngine? _engine;
private ImmutableArray<RazorSourceDocument> _importSources;

private FormattingContext(AdhocWorkspaceFactory workspaceFactory, Uri uri, IDocumentSnapshot originalSnapshot, RazorCodeDocument codeDocument, FormattingOptions options,
bool isFormatOnType, bool automaticallyAddUsings, int hostDocumentIndex, char triggerCharacter)
Expand All @@ -44,14 +41,6 @@ private FormattingContext(AdhocWorkspaceFactory workspaceFactory, Uri uri, IDocu
TriggerCharacter = triggerCharacter;
}

private FormattingContext(RazorProjectEngine engine, ImmutableArray<RazorSourceDocument> importSources, AdhocWorkspaceFactory workspaceFactory, Uri uri, IDocumentSnapshot originalSnapshot, RazorCodeDocument codeDocument, FormattingOptions options,
bool isFormatOnType, bool automaticallyAddUsings, int hostDocumentIndex, char triggerCharacter)
: this(workspaceFactory, uri, originalSnapshot, codeDocument, options, isFormatOnType, automaticallyAddUsings, hostDocumentIndex, triggerCharacter)
{
_engine = engine;
_importSources = importSources;
}

public static bool SkipValidateComponents { get; set; }

public Uri Uri { get; }
Expand Down Expand Up @@ -281,22 +270,13 @@ public async Task<FormattingContext> WithTextAsync(SourceText changedText)
throw new ArgumentNullException(nameof(changedText));
}

if (_engine is null)
{
await InitializeProjectEngineAsync().ConfigureAwait(false);
}

Assumes.NotNull(_engine);

var changedSourceDocument = RazorSourceDocument.Create(changedText, RazorSourceDocumentProperties.Create(OriginalSnapshot.FilePath, OriginalSnapshot.TargetPath));
var changedSnapshot = OriginalSnapshot.WithText(changedText);

var codeDocument = _engine.ProcessDesignTime(changedSourceDocument, OriginalSnapshot.FileKind, _importSources, OriginalSnapshot.Project.TagHelpers);
var codeDocument = await changedSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false);

DEBUG_ValidateComponents(CodeDocument, codeDocument);

var newContext = new FormattingContext(
_engine,
_importSources!,
_workspaceFactory,
Uri,
OriginalSnapshot,
Expand All @@ -310,24 +290,6 @@ public async Task<FormattingContext> WithTextAsync(SourceText changedText)
return newContext;
}

private async Task InitializeProjectEngineAsync()
{
var engine = OriginalSnapshot.Project.GetProjectEngine();

var imports = OriginalSnapshot.GetImports();
using var importSources = new PooledArrayBuilder<RazorSourceDocument>(imports.Length);

foreach (var import in imports)
{
var sourceText = await import.GetTextAsync().ConfigureAwait(false);
var source = RazorSourceDocument.Create(sourceText, RazorSourceDocumentProperties.Create(import.FilePath, import.TargetPath));
importSources.Add(source);
}

_engine = engine;
_importSources = importSources.DrainToImmutable();
}

/// <summary>
/// It can be difficult in the testing infrastructure to correct constructs input files that work consistently across
/// context changes, so this method validates that the number of components isn't changing due to lost tag help info.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
using Microsoft.AspNetCore.Razor.LanguageServer.Protocol;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CommonLanguageServerProtocol.Framework;
Expand Down Expand Up @@ -76,11 +75,12 @@ internal sealed class MapCodeEndpoint(
continue;
}

var (projectEngine, importSources) = await InitializeProjectEngineAsync(documentContext.Snapshot).ConfigureAwait(false);
var tagHelperContext = await documentContext.GetTagHelperContextAsync(cancellationToken).ConfigureAwait(false);
var fileKind = FileKinds.GetFileKindFromFilePath(documentContext.FilePath);
var extension = Path.GetExtension(documentContext.FilePath);

var snapshot = documentContext.Snapshot;

foreach (var content in mapping.Contents)
{
if (content is null)
Expand All @@ -89,8 +89,8 @@ internal sealed class MapCodeEndpoint(
}

// We create a new Razor file based on each content in each mapping order to get the syntax tree that we'll later use to map.
var sourceDocument = RazorSourceDocument.Create(content, "Test" + extension);
var codeToMap = projectEngine.ProcessDesignTime(sourceDocument, fileKind, importSources, tagHelperContext.TagHelpers);
var newSnapshot = snapshot.WithText(SourceText.From(content));
var codeToMap = await newSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false);

var mappingSuccess = await TryMapCodeAsync(
codeToMap, mapping.FocusLocations, changes, documentContext, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -241,24 +241,6 @@ private async Task<bool> TryMapCodeAsync(
return false;
}

private static async Task<(RazorProjectEngine projectEngine, ImmutableArray<RazorSourceDocument> importSources)> InitializeProjectEngineAsync(
IDocumentSnapshot originalSnapshot)
{
var engine = originalSnapshot.Project.GetProjectEngine();

var imports = originalSnapshot.GetImports();
using var importSources = new PooledArrayBuilder<RazorSourceDocument>(imports.Length);

foreach (var import in imports)
{
var sourceText = await import.GetTextAsync().ConfigureAwait(false);
var source = RazorSourceDocument.Create(sourceText, RazorSourceDocumentProperties.Create(import.FilePath, import.TargetPath));
importSources.Add(source);
}

return (engine, importSources.DrainToImmutable());
}

private static List<SyntaxNode> ExtractValidNodesToMap(SyntaxNode rootNode)
{
var validNodesToMap = new List<SyntaxNode>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ public virtual bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocum
result = null;
return false;
}

public IDocumentSnapshot WithText(SourceText text)
{
return new DocumentSnapshot(ProjectInternal, State.WithText(text, VersionStamp.Create()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ internal interface IDocumentSnapshot
bool TryGetText([NotNullWhen(true)] out SourceText? result);
bool TryGetTextVersion(out VersionStamp result);
bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result);

IDocumentSnapshot WithText(SourceText text);
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,7 @@ public bool TryGetTextVersion(out VersionStamp result)

public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result)
=> throw new NotSupportedException();

public IDocumentSnapshot WithText(SourceText text)
=> throw new NotSupportedException();
}
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ private async Task VerifyCSharpOnAutoInsertAsync(string input, string expected,
TestFileMarkupParser.GetPosition(input, out input, out var cursorPosition);

var codeDocument = CreateCodeDocument(input);
var razorFilePath = "file://path/test.razor";
var razorFilePath = "C:/path/test.razor";
var languageServer = await CreateLanguageServerAsync(codeDocument, razorFilePath);

var optionsMonitor = GetOptionsMonitor();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,7 @@ private async Task ValidateCodeActionAsync(
{
TestFileMarkupParser.GetSpan(input, out input, out var textSpan);

var razorFilePath = "file://C:/path/test.razor";
var razorFilePath = "C:/path/test.razor";
var codeDocument = CreateCodeDocument(input, filePath: razorFilePath);
var sourceText = codeDocument.GetSourceText();
var uri = new Uri(razorFilePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,6 @@ private static (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnaps
documentSnapshot
.Setup(d => d.GetGeneratedOutputAsync())
.ReturnsAsync(codeDocument);
documentSnapshot
.Setup(d => d.Project.GetProjectEngine())
.Returns(projectEngine);
documentSnapshot
.Setup(d => d.TargetPath)
.Returns(path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,29 +158,8 @@ private static (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnaps
var projectEngine = RazorProjectEngine.Create(builder => builder.SetRootNamespace("Test"));
var codeDocument = projectEngine.ProcessDesignTime(sourceDocument, fileKind, importSources: default, tagHelpers);

var documentSnapshot = new Mock<IDocumentSnapshot>(MockBehavior.Strict);
documentSnapshot
.Setup(d => d.GetImports())
.Returns(ImmutableArray<IDocumentSnapshot>.Empty);
documentSnapshot
.Setup(d => d.GetGeneratedOutputAsync())
.ReturnsAsync(codeDocument);
documentSnapshot
.Setup(d => d.Project.GetProjectEngine())
.Returns(projectEngine);
documentSnapshot
.Setup(d => d.TargetPath)
.Returns(path);
documentSnapshot
.Setup(d => d.Project.TagHelpers)
.Returns(tagHelpers);
documentSnapshot
.Setup(d => d.FileKind)
.Returns(fileKind);
documentSnapshot
.Setup(d => d.FilePath)
.Returns(path);

return (codeDocument, documentSnapshot.Object);
var documentSnapshot = FormattingTestBase.CreateDocumentSnapshot(path, tagHelpers, fileKind, ImmutableArray<RazorSourceDocument>.Empty, ImmutableArray<IDocumentSnapshot>.Empty, projectEngine, codeDocument);

return (codeDocument, documentSnapshot);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -267,16 +267,22 @@ @using Microsoft.AspNetCore.Components.Web
Assert.False(codeDocument.GetCSharpDocument().Diagnostics.Any(), "Error creating document:" + Environment.NewLine + string.Join(Environment.NewLine, codeDocument.GetCSharpDocument().Diagnostics));
}

var imports = ImmutableArray.Create(importsSnapshot.Object);
var importsDocuments = ImmutableArray.Create(importsDocument);
var documentSnapshot = CreateDocumentSnapshot(path, tagHelpers, fileKind, importsDocuments, imports, projectEngine, codeDocument);

return (codeDocument, documentSnapshot);
}

internal static IDocumentSnapshot CreateDocumentSnapshot(string path, ImmutableArray<TagHelperDescriptor> tagHelpers, string? fileKind, ImmutableArray<RazorSourceDocument> importsDocuments, ImmutableArray<IDocumentSnapshot> imports, RazorProjectEngine projectEngine, RazorCodeDocument codeDocument)
{
var documentSnapshot = new Mock<IDocumentSnapshot>(MockBehavior.Strict);
documentSnapshot
.Setup(d => d.GetGeneratedOutputAsync())
.ReturnsAsync(codeDocument);
documentSnapshot
.Setup(d => d.GetImports())
.Returns(ImmutableArray.Create(importsSnapshot.Object));
documentSnapshot
.Setup(d => d.Project.GetProjectEngine())
.Returns(projectEngine);
.Returns(imports);
documentSnapshot
.Setup(d => d.FilePath)
.Returns(path);
Expand All @@ -292,7 +298,14 @@ @using Microsoft.AspNetCore.Components.Web
documentSnapshot
.Setup(d => d.FileKind)
.Returns(fileKind);

return (codeDocument, documentSnapshot.Object);
documentSnapshot
.Setup(d => d.WithText(It.IsAny<SourceText>()))
.Returns<SourceText>(text =>
{
var sourceDocument = RazorSourceDocument.Create(text, RazorSourceDocumentProperties.Create(path, path));
var codeDocument = projectEngine.ProcessDesignTime(sourceDocument, fileKind, importsDocuments, tagHelpers);
return CreateDocumentSnapshot(path, tagHelpers, fileKind, importsDocuments, imports, projectEngine, codeDocument);
});
return documentSnapshot.Object;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
using Microsoft.AspNetCore.Razor.LanguageServer.Protocol;
using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer;
using Microsoft.AspNetCore.Razor.Test.Common.Mef;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Text;
Expand Down