-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add server side support for refreshing source generated files (#75939)
Client side PR - dotnet/vscode-csharp#7791 Implements support for refreshing source generated files provided by LSP. Refresh notifications are sent to the client based on workspace changes that may affect source generated files. To handle the overreporting of refresh notifications, I also implemented resultId based support in the get text handler - it will now avoid re-sending the entire text to the client if nothing has changed. ![sg_refresh](https://github.com/user-attachments/assets/065a8532-56c7-4e45-a559-0a451d37697a)
- Loading branch information
Showing
11 changed files
with
491 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentCache.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Composition; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Roslyn.Utilities; | ||
|
||
namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SourceGenerators; | ||
|
||
internal record struct SourceGeneratedDocumentGetTextState(Document Document); | ||
|
||
internal sealed class SourceGeneratedDocumentCache(string uniqueKey) : VersionedPullCache<(SourceGeneratorExecutionVersion, VersionStamp), object?, SourceGeneratedDocumentGetTextState, SourceText?>(uniqueKey), ILspService | ||
{ | ||
public override async Task<(SourceGeneratorExecutionVersion, VersionStamp)> ComputeCheapVersionAsync(SourceGeneratedDocumentGetTextState state, CancellationToken cancellationToken) | ||
{ | ||
// The execution version and the dependent version must be considered as one version cached together - | ||
// it is not correct to say that if the execution version is the same then we can re-use results (as in automatic mode the execution version never changes). | ||
var executionVersion = state.Document.Project.Solution.GetSourceGeneratorExecutionVersion(state.Document.Project.Id); | ||
var dependentVersion = await state.Document.Project.GetDependentVersionAsync(cancellationToken).ConfigureAwait(false); | ||
return (executionVersion, dependentVersion); | ||
} | ||
|
||
public override Task<object?> ComputeExpensiveVersionAsync(SourceGeneratedDocumentGetTextState state, CancellationToken cancellationToken) | ||
{ | ||
return SpecializedTasks.Null<object>(); | ||
} | ||
|
||
public override Checksum ComputeChecksum(SourceText? data) | ||
{ | ||
return data is null ? Checksum.Null : Checksum.From(data.GetChecksum()); | ||
} | ||
|
||
public override async Task<SourceText?> ComputeDataAsync(SourceGeneratedDocumentGetTextState state, CancellationToken cancellationToken) | ||
{ | ||
// When a user has a open source-generated file, we ensure that the contents in the LSP snapshot match the contents that we | ||
// get through didOpen/didChanges, like any other file. That way operations in LSP file are in sync with the | ||
// contents the user has. However in this case, we don't want to look at that frozen text, but look at what the | ||
// generator would generate if we ran it again. Otherwise, we'll get "stuck" and never update the file with something new. | ||
// This can return null when the source generated file has been removed (but the queue itself is using the frozen non-null document). | ||
var unfrozenDocument = await state.Document.Project.Solution.WithoutFrozenSourceGeneratedDocuments().GetDocumentAsync(state.Document.Id, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); | ||
return unfrozenDocument == null | ||
? null | ||
: await unfrozenDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); | ||
} | ||
} | ||
|
||
[ExportCSharpVisualBasicLspServiceFactory(typeof(SourceGeneratedDocumentCache)), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal sealed class SourceGeneratedDocumentCacheFactory() : ILspServiceFactory | ||
{ | ||
public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) | ||
{ | ||
return new SourceGeneratedDocumentCache(this.GetType().Name); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 14 additions & 2 deletions
16
src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentText.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,21 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Text.Json.Serialization; | ||
|
||
namespace Microsoft.CodeAnalysis.LanguageServer.Handler; | ||
|
||
internal sealed record SourceGeneratedDocumentText([property: JsonPropertyName("text")] string? Text); | ||
/// <summary> | ||
/// Source generated file text result. The client uses the resultId to inform what the text value is. | ||
/// | ||
/// An unchanged result has a non-null resultId (same as client request resultId) + null text. | ||
/// | ||
/// A changed result has a new non-null resultId + possibly null text (if the sg document no longer exists). | ||
/// | ||
/// In rare circumstances it is possible to get a null resultId + null text - this happens when | ||
/// the source generated document is not open AND the source generated document no longer exists | ||
/// </summary> | ||
internal sealed record SourceGeneratedDocumentText( | ||
[property: JsonPropertyName("resultId")] string? ResultId, | ||
[property: JsonPropertyName("text")] string? Text); |
8 changes: 5 additions & 3 deletions
8
src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorGetTextParams.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Text.Json.Serialization; | ||
using Roslyn.LanguageServer.Protocol; | ||
|
||
namespace Microsoft.CodeAnalysis.LanguageServer.Handler; | ||
namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SourceGenerators; | ||
|
||
internal sealed record SourceGeneratorGetTextParams([property: JsonPropertyName("textDocument")] TextDocumentIdentifier TextDocument) : ITextDocumentParams; | ||
internal sealed record SourceGeneratorGetTextParams( | ||
[property: JsonPropertyName("textDocument")] TextDocumentIdentifier TextDocument, | ||
[property: JsonPropertyName("resultId")] string? ResultId) : ITextDocumentParams; |
Oops, something went wrong.