diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 28d54246fbb..48ceecde7c9 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -323,6 +323,7 @@ store.register_lints(&[ misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::MIXED_CASE_HEX_LITERALS, misc_early::REDUNDANT_PATTERN, + misc_early::SEPARATED_LITERAL_SUFFIX, misc_early::UNNEEDED_FIELD_PATTERN, misc_early::UNNEEDED_WILDCARD_PATTERN, misc_early::UNSEPARATED_LITERAL_SUFFIX, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 419a40b1bb8..bc71602f67e 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -34,6 +34,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::GET_UNWRAP), LintId::of(methods::UNWRAP_USED), LintId::of(misc::FLOAT_CMP_CONST), + LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), diff --git a/clippy_lints/src/misc_early/double_neg.rs b/clippy_lints/src/misc_early/double_neg.rs index 6f65778e119..06ba968fa4e 100644 --- a/clippy_lints/src/misc_early/double_neg.rs +++ b/clippy_lints/src/misc_early/double_neg.rs @@ -1,4 +1,3 @@ -use super::MiscEarlyLints; use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind, UnOp}; use rustc_lint::EarlyContext; @@ -6,18 +5,14 @@ use rustc_lint::EarlyContext; use super::DOUBLE_NEG; pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) { - match expr.kind { - ExprKind::Unary(UnOp::Neg, ref inner) => { - if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { - span_lint( - cx, - DOUBLE_NEG, - expr.span, - "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", - ); - } - }, - ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit), - _ => (), + if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind { + if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { + span_lint( + cx, + DOUBLE_NEG, + expr.span, + "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", + ); + } } } diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs new file mode 100644 index 00000000000..1165c19a0cf --- /dev/null +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::Lit; +use rustc_errors::Applicability; +use rustc_lint::EarlyContext; + +use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX}; + +pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) { + let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { + val + } else { + return; // It's useless so shouldn't lint. + }; + // Do not lint when literal is unsuffixed. + if !suffix.is_empty() { + if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' { + span_lint_and_sugg( + cx, + SEPARATED_LITERAL_SUFFIX, + lit.span, + &format!("{} type suffix should not be separated by an underscore", sugg_type), + "remove the underscore", + format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + UNSEPARATED_LITERAL_SUFFIX, + lit.span, + &format!("{} type suffix should be separated by an underscore", sugg_type), + "add an underscore", + format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 5aad08cdd46..7c3f5f22ade 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -1,15 +1,15 @@ mod builtin_type_shadow; mod double_neg; +mod literal_suffix; mod mixed_case_hex_literals; mod redundant_pattern; mod unneeded_field_pattern; mod unneeded_wildcard_pattern; -mod unseparated_literal_suffix; mod zero_prefixed_literal; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; +use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -115,9 +115,11 @@ declare_clippy_lint! { /// ### What it does /// Warns if literal suffixes are not separated by an /// underscore. + /// To enforce unseparated literal suffix style, + /// see the `separated_literal_suffix` lint. /// /// ### Why is this bad? - /// It is much less readable. + /// Suffix style should be consistent. /// /// ### Example /// ```rust @@ -132,6 +134,28 @@ declare_clippy_lint! { "literals whose suffix is not separated by an underscore" } +declare_clippy_lint! { + /// ### What it does + /// Warns if literal suffixes are separated by an underscore. + /// To enforce separated literal suffix style, + /// see the `unseparated_literal_suffix` lint. + /// + /// ### Why is this bad? + /// Suffix style should be consistent. + /// + /// ### Example + /// ```rust + /// // Bad + /// let y = 123832_i32; + /// + /// // Good + /// let y = 123832i32; + /// ``` + pub SEPARATED_LITERAL_SUFFIX, + restriction, + "literals whose suffix is separated by an underscore" +} + declare_clippy_lint! { /// ### What it does /// Warns if an integral constant literal starts with `0`. @@ -260,6 +284,7 @@ declare_lint_pass!(MiscEarlyLints => [ DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, + SEPARATED_LITERAL_SUFFIX, ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW, REDUNDANT_PATTERN, @@ -310,6 +335,10 @@ impl EarlyLintPass for MiscEarlyLints { if in_external_macro(cx.sess, expr.span) { return; } + + if let ExprKind::Lit(ref lit) = expr.kind { + MiscEarlyLints::check_lit(cx, lit); + } double_neg::check(cx, expr); } } @@ -332,7 +361,7 @@ impl MiscEarlyLints { LitIntType::Unsigned(ty) => ty.name_str(), LitIntType::Unsuffixed => "", }; - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); + literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); if lit_snip.starts_with("0x") { mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip); } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") { @@ -342,7 +371,7 @@ impl MiscEarlyLints { } } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind { let suffix = float_ty.name_str(); - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); + literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); } } } diff --git a/clippy_lints/src/misc_early/unseparated_literal_suffix.rs b/clippy_lints/src/misc_early/unseparated_literal_suffix.rs deleted file mode 100644 index 2018aa6184a..00000000000 --- a/clippy_lints/src/misc_early/unseparated_literal_suffix.rs +++ /dev/null @@ -1,26 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::ast::Lit; -use rustc_errors::Applicability; -use rustc_lint::EarlyContext; - -use super::UNSEPARATED_LITERAL_SUFFIX; - -pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) { - let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { - val - } else { - return; // It's useless so shouldn't lint. - }; - // 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, - &format!("{} type suffix should be separated by an underscore", sugg_type), - "add an underscore", - format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), - Applicability::MachineApplicable, - ); - } -} diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index a72a74b9131..e60ce8492fc 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -2,7 +2,8 @@ #![warn(clippy::mixed_case_hex_literals)] #![warn(clippy::zero_prefixed_literal)] -#![allow(clippy::unseparated_literal_suffix)] +#![warn(clippy::unseparated_literal_suffix)] +#![warn(clippy::separated_literal_suffix)] #![allow(dead_code)] fn main() { diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index 99542e20f78..365b2407473 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -1,25 +1,65 @@ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:12:15 + | +LL | let ok4 = 0xab_cd_i32; + | ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32` + | + = note: `-D clippy::separated-literal-suffix` implied by `-D warnings` + +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:13:15 + | +LL | let ok5 = 0xAB_CD_u32; + | ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32` + +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:14:15 + | +LL | let ok5 = 0xAB_CD_isize; + | ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize` + error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:14:17 + --> $DIR/literals.rs:15:17 | LL | let fail1 = 0xabCD; | ^^^^^^ | = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings` -error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:15:17 +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:16:17 | LL | let fail2 = 0xabCD_u32; - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: remove the underscore: `0xabCDu32` error: inconsistent casing in hexadecimal literal --> $DIR/literals.rs:16:17 | +LL | let fail2 = 0xabCD_u32; + | ^^^^^^^^^^ + +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:17:17 + | +LL | let fail2 = 0xabCD_isize; + | ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize` + +error: inconsistent casing in hexadecimal literal + --> $DIR/literals.rs:17:17 + | LL | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ +error: integer type suffix should be separated by an underscore + --> $DIR/literals.rs:18:27 + | +LL | let fail_multi_zero = 000_123usize; + | ^^^^^^^^^^^^ help: add an underscore: `000_123_usize` + | + = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` + error: this is a decimal constant - --> $DIR/literals.rs:17:27 + --> $DIR/literals.rs:18:27 | LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ @@ -34,8 +74,14 @@ help: if you mean to use an octal constant, use `0o` LL | let fail_multi_zero = 0o123usize; | ~~~~~~~~~~ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:21:16 + | +LL | let ok10 = 0_i64; + | ^^^^^ help: remove the underscore: `0i64` + error: this is a decimal constant - --> $DIR/literals.rs:21:17 + --> $DIR/literals.rs:22:17 | LL | let fail8 = 0123; | ^^^^ @@ -49,8 +95,14 @@ help: if you mean to use an octal constant, use `0o` LL | let fail8 = 0o123; | ~~~~~ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:31:16 + | +LL | let ok17 = 0x123_4567_8901_usize; + | ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize` + error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:33:18 + --> $DIR/literals.rs:34:18 | LL | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` @@ -58,19 +110,19 @@ LL | let fail19 = 12_3456_21; = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:34:18 + --> $DIR/literals.rs:35:18 | LL | let fail22 = 3__4___23; | ^^^^^^^^^ help: consider: `3_423` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:35:18 + --> $DIR/literals.rs:36:18 | LL | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` error: digits of hex or binary literal not grouped by four - --> $DIR/literals.rs:37:18 + --> $DIR/literals.rs:38:18 | LL | let fail24 = 0xAB_ABC_AB; | ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB` @@ -78,10 +130,10 @@ LL | let fail24 = 0xAB_ABC_AB; = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` error: digits of hex or binary literal not grouped by four - --> $DIR/literals.rs:38:18 + --> $DIR/literals.rs:39:18 | LL | let fail25 = 0b01_100_101; | ^^^^^^^^^^^^ help: consider: `0b0110_0101` -error: aborting due to 10 previous errors +error: aborting due to 18 previous errors