[refurb] Minor nits regarding for-loop-writes and for-loop-set-mutations (#15958)

This commit is contained in:
Alex Waygood 2025-02-05 10:21:36 +00:00 committed by GitHub
parent 827a076a2f
commit 7ca778f492
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 49 additions and 25 deletions

View file

@ -4,7 +4,8 @@ use ruff_python_ast::{Expr, Stmt, StmtFor};
use ruff_python_semantic::analyze::typing;
use crate::checkers::ast::Checker;
use crate::rules::refurb::rules::for_loop_writes::parenthesize_loop_iter_if_necessary;
use super::helpers::parenthesize_loop_iter_if_necessary;
/// ## What it does
/// Checks for code that updates a set with the contents of an iterable by
@ -35,6 +36,10 @@ use crate::rules::refurb::rules::for_loop_writes::parenthesize_loop_iter_if_nece
/// s.difference_update((1, 2, 3))
/// ```
///
/// ## Fix safety
/// The fix will be marked as unsafe if applying the fix would delete any comments.
/// Otherwise, it is marked as safe.
///
/// ## References
/// - [Python documentation: `set`](https://docs.python.org/3/library/stdtypes.html#set)
#[derive(ViolationMetadata)]

View file

@ -1,6 +1,5 @@
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::{Expr, ExprList, ExprName, ExprTuple, Stmt, StmtFor};
use ruff_python_semantic::analyze::typing;
use ruff_python_semantic::{Binding, ScopeId, SemanticModel, TypingOnlyBindingsStatus};
@ -8,6 +7,8 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::ast::Checker;
use super::helpers::parenthesize_loop_iter_if_necessary;
/// ## What it does
/// Checks for the use of `IOBase.write` in a for loop.
///
@ -245,26 +246,3 @@ fn loop_variables_are_used_outside_loop(
.iter()
.any(|name| name_overwrites_outer(name) || name_is_used_later(name))
}
pub(super) fn parenthesize_loop_iter_if_necessary(for_stmt: &StmtFor, checker: &Checker) -> String {
let locator = checker.locator();
let iter = for_stmt.iter.as_ref();
let original_parenthesized_range = parenthesized_range(
iter.into(),
for_stmt.into(),
checker.comment_ranges(),
checker.source(),
);
if let Some(range) = original_parenthesized_range {
return locator.slice(range).to_string();
}
let iter_in_source = locator.slice(iter);
match iter {
Expr::Tuple(tuple) if !tuple.parenthesized => format!("({iter_in_source})"),
_ => iter_in_source.to_string(),
}
}

View file

@ -0,0 +1,40 @@
use std::borrow::Cow;
use ruff_python_ast::{self as ast, parenthesize::parenthesized_range};
use crate::checkers::ast::Checker;
/// A helper function that extracts the `iter` from a [`ast::StmtFor`] node and,
/// if the `iter` is an unparenthesized tuple, adds parentheses:
///
/// - `for x in z: ...` -> `"x"`
/// - `for (x, y) in z: ...` -> `"(x, y)"`
/// - `for [x, y] in z: ...` -> `"[x, y]"`
/// - `for x, y in z: ...` -> `"(x, y)"` # <-- Parentheses added only for this example
pub(super) fn parenthesize_loop_iter_if_necessary<'a>(
for_stmt: &'a ast::StmtFor,
checker: &'a Checker,
) -> Cow<'a, str> {
let locator = checker.locator();
let iter = for_stmt.iter.as_ref();
let original_parenthesized_range = parenthesized_range(
iter.into(),
for_stmt.into(),
checker.comment_ranges(),
checker.source(),
);
if let Some(range) = original_parenthesized_range {
return Cow::Borrowed(locator.slice(range));
}
let iter_in_source = locator.slice(iter);
match iter {
ast::Expr::Tuple(tuple) if !tuple.parenthesized => {
Cow::Owned(format!("({iter_in_source})"))
}
_ => Cow::Borrowed(iter_in_source),
}
}

View file

@ -42,6 +42,7 @@ mod for_loop_writes;
mod fstring_number_format;
mod hardcoded_string_charset;
mod hashlib_digest_hex;
mod helpers;
mod if_exp_instead_of_or_operator;
mod if_expr_min_max;
mod implicit_cwd;