Skip to content

Conversation

@mikeleppane
Copy link
Contributor

Summary

Problem

The ISC003 rule was flagging explicit string concatenation ("a" + "b") in all contexts, but it should only apply when the concatenation is inside brackets (parentheses or braces) where implicit concatenation is possible.

Solution

Added a new is_inside_brackets() helper function that:

  • Locates the current statement containing the expression
  • Searches for opening brackets (( or {) before the expression
  • Searches for closing brackets () or }) after the expression
  • Only reports violations when both bracket types are present

Example

Input

# input
_ = "Line1\n" + (
        "Line2\n"
        + "Line3"
)

ruff check --fix =>

_ = "Line1\n" + (
        "Line2\n"
         "Line3"
)

ISSUE

Test Plan

cargo test

… inside brackets (astral-sh#19757)

## Summary

This update introduces stricter behavior for the ISC003 rule by detecting explicitly concatenated strings only if they are within brackets. Adds a helper function `is_inside_brackets` to verify bracket context and adjusts diagnostics accordingly.

## Test Plan

```bash
cargo test
```
@github-actions
Copy link
Contributor

github-actions bot commented Aug 6, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@ntBre ntBre linked an issue Aug 6, 2025 that may be closed by this pull request
@ntBre ntBre added bug Something isn't working fixes Related to suggested fixes for violations labels Aug 6, 2025
Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd prefer a different approach here, but thanks for working on it!

}
}

fn is_inside_brackets(checker: &Checker, expr_range: TextRange) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel like the right fix to me, and processing characters individually like this seems very brittle. My understanding of the issue in the report was that we just need to check if either the left- or right-hand-side of the binary concatenation operator is parenthesized because the fix simply strips out the + between them.

This is just a limitation in the concatable check because Ruff knows that ("1" "2") resolves to a single StringLiteral node in the AST.

I think we can probably just use this helper function to check if left and right are parenthesized and avoid the fix if either of them is:

/// Returns the [`TextRange`] of a given expression including parentheses, if the expression is
/// parenthesized; or `None`, if the expression is not parenthesized.
pub fn parenthesized_range(
expr: ExprRef,
parent: AnyNodeRef,

We can also still report a diagnostic in this case, we just can't autofix it. Another option would be to try to move one of the expressions into the existing parentheses from the other expression, but that might be too involved. I'd be happy with just offering a diagnostic but no fix if one of them is parenthesized to avoid causing the runtime error.

@MichaReiser
Copy link
Member

@mikeleppane thanks for working on this. Do you plan to come back to this PR or should we close it (don't feel pressued that you have to, just checking in on the status of this PR is).

@MichaReiser
Copy link
Member

Thanks for working on this fix. I'll close this PR due to inactivity. A new PR (from you or anyone else who wants to work on this fix) with Brent's feedback would be welcomed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working fixes Related to suggested fixes for violations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Autofix for ISC003 produces malformed code

3 participants