Skip to content

Commit

Permalink
[ruff] Needless else clause (RUF047) (#15051)
Browse files Browse the repository at this point in the history
Co-authored-by: Micha Reiser <micha@reiser.io>
  • Loading branch information
InSyncWithFoo and MichaReiser authored Jan 21, 2025
1 parent 4cfa355 commit c616650
Show file tree
Hide file tree
Showing 14 changed files with 876 additions and 7 deletions.
49 changes: 49 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF047_for.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
### Errors

for _ in range(0):
loop_body_is_not_checked()
break
else:
pass


for this in comment:
belongs_to() # `for`
else:
...


for of in course():
this()
else:
...
# this comment does not belong to the else


### No errors

for this in second_comment:
belongs() # to
# `else`
else:
pass


for _and in so:
does()
# this
else:
pass


for of in course():
this()
else:
... # too


for of in course():
this()
else:
...
# too
84 changes: 84 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF047_if.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
### Errors

if False:
condition_is_not_evaluated()
else:
pass


if this_comment():
belongs_to() # `if`
else:
...


if elif_is():
treated()
elif the_same():
as_if()
else:
pass


if this_second_comment():
belongs() # to
# `if`
else:
pass

if this_second_comment():
belongs() # to
# `if`
else:
pass


if of_course():
this()
else:
...
# this comment doesn't belong to the if


if of_course: this()
else: ...


if of_course:
this() # comment
else: ...


def nested():
if a:
b()
else:
...


### No errors


if this_second_comment():
belongs() # to
# `else`
else:
pass


if of_course():
this()
else:
... # too


if of_course():
this()
else:
...
# comment


if of_course:
this() # comment
else: ... # trailing
76 changes: 76 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF047_try.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
### Errors

try:
raise try_body_is_not_checked()
except:
pass
else:
pass


try:
this()
except comment:
belongs()
except:
to() # `except`
else:
...


try:
of_course()
except:
this()
else:
...
# This comment belongs to finally
finally:
pass


try:
of_course()
except:
this()
else:
...
# This comment belongs to the statement coming after the else


### No errors

try:
this()
except (second, comment):
belongs() # to
# `else`
else:
pass


try:
and_so()
except:
does()
# this
else:
...


try:
of_course()
except:
this()
else:
... # too

try:
of_course()
except:
this()
else:
...
# This comment belongs to else
finally:
pass
49 changes: 49 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF047_while.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
### No errors

while True:
loop_body_is_not_checked()
break
else:
pass


while this_comment:
belongs_to() # `for`
else:
...


while of_course():
this()
else:
...
# this comment belongs to the statement coming after the else


### No errors

while this_second_comment:
belongs() # to
# `else`
else:
pass


while and_so:
does()
# this
else:
...


while of_course():
this()
else:
... # too

while of_course():
this()
else:
...
# this comment belongs to the else

28 changes: 21 additions & 7 deletions crates/ruff_linter/src/checkers/ast/analyze/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::IfKeyInDictDel) {
ruff::rules::if_key_in_dict_del(checker, if_);
}
if checker.enabled(Rule::NeedlessElse) {
ruff::rules::needless_else(checker, if_.into());
}
}
Stmt::Assert(
assert_stmt @ ast::StmtAssert {
Expand Down Expand Up @@ -1349,6 +1352,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::AsyncBusyWait) {
flake8_async::rules::async_busy_wait(checker, while_stmt);
}
if checker.enabled(Rule::NeedlessElse) {
ruff::rules::needless_else(checker, while_stmt.into());
}
}
Stmt::For(
for_stmt @ ast::StmtFor {
Expand Down Expand Up @@ -1438,14 +1444,19 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
refurb::rules::for_loop_writes(checker, for_stmt);
}
}
if checker.enabled(Rule::NeedlessElse) {
ruff::rules::needless_else(checker, for_stmt.into());
}
}
Stmt::Try(ast::StmtTry {
body,
handlers,
orelse,
finalbody,
..
}) => {
Stmt::Try(
try_stmt @ ast::StmtTry {
body,
handlers,
orelse,
finalbody,
..
},
) => {
if checker.enabled(Rule::TooManyNestedBlocks) {
pylint::rules::too_many_nested_blocks(checker, stmt);
}
Expand Down Expand Up @@ -1512,6 +1523,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::ErrorInsteadOfException) {
tryceratops::rules::error_instead_of_exception(checker, handlers);
}
if checker.enabled(Rule::NeedlessElse) {
ruff::rules::needless_else(checker, try_stmt.into());
}
}
Stmt::Assign(assign @ ast::StmtAssign { targets, value, .. }) => {
if checker.enabled(Rule::SelfOrClsAssignment) {
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_linter/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "041") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryNestedLiteral),
(Ruff, "043") => (RuleGroup::Preview, rules::ruff::rules::PytestRaisesAmbiguousPattern),
(Ruff, "046") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryCastToInt),
(Ruff, "047") => (RuleGroup::Preview, rules::ruff::rules::NeedlessElse),
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "049") => (RuleGroup::Preview, rules::ruff::rules::DataclassEnum),
(Ruff, "051") => (RuleGroup::Preview, rules::ruff::rules::IfKeyInDictDel),
Expand Down
4 changes: 4 additions & 0 deletions crates/ruff_linter/src/rules/ruff/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ mod tests {
#[test_case(Rule::InvalidAssertMessageLiteralArgument, Path::new("RUF040.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.pyi"))]
#[test_case(Rule::NeedlessElse, Path::new("RUF047_if.py"))]
#[test_case(Rule::NeedlessElse, Path::new("RUF047_for.py"))]
#[test_case(Rule::NeedlessElse, Path::new("RUF047_while.py"))]
#[test_case(Rule::NeedlessElse, Path::new("RUF047_try.py"))]
#[test_case(Rule::IfKeyInDictDel, Path::new("RUF051.py"))]
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"))]
#[test_case(Rule::FalsyDictGetFallback, Path::new("RUF056.py"))]
Expand Down
2 changes: 2 additions & 0 deletions crates/ruff_linter/src/rules/ruff/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub(crate) use missing_fstring_syntax::*;
pub(crate) use mutable_class_default::*;
pub(crate) use mutable_dataclass_default::*;
pub(crate) use mutable_fromkeys_value::*;
pub(crate) use needless_else::*;
pub(crate) use never_union::*;
pub(crate) use none_not_at_end_of_union::*;
pub(crate) use parenthesize_chained_operators::*;
Expand Down Expand Up @@ -75,6 +76,7 @@ mod missing_fstring_syntax;
mod mutable_class_default;
mod mutable_dataclass_default;
mod mutable_fromkeys_value;
mod needless_else;
mod never_union;
mod none_not_at_end_of_union;
mod parenthesize_chained_operators;
Expand Down
Loading

0 comments on commit c616650

Please sign in to comment.