Add zero_prefixed_literal lint

This commit is contained in:
mcarton 2016-08-20 18:11:15 +02:00
parent cf2b0c8dd6
commit 507b626b36
5 changed files with 64 additions and 2 deletions

View File

@ -1,6 +1,9 @@
# Change Log
All notable changes to this project will be documented in this file.
## 0.0.86 — ?
* New lint: [`zero_prefixed_literal`]
## 0.0.85 — 2016-08-19
* Fix ICE with [`useless_attribute`]
* [`useless_attribute`] ignores [`unused_imports`] on `use` statements
@ -329,5 +332,6 @@ All notable changes to this project will be documented in this file.
[`wrong_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention
[`wrong_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute
[`zero_divided_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero
[`zero_prefixed_literal`]: https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal
[`zero_width_space`]: https://github.com/Manishearth/rust-clippy/wiki#zero_width_space
<!-- end autogenerated links to wiki -->

View File

@ -187,6 +187,7 @@ name
[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention
[wrong_transmute](https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute) | warn | transmutes that are confusing at best, undefined behaviour at worst and always useless
[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN
[zero_prefixed_literal](https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal) | warn | integer literals starting with `0`
[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing
More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas!

View File

@ -387,6 +387,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_CLOSURE_CALL,
misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::ZERO_PREFIXED_LITERAL,
module_inception::MODULE_INCEPTION,
mut_reference::UNNECESSARY_MUT_PASSED,
mutex_atomic::MUTEX_ATOMIC,

View File

@ -105,6 +105,42 @@ declare_lint! {
"literals whose suffix is not separated by an underscore"
}
/// **What it does:** Warns if a integral constant literal starts with `0`.
///
/// **Why is this bad?** In some languages (including the infamous C language and most of its
/// familly), this marks an octal constant. In Rust however, this is a decimal constant. This could
/// be confusing for both the writer and a reader of the constant.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// In Rust:
/// ```rust
/// fn main() {
/// let a = 0123;
/// println!("{}", a);
/// }
/// ```
///
/// prints `123`, while in C:
///
/// ```c
/// #include <stdio.h>
///
/// int main() {
/// int a = 0123;
/// printf("%d\n", a);
/// }
/// ```
///
/// prints `83` (as `89 == 0o123` while `123 == 0o173`).
declare_lint! {
pub ZERO_PREFIXED_LITERAL,
Warn,
"integer literals starting with `0`"
}
#[derive(Copy, Clone)]
pub struct MiscEarly;
@ -112,7 +148,8 @@ pub struct MiscEarly;
impl LintPass for MiscEarly {
fn get_lints(&self) -> LintArray {
lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL,
DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX)
DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL)
}
}
@ -220,7 +257,7 @@ impl EarlyLintPass for MiscEarly {
}
ExprKind::Lit(ref lit) => {
if_let_chain! {[
let LitKind::Int(..) = lit.node,
let LitKind::Int(value, ..) = lit.node,
let Some(src) = snippet_opt(cx, lit.span),
let Some(firstch) = src.chars().next(),
char::to_digit(firstch, 10).is_some()
@ -250,6 +287,15 @@ impl EarlyLintPass for MiscEarly {
span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
"inconsistent casing in hexadecimal literal");
}
} else if value != 0 && src.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[1..].to_string());
db.span_suggestion(lit.span, "if you mean to use an octal constant, use `0o`:", format!("0o{}", &src[1..]));
});
}
}}
if_let_chain! {[

View File

@ -2,6 +2,7 @@
#![plugin(clippy)]
#![deny(mixed_case_hex_literals)]
#![deny(unseparated_literal_suffix)]
#![deny(zero_prefixed_literal)]
#![allow(dead_code)]
fn main() {
@ -22,4 +23,13 @@ fn main() {
let fail5 = 1234isize; //~ERROR integer type suffix should be separated
let fail6 = 1234usize; //~ERROR integer type suffix should be separated
let fail7 = 1.5f32; //~ERROR float type suffix should be separated
let ok9 = 0;
let ok10 = 0_i64;
let fail8 = 0123;
//~^ERROR decimal constant
//~|HELP remove the `0`
//~|SUGGESTION = 123;
//~|HELP use `0o`
//~|SUGGESTION = 0o123;
}