diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/CodeGeneration/CSharpCodeWriterTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/CodeGeneration/CSharpCodeWriterTest.cs index 2d2133483bc..ad130db29d9 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/CodeGeneration/CSharpCodeWriterTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/CodeGeneration/CSharpCodeWriterTest.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Razor.Language.Intermediate; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration; @@ -439,4 +440,46 @@ class C """, output); } + + [Fact, WorkItem("https://github.com/dotnet/core/issues/9885")] + public void AlignedPages_WritesCorrectlyWhenPageAndBufferAreAligned() + { + var pages = new LinkedList[]>(); + + const string FirstLine = "First Line"; + pages.AddLast([(FirstLine + FirstLine).AsMemory(), "Second".AsMemory()]); + + var testReader = CodeWriter.GetTestTextReader(pages); + var output = new char[FirstLine.Length]; + + testReader.Read(output, 0, output.Length); + Assert.Equal(FirstLine, string.Join("", output)); + Array.Clear(output, 0, output.Length); + + testReader.Read(output, 0, output.Length); + Assert.Equal(FirstLine, string.Join("", output)); + Array.Clear(output, 0, output.Length); + + testReader.Read(output, 0, output.Length); + Assert.Equal("Second\0\0\0\0", string.Join("", output)); + } + + [Fact] + public void ReaderOnlyReadsAsMuchAsRequested() + { + var pages = new LinkedList[]>(); + + const string FirstLine = "First Line"; + pages.AddLast([FirstLine.AsMemory()]); + + var testReader = CodeWriter.GetTestTextReader(pages); + var output = new char[FirstLine.Length]; + + testReader.Read(output, 0, 2); + Assert.Equal("Fi\0\0\0\0\0\0\0\0", string.Join("", output)); + Array.Clear(output, 0, output.Length); + + testReader.Read(output, 0, output.Length); + Assert.Equal("rst Line\0\0", string.Join("", output)); + } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/CodeGeneration/CodeWriter.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/CodeGeneration/CodeWriter.cs index cff8797938a..1496438f940 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/CodeGeneration/CodeWriter.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/CodeGeneration/CodeWriter.cs @@ -323,14 +323,20 @@ public CodeWriter WriteLine([InterpolatedStringHandlerArgument("")] ref WriteInt public SourceText GetText() { - using var reader = new Reader(this); + using var reader = new Reader(_pages, Length); return SourceText.From(reader, Length, Encoding.UTF8); } - private sealed class Reader(CodeWriter codeWriter) : TextReader + // Internal for testing + internal static TextReader GetTestTextReader(LinkedList[]> pages) { - private LinkedListNode[]>? _page = codeWriter._pages.First; - private int _remainingLength = codeWriter.Length; + return new Reader(pages, pages.Count); + } + + private sealed class Reader(LinkedList[]> pages, int length) : TextReader + { + private LinkedListNode[]>? _page = pages.First; + private int _remainingLength = length; private int _chunkIndex; private int _charIndex; @@ -413,7 +419,7 @@ public override int Read(char[] buffer, int index, int count) return -1; } - var destination = buffer.AsSpan(index); + var destination = buffer.AsSpan(index, count); var charsWritten = 0; var page = _page; @@ -443,18 +449,17 @@ public override int Read(char[] buffer, int index, int count) } } - var endOfChunkWritten = true; - // Are we about to write past the end of the buffer? If so, adjust source. // This will be the last chunk we write, so be sure to update charIndex. if (source.Length > destination.Length) { source = source[..destination.Length]; charIndex += source.Length; - - // There's more to this chunk to write! Note this so that we don't update - // chunkIndex later. - endOfChunkWritten = false; + } + else + { + chunkIndex++; + charIndex = 0; } source.CopyTo(destination); @@ -462,19 +467,11 @@ public override int Read(char[] buffer, int index, int count) charsWritten += source.Length; - // Be careful not to increment chunkIndex unless we actually wrote to the end of the chunk. - if (endOfChunkWritten) - { - chunkIndex++; - } - // Break if we are done writing. chunkIndex and charIndex should have their correct values at this point. if (destination.IsEmpty) { break; } - - charIndex = 0; } if (destination.IsEmpty)