Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
diceroll123 committed Jan 20, 2024
1 parent 4e3db64 commit a4446d5
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 130 deletions.
18 changes: 15 additions & 3 deletions crates/ruff_linter/src/checkers/ast/analyze/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
range: _,
},
) => {
if checker.enabled(Rule::TooManyNestedBlocks) {
pylint::rules::too_many_nested_blocks(checker, body);
}
if checker.enabled(Rule::DjangoNonLeadingReceiverDecorator) {
flake8_django::rules::non_leading_receiver_decorator(checker, decorator_list);
}
Expand Down Expand Up @@ -1079,6 +1076,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
..
},
) => {
if checker.enabled(Rule::TooManyNestedBlocks) {
pylint::rules::too_many_nested_blocks(checker, stmt);
}
if checker.enabled(Rule::EmptyTypeCheckingBlock) {
if typing::is_type_checking_block(if_, &checker.semantic) {
flake8_type_checking::rules::empty_type_checking_block(checker, if_);
Expand Down Expand Up @@ -1213,6 +1213,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
Stmt::With(with_stmt @ ast::StmtWith { items, body, .. }) => {
if checker.enabled(Rule::TooManyNestedBlocks) {
pylint::rules::too_many_nested_blocks(checker, stmt);
}
if checker.enabled(Rule::AssertRaisesException) {
flake8_bugbear::rules::assert_raises_exception(checker, items);
}
Expand Down Expand Up @@ -1240,6 +1243,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
Stmt::While(while_stmt @ ast::StmtWhile { body, orelse, .. }) => {
if checker.enabled(Rule::TooManyNestedBlocks) {
pylint::rules::too_many_nested_blocks(checker, stmt);
}
if checker.enabled(Rule::FunctionUsesLoopVariable) {
flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Stmt(stmt));
}
Expand All @@ -1263,6 +1269,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
range: _,
},
) => {
if checker.enabled(Rule::TooManyNestedBlocks) {
pylint::rules::too_many_nested_blocks(checker, stmt);
}
if checker.any_enabled(&[
Rule::EnumerateForLoop,
Rule::IncorrectDictIterator,
Expand Down Expand Up @@ -1327,6 +1336,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
finalbody,
..
}) => {
if checker.enabled(Rule::TooManyNestedBlocks) {
pylint::rules::too_many_nested_blocks(checker, stmt);
}
if checker.enabled(Rule::JumpStatementInFinally) {
flake8_bugbear::rules::jump_statement_in_finally(checker, finalbody);
}
Expand Down
205 changes: 78 additions & 127 deletions crates/ruff_linter/src/rules/pylint/rules/too_many_nested_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ast::ExceptHandler;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Stmt};
use ruff_text_size::{Ranged, TextRange};
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;

Expand Down Expand Up @@ -36,143 +36,94 @@ impl Violation for TooManyNestedBlocks {
}

/// PLR1702
pub(crate) fn too_many_nested_blocks(checker: &mut Checker, body: &[Stmt]) {
let max_nested_blocks = checker.settings.pylint.max_nested_blocks;

for stmt in body {
let (count, deepest) = count_blocks(&[stmt.to_owned()]);

if deepest.is_none() {
continue;
}

if count <= max_nested_blocks {
continue;
}

checker.diagnostics.push(Diagnostic::new(
TooManyNestedBlocks {
nested_blocks: count,
max_nested_blocks,
},
TextRange::new(stmt.range().start(), deepest.unwrap().range().end()),
));
pub(crate) fn too_many_nested_blocks(checker: &mut Checker, stmt: &Stmt) {
// check that we're in a function
// if not, return
if !checker.semantic().current_scope().kind.is_function() {
return;
}
}

fn count_blocks(stmts: &[Stmt]) -> (usize, Option<Stmt>) {
let mut count = 0;
let mut deepest: Option<Stmt> = None;
for stmt in stmts {
match stmt {
Stmt::If(ast::StmtIf {
body,
elif_else_clauses,
..
}) => {
let (result, deepest_if) = count_blocks(body);
count = result;
deepest = deepest_if;
// check if this statement has any more branching statements
// if so, return
if stmt_has_more_stmts(stmt) {
return;
}

for clause in elif_else_clauses {
let (result, deepest_if) = count_blocks(&clause.body);
if result > count {
count = result;
deepest = deepest_if;
count += result;
}
}
count += 1;
}
Stmt::For(ast::StmtFor { body, orelse, .. }) => {
let (result, deepest_for) = count_blocks(body);
count = result;
deepest = deepest_for;
let max_nested_blocks = checker.settings.pylint.max_nested_blocks;

let (result, deepest_else) = count_blocks(orelse);
if result > count {
count = result;
deepest = deepest_else;
let (count, oldest_ancestor_id) =
checker
.semantic()
.current_statement_ids()
.fold((0, None), |(count, previous_id), id| {
let stmt = checker.semantic().statement(id);
if stmt.is_with_stmt()
|| stmt.is_if_stmt()
|| stmt.is_try_stmt()
|| stmt.is_while_stmt()
|| stmt.is_for_stmt()
{
// we want to emit the diagnostic on the
// oldest nested statement
return (count + 1, Some(id));
}
(count, previous_id)
});

count += 1;
}
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
let (result, deepest_while) = count_blocks(body);
count = result;
deepest = deepest_while;

let (result, deepest_else) = count_blocks(orelse);
if result > count {
count = result;
deepest = deepest_else;
}
let Some(oldest_ancestor_id) = oldest_ancestor_id else {
return;
};

count += 1;
}
Stmt::Match(ast::StmtMatch { cases, .. }) => {
for case in cases {
let (result, deepest_case) = count_blocks(&case.body);
if result > count {
count = result;
deepest = deepest_case;
}
}
count += 1;
}
Stmt::Try(ast::StmtTry {
body,
handlers,
orelse,
finalbody,
..
}) => {
let (result, deepest_try) = count_blocks(body);
count = result;
deepest = deepest_try;
if count <= max_nested_blocks {
return;
}

if !orelse.is_empty() {
let (result, deepest_else) = count_blocks(orelse);
if result > count {
count = result;
deepest = deepest_else;
}
}
let oldest_ancestor = checker.semantic().statement(oldest_ancestor_id);

if !finalbody.is_empty() {
let (result, deepest_finally) = count_blocks(finalbody);
if result > count {
count = result;
deepest = deepest_finally;
}
}
checker.diagnostics.push(Diagnostic::new(
TooManyNestedBlocks {
nested_blocks: count,
max_nested_blocks,
},
oldest_ancestor.range(),
));
}

for handler in handlers {
let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
fn stmt_has_more_stmts(stmt: &Stmt) -> bool {
match stmt {
Stmt::If(ast::StmtIf {
body,
elif_else_clauses,
..
}) => {
body.iter().any(stmt_has_more_stmts)
|| elif_else_clauses
.iter()
.any(|elif_else| elif_else.body.iter().any(stmt_has_more_stmts))
}
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
body.iter().any(stmt_has_more_stmts) || orelse.iter().any(stmt_has_more_stmts)
}
Stmt::For(ast::StmtFor { body, orelse, .. }) => {
body.iter().any(stmt_has_more_stmts) || orelse.iter().any(stmt_has_more_stmts)
}
Stmt::Try(ast::StmtTry {
body,
handlers,
orelse,
finalbody,
..
}) => {
body.iter().any(stmt_has_more_stmts)
|| handlers.iter().any(|handler| match handler {
ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
body, ..
}) = handler;
let (result, deepest_handler) = count_blocks(body);
if result > count {
count = result;
deepest = deepest_handler;
}
}

count += 1;
}
Stmt::With(ast::StmtWith { body, .. }) => {
let (result, deepest_with) = count_blocks(body);
count = result;
deepest = deepest_with;
count += 1;
}
_ => {}
}) => body.iter().any(stmt_has_more_stmts),
})
|| orelse.iter().any(stmt_has_more_stmts)
|| finalbody.iter().any(stmt_has_more_stmts)
}
}

if deepest.is_none() {
(count, stmts.first().cloned())
} else {
(count, deepest)
Stmt::With(ast::StmtWith { body, .. }) => body.iter().any(stmt_has_more_stmts),
_ => false,
}
}

0 comments on commit a4446d5

Please sign in to comment.