Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion SourceGeneratorToolkit.Test/GeneratorBaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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]", "}");
Expand All @@ -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]
Expand Down
18 changes: 16 additions & 2 deletions SourceGeneratorToolkit/MetadataFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/// <summary>
/// Says whether the character at an offset ends a line as System.Text.Json counts lines: a
/// <c>\n</c>, or the <c>\r</c> of a <c>\r\n</c> pair.
/// </summary>
/// <param name="index">The offset of the character.</param>
/// <returns><see langword="true"/> when the character ends the line.</returns>
/// <remarks>
/// A lone <c>\r</c> 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 <c>\r</c> would clamp the position to the end of the first line.
/// </remarks>
private bool EndsLine(int index) =>
Text[index] == '\n' || (Text[index] == '\r' && index + 1 < Text.Length && Text[index + 1] == '\n');

/// <summary>
/// Finds where a line starts, counting lines by <c>\n</c> line feeds as System.Text.Json does.
/// </summary>
Expand Down
Loading