diff --git a/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs b/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs index 7ff495f..4698c6b 100644 --- a/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs +++ b/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs @@ -78,6 +78,7 @@ public void AMalformedMetadataFileIsReportedRatherThanSwallowed() [TestMethod] [DataRow("\n", DisplayName = "LF")] [DataRow("\r\n", DisplayName = "CRLF")] + [DataRow("\r", DisplayName = "CR")] public void AMalformedMetadataFileIsReportedAtTheBadLine(string newLine) { string json = string.Join(newLine, "{", " \"things\":", " [1,,2]", "}"); @@ -90,7 +91,7 @@ public void AMalformedMetadataFileIsReportedAtTheBadLine(string newLine) Assert.AreEqual(2, span.StartLinePosition.Line); // System.Text.Json reports the position it had reached, which is the first comma of the pair. - Assert.AreEqual(json.Split('\n')[2].IndexOf(",,", StringComparison.Ordinal), span.StartLinePosition.Character); + Assert.AreEqual(" [1,,2]".IndexOf(",,", StringComparison.Ordinal), span.StartLinePosition.Character); } [TestMethod] diff --git a/SourceGeneratorToolkit/MetadataFile.cs b/SourceGeneratorToolkit/MetadataFile.cs index 02ccee2..363f6ff 100644 --- a/SourceGeneratorToolkit/MetadataFile.cs +++ b/SourceGeneratorToolkit/MetadataFile.cs @@ -223,17 +223,31 @@ private Location LocationOf(JsonException ex) } long bytes = ex.BytePositionInLine ?? 0; - while (bytes > 0 && index < Text.Length && Text[index] is not '\r' and not '\n') + while (bytes > 0 && index < Text.Length && !EndsLine(index)) { int width = CharactersAt(index); bytes -= Utf8Bytes(index, width); index += width; } - int length = index < Text.Length && Text[index] is not '\r' and not '\n' ? 1 : 0; + int length = index < Text.Length && !EndsLine(index) ? 1 : 0; return LocationAt(index, length); } + /// + /// Says whether the character at an offset ends a line as System.Text.Json counts lines: a + /// \n, or the \r of a \r\n pair. + /// + /// The offset of the character. + /// when the character ends the line. + /// + /// A lone \r is not a line break to System.Text.Json, so in a file with CR-only line + /// endings it reports every position on line zero, measured from the start of the file. Stopping + /// at that \r would clamp the position to the end of the first line. + /// + private bool EndsLine(int index) => + Text[index] == '\n' || (Text[index] == '\r' && index + 1 < Text.Length && Text[index + 1] == '\n'); + /// /// Finds where a line starts, counting lines by \n line feeds as System.Text.Json does. ///