Skip to content

Commit 2f8247a

Browse files
committed
Lint literal suffixes not separated by underscores (see #703)
1 parent ab58331 commit 2f8247a

File tree

10 files changed

+77
-16
lines changed

10 files changed

+77
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ All notable changes to this project will be documented in this file.
281281
[`unnecessary_operation`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation
282282
[`unneeded_field_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern
283283
[`unsafe_removed_from_name`]: https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name
284+
[`unseparated_literal_suffix`]: https://github.com/Manishearth/rust-clippy/wiki#unseparated_literal_suffix
284285
[`unstable_as_mut_slice`]: https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice
285286
[`unstable_as_slice`]: https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice
286287
[`unused_collect`]: https://github.com/Manishearth/rust-clippy/wiki#unused_collect

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Table of contents:
1717

1818
## Lints
1919

20-
There are 161 lints included in this crate:
20+
There are 162 lints included in this crate:
2121

2222
name | default | meaning
2323
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -166,6 +166,7 @@ name
166166
[unnecessary_operation](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation) | warn | outer expressions with no effect
167167
[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..`
168168
[unsafe_removed_from_name](https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name) | warn | unsafe removed from name
169+
[unseparated_literal_suffix](https://github.com/Manishearth/rust-clippy/wiki#unseparated_literal_suffix) | allow | literal suffixes should be separated with an underscore
169170
[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop
170171
[unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused label
171172
[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
277277
methods::RESULT_UNWRAP_USED,
278278
methods::WRONG_PUB_SELF_CONVENTION,
279279
misc::USED_UNDERSCORE_BINDING,
280+
misc_early::UNSEPARATED_LITERAL_SUFFIX,
280281
mut_mut::MUT_MUT,
281282
mutex_atomic::MUTEX_INTEGER,
282283
non_expressive_names::SIMILAR_NAMES,

clippy_lints/src/misc_early.rs

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc::lint::*;
22
use std::collections::HashMap;
3+
use std::char;
34
use syntax::ast::*;
45
use syntax::codemap::Span;
56
use syntax::visit::FnKind;
@@ -79,14 +80,29 @@ declare_lint! {
7980
"letter digits in hex literals should be either completely upper- or lowercased"
8081
}
8182

83+
/// **What it does:** Warns if literal suffixes are not separated by an underscore.
84+
///
85+
/// **Why is this bad?** It is much less readable.
86+
///
87+
/// **Known problems:** None.
88+
///
89+
/// **Example:**
90+
/// ```rust
91+
/// let y = 123832i32;
92+
/// ```
93+
declare_lint! {
94+
pub UNSEPARATED_LITERAL_SUFFIX, Allow,
95+
"literal suffixes should be separated with an underscore"
96+
}
97+
8298

8399
#[derive(Copy, Clone)]
84100
pub struct MiscEarly;
85101

86102
impl LintPass for MiscEarly {
87103
fn get_lints(&self) -> LintArray {
88104
lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL,
89-
DOUBLE_NEG, MIXED_CASE_HEX_LITERALS)
105+
DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX)
90106
}
91107
}
92108

@@ -196,20 +212,52 @@ impl EarlyLintPass for MiscEarly {
196212
if_let_chain! {[
197213
let LitKind::Int(..) = lit.node,
198214
let Some(src) = snippet_opt(cx, lit.span),
199-
src.starts_with("0x")
215+
let Some(firstch) = src.chars().next(),
216+
char::to_digit(firstch, 10).is_some()
200217
], {
201-
let mut seen = (false, false);
218+
let mut prev = '\0';
202219
for ch in src.chars() {
203-
match ch {
204-
'a' ... 'f' => seen.0 = true,
205-
'A' ... 'F' => seen.1 = true,
206-
'i' | 'u' => break, // start of suffix already
207-
_ => ()
220+
if ch == 'i' || ch == 'u' {
221+
if prev != '_' {
222+
span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
223+
"integer type suffix should be separated by an underscore");
224+
}
225+
break;
208226
}
227+
prev = ch;
209228
}
210-
if seen.0 && seen.1 {
211-
span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
212-
"inconsistent casing in hexadecimal literal");
229+
if src.starts_with("0x") {
230+
let mut seen = (false, false);
231+
for ch in src.chars() {
232+
match ch {
233+
'a' ... 'f' => seen.0 = true,
234+
'A' ... 'F' => seen.1 = true,
235+
'i' | 'u' => break, // start of suffix already
236+
_ => ()
237+
}
238+
}
239+
if seen.0 && seen.1 {
240+
span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
241+
"inconsistent casing in hexadecimal literal");
242+
}
243+
}
244+
}}
245+
if_let_chain! {[
246+
let LitKind::Float(..) = lit.node,
247+
let Some(src) = snippet_opt(cx, lit.span),
248+
let Some(firstch) = src.chars().next(),
249+
char::to_digit(firstch, 10).is_some()
250+
], {
251+
let mut prev = '\0';
252+
for ch in src.chars() {
253+
if ch == 'f' {
254+
if prev != '_' {
255+
span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
256+
"float type suffix should be separated by an underscore");
257+
}
258+
break;
259+
}
260+
prev = ch;
213261
}
214262
}}
215263
}

tests/compile-fail/doc.rs

100755100644
File mode changed.

tests/compile-fail/entry.rs

100755100644
File mode changed.

tests/compile-fail/filter_methods.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ fn main() {
88
.map(|x| x * 2)
99
.collect();
1010

11-
let _: Vec<_> = vec![5i8; 6].into_iter() //~ERROR called `filter(p).flat_map(q)` on an `Iterator`
11+
let _: Vec<_> = vec![5_i8; 6].into_iter() //~ERROR called `filter(p).flat_map(q)` on an `Iterator`
1212
.filter(|&x| x == 0)
1313
.flat_map(|x| x.checked_mul(2))
1414
.collect();
1515

16-
let _: Vec<_> = vec![5i8; 6].into_iter() //~ERROR called `filter_map(p).flat_map(q)` on an `Iterator`
16+
let _: Vec<_> = vec![5_i8; 6].into_iter() //~ERROR called `filter_map(p).flat_map(q)` on an `Iterator`
1717
.filter_map(|x| x.checked_mul(2))
1818
.flat_map(|x| x.checked_mul(2))
1919
.collect();
2020

21-
let _: Vec<_> = vec![5i8; 6].into_iter() //~ERROR called `filter_map(p).map(q)` on an `Iterator`
21+
let _: Vec<_> = vec![5_i8; 6].into_iter() //~ERROR called `filter_map(p).map(q)` on an `Iterator`
2222
.filter_map(|x| x.checked_mul(2))
2323
.map(|x| x.checked_mul(2))
2424
.collect();

tests/compile-fail/if_not_else.rs

100755100644
File mode changed.

tests/compile-fail/literals.rs

100755100644
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![feature(plugin)]
22
#![plugin(clippy)]
33
#![deny(mixed_case_hex_literals)]
4+
#![deny(unseparated_literal_suffix)]
45
#![allow(dead_code)]
56

67
fn main() {
@@ -12,4 +13,13 @@ fn main() {
1213
let fail1 = 0xabCD; //~ERROR inconsistent casing in hexadecimal literal
1314
let fail2 = 0xabCD_u32; //~ERROR inconsistent casing in hexadecimal literal
1415
let fail2 = 0xabCD_isize; //~ERROR inconsistent casing in hexadecimal literal
16+
17+
let ok6 = 1234_i32;
18+
let ok7 = 1234_f32;
19+
let ok8 = 1234_isize;
20+
let fail3 = 1234i32; //~ERROR integer type suffix should be separated
21+
let fail4 = 1234u32; //~ERROR integer type suffix should be separated
22+
let fail5 = 1234isize; //~ERROR integer type suffix should be separated
23+
let fail6 = 1234usize; //~ERROR integer type suffix should be separated
24+
let fail7 = 1.5f32; //~ERROR float type suffix should be separated
1525
}

tests/compile-fail/shadow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn main() {
2020
let y = 1;
2121
let x = y; //~ERROR `x` is shadowed by `y`
2222

23-
let o = Some(1u8);
23+
let o = Some(1_u8);
2424

2525
if let Some(p) = o { assert_eq!(1, p); }
2626
match o {

0 commit comments

Comments
 (0)