-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Conversation
|
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); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat!
crates/ruff_linter/src/noqa.rs
Outdated
} | ||
|
||
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> { |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
crates/ruff_linter/src/noqa.rs
Outdated
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(); |
There was a problem hiding this comment.
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
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(); |
crates/ruff_linter/src/noqa.rs
Outdated
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), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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), | |
}); |
crates/ruff_linter/src/noqa.rs
Outdated
} | ||
|
||
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> { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Perfect. Let me know when it's ready to merge and I hit the button |
Awesome, thanks for the reviews! I just noticed that the snapshot metadata is not correct anymore after the signature change (the Otherwise ready to merge! |
Ideally yes. You can also try to update |
I think the newest version of insta might be the problem (mitsuhiko/insta#676; adding |
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 |
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 toDirective
, with a sequence ofCodes
withTextRange
s 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.