better help for mixed_case_hex_literals (#14235)

It can be error-prone for developers to manually change literals with
mixed uppercase and lowercase letters into consistently all-lowercase or
all-uppercase literals. Therefore, this lint rule should suggest
alternative literals.

changelog: [`mixed_case_hex_literals`]: add alternative suggestions
This commit is contained in:
Alex Macleod 2025-03-04 14:10:44 +00:00 committed by GitHub
commit dd8cf052c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 20 deletions

View file

@ -1,32 +1,51 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_lint::EarlyContext;
use rustc_span::Span;
use super::MIXED_CASE_HEX_LITERALS;
pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, suffix: &str, lit_snip: &str) {
let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
return; // It's useless so shouldn't lint.
let num_end_idx = match lit_snip.strip_suffix(suffix) {
Some(p) if p.ends_with('_') => lit_snip.len() - (suffix.len() + 1),
Some(_) => lit_snip.len() - suffix.len(),
None => lit_snip.len(),
};
if maybe_last_sep_idx <= 2 {
if num_end_idx <= 2 {
// It's meaningless or causes range error.
return;
}
let mut seen = (false, false);
for ch in &lit_snip.as_bytes()[2..=maybe_last_sep_idx] {
for ch in &lit_snip.as_bytes()[2..num_end_idx] {
match ch {
b'a'..=b'f' => seen.0 = true,
b'A'..=b'F' => seen.1 = true,
_ => {},
}
if seen.0 && seen.1 {
span_lint(
let raw_digits = &lit_snip[2..num_end_idx];
let (sugg_lower, sugg_upper) = if suffix.is_empty() {
(
format!("0x{}", raw_digits.to_lowercase()),
format!("0x{}", raw_digits.to_uppercase()),
)
} else {
(
format!("0x{}_{}", raw_digits.to_lowercase(), suffix),
format!("0x{}_{}", raw_digits.to_uppercase(), suffix),
)
};
span_lint_and_help(
cx,
MIXED_CASE_HEX_LITERALS,
lit_span,
"inconsistent casing in hexadecimal literal",
None,
format!("consider using `{sugg_lower}` or `{sugg_upper}`"),
);
break;
return;
}
}
}