|
1 | 1 | use itertools::Itertools; |
2 | 2 | use ruff_diagnostics::{Applicability, Edit, Fix}; |
| 3 | +use ruff_python_ast::Stmt; |
3 | 4 | use ruff_python_ast::name::Name; |
4 | | -use ruff_python_ast::traversal::EnclosingSuite; |
5 | | -use ruff_python_ast::{Stmt, traversal}; |
6 | | -use ruff_python_semantic::SemanticModel; |
| 5 | +use ruff_python_semantic::Definition; |
7 | 6 | use ruff_text_size::{Ranged, TextRange, TextSize}; |
8 | 7 |
|
9 | 8 | use ruff_macros::{ViolationMetadata, derive_message_formats}; |
@@ -42,7 +41,7 @@ use crate::checkers::ast::Checker; |
42 | 41 | /// exception case, applying the quick fix would remove comments between the |
43 | 42 | /// assignment statements. |
44 | 43 | #[derive(ViolationMetadata)] |
45 | | -#[violation_metadata(preview_since = "0.14.11")] |
| 44 | +#[violation_metadata(preview_since = "0.15.1")] |
46 | 45 | pub(crate) struct SwapWithTemporaryVariable<'a> { |
47 | 46 | first_var: &'a Name, |
48 | 47 | second_var: &'a Name, |
@@ -79,13 +78,14 @@ impl Violation for SwapWithTemporaryVariable<'_> { |
79 | 78 | } |
80 | 79 | } |
81 | 80 |
|
82 | | -pub(crate) fn swap_with_temporary_variable(checker: &Checker, assignment: &Stmt) { |
83 | | - let Some(consecutive_assignments) = |
84 | | - match_consecutive_assignments(assignment, checker.semantic()) |
85 | | - else { |
86 | | - return; |
87 | | - }; |
88 | | - for (stmt_a, stmt_b, stmt_c) in consecutive_assignments.tuple_windows() { |
| 81 | +pub(crate) fn swap_with_temporary_variable(checker: &Checker, definition: &Definition) { |
| 82 | + let consecutive_assignments = match_consecutive_assignments(definition); |
| 83 | + |
| 84 | + for stmt_sequence in consecutive_assignments.tuple_windows() { |
| 85 | + let (Some(stmt_a), Some(stmt_b), Some(stmt_c)) = stmt_sequence else { |
| 86 | + continue; |
| 87 | + }; |
| 88 | + |
89 | 89 | // Detect patterns like: |
90 | 90 | // temp = x |
91 | 91 | // x = y |
@@ -134,41 +134,14 @@ pub(crate) fn swap_with_temporary_variable(checker: &Checker, assignment: &Stmt) |
134 | 134 | /// |
135 | 135 | /// Also see the `repeated_append` rule for a similar use case. |
136 | 136 | fn match_consecutive_assignments<'a>( |
137 | | - stmt: &'a Stmt, |
138 | | - semantic: &'a SemanticModel, |
139 | | -) -> Option<impl Iterator<Item = VarToVarAssignment<'a>>> { |
140 | | - let root_assignment = VarToVarAssignment::from_stmt(stmt)?; |
141 | | - |
142 | | - // In order to match consecutive statements, we need to go to the tree ancestor of the |
143 | | - // given statement, find its position there, and match all 'appends' from there. |
144 | | - let suite = if semantic.at_top_level() { |
145 | | - // If the statement is at the top level, we should go to the parent module. |
146 | | - // Module is available in the definitions list. |
147 | | - EnclosingSuite::new(semantic.definitions.python_ast()?, stmt.into())? |
148 | | - } else { |
149 | | - // Otherwise, go to the parent, and take its body as a sequence of siblings. |
150 | | - semantic |
151 | | - .current_statement_parent() |
152 | | - .and_then(|parent| traversal::suite(stmt, parent))? |
| 137 | + definition: &'a Definition, |
| 138 | +) -> impl Iterator<Item = Option<VarToVarAssignment<'a>>> { |
| 139 | + let suite = match definition { |
| 140 | + Definition::Module(module) => module.python_ast, |
| 141 | + Definition::Member(member) => member.body(), |
153 | 142 | }; |
154 | 143 |
|
155 | | - // We shouldn't repeat the same work for many 'assignments' that go in a row. Let's check |
156 | | - // that this statement is at the beginning of such a group. |
157 | | - if suite |
158 | | - .previous_sibling() |
159 | | - .is_some_and(|previous_stmt| VarToVarAssignment::from_stmt(previous_stmt).is_some()) |
160 | | - { |
161 | | - return None; |
162 | | - } |
163 | | - |
164 | | - Some( |
165 | | - std::iter::once(root_assignment).chain( |
166 | | - suite |
167 | | - .next_siblings() |
168 | | - .iter() |
169 | | - .map_while(VarToVarAssignment::from_stmt), |
170 | | - ), |
171 | | - ) |
| 144 | + suite.iter().map(VarToVarAssignment::from_stmt) |
172 | 145 | } |
173 | 146 |
|
174 | 147 | #[derive(Eq, PartialEq, Debug, Clone)] |
|
0 commit comments