Auto merge of #4421 - lzutao:unsep_literal, r=flip1995

Cleaner code for unsep literals

Continuing discussion in https://github.com/rust-lang/rust-clippy/pull/4401#issuecomment-522498754
changelog: none
r? @flip1995
This commit is contained in:
bors
2019-08-26 10:32:24 +00:00
5 changed files with 126 additions and 83 deletions

View File

@@ -6,7 +6,6 @@ use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, Lin
use rustc::{declare_lint_pass, declare_tool_lint}; use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use std::char;
use syntax::ast::*; use syntax::ast::*;
use syntax::source_map::Span; use syntax::source_map::Span;
use syntax::visit::{walk_expr, FnKind, Visitor}; use syntax::visit::{walk_expr, FnKind, Visitor};
@@ -391,93 +390,94 @@ impl EarlyLintPass for MiscEarlyLints {
impl MiscEarlyLints { impl MiscEarlyLints {
fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
if_chain! { // The `line!()` macro is compiler built-in and a special case for these lints.
if let LitKind::Int(value, ..) = lit.node; let lit_snip = match snippet_opt(cx, lit.span) {
if let Some(src) = snippet_opt(cx, lit.span); Some(snip) => {
if let Some(firstch) = src.chars().next(); if snip.contains('!') {
if char::to_digit(firstch, 10).is_some(); return;
then { }
let mut prev = '\0'; snip
for (idx, ch) in src.chars().enumerate() { },
if ch == 'i' || ch == 'u' { _ => return,
if prev != '_' { };
if let LitKind::Int(value, lit_int_type) = lit.node {
let suffix = match lit_int_type {
LitIntType::Signed(ty) => ty.ty_to_string(),
LitIntType::Unsigned(ty) => ty.ty_to_string(),
LitIntType::Unsuffixed => "",
};
let maybe_last_sep_idx = lit_snip.len() - suffix.len() - 1;
// Do not lint when literal is unsuffixed.
if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
UNSEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX,
lit.span, lit.span,
"integer type suffix should be separated by an underscore", "integer type suffix should be separated by an underscore",
"add an underscore", "add an underscore",
format!("{}_{}", &src[0..idx], &src[idx..]), format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
break;
} if lit_snip.starts_with("0x") {
prev = ch;
}
if src.starts_with("0x") {
let mut seen = (false, false); let mut seen = (false, false);
for ch in src.chars() { for ch in lit_snip.as_bytes()[2..=maybe_last_sep_idx].iter() {
match ch { match ch {
'a' ..= 'f' => seen.0 = true, b'a'..=b'f' => seen.0 = true,
'A' ..= 'F' => seen.1 = true, b'A'..=b'F' => seen.1 = true,
'i' | 'u' => break, // start of suffix already _ => {},
_ => ()
}
} }
if seen.0 && seen.1 { if seen.0 && seen.1 {
span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span, span_lint(
"inconsistent casing in hexadecimal literal"); cx,
MIXED_CASE_HEX_LITERALS,
lit.span,
"inconsistent casing in hexadecimal literal",
);
break;
} }
} else if src.starts_with("0b") || src.starts_with("0o") { }
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
/* nothing to do */ /* nothing to do */
} else if value != 0 && src.starts_with('0') { } else if value != 0 && lit_snip.starts_with('0') {
span_lint_and_then(cx, span_lint_and_then(
cx,
ZERO_PREFIXED_LITERAL, ZERO_PREFIXED_LITERAL,
lit.span, lit.span,
"this is a decimal constant", "this is a decimal constant",
|db| { |db| {
db.span_suggestion( db.span_suggestion(
lit.span, lit.span,
"if you mean to use a decimal constant, remove the `0` to remove confusion", "if you mean to use a decimal constant, remove the `0` to avoid confusion",
src.trim_start_matches(|c| c == '_' || c == '0').to_string(), lit_snip.trim_start_matches(|c| c == '_' || c == '0').to_string(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
db.span_suggestion( db.span_suggestion(
lit.span, lit.span,
"if you mean to use an octal constant, use `0o`", "if you mean to use an octal constant, use `0o`",
format!("0o{}", src.trim_start_matches(|c| c == '_' || c == '0')), format!("0o{}", lit_snip.trim_start_matches(|c| c == '_' || c == '0')),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
}); },
);
} }
} } else if let LitKind::Float(_, float_ty) = lit.node {
} let suffix = float_ty.ty_to_string();
if_chain! { let maybe_last_sep_idx = lit_snip.len() - suffix.len() - 1;
if let LitKind::Float(..) = lit.node; if lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
if let Some(src) = snippet_opt(cx, lit.span);
if let Some(firstch) = src.chars().next();
if char::to_digit(firstch, 10).is_some();
then {
let mut prev = '\0';
for (idx, ch) in src.chars().enumerate() {
if ch == 'f' {
if prev != '_' {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
UNSEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX,
lit.span, lit.span,
"float type suffix should be separated by an underscore", "float type suffix should be separated by an underscore",
"add an underscore", "add an underscore",
format!("{}_{}", &src[0..idx], &src[idx..]), format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
break;
}
prev = ch;
}
}
} }
} }
} }

View File

@@ -25,7 +25,7 @@ LL | let fail_multi_zero = 000_123usize;
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
| |
= note: `-D clippy::zero-prefixed-literal` implied by `-D warnings` = note: `-D clippy::zero-prefixed-literal` implied by `-D warnings`
help: if you mean to use a decimal constant, remove the `0` to remove confusion help: if you mean to use a decimal constant, remove the `0` to avoid confusion
| |
LL | let fail_multi_zero = 123usize; LL | let fail_multi_zero = 123usize;
| ^^^^^^^^ | ^^^^^^^^
@@ -39,7 +39,7 @@ error: this is a decimal constant
| |
LL | let fail8 = 0123; LL | let fail8 = 0123;
| ^^^^ | ^^^^
help: if you mean to use a decimal constant, remove the `0` to remove confusion help: if you mean to use a decimal constant, remove the `0` to avoid confusion
| |
LL | let fail8 = 123; LL | let fail8 = 123;
| ^^^ | ^^^

View File

@@ -3,6 +3,12 @@
#![warn(clippy::unseparated_literal_suffix)] #![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)] #![allow(dead_code)]
macro_rules! lit_from_macro {
() => {
42_usize
};
}
fn main() { fn main() {
let _ok1 = 1234_i32; let _ok1 = 1234_i32;
let _ok2 = 1234_isize; let _ok2 = 1234_isize;
@@ -17,4 +23,12 @@ fn main() {
let _okf2 = 1_f32; let _okf2 = 1_f32;
let _failf1 = 1.5_f32; let _failf1 = 1.5_f32;
let _failf2 = 1_f32; let _failf2 = 1_f32;
// Test for macro
let _ = lit_from_macro!();
// Counter example
let _ = line!();
// Because `assert!` contains `line!()` macro.
assert_eq!(4897_u32, 32223);
} }

View File

@@ -3,6 +3,12 @@
#![warn(clippy::unseparated_literal_suffix)] #![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)] #![allow(dead_code)]
macro_rules! lit_from_macro {
() => {
42usize
};
}
fn main() { fn main() {
let _ok1 = 1234_i32; let _ok1 = 1234_i32;
let _ok2 = 1234_isize; let _ok2 = 1234_isize;
@@ -17,4 +23,12 @@ fn main() {
let _okf2 = 1_f32; let _okf2 = 1_f32;
let _failf1 = 1.5f32; let _failf1 = 1.5f32;
let _failf2 = 1f32; let _failf2 = 1f32;
// Test for macro
let _ = lit_from_macro!();
// Counter example
let _ = line!();
// Because `assert!` contains `line!()` macro.
assert_eq!(4897u32, 32223);
} }

View File

@@ -1,5 +1,5 @@
error: integer type suffix should be separated by an underscore error: integer type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:10:18 --> $DIR/unseparated_prefix_literals.rs:16:18
| |
LL | let _fail1 = 1234i32; LL | let _fail1 = 1234i32;
| ^^^^^^^ help: add an underscore: `1234_i32` | ^^^^^^^ help: add an underscore: `1234_i32`
@@ -7,40 +7,55 @@ LL | let _fail1 = 1234i32;
= note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
error: integer type suffix should be separated by an underscore error: integer type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:11:18 --> $DIR/unseparated_prefix_literals.rs:17:18
| |
LL | let _fail2 = 1234u32; LL | let _fail2 = 1234u32;
| ^^^^^^^ help: add an underscore: `1234_u32` | ^^^^^^^ help: add an underscore: `1234_u32`
error: integer type suffix should be separated by an underscore error: integer type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:12:18 --> $DIR/unseparated_prefix_literals.rs:18:18
| |
LL | let _fail3 = 1234isize; LL | let _fail3 = 1234isize;
| ^^^^^^^^^ help: add an underscore: `1234_isize` | ^^^^^^^^^ help: add an underscore: `1234_isize`
error: integer type suffix should be separated by an underscore error: integer type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:13:18 --> $DIR/unseparated_prefix_literals.rs:19:18
| |
LL | let _fail4 = 1234usize; LL | let _fail4 = 1234usize;
| ^^^^^^^^^ help: add an underscore: `1234_usize` | ^^^^^^^^^ help: add an underscore: `1234_usize`
error: integer type suffix should be separated by an underscore error: integer type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:14:18 --> $DIR/unseparated_prefix_literals.rs:20:18
| |
LL | let _fail5 = 0x123isize; LL | let _fail5 = 0x123isize;
| ^^^^^^^^^^ help: add an underscore: `0x123_isize` | ^^^^^^^^^^ help: add an underscore: `0x123_isize`
error: float type suffix should be separated by an underscore error: float type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:18:19 --> $DIR/unseparated_prefix_literals.rs:24:19
| |
LL | let _failf1 = 1.5f32; LL | let _failf1 = 1.5f32;
| ^^^^^^ help: add an underscore: `1.5_f32` | ^^^^^^ help: add an underscore: `1.5_f32`
error: float type suffix should be separated by an underscore error: float type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:19:19 --> $DIR/unseparated_prefix_literals.rs:25:19
| |
LL | let _failf2 = 1f32; LL | let _failf2 = 1f32;
| ^^^^ help: add an underscore: `1_f32` | ^^^^ help: add an underscore: `1_f32`
error: aborting due to 7 previous errors error: integer type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:8:9
|
LL | 42usize
| ^^^^^^^ help: add an underscore: `42_usize`
...
LL | let _ = lit_from_macro!();
| ----------------- in this macro invocation
error: integer type suffix should be separated by an underscore
--> $DIR/unseparated_prefix_literals.rs:33:16
|
LL | assert_eq!(4897u32, 32223);
| ^^^^^^^ help: add an underscore: `4897_u32`
error: aborting due to 9 previous errors