[ty] Fix a few more diagnostic differences from Ruff#19806
Conversation
|
MichaReiser
left a comment
There was a problem hiding this comment.
Nice!
My only suggestion is to use last-line:last-column for the eof case instead of last_line+1:1 to more closely match the rendered snippet
| } = item | ||
| { | ||
| if main_range >= range.0 && main_range < range.1 + max(*end_line as usize, 1) { | ||
| let end_of_range = range.1 + max(*end_line as usize, 1); |
There was a problem hiding this comment.
I'd find a comment what's happening here useful :) Together with a comment that this is another upstream divergence
There was a problem hiding this comment.
Yeah definitely makes sense to put the comment here, rather than on the test!
| line_offset = lineno.unwrap_or(1); | ||
| break; | ||
| } else if main_range == end_of_range { | ||
| line_offset = lineno.map_or(1, |line| line + 1); |
There was a problem hiding this comment.
Is the +1 because the line is zero indexed or because we want to point to the next line.
I think it would also be okay to say last_line:after_last_column which would better align with how the snippet is rendered.
There was a problem hiding this comment.
Yes, the +1 is to point to the next line to match Ruff's current behavior:
I agree with you that 29:2 would make sense and more closely align with the rendering, though.
One issue I ran into here was that (naively) computing the column breaks some other annotate-snippets tests. Maybe that's a sign that it's not the right fix.
I'll look at this a bit more.
There was a problem hiding this comment.
I have a more robust fix working, but this will also be a mismatch from the concise rendering. Should I update that as well? It looks like those numbers come from our LineIndex code.
There was a problem hiding this comment.
Fixing LineIndex does sound reasonable if that's where the numbers are coming from. But I don't have a good sense of the blast radius. You might have to try to see what changes (Updating concise makes sense to me, we want the line numbers to match across formats)
There was a problem hiding this comment.
Yeah I definitely want them to match, I was more wondering if you'd rather align on this new behavior or preserve the old behavior. I'll have to double check the other output formats too. Hopefully they all use the line index. I guess full is the only case where the output is noticeably questionable with the caret on a different line from what the range reports.
There was a problem hiding this comment.
I'd prefer aligning on the new behavior. I think the existing behavior is even confusing in the context of the new newline at end of file because it suggests that there's a newline (which obviously there isn't)
There was a problem hiding this comment.
For future reference, we discussed this on Discord and decided to move ahead with preserving the old behavior for now. This seems like the same, or a closely-related, issue as #15510, so we can follow-up on resolving the header-rendering mismatch separately. I added some notes there (#15510 (comment)) from looking into it today too.
There was a problem hiding this comment.
Perfect. Thank you for looking into it so carefully! Let's merge :)
| for (index, c) in source.char_indices() { | ||
| if let Some(printable) = unprintable_replacement(c) { | ||
| // normalize `\r` line endings but don't double `\r\n` | ||
| if c == '\r' && !matches!(source.get(index + 1..index + 2), Some("\n")) { |
There was a problem hiding this comment.
What I like doing here is &source[index + 1..].starts_width('\n')
| const BOM: char = '\u{feff}'; | ||
| let bom_len = BOM.text_len(); | ||
| let (snippet, snippet_start) = | ||
| if snippet_start == TextSize::default() && snippet.starts_with(BOM) { |
There was a problem hiding this comment.
Very very minor, but it might be nice if we had a TextSize::ZERO constant or something. Using default() for this feels a little funny.
There was a problem hiding this comment.
You can do TextSize::new(0) but agree that ZERO would be nice`
There was a problem hiding this comment.
Added! I think ONE might be helpful too, but not in this PR.
Summary -- This fixes a regression caused by the BOM handling in #19806. Most diagnostics already account for the BOM in their ranges, but those that use `TextRange::default` to mean the beginning of the file do not, causing an underflow in `RenderableAnnotation::new` when subtracting the BOM-shifted `snippet_start` from the annotation range. I ran into this when trying to run benchmarks on CPython in preparation for caching work. The file `cpython/Lib/test/bad_coding2.py` was causing a crash because it had a default-range `I002` diagnostic, with a BOM. https://github.com/astral-sh/ruff/blob/7cc3f1ebe9386e77e7009bc411fc6480d3851015/crates/ruff_linter/src/rules/isort/rules/add_required_imports.rs#L122-L126 The fix here is just to saturate to zero instead of panicking. I considered adding a `TextRange::saturating_sub` method, but I wasn't sure it was worth it for this one use. I'm happy to do that if preferred, though. Saturating seemed easier than shifting the affected annotations over, but that could be another solution. Test Plan -- A new `ruff_db` test that reproduced the issue and manual testing against the CPython file mentioned above
Summary -- This fixes a regression caused by the BOM handling in #19806. Most diagnostics already account for the BOM in their ranges, but those that use `TextRange::default` to mean the beginning of the file do not, causing an underflow in `RenderableAnnotation::new` when subtracting the BOM-shifted `snippet_start` from the annotation range. I ran into this when trying to run benchmarks on CPython in preparation for caching work. The file `cpython/Lib/test/bad_coding2.py` was causing a crash because it had a default-range `I002` diagnostic, with a BOM. https://github.com/astral-sh/ruff/blob/7cc3f1ebe9386e77e7009bc411fc6480d3851015/crates/ruff_linter/src/rules/isort/rules/add_required_imports.rs#L122-L126 The fix here is just to saturate to zero instead of panicking. I considered adding a `TextRange::saturating_sub` method, but I wasn't sure it was worth it for this one use. I'm happy to do that if preferred, though. Saturating seemed easier than shifting the affected annotations over, but that could be another solution. Test Plan -- A new `ruff_db` test that reproduced the issue and manual testing against the CPython file mentioned above
Summary
Fixes the remaining range reporting differences between the
ruff_dbdiagnostic rendering and Ruff's existing rendering, as noted in #19415 (comment).This PR is structured as a series of three pairs. The first commit in each pair adds a test showing the previous behavior, followed by a fix and the updated snapshot. It's quite a small PR, but that might be helpful just for the contrast.
You can also look at this range of commits from #19415 to see the impact on real Ruff diagnostics. I spun these commits out of that PR.
Test Plan
New
ruff_dbtests