Skip to content

Commit a93992f

Browse files
dylwil3ntBre
authored andcommitted
[flake8-return] Stabilize only add return None at the end when fixing implicit-return (RET503) (#18516)
This involved slightly more code changes than usual for a stabilization - so maybe worth double-checking the logic! I did verify by hand that the new stable behavior on the test fixture matches the old preview behavior, even after the internal refactor.
1 parent 50f8480 commit a93992f

File tree

5 files changed

+150
-626
lines changed

5 files changed

+150
-626
lines changed

crates/ruff_linter/src/preview.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ pub(crate) const fn is_bad_version_info_in_non_stub_enabled(settings: &LinterSet
4040
settings.preview.is_enabled()
4141
}
4242

43-
// https://github.com/astral-sh/ruff/pull/11074
44-
pub(crate) const fn is_only_add_return_none_at_end_enabled(settings: &LinterSettings) -> bool {
45-
settings.preview.is_enabled()
46-
}
47-
4843
// https://github.com/astral-sh/ruff/pull/16719
4944
pub(crate) const fn is_fix_manual_dict_comprehension_enabled(settings: &LinterSettings) -> bool {
5045
settings.preview.is_enabled()

crates/ruff_linter/src/rules/flake8_return/mod.rs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ mod tests {
1111
use anyhow::Result;
1212
use test_case::test_case;
1313

14+
use crate::assert_messages;
1415
use crate::registry::Rule;
1516
use crate::settings::LinterSettings;
16-
use crate::settings::types::PreviewMode;
1717
use crate::test::test_path;
18-
use crate::{assert_messages, settings};
1918

2019
#[test_case(Rule::UnnecessaryReturnNone, Path::new("RET501.py"))]
2120
#[test_case(Rule::ImplicitReturnValue, Path::new("RET502.py"))]
@@ -34,22 +33,4 @@ mod tests {
3433
assert_messages!(snapshot, diagnostics);
3534
Ok(())
3635
}
37-
38-
#[test_case(Rule::ImplicitReturn, Path::new("RET503.py"))]
39-
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
40-
let snapshot = format!(
41-
"preview__{}_{}",
42-
rule_code.noqa_code(),
43-
path.to_string_lossy()
44-
);
45-
let diagnostics = test_path(
46-
Path::new("flake8_return").join(path).as_path(),
47-
&settings::LinterSettings {
48-
preview: PreviewMode::Enabled,
49-
..settings::LinterSettings::for_rule(rule_code)
50-
},
51-
)?;
52-
assert_messages!(snapshot, diagnostics);
53-
Ok(())
54-
}
5536
}

crates/ruff_linter/src/rules/flake8_return/rules/function.rs

Lines changed: 30 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
1616
use crate::checkers::ast::Checker;
1717
use crate::fix::edits;
1818
use crate::fix::edits::adjust_indentation;
19-
use crate::preview::is_only_add_return_none_at_end_enabled;
2019
use crate::registry::Rule;
2120
use crate::rules::flake8_return::helpers::end_of_last_statement;
2221
use crate::{AlwaysFixableViolation, FixAvailability, Violation};
@@ -462,96 +461,70 @@ fn add_return_none(checker: &Checker, stmt: &Stmt, range: TextRange) {
462461
}
463462
}
464463

