Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ruff] Detect redirected-noqa in file-level comments (RUF101) #14635

Merged
merged 11 commits into from
Nov 27, 2024

Conversation

ntBre
Copy link
Contributor

@ntBre ntBre commented Nov 27, 2024

Summary

Fixes #14531, where ruff was not reporting diagnostics on file-level # ruff: noqa comments with redirected rule codes.

The main change here is making ParsedFileExemption closer in structure to Directive, with a sequence of Codes with TextRanges instead of just &str for diagnostic reporting.

Test Plan

The changes were tested against the example code from #14531 to make sure the diagnostic is now emitted.

Copy link
Contributor

github-actions bot commented Nov 27, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Comment on lines 81 to 97
for code in codes.iter() {
if let Some(redirected) = get_redirect_target(code.as_str()) {
let mut diagnostic = Diagnostic::new(
RedirectedNOQA {
original: code.to_string(),
target: redirected.to_string(),
},
code.range(),
);
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
redirected.to_string(),
code.range(),
)));
diagnostics.push(diagnostic);
}
}
}
Copy link
Member

@MichaReiser MichaReiser Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it's annoying that FileNoqaDirectives and NoqaDirectives have such a different structure. But maybe there's an opportunity to reuse some of the code in this loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, great idea! I factored this out into a build_diagnostics function.


RUF101 should trigger here because the TCH rules have been recoded to TC.
"""
# ruff: noqa: TCH002
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding an example where it's a non-direct-match redirect. E.g. TCH or TCH0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried # ruff: noqa: TCH, and it looks like it's not even being detected as a valid code (ParsedFileExemption::try_extract returns Err(MissingCodes)). Is that what you expected, or am I misunderstanding/broke something? I rolled back to before my changes, and I'm still seeing the Err(MissingCodes), so I'm probably misunderstanding.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably me. It's very likely that Ruff doesn't support file-level suppressions for selectors? If that's the case, then we're all good here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think it has to be an exact code or a catch-all (so TCH wouldn't be allowed).

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat!

}

impl<'a> ParsedFileExemption<'a> {
/// Return a [`ParsedFileExemption`] for a given comment line.
fn try_extract(line: &'a str) -> Result<Option<Self>, ParseError> {
fn try_extract(line: &'a str, offset: TextSize) -> Result<Option<Self>, ParseError> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The current signature is ambigious in the sense that it's unclear whether offset is an offset relative to line (that's what I would assume) or if it's an absolute index into the source text.

I suggest changingt the signature to try_extract(comment_range: TextRange, source: &'a str) to make this clear (we commonly use source to refer to the entire source text).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that makes sense. I was just trying to copy the signature of Directive::try_extract, but this makes more sense here.

Comment on lines 439 to 444
let init_line_len = line.len();
let line = Self::lex_whitespace(line);
let Some(line) = Self::lex_char(line, '#') else {
return Ok(None);
};
let comment_start = init_line_len - line.len() - '#'.len_utf8();
Copy link
Member

@MichaReiser MichaReiser Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I suggest using TextLen methods here to avoid the conversion further down

Suggested change
let init_line_len = line.len();
let line = Self::lex_whitespace(line);
let Some(line) = Self::lex_char(line, '#') else {
return Ok(None);
};
let comment_start = init_line_len - line.len() - '#'.len_utf8();
let init_line_len = line.text_len();
let line = Self::lex_whitespace(line);
let Some(line) = Self::lex_char(line, '#') else {
return Ok(None);
};
let comment_start = init_line_len - line.text_len() - '#'.text_len();

Comment on lines 475 to 480
let codes_end = init_line_len - line.len();
codes.push(Code {
code,
range: TextRange::at(TextSize::try_from(codes_end).unwrap(), code.text_len())
.add(offset),
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let codes_end = init_line_len - line.len();
codes.push(Code {
code,
range: TextRange::at(TextSize::try_from(codes_end).unwrap(), code.text_len())
.add(offset),
});
let codes_end = init_line_len - line.text_len();
codes.push(Code {
code,
range: TextRange::at(codes_end, code.text_len()).add(offset),
});

@MichaReiser MichaReiser added the rule Implementing or modifying a lint rule label Nov 27, 2024
}

impl<'a> ParsedFileExemption<'a> {
/// Return a [`ParsedFileExemption`] for a given comment line.
fn try_extract(line: &'a str) -> Result<Option<Self>, ParseError> {
let line = Self::lex_whitespace(line);
fn try_extract(comment_range: TextSize, source: &'a str) -> Result<Option<Self>, ParseError> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry that I haven't been clear about what signature I'd expect. I think this signature still has the same "flaw" in that it's unclear if comment_range is an offset relative to source or the entire source text of the file.

To avoid this, I suggest changing the signature to try_extract(comment_range: TextRange, source; &'a str) and then call it like this: ParsedFileExemption::try_extract(range, locator.contents()); It's then the try_extract's responsible to slice the comment text out of the source text.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry about that. I missed that you suggested TextRange instead of TextSize 🤦 This makes much more sense to me now.

@MichaReiser
Copy link
Member

Perfect. Let me know when it's ready to merge and I hit the button

@ntBre
Copy link
Contributor Author

ntBre commented Nov 27, 2024

Awesome, thanks for the reviews! I just noticed that the snapshot metadata is not correct anymore after the signature change (the expression lines should look like expression: "ParsedFileExemption::try_extract(TextRange::up_to(source.text_len()), source,)" now). I ran cargo insta test --force-update-snapshots, but it changed the metadata in a ton of other snapshots too. Should I just update the ones I actually changed here, or ignore this for now?

Otherwise ready to merge!

@MichaReiser
Copy link
Member

Should I just update the ones I actually changed here, or ignore this for now?

Ideally yes. You can also try to update cargo-insta to a newer version

@ntBre
Copy link
Contributor Author

ntBre commented Nov 27, 2024

I think the newest version of insta might be the problem (mitsuhiko/insta#676; adding snapshot_kind: text to the metadata now), but I just added the real changes I caused.

@MichaReiser
Copy link
Member

I think the newest version of insta might be the problem (mitsuhiko/insta#676; adding snapshot_kind: text to the metadata now), but I just added the real changes I caused.

Oh interesting: I thought I updated all snapshots to use the new format but quiet possible that I missed some.

@MichaReiser MichaReiser merged commit 6fcbe8e into astral-sh:main Nov 27, 2024
21 checks passed
@AlexWaygood
Copy link
Member

AlexWaygood commented Nov 27, 2024

Oh interesting: I thought I updated all snapshots to use the new format but quiet possible that I missed some.

I think some of them have been changed back (and some new ones with the old format have been added) because not all contributors have the latest version of cargo-insta installed

@ntBre ntBre deleted the brent/fix-14531 branch November 27, 2024 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rule Implementing or modifying a lint rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

redirected-noqa (RUF101) does not detect file-level # ruff: noqa comments
4 participants