Skip to content

Commit dd8cf05

Browse files
authored
better help for mixed_case_hex_literals (rust-lang#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
2 parents cdc1d9d + e587a5d commit dd8cf05

File tree

3 files changed

+62
-20
lines changed

3 files changed

+62
-20
lines changed
Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,51 @@
1-
use clippy_utils::diagnostics::span_lint;
1+
use clippy_utils::diagnostics::span_lint_and_help;
22
use rustc_lint::EarlyContext;
33
use rustc_span::Span;
44

55
use super::MIXED_CASE_HEX_LITERALS;
66

77
pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, suffix: &str, lit_snip: &str) {
8-
let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
9-
return; // It's useless so shouldn't lint.
8+
let num_end_idx = match lit_snip.strip_suffix(suffix) {
9+
Some(p) if p.ends_with('_') => lit_snip.len() - (suffix.len() + 1),
10+
Some(_) => lit_snip.len() - suffix.len(),
11+
None => lit_snip.len(),
1012
};
11-
if maybe_last_sep_idx <= 2 {
13+
14+
if num_end_idx <= 2 {
1215
// It's meaningless or causes range error.
1316
return;
1417
}
18+
1519
let mut seen = (false, false);
16-
for ch in &lit_snip.as_bytes()[2..=maybe_last_sep_idx] {
20+
for ch in &lit_snip.as_bytes()[2..num_end_idx] {
1721
match ch {
1822
b'a'..=b'f' => seen.0 = true,
1923
b'A'..=b'F' => seen.1 = true,
2024
_ => {},
2125
}
2226
if seen.0 && seen.1 {
23-
span_lint(
27+
let raw_digits = &lit_snip[2..num_end_idx];
28+
let (sugg_lower, sugg_upper) = if suffix.is_empty() {
29+
(
30+
format!("0x{}", raw_digits.to_lowercase()),
31+
format!("0x{}", raw_digits.to_uppercase()),
32+
)
33+
} else {
34+
(
35+
format!("0x{}_{}", raw_digits.to_lowercase(), suffix),
36+
format!("0x{}_{}", raw_digits.to_uppercase(), suffix),
37+
)
38+
};
39+
40+
span_lint_and_help(
2441
cx,
2542
MIXED_CASE_HEX_LITERALS,
2643
lit_span,
2744
"inconsistent casing in hexadecimal literal",
45+
None,
46+
format!("consider using `{sugg_lower}` or `{sugg_upper}`"),
2847
);
29-
break;
48+
return;
3049
}
3150
}
3251
}

tests/ui/literals.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ fn main() {
3030
//~^ separated_literal_suffix
3131
//~| mixed_case_hex_literals
3232

33+
let fail2 = 0xab_CD_isize;
34+
//~^ separated_literal_suffix
35+
//~| mixed_case_hex_literals
36+
3337
let fail_multi_zero = 000_123usize;
3438
//~^ unseparated_literal_suffix
3539
//~| zero_prefixed_literal

tests/ui/literals.stderr

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ error: inconsistent casing in hexadecimal literal
2525
LL | let fail1 = 0xabCD;
2626
| ^^^^^^
2727
|
28+
= help: consider using `0xabcd` or `0xABCD`
2829
= note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
2930
= help: to override `-D warnings` add `#[allow(clippy::mixed_case_hex_literals)]`
3031

@@ -39,6 +40,8 @@ error: inconsistent casing in hexadecimal literal
3940
|
4041
LL | let fail2 = 0xabCD_u32;
4142
| ^^^^^^^^^^
43+
|
44+
= help: consider using `0xabcd_u32` or `0xABCD_u32`
4245

4346
error: integer type suffix should not be separated by an underscore
4447
--> tests/ui/literals.rs:29:17
@@ -51,9 +54,25 @@ error: inconsistent casing in hexadecimal literal
5154
|
5255
LL | let fail2 = 0xabCD_isize;
5356
| ^^^^^^^^^^^^
57+
|
58+
= help: consider using `0xabcd_isize` or `0xABCD_isize`
59+
60+
error: integer type suffix should not be separated by an underscore
61+
--> tests/ui/literals.rs:33:17
62+
|
63+
LL | let fail2 = 0xab_CD_isize;
64+
| ^^^^^^^^^^^^^ help: remove the underscore: `0xab_CDisize`
65+
66+
error: inconsistent casing in hexadecimal literal
67+
--> tests/ui/literals.rs:33:17
68+
|
69+
LL | let fail2 = 0xab_CD_isize;
70+
| ^^^^^^^^^^^^^
71+
|
72+
= help: consider using `0xab_cd_isize` or `0xAB_CD_isize`
5473

5574
error: integer type suffix should be separated by an underscore
56-
--> tests/ui/literals.rs:33:27
75+
--> tests/ui/literals.rs:37:27
5776
|
5877
LL | let fail_multi_zero = 000_123usize;
5978
| ^^^^^^^^^^^^ help: add an underscore: `000_123_usize`
@@ -62,7 +81,7 @@ LL | let fail_multi_zero = 000_123usize;
6281
= help: to override `-D warnings` add `#[allow(clippy::unseparated_literal_suffix)]`
6382

6483
error: this is a decimal constant
65-
--> tests/ui/literals.rs:33:27
84+
--> tests/ui/literals.rs:37:27
6685
|
6786
LL | let fail_multi_zero = 000_123usize;
6887
| ^^^^^^^^^^^^
@@ -81,13 +100,13 @@ LL + let fail_multi_zero = 0o123usize;
81100
|
82101

83102
error: integer type suffix should not be separated by an underscore
84-
--> tests/ui/literals.rs:38:16
103+
--> tests/ui/literals.rs:42:16
85104
|
86105
LL | let ok10 = 0_i64;
87106
| ^^^^^ help: remove the underscore: `0i64`
88107

89108
error: this is a decimal constant
90-
--> tests/ui/literals.rs:41:17
109+
--> tests/ui/literals.rs:45:17
91110
|
92111
LL | let fail8 = 0123;
93112
| ^^^^
@@ -103,13 +122,13 @@ LL | let fail8 = 0o123;
103122
| +
104123

105124
error: integer type suffix should not be separated by an underscore
106-
--> tests/ui/literals.rs:51:16
125+
--> tests/ui/literals.rs:55:16
107126
|
108127
LL | let ok17 = 0x123_4567_8901_usize;
109128
| ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize`
110129

111130
error: digits grouped inconsistently by underscores
112-
--> tests/ui/literals.rs:56:18
131+
--> tests/ui/literals.rs:60:18
113132
|
114133
LL | let fail19 = 12_3456_21;
115134
| ^^^^^^^^^^ help: consider: `12_345_621`
@@ -118,19 +137,19 @@ LL | let fail19 = 12_3456_21;
118137
= help: to override `-D warnings` add `#[allow(clippy::inconsistent_digit_grouping)]`
119138

120139
error: digits grouped inconsistently by underscores
121-
--> tests/ui/literals.rs:59:18
140+
--> tests/ui/literals.rs:63:18
122141
|
123142
LL | let fail22 = 3__4___23;
124143
| ^^^^^^^^^ help: consider: `3_423`
125144

126145
error: digits grouped inconsistently by underscores
127-
--> tests/ui/literals.rs:62:18
146+
--> tests/ui/literals.rs:66:18
128147
|
129148
LL | let fail23 = 3__16___23;
130149
| ^^^^^^^^^^ help: consider: `31_623`
131150

132151
error: digits of hex, binary or octal literal not in groups of equal size
133-
--> tests/ui/literals.rs:65:18
152+
--> tests/ui/literals.rs:69:18
134153
|
135154
LL | let fail24 = 0xAB_ABC_AB;
136155
| ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB`
@@ -139,7 +158,7 @@ LL | let fail24 = 0xAB_ABC_AB;
139158
= help: to override `-D warnings` add `#[allow(clippy::unusual_byte_groupings)]`
140159

141160
error: this is a decimal constant
142-
--> tests/ui/literals.rs:75:13
161+
--> tests/ui/literals.rs:79:13
143162
|
144163
LL | let _ = 08;
145164
| ^^
@@ -151,7 +170,7 @@ LL + let _ = 8;
151170
|
152171

153172
error: this is a decimal constant
154-
--> tests/ui/literals.rs:78:13
173+
--> tests/ui/literals.rs:82:13
155174
|
156175
LL | let _ = 09;
157176
| ^^
@@ -163,7 +182,7 @@ LL + let _ = 9;
163182
|
164183

165184
error: this is a decimal constant
166-
--> tests/ui/literals.rs:81:13
185+
--> tests/ui/literals.rs:85:13
167186
|
168187
LL | let _ = 089;
169188
| ^^^
@@ -174,5 +193,5 @@ LL - let _ = 089;
174193
LL + let _ = 89;
175194
|
176195

177-
error: aborting due to 20 previous errors
196+
error: aborting due to 22 previous errors
178197

0 commit comments

Comments
 (0)