465-
/// Returns a list of all implicit returns in the given statement.
466-
///
467-
/// Note: The function should be refactored to `has_implicit_return` with an early return (when seeing the first implicit return)
468-
/// when removing the preview gating.
469-
fn implicit_returns<'a>(checker: &Checker, stmt: &'a Stmt) -> Vec<&'a Stmt> {
464+
fn has_implicit_return(checker: &Checker, stmt: &Stmt) -> bool {
470465
match stmt {
471466
Stmt::If(ast::StmtIf {
472467
body,
473468
elif_else_clauses,
474469
..
475470
}) => {
476-
let mut implicit_stmts = body
471+
if body
477472
.last()
478-
.map(|last| implicit_returns(checker, last))
479-
.unwrap_or_default();
480-
481-
for clause in elif_else_clauses {
482-
implicit_stmts.extend(
483-
clause
484-
.body
485-
.last()
486-
.iter()
487-
.flat_map(|last| implicit_returns(checker, last)),
488-
);
473+
.is_some_and(|last| has_implicit_return(checker, last))
474+
{
475+
return true;
476+
}
477+
478+
if elif_else_clauses.iter().any(|clause| {
479+
clause
480+
.body
481+
.last()
482+
.is_some_and(|last| has_implicit_return(checker, last))
483+
}) {
484+
return true;
489485
}
490486

491487
// Check if we don't have an else clause
492-
if matches!(
488+
matches!(
493489
elif_else_clauses.last(),
494490
None | Some(ast::ElifElseClause { test: Some(_), .. })
495-
) {
496-
implicit_stmts.push(stmt);
497-
}
498-
implicit_stmts
491+
)
499492
}
500-
Stmt::Assert(ast::StmtAssert { test, .. }) if is_const_false(test) => vec![],
501-
Stmt::While(ast::StmtWhile { test, .. }) if is_const_true(test) => vec![],
493+
Stmt::Assert(ast::StmtAssert { test, .. }) if is_const_false(test) => false,
494+
Stmt::While(ast::StmtWhile { test, .. }) if is_const_true(test) => false,
502495
Stmt::For(ast::StmtFor { orelse, .. }) | Stmt::While(ast::StmtWhile { orelse, .. }) => {
503496
if let Some(last_stmt) = orelse.last() {
504-
implicit_returns(checker, last_stmt)
497+
has_implicit_return(checker, last_stmt)
505498
} else {
506-
vec![stmt]
507-
}
508-
}
509-
Stmt::Match(ast::StmtMatch { cases, .. }) => {
510-
let mut implicit_stmts = vec![];
511-
for case in cases {
512-
implicit_stmts.extend(
513-
case.body
514-
.last()
515-
.into_iter()
516-
.flat_map(|last_stmt| implicit_returns(checker, last_stmt)),
517-
);
499+
true
518500
}
519-
implicit_stmts
520501
}
502+
Stmt::Match(ast::StmtMatch { cases, .. }) => cases.iter().any(|case| {
503+
case.body
504+
.last()
505+
.is_some_and(|last| has_implicit_return(checker, last))
506+
}),
521507
Stmt::With(ast::StmtWith { body, .. }) => body
522508
.last()
523-
.map(|last_stmt| implicit_returns(checker, last_stmt))
524-
.unwrap_or_default(),
525-
Stmt::Return(_) | Stmt::Raise(_) | Stmt::Try(_) => vec![],
509+
.is_some_and(|last_stmt| has_implicit_return(checker, last_stmt)),
510+
Stmt::Return(_) | Stmt::Raise(_) | Stmt::Try(_) => false,
526511
Stmt::Expr(ast::StmtExpr { value, .. })
527512
if matches!(
528513
value.as_ref(),
529514
Expr::Call(ast::ExprCall { func, .. })
530515
if is_noreturn_func(func, checker.semantic())
531516
) =>
532517
{
533-
vec![]
534-
}
535-
_ => {
536-
vec![stmt]
518+
false
537519
}
520+
_ => true,
538521
}
539522
}
540523

541524
/// RET503
542525
fn implicit_return(checker: &Checker, function_def: &ast::StmtFunctionDef, stmt: &Stmt) {
543-
let implicit_stmts = implicit_returns(checker, stmt);
544-
545-
if implicit_stmts.is_empty() {
546-
return;
547-
}
548-
549-
if is_only_add_return_none_at_end_enabled(checker.settings) {
526+
if has_implicit_return(checker, stmt) {
550527
add_return_none(checker, stmt, function_def.range());
551-
} else {
552-
for implicit_stmt in implicit_stmts {
553-
add_return_none(checker, implicit_stmt, implicit_stmt.range());
554-
}
555528
}
556529
}
557530

0 commit comments

Comments
 (0)