Skip to content

Commit 94cbd0b

Browse files
authored
Preserve encoding during DocumentState updates (#77354)
Fixes dotnet/sdk#46780 This issue was introduced by #74623, which changed `Document.WithSyntaxRoot` to always use the encoding specified by the new syntax root. APIs like SyntaxRewriter do not preserve the input encoding during node rewrites, so `Formatter.Format` would overwrite the document syntax root with a node that did not specify any encoding. The fix _allows_ `WithSyntaxRoot` to specify a new encoding, but for cases where the encoding of the new syntax root is not known, we fall back to the original behavior of preserving the encoding from the previous root and/or document text.
2 parents 9e6dca8 + 908cf87 commit 94cbd0b

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,20 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode)
497497

498498
// use the encoding that we get from the new root
499499
var encoding = newRoot.SyntaxTree.Encoding;
500+
if (encoding is null)
501+
{
502+
// The new tree doesn't specify an encoding. For these cases, continue to use the previous encoding of the
503+
// document.
504+
if (TryGetSyntaxTree(out var priorTree))
505+
{
506+
// this is most likely available since UpdateTree is normally called after modifying the existing tree.
507+
encoding = priorTree.Encoding;
508+
}
509+
else if (TryGetText(out var priorText))
510+
{
511+
encoding = priorText.Encoding;
512+
}
513+
}
500514

501515
var syntaxTreeFactory = LanguageServices.GetRequiredService<ISyntaxTreeFactoryService>();
502516

src/Workspaces/MSBuild/Test/VisualStudioMSBuildWorkspaceTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2898,13 +2898,14 @@ class C { }";
28982898
Assert.Equal(encoding.EncodingName, text.Encoding.EncodingName);
28992899
Assert.Equal(fileContent, text.ToString());
29002900

2901-
// update root blindly again, after observing encoding, see that encoding is overridden to null
2901+
// update root blindly again, after observing encoding, see that encoding is preserved
2902+
// 🐉 Tools rely on encoding preservation; see https://github.com/dotnet/sdk/issues/46780
29022903
var doc3 = document.WithSyntaxRoot(gen.CompilationUnit()); // empty CU
29032904
var doc3text = await doc3.GetTextAsync();
2904-
Assert.Null(doc3text.Encoding);
2905+
Assert.Same(text.Encoding, doc3text.Encoding);
29052906
var doc3tree = await doc3.GetSyntaxTreeAsync();
2906-
Assert.Null(doc3tree.Encoding);
2907-
Assert.Null(doc3tree.GetText().Encoding);
2907+
Assert.Same(text.Encoding, doc3tree.Encoding);
2908+
Assert.Same(text.Encoding, doc3tree.GetText().Encoding);
29082909

29092910
// change doc to have no encoding, still succeeds at writing to disk with old encoding
29102911
var root = await document.GetSyntaxRootAsync();

0 commit comments

Comments
 (0)