diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs
index e4b128860bafd..b0d05af388885 100644
--- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs
@@ -708,20 +708,13 @@ public SolutionCompilationState WithDocumentFilePath(
this.SolutionState.WithDocumentFilePath(documentId, filePath), documentId);
}
- ///
- public SolutionCompilationState WithDocumentText(DocumentId documentId, SourceText text, PreservationMode mode)
- => WithDocumentTexts([(documentId, text, mode)]);
-
- internal SolutionCompilationState WithDocumentTexts(
- ImmutableArray<(DocumentId documentId, SourceText text, PreservationMode mode)> texts)
- {
- return WithDocumentContents(
- texts, IsUnchanged,
+ internal SolutionCompilationState WithDocumentTexts(ImmutableArray<(DocumentId documentId, SourceText text, PreservationMode mode)> texts)
+ => WithDocumentContents(
+ texts, SourceTextIsUnchanged,
static (documentState, text, mode) => documentState.UpdateText(text, mode));
- static bool IsUnchanged(DocumentState oldDocument, SourceText text)
- => oldDocument.TryGetText(out var oldText) && text == oldText;
- }
+ private static bool SourceTextIsUnchanged(DocumentState oldDocument, SourceText text)
+ => oldDocument.TryGetText(out var oldText) && text == oldText;
private SolutionCompilationState WithDocumentContents(
ImmutableArray<(DocumentId documentId, TContent content, PreservationMode mode)> texts,
@@ -1658,7 +1651,7 @@ public SolutionCompilationState WithCachedSourceGeneratorState(ProjectId project
///
public SolutionCompilationState WithDocumentText(IEnumerable documentIds, SourceText text, PreservationMode mode)
{
- var result = this;
+ using var _ = ArrayBuilder<(DocumentId, SourceText, PreservationMode)>.GetInstance(out var changedDocuments);
foreach (var documentId in documentIds)
{
@@ -1670,10 +1663,22 @@ public SolutionCompilationState WithDocumentText(IEnumerable docume
var documentState = this.SolutionState.GetProjectState(documentId.ProjectId)?.DocumentStates.GetState(documentId);
if (documentState != null)
- result = result.WithDocumentText(documentId, text, mode);
+ {
+ // before allocating an array below (and calling into a function that does a fair amount of linq work),
+ // do a fast check if the text has actually changed. this shows up in allocation traces and is
+ // worthwhile to avoid for the common case where we're continually being asked to update the same doc to
+ // the same text (for example, when GetOpenDocumentInCurrentContextWithChanges) is called.
+ //
+ // The use of GetRequiredState mirrors what happens in WithDocumentTexts
+ if (!SourceTextIsUnchanged(documentState, text))
+ changedDocuments.Add((documentId, text, mode));
+ }
}
- return result;
+ if (changedDocuments.Count == 0)
+ return this;
+
+ return this.WithDocumentTexts(changedDocuments.ToImmutableAndClear());
}
internal TestAccessor GetTestAccessor()