From 22d5b0071d6c87c0b5433c61cf645c7309282739 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 28 Mar 2023 12:31:06 -0400 Subject: [PATCH] Rename `end_of_statement` to `end_of_last_statement` (#3775) --- .../ruff/src/rules/flake8_return/helpers.rs | 35 ++++++++++++++++++- crates/ruff/src/rules/flake8_return/rules.rs | 9 ++--- crates/ruff_python_ast/src/helpers.rs | 27 -------------- 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/crates/ruff/src/rules/flake8_return/helpers.rs b/crates/ruff/src/rules/flake8_return/helpers.rs index 23e60c2002..1d89603076 100644 --- a/crates/ruff/src/rules/flake8_return/helpers.rs +++ b/crates/ruff/src/rules/flake8_return/helpers.rs @@ -1,4 +1,8 @@ -use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt}; +use rustpython_parser::ast::{Constant, Expr, ExprKind, Location, Stmt}; + +use ruff_python_ast::helpers::to_absolute; +use ruff_python_ast::newlines::StrExt; +use ruff_python_ast::source_code::Locator; /// Return `true` if a function's return statement include at least one /// non-`None` value. @@ -16,3 +20,32 @@ pub fn result_exists(returns: &[(&Stmt, Option<&Expr>)]) -> bool { .unwrap_or(false) }) } + +/// Given a statement, find its "logical end". +/// +/// For example: the statement could be following by a trailing semicolon, by an end-of-line +/// comment, or by any number of continuation lines (and then by a comment, and so on). +/// +/// This method assumes that the statement is the last statement in its body; specifically, that +/// the statement isn't followed by a semicolon, followed by a multi-line statement. +pub fn end_of_last_statement(stmt: &Stmt, locator: &Locator) -> Location { + let contents = locator.skip(stmt.end_location.unwrap()); + + // End-of-file, so just return the end of the statement. + if contents.is_empty() { + return stmt.end_location.unwrap(); + } + + // Otherwise, find the end of the last line that's "part of" the statement. + for (lineno, line) in contents.universal_newlines().enumerate() { + if line.ends_with('\\') { + continue; + } + return to_absolute( + Location::new(lineno + 1, line.chars().count()), + stmt.end_location.unwrap(), + ); + } + + unreachable!("Expected to find end-of-statement") +} diff --git a/crates/ruff/src/rules/flake8_return/rules.rs b/crates/ruff/src/rules/flake8_return/rules.rs index 334c783641..7534c4b359 100644 --- a/crates/ruff/src/rules/flake8_return/rules.rs +++ b/crates/ruff/src/rules/flake8_return/rules.rs @@ -4,14 +4,15 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Location, Stmt, StmtKind} use ruff_diagnostics::{AlwaysAutofixableViolation, Violation}; use ruff_diagnostics::{Diagnostic, Edit}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::helpers::elif_else_range; use ruff_python_ast::helpers::is_const_none; -use ruff_python_ast::helpers::{elif_else_range, end_of_statement}; use ruff_python_ast::types::Range; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::whitespace::indentation; use crate::checkers::ast::Checker; use crate::registry::{AsRule, Rule}; +use crate::rules::flake8_return::helpers::end_of_last_statement; use super::branch::Branch; use super::helpers::result_exists; @@ -222,7 +223,7 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) { content.push_str("return None"); diagnostic.set_fix(Edit::insertion( content, - end_of_statement(stmt, checker.locator), + end_of_last_statement(stmt, checker.locator), )); } } @@ -260,7 +261,7 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) { content.push_str("return None"); diagnostic.set_fix(Edit::insertion( content, - end_of_statement(stmt, checker.locator), + end_of_last_statement(stmt, checker.locator), )); } } @@ -299,7 +300,7 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) { content.push_str("return None"); diagnostic.set_fix(Edit::insertion( content, - end_of_statement(stmt, checker.locator), + end_of_last_statement(stmt, checker.locator), )); } } diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 906e0aa6db..c66f832539 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -13,7 +13,6 @@ use rustpython_parser::{lexer, Mode, StringKind, Tok}; use smallvec::{smallvec, SmallVec}; use crate::context::Context; -use crate::newlines::StrExt; use crate::scope::{Binding, BindingKind}; use crate::source_code::{Generator, Indexer, Locator, Stylist}; use crate::types::{CallPath, Range}; @@ -1139,32 +1138,6 @@ pub fn first_colon_range(range: Range, locator: &Locator) -> Option { range } -/// Given a statement, find its "logical end". -/// -/// For example: the statement could be following by a trailing semicolon, by an end-of-line -/// comment, or by any number of continuation lines (and then by a comment, and so on). -pub fn end_of_statement(stmt: &Stmt, locator: &Locator) -> Location { - let contents = locator.skip(stmt.end_location.unwrap()); - - // End-of-file, so just return the end of the statement. - if contents.is_empty() { - return stmt.end_location.unwrap(); - } - - // Otherwise, find the end of the last line that's "part of" the statement. - for (lineno, line) in contents.universal_newlines().enumerate() { - if line.ends_with('\\') { - continue; - } - return to_absolute( - Location::new(lineno + 1, line.chars().count()), - stmt.end_location.unwrap(), - ); - } - - unreachable!("Expected to find end-of-statement") -} - /// Return the `Range` of the first `Elif` or `Else` token in an `If` statement. pub fn elif_else_range(stmt: &Stmt, locator: &Locator) -> Option { let StmtKind::If { body, orelse, .. } = &stmt.node else {