[flake8-simplify] Make fix unsafe if it deletes comments (SIM911) (#22661)

<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
This commit is contained in:
chiri
2026-01-20 18:15:46 +03:00
committed by GitHub
parent 94ccbd28cf
commit c1491a7a72
3 changed files with 52 additions and 4 deletions

View File

@@ -38,3 +38,13 @@ for country, stars in(zip)(flag_stars.keys(), flag_stars.values()):...
# Regression test for https://github.com/astral-sh/ruff/issues/18778
d = {}
for country, stars in zip(d.keys(*x), d.values("hello")):...
flag_stars = {"USA": 50, "Slovenia": 3, "Panama": 2, "Australia": 6}
for country, stars in zip(
flag_stars.keys(),
# text
flag_stars.values(),
):
print(f"{country}'s flag has {stars} stars.")

View File

@@ -1,4 +1,5 @@
use ast::{ExprAttribute, ExprName, Identifier};
use ruff_diagnostics::Applicability;
use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_python_ast::{self as ast, Arguments, Expr};
use ruff_python_semantic::analyze::typing::is_dict;
@@ -30,6 +31,9 @@ use crate::{checkers::ast::Checker, fix::snippet::SourceCodeSnippet};
/// print(f"{country}'s flag has {stars} stars.")
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as safe, unless the expression contains comments.
///
/// ## References
/// - [Python documentation: `dict.items`](https://docs.python.org/3/library/stdtypes.html#dict.items)
#[derive(ViolationMetadata)]
@@ -122,10 +126,17 @@ pub(crate) fn zip_dict_keys_and_values(checker: &Checker, expr: &ast::ExprCall)
},
expr.range(),
);
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
expected,
expr.range(),
)));
let applicability = if checker.comment_ranges().intersects(expr.range()) {
Applicability::Unsafe
} else {
Applicability::Safe
};
diagnostic.set_fix(Fix::applicable_edit(
Edit::range_replacement(expected, expr.range()),
applicability,
));
}
fn get_var_attr_args(expr: &Expr) -> Option<(&ExprName, &Identifier, &Arguments)> {

View File

@@ -93,3 +93,30 @@ help: Replace `(zip)(flag_stars.keys(), flag_stars.values())` with ` flag_stars.
37 |
38 | # Regression test for https://github.com/astral-sh/ruff/issues/18778
39 | d = {}
SIM911 [*] Use `dict.items()` instead of `zip(dict.keys(), dict.values())`
--> SIM911.py:45:23
|
43 | flag_stars = {"USA": 50, "Slovenia": 3, "Panama": 2, "Australia": 6}
44 |
45 | for country, stars in zip(
| _______________________^
46 | | flag_stars.keys(),
47 | | # text
48 | | flag_stars.values(),
49 | | ):
| |_^
50 | print(f"{country}'s flag has {stars} stars.")
|
help: Replace `zip(dict.keys(), dict.values())` with `dict.items()`
42 |
43 | flag_stars = {"USA": 50, "Slovenia": 3, "Panama": 2, "Australia": 6}
44 |
- for country, stars in zip(
- flag_stars.keys(),
- # text
- flag_stars.values(),
- ):
45 + for country, stars in flag_stars.items():
46 | print(f"{country}'s flag has {stars} stars.")
note: This is an unsafe fix and may change runtime behavior