Skip to content

Commit 050bb33

Browse files
committed
Cleaner code for unsep literals
1 parent 56f51b3 commit 050bb33

5 files changed

+137
-85
lines changed

clippy_lints/src/misc_early.rs

Lines changed: 84 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, Lin
66
use rustc::{declare_lint_pass, declare_tool_lint};
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_errors::Applicability;
9-
use std::char;
109
use syntax::ast::*;
1110
use syntax::source_map::Span;
1211
use syntax::visit::{walk_expr, FnKind, Visitor};
@@ -391,92 +390,102 @@ impl EarlyLintPass for MiscEarlyLints {
391390

392391
impl MiscEarlyLints {
393392
fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
394-
if_chain! {
395-
if let LitKind::Int(value, ..) = lit.node;
396-
if let Some(src) = snippet_opt(cx, lit.span);
397-
if let Some(firstch) = src.chars().next();
398-
if char::to_digit(firstch, 10).is_some();
399-
then {
400-
let mut prev = '\0';
401-
for (idx, ch) in src.chars().enumerate() {
402-
if ch == 'i' || ch == 'u' {
403-
if prev != '_' {
404-
span_lint_and_sugg(
405-
cx,
406-
UNSEPARATED_LITERAL_SUFFIX,
407-
lit.span,
408-
"integer type suffix should be separated by an underscore",
409-
"add an underscore",
410-
format!("{}_{}", &src[0..idx], &src[idx..]),
411-
Applicability::MachineApplicable,
412-
);
413-
}
414-
break;
415-
}
416-
prev = ch;
393+
// The `line!()` macro is compiler built-in and a special case for these lints.
394+
let lit_snip = match snippet_opt(cx, lit.span) {
395+
Some(snip) => {
396+
if snip.contains('!') {
397+
return;
417398
}
418-
if src.starts_with("0x") {
419-
let mut seen = (false, false);
420-
for ch in src.chars() {
421-
match ch {
422-
'a' ..= 'f' => seen.0 = true,
423-
'A' ..= 'F' => seen.1 = true,
424-
'i' | 'u' => break, // start of suffix already
425-
_ => ()
426-
}
427-
}
428-
if seen.0 && seen.1 {
429-
span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
430-
"inconsistent casing in hexadecimal literal");
399+
snip
400+
},
401+
_ => return,
402+
};
403+
404+
if let LitKind::Int(value, lit_int_type) = lit.node {
405+
let suffix = match lit_int_type {
406+
LitIntType::Signed(ty) => ty.ty_to_string(),
407+
LitIntType::Unsigned(ty) => ty.ty_to_string(),
408+
LitIntType::Unsuffixed => "",
409+
};
410+
411+
let maybe_last_sep_idx = lit_snip.len() - suffix.len() - 1;
412+
// Do not lint when literal is unsuffixed.
413+
if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
414+
span_lint_and_sugg(
415+
cx,
416+
UNSEPARATED_LITERAL_SUFFIX,
417+
lit.span,
418+
"integer type suffix should be separated by an underscore",
419+
"add an underscore",
420+
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
421+
Applicability::MachineApplicable,
422+
);
423+
}
424+
425+
if lit_snip.starts_with("0x") {
426+
let mut seen = (false, false);
427+
for ch in lit_snip.as_bytes()[2..=maybe_last_sep_idx].iter() {
428+
match ch {
429+
b'a'..=b'f' => {
430+
seen.0 = true;
431+
if seen.1 {
432+
break;
433+
}
434+
},
435+
b'A'..=b'F' => {
436+
seen.1 = true;
437+
if seen.0 {
438+
break;
439+
}
440+
},
441+
_ => {},
431442
}
432-
} else if src.starts_with("0b") || src.starts_with("0o") {
433-
/* nothing to do */
434-
} else if value != 0 && src.starts_with('0') {
435-
span_lint_and_then(cx,
436-
ZERO_PREFIXED_LITERAL,
437-
lit.span,
438-
"this is a decimal constant",
439-
|db| {
443+
}
444+
if seen.0 && seen.1 {
445+
span_lint(
446+
cx,
447+
MIXED_CASE_HEX_LITERALS,
448+
lit.span,
449+
"inconsistent casing in hexadecimal literal",
450+
);
451+
}
452+
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
453+
/* nothing to do */
454+
} else if value != 0 && lit_snip.starts_with('0') {
455+
span_lint_and_then(
456+
cx,
457+
ZERO_PREFIXED_LITERAL,
458+
lit.span,
459+
"this is a decimal constant",
460+
|db| {
440461
db.span_suggestion(
441462
lit.span,
442-
"if you mean to use a decimal constant, remove the `0` to remove confusion",
443-
src.trim_start_matches(|c| c == '_' || c == '0').to_string(),
463+
"if you mean to use a decimal constant, remove the `0` to avoid confusion",
464+
lit_snip.trim_start_matches(|c| c == '_' || c == '0').to_string(),
444465
Applicability::MaybeIncorrect,
445466
);
446467
db.span_suggestion(
447468
lit.span,
448469
"if you mean to use an octal constant, use `0o`",
449-
format!("0o{}", src.trim_start_matches(|c| c == '_' || c == '0')),
470+
format!("0o{}", lit_snip.trim_start_matches(|c| c == '_' || c == '0')),
450471
Applicability::MaybeIncorrect,
451472
);
452-
});
453-
}
473+
},
474+
);
454475
}
455-
}
456-
if_chain! {
457-
if let LitKind::Float(..) = lit.node;
458-
if let Some(src) = snippet_opt(cx, lit.span);
459-
if let Some(firstch) = src.chars().next();
460-
if char::to_digit(firstch, 10).is_some();
461-
then {
462-
let mut prev = '\0';
463-
for (idx, ch) in src.chars().enumerate() {
464-
if ch == 'f' {
465-
if prev != '_' {
466-
span_lint_and_sugg(
467-
cx,
468-
UNSEPARATED_LITERAL_SUFFIX,
469-
lit.span,
470-
"float type suffix should be separated by an underscore",
471-
"add an underscore",
472-
format!("{}_{}", &src[0..idx], &src[idx..]),
473-
Applicability::MachineApplicable,
474-
);
475-
}
476-
break;
477-
}
478-
prev = ch;
479-
}
476+
} else if let LitKind::Float(_, float_ty) = lit.node {
477+
let suffix = float_ty.ty_to_string();
478+
let maybe_last_sep_idx = lit_snip.len() - suffix.len() - 1;
479+
if lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
480+
span_lint_and_sugg(
481+
cx,
482+
UNSEPARATED_LITERAL_SUFFIX,
483+
lit.span,
484+
"float type suffix should be separated by an underscore",
485+
"add an underscore",
486+
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
487+
Applicability::MachineApplicable,
488+
);
480489
}
481490
}
482491
}

tests/ui/literals.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ LL | let fail_multi_zero = 000_123usize;
2525
| ^^^^^^^^^^^^
2626
|
2727
= note: `-D clippy::zero-prefixed-literal` implied by `-D warnings`
28-
help: if you mean to use a decimal constant, remove the `0` to remove confusion
28+
help: if you mean to use a decimal constant, remove the `0` to avoid confusion
2929
|
3030
LL | let fail_multi_zero = 123usize;
3131
| ^^^^^^^^
@@ -39,7 +39,7 @@ error: this is a decimal constant
3939
|
4040
LL | let fail8 = 0123;
4141
| ^^^^
42-
help: if you mean to use a decimal constant, remove the `0` to remove confusion
42+
help: if you mean to use a decimal constant, remove the `0` to avoid confusion
4343
|
4444
LL | let fail8 = 123;
4545
| ^^^

tests/ui/unseparated_prefix_literals.fixed

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
#![warn(clippy::unseparated_literal_suffix)]
44
#![allow(dead_code)]
55

6+
macro_rules! lit_from_macro {
7+
() => {
8+
42_usize
9+
};
10+
}
11+
612
fn main() {
713
let _ok1 = 1234_i32;
814
let _ok2 = 1234_isize;
@@ -17,4 +23,12 @@ fn main() {
1723
let _okf2 = 1_f32;
1824
let _failf1 = 1.5_f32;
1925
let _failf2 = 1_f32;
26+
27+
// Test for macro
28+
let _ = lit_from_macro!();
29+
30+
// Counter example
31+
let _ = line!();
32+
// Because `assert!` contains `line!()` macro.
33+
assert_eq!(4897_u32, 32223);
2034
}

tests/ui/unseparated_prefix_literals.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
#![warn(clippy::unseparated_literal_suffix)]
44
#![allow(dead_code)]
55

6+
macro_rules! lit_from_macro {
7+
() => {
8+
42usize
9+
};
10+
}
11+
612
fn main() {
713
let _ok1 = 1234_i32;
814
let _ok2 = 1234_isize;
@@ -17,4 +23,12 @@ fn main() {
1723
let _okf2 = 1_f32;
1824
let _failf1 = 1.5f32;
1925
let _failf2 = 1f32;
26+
27+
// Test for macro
28+
let _ = lit_from_macro!();
29+
30+
// Counter example
31+
let _ = line!();
32+
// Because `assert!` contains `line!()` macro.
33+
assert_eq!(4897u32, 32223);
2034
}
Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,61 @@
11
error: integer type suffix should be separated by an underscore
2-
--> $DIR/unseparated_prefix_literals.rs:10:18
2+
--> $DIR/unseparated_prefix_literals.rs:16:18
33
|
44
LL | let _fail1 = 1234i32;
55
| ^^^^^^^ help: add an underscore: `1234_i32`
66
|
77
= note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
88

99
error: integer type suffix should be separated by an underscore
10-
--> $DIR/unseparated_prefix_literals.rs:11:18
10+
--> $DIR/unseparated_prefix_literals.rs:17:18
1111
|
1212
LL | let _fail2 = 1234u32;
1313
| ^^^^^^^ help: add an underscore: `1234_u32`
1414

1515
error: integer type suffix should be separated by an underscore
16-
--> $DIR/unseparated_prefix_literals.rs:12:18
16+
--> $DIR/unseparated_prefix_literals.rs:18:18
1717
|
1818
LL | let _fail3 = 1234isize;
1919
| ^^^^^^^^^ help: add an underscore: `1234_isize`
2020

2121
error: integer type suffix should be separated by an underscore
22-
--> $DIR/unseparated_prefix_literals.rs:13:18
22+
--> $DIR/unseparated_prefix_literals.rs:19:18
2323
|
2424
LL | let _fail4 = 1234usize;
2525
| ^^^^^^^^^ help: add an underscore: `1234_usize`
2626

2727
error: integer type suffix should be separated by an underscore
28-
--> $DIR/unseparated_prefix_literals.rs:14:18
28+
--> $DIR/unseparated_prefix_literals.rs:20:18
2929
|
3030
LL | let _fail5 = 0x123isize;
3131
| ^^^^^^^^^^ help: add an underscore: `0x123_isize`
3232

3333
error: float type suffix should be separated by an underscore
34-
--> $DIR/unseparated_prefix_literals.rs:18:19
34+
--> $DIR/unseparated_prefix_literals.rs:24:19
3535
|
3636
LL | let _failf1 = 1.5f32;
3737
| ^^^^^^ help: add an underscore: `1.5_f32`
3838

3939
error: float type suffix should be separated by an underscore
40-
--> $DIR/unseparated_prefix_literals.rs:19:19
40+
--> $DIR/unseparated_prefix_literals.rs:25:19
4141
|
4242
LL | let _failf2 = 1f32;
4343
| ^^^^ help: add an underscore: `1_f32`
4444

45-
error: aborting due to 7 previous errors
45+
error: integer type suffix should be separated by an underscore
46+
--> $DIR/unseparated_prefix_literals.rs:8:9
47+
|
48+
LL | 42usize
49+
| ^^^^^^^ help: add an underscore: `42_usize`
50+
...
51+
LL | let _ = lit_from_macro!();
52+
| ----------------- in this macro invocation
53+
54+
error: integer type suffix should be separated by an underscore
55+
--> $DIR/unseparated_prefix_literals.rs:33:16
56+
|
57+
LL | assert_eq!(4897u32, 32223);
58+
| ^^^^^^^ help: add an underscore: `4897_u32`
59+
60+
error: aborting due to 9 previous errors
4661

0 commit comments

Comments
 (0)