Remove parenthesis lexing in RSE102 (#6732)

## Summary

Now that we have an `Arguments` node, we can just use the range of the
arguments directly to find the parentheses in `raise Error()`.
This commit is contained in:
Charlie Marsh 2023-08-21 16:59:06 -04:00 committed by GitHub
parent b182368008
commit 4678f7dafe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 108 additions and 102 deletions

View File

@ -19,11 +19,20 @@ raise TypeError ()
raise TypeError \
()
# RSE102
raise TypeError \
();
# RSE102
raise TypeError(
)
# RSE102
raise (TypeError) (
)
# RSE102
raise TypeError(
# Hello, world!

View File

@ -1,10 +1,6 @@
use ruff_python_ast::{self as ast, Arguments, Expr, PySourceType, Ranged};
use ruff_python_parser::{lexer, AsMode, Tok};
use ruff_text_size::{TextRange, TextSize};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_source_file::Locator;
use ruff_python_ast::{self as ast, Expr, Ranged};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
@ -49,19 +45,14 @@ impl AlwaysAutofixableViolation for UnnecessaryParenOnRaiseException {
pub(crate) fn unnecessary_paren_on_raise_exception(checker: &mut Checker, expr: &Expr) {
let Expr::Call(ast::ExprCall {
func,
arguments:
Arguments {
args,
keywords,
range: _,
},
arguments,
range: _,
}) = expr
else {
return;
};
if args.is_empty() && keywords.is_empty() {
if arguments.is_empty() {
// `raise func()` still requires parentheses; only `raise Class()` does not.
if checker
.semantic()
@ -81,49 +72,10 @@ pub(crate) fn unnecessary_paren_on_raise_exception(checker: &mut Checker, expr:
return;
}
let range = match_parens(func.end(), checker.locator(), checker.source_type)
.expect("Expected call to include parentheses");
let mut diagnostic = Diagnostic::new(UnnecessaryParenOnRaiseException, range);
let mut diagnostic = Diagnostic::new(UnnecessaryParenOnRaiseException, arguments.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(Fix::automatic(Edit::deletion(func.end(), range.end())));
diagnostic.set_fix(Fix::automatic(Edit::range_deletion(arguments.range())));
}
checker.diagnostics.push(diagnostic);
}
}
/// Return the range of the first parenthesis pair after a given [`TextSize`].
fn match_parens(
start: TextSize,
locator: &Locator,
source_type: PySourceType,
) -> Option<TextRange> {
let contents = &locator.contents()[usize::from(start)..];
let mut fix_start = None;
let mut fix_end = None;
let mut count = 0u32;
for (tok, range) in lexer::lex_starts_at(contents, source_type.as_mode(), start).flatten() {
match tok {
Tok::Lpar => {
if count == 0 {
fix_start = Some(range.start());
}
count = count.saturating_add(1);
}
Tok::Rpar => {
count = count.saturating_sub(1);
if count == 0 {
fix_end = Some(range.end());
break;
}
}
_ => {}
}
}
match (fix_start, fix_end) {
(Some(start), Some(end)) => Some(TextRange::new(start, end)),
_ => None,
}
}

View File

@ -57,7 +57,7 @@ RSE102.py:16:17: RSE102 [*] Unnecessary parentheses on raised exception
14 14 |
15 15 | # RSE102
16 |-raise TypeError ()
16 |+raise TypeError
16 |+raise TypeError
17 17 |
18 18 | # RSE102
19 19 | raise TypeError \
@ -74,64 +74,109 @@ RSE102.py:20:5: RSE102 [*] Unnecessary parentheses on raised exception
= help: Remove unnecessary parentheses
Fix
16 16 | raise TypeError ()
17 17 |
18 18 | # RSE102
19 |-raise TypeError \
19 19 | raise TypeError \
20 |- ()
19 |+raise TypeError
21 20 |
22 21 | # RSE102
23 22 | raise TypeError(
RSE102.py:23:16: RSE102 [*] Unnecessary parentheses on raised exception
|
22 | # RSE102
23 | raise TypeError(
| ________________^
24 | |
25 | | )
| |_^ RSE102
26 |
27 | # RSE102
|
= help: Remove unnecessary parentheses
Fix
20 20 | ()
20 |+
21 21 |
22 22 | # RSE102
23 |-raise TypeError(
24 |-
25 |-)
23 |+raise TypeError
26 24 |
27 25 | # RSE102
28 26 | raise TypeError(
23 23 | raise TypeError \
RSE102.py:28:16: RSE102 [*] Unnecessary parentheses on raised exception
RSE102.py:24:5: RSE102 [*] Unnecessary parentheses on raised exception
|
27 | # RSE102
28 | raise TypeError(
| ________________^
29 | | # Hello, world!
30 | | )
| |_^ RSE102
31 |
32 | # OK
22 | # RSE102
23 | raise TypeError \
24 | ();
| ^^ RSE102
25 |
26 | # RSE102
|
= help: Remove unnecessary parentheses
Fix
25 25 | )
26 26 |
27 27 | # RSE102
28 |-raise TypeError(
29 |- # Hello, world!
30 |-)
28 |+raise TypeError
31 29 |
32 30 | # OK
33 31 | raise AssertionError
21 21 |
22 22 | # RSE102
23 23 | raise TypeError \
24 |- ();
24 |+ ;
25 25 |
26 26 | # RSE102
27 27 | raise TypeError(
RSE102.py:27:16: RSE102 [*] Unnecessary parentheses on raised exception
|
26 | # RSE102
27 | raise TypeError(
| ________________^
28 | |
29 | | )
| |_^ RSE102
30 |
31 | # RSE102
|
= help: Remove unnecessary parentheses
Fix
24 24 | ();
25 25 |
26 26 | # RSE102
27 |-raise TypeError(
28 |-
29 |-)
27 |+raise TypeError
30 28 |
31 29 | # RSE102
32 30 | raise (TypeError) (
RSE102.py:32:19: RSE102 [*] Unnecessary parentheses on raised exception
|
31 | # RSE102
32 | raise (TypeError) (
| ___________________^
33 | |
34 | | )
| |_^ RSE102
35 |
36 | # RSE102
|
= help: Remove unnecessary parentheses
Fix
29 29 | )
30 30 |
31 31 | # RSE102
32 |-raise (TypeError) (
33 |-
34 |-)
32 |+raise (TypeError)
35 33 |
36 34 | # RSE102
37 35 | raise TypeError(
RSE102.py:37:16: RSE102 [*] Unnecessary parentheses on raised exception
|
36 | # RSE102
37 | raise TypeError(
| ________________^
38 | | # Hello, world!
39 | | )
| |_^ RSE102
40 |
41 | # OK
|
= help: Remove unnecessary parentheses
Fix
34 34 | )
35 35 |
36 36 | # RSE102
37 |-raise TypeError(
38 |- # Hello, world!
39 |-)
37 |+raise TypeError
40 38 |
41 39 | # OK
42 40 | raise AssertionError