From 4d8b8a6f39f725627af661bfc87a20fe0a976ffc Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 8 May 2024 19:04:02 -0700 Subject: [PATCH] Merge touch document actions --- ...pilationState.TranslationAction_Actions.cs | 87 +++++-------------- .../Solution/SolutionCompilationState.cs | 8 +- 2 files changed, 24 insertions(+), 71 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs index 572aaa4cb182..cb8e4c37c351 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; @@ -15,24 +16,29 @@ internal partial class SolutionCompilationState { private abstract partial class TranslationAction { - internal sealed class TouchDocumentAction( + internal sealed class TouchDocumentsAction( ProjectState oldProjectState, ProjectState newProjectState, - DocumentState oldState, - DocumentState newState) - : TranslationAction(oldProjectState, newProjectState) + ImmutableArray newStates) : TranslationAction(oldProjectState, newProjectState) { - private readonly DocumentState _oldState = oldState; - private readonly DocumentState _newState = newState; + private readonly ImmutableArray _oldStates = newStates.SelectAsArray(s => oldProjectState.DocumentStates.GetRequiredState(s.Id)); + private readonly ImmutableArray _newStates = newStates; public override async Task TransformCompilationAsync(Compilation oldCompilation, CancellationToken cancellationToken) { - return oldCompilation.ReplaceSyntaxTree( - await _oldState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false), - await _newState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); - } + var finalCompilation = oldCompilation; + for (int i = 0, n = _newStates.Length; i < n; i++) + { + cancellationToken.ThrowIfCancellationRequested(); + var newState = _newStates[i]; + var oldState = _oldStates[i]; + finalCompilation = finalCompilation.ReplaceSyntaxTree( + await oldState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false), + await newState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); + } - public DocumentId DocumentId => _newState.Attributes.Id; + return finalCompilation; + } /// /// Replacing a single tree doesn't impact the generated trees in a compilation, so we can use this against @@ -45,71 +51,18 @@ public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generat public override TranslationAction? TryMergeWithPrior(TranslationAction priorAction) { - if (priorAction is TouchDocumentAction priorTouchAction && - priorTouchAction._newState == _oldState) + if (priorAction is TouchDocumentsAction priorTouchAction && + priorTouchAction._newStates.SequenceEqual(_oldStates)) { // As we're merging ourselves with the prior touch action, we want to keep the old project state // that we are translating from. - return new TouchDocumentAction(priorAction.OldProjectState, this.NewProjectState, priorTouchAction._oldState, _newState); + return new TouchDocumentsAction(priorAction.OldProjectState, this.NewProjectState, _newStates); } return null; } } - internal sealed class TouchDocumentsAction : TranslationAction - { - private readonly ImmutableArray _newStates; - - private TouchDocumentsAction( - ProjectState oldProjectState, - ProjectState newProjectState, - ImmutableArray newStates) - : base(oldProjectState, newProjectState) - { - _newStates = newStates; - } - - public static TranslationAction Create( - ProjectState oldProjectState, - ProjectState newProjectState, - ImmutableArray newStates) - { - // Special case when we're only updating a single document. This case can be optimized more, and - // corresponds to the common case of a single file being edited. - return newStates.Length == 1 - ? new TouchDocumentAction(oldProjectState, newProjectState, oldProjectState.DocumentStates.GetRequiredState(newStates[0].Id), newStates[0]) - : new TouchDocumentsAction(oldProjectState, newProjectState, newStates); - } - - public override async Task TransformCompilationAsync(Compilation oldCompilation, CancellationToken cancellationToken) - { - var finalCompilation = oldCompilation; - for (int i = 0, n = _newStates.Length; i < n; i++) - { - cancellationToken.ThrowIfCancellationRequested(); - var newState = _newStates[i]; - var oldState = this.OldProjectState.DocumentStates.GetRequiredState(newState.Id); - finalCompilation = finalCompilation.ReplaceSyntaxTree( - await oldState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false), - await newState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); - } - - return finalCompilation; - } - - /// - public override bool CanUpdateCompilationWithStaleGeneratedTreesIfGeneratorsGiveSameOutput - => true; - - /// - public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generatorDriver) - => generatorDriver; - - public override TranslationAction? TryMergeWithPrior(TranslationAction priorAction) - => null; - } - internal sealed class TouchAdditionalDocumentAction( ProjectState oldProjectState, ProjectState newProjectState, diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs index 779dda124c3f..bac6a494cd71 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs @@ -735,7 +735,7 @@ internal SolutionCompilationState WithDocumentTexts( }), static (projectState, newDocumentStates) => { - return TranslationAction.TouchDocumentsAction.Create( + return new TranslationAction.TouchDocumentsAction( projectState, projectState.UpdateDocuments(newDocumentStates, contentChanged: true), newDocumentStates); @@ -816,7 +816,7 @@ public SolutionCompilationState WithDocumentSyntaxRoots(ImmutableArray<(Document }), static (projectState, newDocumentStates) => { - return TranslationAction.TouchDocumentsAction.Create( + return new TranslationAction.TouchDocumentsAction( projectState, projectState.UpdateDocuments(newDocumentStates, contentChanged: true), newDocumentStates); @@ -899,10 +899,10 @@ private SolutionCompilationState UpdateDocumentState(StateChange stateChange, Do // This function shouldn't have been called if the document has not changed Debug.Assert(stateChange.OldProjectState != stateChange.NewProjectState); - var oldDocument = stateChange.OldProjectState.DocumentStates.GetRequiredState(documentId); var newDocument = stateChange.NewProjectState.DocumentStates.GetRequiredState(documentId); - return new TranslationAction.TouchDocumentAction(stateChange.OldProjectState, stateChange.NewProjectState, oldDocument, newDocument); + return new TranslationAction.TouchDocumentsAction( + stateChange.OldProjectState, stateChange.NewProjectState, [newDocument]); }, forkTracker: true, arg: documentId);