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

Code before:
        {
            let concatable = matches!(
                (left.as_ref(), right.as_ref()),
                (
                    Expr::StringLiteral(_) | Expr::FString(_),
                    Expr::StringLiteral(_) | Expr::FString(_)
                ) | (Expr::BytesLiteral(_), Expr::BytesLiteral(_))
                    | (Expr::TString(_), Expr::TString(_))
            );
            if concatable
                && checker
                    .locator()
                    .contains_line_break(TextRange::new(left.end(), right.start()))
            {
                let mut diagnostic =
                    checker.report_diagnostic(ExplicitStringConcatenation, expr.range());

                let is_parenthesized = |expr: &Expr| {
                    parenthesized_range(
                        expr.into(),
                        bin_op.into(),
                        checker.comment_ranges(),
                        checker.source(),
                    )
                    .is_some()
                };
                // If either `left` or `right` is parenthesized, generating
                // a fix would be too involved. Just report the diagnostic.
                if is_parenthesized(left) || is_parenthesized(right) {
                    return;
                }

                diagnostic.set_fix(generate_fix(checker, bin_op));
            }
        }
    }
}

fn generate_fix(checker: &Checker, expr_bin_op: &ast::ExprBinOp) -> Fix {
    let ast::ExprBinOp { left, right, .. } = expr_bin_op;

    let between_operands_range = TextRange::new(left.end(), right.start());
    let between_operands = checker.locator().slice(between_operands_range);
    let (before_plus, after_plus) = between_operands.split_once('+').unwrap();

    let linebreak_before_operator =
        before_plus.contains_line_break(TextRange::at(TextSize::new(0), before_plus.text_len()));

    // If removing `+` from first line trim trailing spaces
    // Preserve indentation when removing `+` from second line
    let before_plus = if linebreak_before_operator {

Review comment (suggestion):
I think it's preferred to have this as a separate function that takes appropriate arguments rather than a block.

I think it would also be better to have a function that takes both left and right sides at the same time, and then the code below could be something like:

```rust
if !is_either_side_parenthesized(left, right, ...) {
    diagnostic.set_fix(...);
}
```

Code after:
        {
            let concatable = matches!(
                (left.as_ref(), right.as_ref()),
                (
                    Expr::StringLiteral(_) | Expr::FString(_),
                    Expr::StringLiteral(_) | Expr::FString(_)
                ) | (Expr::BytesLiteral(_), Expr::BytesLiteral(_))
                    | (Expr::TString(_), Expr::TString(_))
            );
            if concatable
                && checker
                    .locator()
                    .contains_line_break(TextRange::new(left.end(), right.start()))
            {
                let mut diagnostic =
                    checker.report_diagnostic(ExplicitStringConcatenation, expr.range());

                let is_parenthesized = |expr: &Expr| {
                    parenthesized_range(
                        expr.into(),
                        bin_op.into(),
                        checker.comment_ranges(),
                        checker.source(),
                    )
                    .is_some()
                };
                // If either `left` or `right` is parenthesized, generating
                // a fix would be too involved. Just report the diagnostic.
                // Currently, attempting `generate_fix` would result in
                // an invalid code. See: #19757
                if is_parenthesized(left) || is_parenthesized(right) {
                    return;
                }

                diagnostic.set_fix(generate_fix(checker, bin_op));
            }
        }
    }
}

fn generate_fix(checker: &Checker, expr_bin_op: &ast::ExprBinOp) -> Fix {
    let ast::ExprBinOp { left, right, .. } = expr_bin_op;

    let between_operands_range = TextRange::new(left.end(), right.start());
    let between_operands = checker.locator().slice(between_operands_range);
    let (before_plus, after_plus) = between_operands.split_once('+').unwrap();

    let linebreak_before_operator =
        before_plus.contains_line_break(TextRange::at(TextSize::new(0), before_plus.text_len()));

    // If removing `+` from first line trim trailing spaces