Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/pylint/rules/swap_with_temporary_variable.rs (Rust)

Code before:
}

/// Match consecutive assignment statements.
///
/// Also see the `repeated_append` rule for a similar use case.
fn match_consecutive_assignments<'a>(
    semantic: &'a SemanticModel<'a>,
    scope_id: ScopeId,
    binding_id: BindingId,
) -> Option<(
    VarToVarAssignment<'a>,
    VarToVarAssignment<'a>,
    VarToVarAssignment<'a>,
)> {
    let binding = semantic.binding(binding_id);

    // Only consider simple assignments (no imports, function defs, etc.)
    if !binding.kind.is_assignment() {
        return None;
    }

    let node_id = binding.source?;

    let stmt = binding
        .statement(semantic)
        .expect("binding with source should have statement");

    let stmt_a = VarToVarAssignment::from_stmt(stmt)?;

    // Find the enclosing suite so we can look at the next siblings.
    // For the global scope, use the module body; otherwise, find the parent statement.
    let suite = if scope_id.is_global() {
        semantic
            .definitions
            .python_ast()
            .and_then(|module| traversal::EnclosingSuite::new(module, stmt.into()))
    } else {
        semantic
            .parent_statement(node_id)
            .and_then(|parent| traversal::suite(stmt, parent))
    }?;

    let stmt_b = suite
        .next_sibling()
        .and_then(VarToVarAssignment::from_stmt)?;
    let stmt_c = suite
        .next_siblings()
        .get(1)
        .and_then(VarToVarAssignment::from_stmt)?;

    Some((stmt_a, stmt_b, stmt_c))

Review comment (bug):
This is probably safe to do, but since we're returning an option anyway, I'd probably just use `?`:


```suggestion
        ?;
```

If you really want to assert that this is always `Some`, we could use `debug_assert!`. I'd just prefer to avoid the potential to panic in release builds.

Code after:
    VarToVarAssignment<'a>,
)> {
    let binding = semantic.binding(binding_id);

    // Only consider simple assignments (no imports, function defs, etc.)
    if !binding.kind.is_assignment() {
        return None;
    }

    let node_id = binding.source?;

    let stmt = binding.statement(semantic)?;
    let stmt_a = VarToVarAssignment::from_stmt(stmt)?;

    // Find the enclosing suite so we can look at the next siblings.
    // For the global scope, use the module body; otherwise, find the parent statement.
    let suite = if scope_id.is_global() {
        traversal::EnclosingSuite::new(semantic.definitions.python_ast()?, stmt.into())
    } else {
        traversal::suite(stmt, semantic.parent_statement(node_id)?)
    }?;

    let stmt_b = VarToVarAssignment::from_stmt(suite.next_sibling()?)?;
    let stmt_c = VarToVarAssignment::from_stmt(suite.next_siblings().get(1)?)?;

    Some((stmt_a, stmt_b, stmt_c))
}

#[derive(Eq, PartialEq, Debug, Clone)]
struct VarToVarAssignment<'a> {
    target: &'a Name,
    value: &'a Name,
    range: TextRange,
}

impl Ranged for VarToVarAssignment<'_> {
    fn range(&self) -> TextRange {
        self.range
    }
}

impl<'a> VarToVarAssignment<'a> {
    fn from_stmt(stmt: &'a Stmt) -> Option<VarToVarAssignment<'a>> {
        let (target, value) = match stmt {
            Stmt::Assign(stmt_assign) => {
                // only one variable is expected for matching the pattern
                let [target_variable] = stmt_assign.targets.as_slice() else {
                    return None;
                };

                (target_variable, &stmt_assign.value)