Skip to content

[flake8-bugbear] Fix break/continue handling in loop-iterator-mutation (B909)#24440

Merged
MichaReiser merged 5 commits into
astral-sh:mainfrom
anishgirianish:fix/b909-break-continue-branch-tracking
Apr 21, 2026
Merged

[flake8-bugbear] Fix break/continue handling in loop-iterator-mutation (B909)#24440
MichaReiser merged 5 commits into
astral-sh:mainfrom
anishgirianish:fix/b909-break-continue-branch-tracking

Conversation

@anishgirianish
Copy link
Copy Markdown
Contributor

@anishgirianish anishgirianish commented Apr 6, 2026

Summary

Fixes #12402.

B909's branch tracking had a few issues: the branch counter wasn't restored after if blocks, continue wasn't handled as a terminator, nested loop break/continue was incorrectly treated as exiting the outer loop, and there was no branch isolation for for/else, while/else, or try/except/else/finally.

Fixed by tracking loop_depth so nested break only affects the inner loop, giving each arm of forking statements its own branch (merged back into the parent on exit), and pre-scanning loop bodies to determine whether else is unconditional.

Test Plan

Added 8 fixture cases covering nested break/continue, for/else, while/else, and try/except/else/finally.

@astral-sh-bot astral-sh-bot Bot requested a review from ntBre April 6, 2026 06:18
@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented Apr 6, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+0 -2 violations, +0 -0 fixes in 2 projects; 54 projects unchanged)

binary-husky/gpt_academic (+0 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- shared_utils/nltk_downloader.py:2141:17: B909 Mutation to loop iterable `self._download_msg_queue` during iteration

pytest-dev/pytest (+0 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- scripts/release.py:65:17: B909 Mutation to loop iterable `lines` during iteration

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
B909 2 0 2 0 0

@MichaReiser MichaReiser added rule Implementing or modifying a lint rule preview Related to preview mode features labels Apr 8, 2026
Comment thread crates/ruff_linter/src/rules/flake8_bugbear/rules/loop_iterator_mutation.rs Outdated
Comment thread crates/ruff_linter/src/rules/flake8_bugbear/rules/loop_iterator_mutation.rs Outdated
@MichaReiser MichaReiser assigned MichaReiser and unassigned ntBre Apr 9, 2026
@anishgirianish
Copy link
Copy Markdown
Contributor Author

@MichaReiser Thank you so much for the review. Addressed both comments, nested break/continue is now gated by loop depth, and branch tracking covers for/else, while/else, and try/except/else/finally. Ready for re-review whenever you have time!

Thank you

@ntBre ntBre removed their request for review April 13, 2026 13:37
@MichaReiser MichaReiser changed the title [flake8-bugbear] Fix break/continue handling in loop-iterator-mutation [flake8-bugbear] Fix break/continue handling in loop-iterator-mutation (B909) Apr 14, 2026
Comment thread crates/ruff_linter/src/rules/flake8_bugbear/rules/loop_iterator_mutation.rs Outdated
Comment thread crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B909.py
Comment thread crates/ruff_linter/src/rules/flake8_bugbear/rules/loop_iterator_mutation.rs Outdated
Copy link
Copy Markdown
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

Thank you. I found one more false positive which we should fix if it's easy to do so. If not, that's fine also.

This PR is certainly a big improvement!

Comment thread crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B909.py
@anishgirianish anishgirianish force-pushed the fix/b909-break-continue-branch-tracking branch from a7d4d02 to e947692 Compare April 18, 2026 19:31
@MichaReiser MichaReiser merged commit 11db358 into astral-sh:main Apr 21, 2026
44 checks passed
nicopauss pushed a commit to Intersec/lib-common that referenced this pull request Jun 4, 2026
##### [\`v0.15.12\`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#01512)

Released on 2026-04-24.

##### Preview features

- Implement `#ruff:file-ignore` file-level suppressions ([#23599](astral-sh/ruff#23599))
- Implement `#ruff:ignore` logical-line suppressions ([#23404](astral-sh/ruff#23404))
- Revert preview changes to displayed diagnostic severity in LSP ([#24789](astral-sh/ruff#24789))
- \[`airflow`] Implement `task-branch-as-short-circuit` (`AIR004`) ([#23579](astral-sh/ruff#23579))
- \[`flake8-bugbear`] Fix `break`/`continue` handling in `loop-iterator-mutation` (`B909`) ([#24440](astral-sh/ruff#24440))
- \[`pylint`] Fix `PLC2701` for type parameter scopes ([#24576](astral-sh/ruff#24576))

##### Rule changes

- \[`pandas-vet`] Suggest `.array` as well in `PD011` ([#24805](astral-sh/ruff#24805))

##### CLI

- Respect default Unix permissions for cache files ([#24794](astral-sh/ruff#24794))

##### Documentation

- \[`pylint`] Fix `PLR0124` description not to claim self-comparison always returns the same value ([#24749](astral-sh/ruff#24749))
- \[`pyupgrade`] Expand docs on reusable `TypeVar`s and scoping (`UP046`) ([#24153](astral-sh/ruff#24153))
- Improve rules table accessibility ([#24711](astral-sh/ruff#24711))

##### Contributors

- [@dylwil3](https://github.com/dylwil3)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@woodruffw](https://github.com/woodruffw)
- [@avasis-ai](https://github.com/avasis-ai)
- [@Dev-iL](https://github.com/Dev-iL)
- [@denyszhak](https://github.com/denyszhak)
- [@ShipItAndPray](https://github.com/ShipItAndPray)
- [@anishgirianish](https://github.com/anishgirianish)
- [@augustelalande](https://github.com/augustelalande)
- [@amyreese](https://github.com/amyreese)
- [@majiayu000](https://github.com/majiayu000)
##### [\`v0.15.11\`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#01511)

Released on 2026-04-16.

##### Preview features

- \[`ruff`] Ignore `RUF029` when function is decorated with `asynccontextmanager` ([#24642](astral-sh/ruff#24642))
- \[`airflow`] Implement `airflow-xcom-pull-in-template-string` (`AIR201`) ([#23583](astral-sh/ruff#23583))
- \[`flake8-bandit`] Fix `S103` false positives and negatives in mask analysis ([#24424](astral-sh/ruff#24424))

##### Bug fixes

- \[`flake8-async`] Omit overridden methods for `ASYNC109` ([#24648](astral-sh/ruff#24648))

##### Documentation

- \[`flake8-async`] Add override mention to `ASYNC109` docs ([#24666](astral-sh/ruff#24666))
- Update Neovim config examples to use `vim.lsp.config` ([#24577](astral-sh/ruff#24577))

##### Contributors

- [@augustelalande](https://github.com/augustelalande)
- [@anishgirianish](https://github.com/anishgirianish)
- [@benberryallwood](https://github.com/benberryallwood)
- [@charliermarsh](https://github.com/charliermarsh)
- [@Dev-iL](https://github.com/Dev-iL)

Renovate-Branch: renovate/2024.6-ruff-0.15.x
Change-Id: I2c5de44f14ce3133db71161eae18c7b43f7ba09b
Priv-Id: 9c1a7f10043a2db2338a90de9a62a4d7989df14d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Related to preview mode features rule Implementing or modifying a lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

loop-iterator-mutation (B909) - logic to determine whether the mutation is followed by a break statement is incorrect

3 participants