[refurb] Make fix unsafe if it deletes comments (FURB181) (#22666)

<!--
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 19:49:47 +03:00
committed by GitHub
parent f0534e9cfd
commit fa42b09e3f
3 changed files with 50 additions and 4 deletions

View File

@@ -55,3 +55,12 @@ class Hash:
Hash().digest().hex()
hashed = (
sha512(b"some data")
.digest(
# text
)
.hex()
)

View File

@@ -1,3 +1,4 @@
use ruff_diagnostics::Applicability;
use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_python_ast::{Expr, ExprAttribute, ExprCall};
use ruff_python_semantic::Modules;
@@ -28,6 +29,9 @@ use crate::{Edit, Fix, FixAvailability, Violation};
/// hashed = sha512(b"some data").hexdigest()
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as safe, unless the expression contains comments.
///
/// ## References
/// - [Python documentation: `hashlib`](https://docs.python.org/3/library/hashlib.html)
#[derive(ViolationMetadata)]
@@ -112,10 +116,18 @@ pub(crate) fn hashlib_digest_hex(checker: &Checker, call: &ExprCall) {
{
let mut diagnostic = checker.report_diagnostic(HashlibDigestHex, call.range());
if arguments.is_empty() {
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
".hexdigest".to_string(),
TextRange::new(value.end(), call.func.end()),
)));
let replacement_range = TextRange::new(value.end(), call.func.end());
let applicability = if checker.comment_ranges().intersects(replacement_range) {
Applicability::Unsafe
} else {
Applicability::Safe
};
diagnostic.set_fix(Fix::applicable_edit(
Edit::range_replacement(".hexdigest".to_string(), replacement_range),
applicability,
));
}
}
}

View File

@@ -322,3 +322,28 @@ help: Replace with `.hexdigest()`
39 |
40 | # not yet supported
41 | h = sha256()
FURB181 [*] Use of hashlib's `.digest().hex()`
--> FURB181.py:61:5
|
60 | hashed = (
61 | / sha512(b"some data")
62 | | .digest(
63 | | # text
64 | | )
65 | | .hex()
| |__________^
66 | )
|
help: Replace with `.hexdigest()`
58 |
59 |
60 | hashed = (
- sha512(b"some data")
- .digest(
- # text
- )
- .hex()
61 + sha512(b"some data").hexdigest()
62 | )
note: This is an unsafe fix and may change runtime behavior