From ab58331f220a77538eb02ad1bef828ca7230e7ac Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 5 Aug 2016 18:30:07 +0200 Subject: [PATCH] Lint inconsistent casing in hex literals (closes #703) --- CHANGELOG.md | 1 + README.md | 3 ++- clippy_lints/src/lib.rs | 1 + clippy_lints/src/misc_early.rs | 43 +++++++++++++++++++++++++++++++--- tests/compile-fail/literals.rs | 15 ++++++++++++ 5 files changed, 59 insertions(+), 4 deletions(-) create mode 100755 tests/compile-fail/literals.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 10de2fc4b..4081d3d25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -211,6 +211,7 @@ All notable changes to this project will be documented in this file. [`mem_forget`]: https://github.com/Manishearth/rust-clippy/wiki#mem_forget [`min_max`]: https://github.com/Manishearth/rust-clippy/wiki#min_max [`misrefactored_assign_op`]: https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op +[`mixed_case_hex_literals`]: https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals [`modulo_one`]: https://github.com/Manishearth/rust-clippy/wiki#modulo_one [`mut_mut`]: https://github.com/Manishearth/rust-clippy/wiki#mut_mut [`mutex_atomic`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic diff --git a/README.md b/README.md index 584db6a68..7edb751fb 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 160 lints included in this crate: +There are 161 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -98,6 +98,7 @@ name [mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `mem::forget` usage on `Drop` types is likely to cause memory leaks [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [misrefactored_assign_op](https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op) | warn | having a variable on both sides of an assign op +[mixed_case_hex_literals](https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals) | warn | letter digits in hex literals should be either completely upper- or lowercased [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` [mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a mutex where an atomic value could be used instead diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7308a6565..eaac42c5c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -377,6 +377,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { misc::TOPLEVEL_REF_ARG, misc_early::DOUBLE_NEG, misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, + misc_early::MIXED_CASE_HEX_LITERALS, misc_early::REDUNDANT_CLOSURE_CALL, misc_early::UNNEEDED_FIELD_PATTERN, mut_reference::UNNECESSARY_MUT_PASSED, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index a8127ef88..2d6b0a357 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use syntax::ast::*; use syntax::codemap::Span; use syntax::visit::FnKind; -use utils::{span_lint, span_help_and_lint, snippet, span_lint_and_then}; +use utils::{span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then}; /// **What it does:** This lint checks for structure field patterns bound to wildcards. /// /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on the fields that are actually bound. @@ -64,13 +64,29 @@ declare_lint! { "`--x` is a double negation of `x` and not a pre-decrement as in C or C++" } +/// **What it does:** Warns on hexadecimal literals with mixed-case letter digits. +/// +/// **Why is this bad?** It looks confusing. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let y = 0x1a9BAcD; +/// ``` +declare_lint! { + pub MIXED_CASE_HEX_LITERALS, Warn, + "letter digits in hex literals should be either completely upper- or lowercased" +} + #[derive(Copy, Clone)] 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) + lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL, + DOUBLE_NEG, MIXED_CASE_HEX_LITERALS) } } @@ -174,7 +190,28 @@ impl EarlyLintPass for MiscEarly { DOUBLE_NEG, expr.span, "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op"); - } + } + } + ExprKind::Lit(ref lit) => { + if_let_chain! {[ + let LitKind::Int(..) = lit.node, + let Some(src) = snippet_opt(cx, lit.span), + 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 + _ => () + } + } + if seen.0 && seen.1 { + span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span, + "inconsistent casing in hexadecimal literal"); + } + }} } _ => () } diff --git a/tests/compile-fail/literals.rs b/tests/compile-fail/literals.rs new file mode 100755 index 000000000..fb031ea7c --- /dev/null +++ b/tests/compile-fail/literals.rs @@ -0,0 +1,15 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(mixed_case_hex_literals)] +#![allow(dead_code)] + +fn main() { + let ok1 = 0xABCD; + let ok3 = 0xab_cd; + let ok4 = 0xab_cd_i32; + let ok5 = 0xAB_CD_u32; + let ok5 = 0xAB_CD_isize; + let fail1 = 0xabCD; //~ERROR inconsistent casing in hexadecimal literal + let fail2 = 0xabCD_u32; //~ERROR inconsistent casing in hexadecimal literal + let fail2 = 0xabCD_isize; //~ERROR inconsistent casing in hexadecimal literal +}