Skip to content

Cleaner code for unsep literals #4421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 73 additions & 73 deletions clippy_lints/src/misc_early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, Lin
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use std::char;
use syntax::ast::*;
use syntax::source_map::Span;
use syntax::visit::{walk_expr, FnKind, Visitor};
Expand Down Expand Up @@ -391,92 +390,93 @@ impl EarlyLintPass for MiscEarlyLints {

impl MiscEarlyLints {
fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
if_chain! {
if let LitKind::Int(value, ..) = lit.node;
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 == 'i' || ch == 'u' {
if prev != '_' {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
"integer type suffix should be separated by an underscore",
"add an underscore",
format!("{}_{}", &src[0..idx], &src[idx..]),
Applicability::MachineApplicable,
);
}
break;
}
prev = ch;
// The `line!()` macro is compiler built-in and a special case for these lints.
let lit_snip = match snippet_opt(cx, lit.span) {
Some(snip) => {
if snip.contains('!') {
return;
}
if src.starts_with("0x") {
let mut seen = (false, false);
for ch in src.chars() {
match ch {
'a' ..= 'f' => seen.0 = true,
'A' ..= 'F' => seen.1 = true,
'i' | 'u' => break, // start of suffix already
_ => ()
}
snip
},
_ => return,
};

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(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
"integer type suffix should be separated by an underscore",
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}

if lit_snip.starts_with("0x") {
let mut seen = (false, false);
for ch in lit_snip.as_bytes()[2..=maybe_last_sep_idx].iter() {
match ch {
b'a'..=b'f' => seen.0 = true,
b'A'..=b'F' => seen.1 = true,
_ => {},
}
if seen.0 && seen.1 {
span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
"inconsistent casing in hexadecimal literal");
span_lint(
cx,
MIXED_CASE_HEX_LITERALS,
lit.span,
"inconsistent casing in hexadecimal literal",
);
break;
}
} else if src.starts_with("0b") || src.starts_with("0o") {
/* nothing to do */
} else if value != 0 && src.starts_with('0') {
span_lint_and_then(cx,
ZERO_PREFIXED_LITERAL,
lit.span,
"this is a decimal constant",
|db| {
}
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
/* nothing to do */
} else if value != 0 && lit_snip.starts_with('0') {
span_lint_and_then(
cx,
ZERO_PREFIXED_LITERAL,
lit.span,
"this is a decimal constant",
|db| {
db.span_suggestion(
lit.span,
"if you mean to use a decimal constant, remove the `0` to remove confusion",
src.trim_start_matches(|c| c == '_' || c == '0').to_string(),
"if you mean to use a decimal constant, remove the `0` to avoid confusion",
lit_snip.trim_start_matches(|c| c == '_' || c == '0').to_string(),
Applicability::MaybeIncorrect,
);
db.span_suggestion(
lit.span,
"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,
);
});
}
},
);
}
}
if_chain! {
if let LitKind::Float(..) = lit.node;
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(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
"float type suffix should be separated by an underscore",
"add an underscore",
format!("{}_{}", &src[0..idx], &src[idx..]),
Applicability::MachineApplicable,
);
}
break;
}
prev = ch;
}
} else if let LitKind::Float(_, float_ty) = lit.node {
let suffix = float_ty.ty_to_string();
let maybe_last_sep_idx = lit_snip.len() - suffix.len() - 1;
if lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
"float type suffix should be separated by an underscore",
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/literals.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ LL | let fail_multi_zero = 000_123usize;
| ^^^^^^^^^^^^
|
= 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;
| ^^^^^^^^
Expand All @@ -39,7 +39,7 @@ error: this is a decimal constant
|
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;
| ^^^
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/unseparated_prefix_literals.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
#![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)]

macro_rules! lit_from_macro {
() => {
42_usize
};
}

fn main() {
let _ok1 = 1234_i32;
let _ok2 = 1234_isize;
Expand All @@ -17,4 +23,12 @@ fn main() {
let _okf2 = 1_f32;
let _failf1 = 1.5_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);
}
14 changes: 14 additions & 0 deletions tests/ui/unseparated_prefix_literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
#![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)]

macro_rules! lit_from_macro {
() => {
42usize
};
}

fn main() {
let _ok1 = 1234_i32;
let _ok2 = 1234_isize;
Expand All @@ -17,4 +23,12 @@ fn main() {
let _okf2 = 1_f32;
let _failf1 = 1.5f32;
let _failf2 = 1f32;

// Test for macro
let _ = lit_from_macro!();

// Counter example
let _ = line!();
// Because `assert!` contains `line!()` macro.
assert_eq!(4897u32, 32223);
}
31 changes: 23 additions & 8 deletions tests/ui/unseparated_prefix_literals.stderr
Original file line number Diff line number Diff line change
@@ -1,46 +1,61 @@
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;
| ^^^^^^^ help: add an underscore: `1234_i32`
|
= note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`

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;
| ^^^^^^^ help: add an underscore: `1234_u32`

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;
| ^^^^^^^^^ help: add an underscore: `1234_isize`

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;
| ^^^^^^^^^ help: add an underscore: `1234_usize`

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;
| ^^^^^^^^^^ help: add an underscore: `0x123_isize`

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;
| ^^^^^^ help: add an underscore: `1.5_f32`

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;
| ^^^^ 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