From f191e916bdbb98ef91a35b3c82376b3c517654fb Mon Sep 17 00:00:00 2001 From: mgr-inz-rafal Date: Thu, 26 Dec 2019 13:34:18 +0100 Subject: [PATCH 1/3] Add new lint (modulo_arithmetic) --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 + clippy_lints/src/modulo_arithmetic.rs | 149 ++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +- 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/modulo_arithmetic.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f0684ea44cc..50a7f44ad8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1186,6 +1186,7 @@ Released 2018-09-13 [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals [`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions +[`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl diff --git a/README.md b/README.md index be5433029de..01fc20f0f27 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 341 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 342 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c83be8e2c19..8b8f6b27a95 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -239,6 +239,7 @@ pub mod misc_early; pub mod missing_const_for_fn; pub mod missing_doc; pub mod missing_inline; +pub mod modulo_arithmetic; pub mod mul_add; pub mod multiple_crate_versions; pub mod mut_key; @@ -667,6 +668,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &missing_const_for_fn::MISSING_CONST_FOR_FN, &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, + &modulo_arithmetic::MODULO_ARITHMETIC, &mul_add::MANUAL_MUL_ADD, &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, &mut_key::MUTABLE_KEY_TYPE, @@ -943,6 +945,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box comparison_chain::ComparisonChain); store.register_late_pass(|| box mul_add::MulAddCheck); store.register_late_pass(|| box mut_key::MutableKeyType); + store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); store.register_early_pass(|| box reference::DerefAddrOf); store.register_early_pass(|| box reference::RefInDeref); store.register_early_pass(|| box double_parens::DoubleParens); @@ -1003,6 +1006,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&misc::FLOAT_CMP_CONST), LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), + LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC), LintId::of(&panic_unimplemented::PANIC), LintId::of(&panic_unimplemented::TODO), LintId::of(&panic_unimplemented::UNIMPLEMENTED), diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs new file mode 100644 index 00000000000..308bb00fe76 --- /dev/null +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -0,0 +1,149 @@ +use crate::consts::{constant, Constant}; +use crate::utils::{sext, span_lint_and_then}; +use if_chain::if_chain; +use rustc::declare_lint_pass; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty::{self}; +use rustc_session::declare_tool_lint; +use std::fmt::Display; + +declare_clippy_lint! { + /// **What it does:** Checks for modulo arithemtic. + /// + /// **Why is this bad?** The results of modulo (%) operation might differ + /// depending on the language, when negative numbers are involved. + /// If you interop with different languages it might be beneficial + /// to double check all places that use modulo arithmetic. + /// + /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// let x = -17 % 3; + /// ``` + pub MODULO_ARITHMETIC, + restriction, + "any modulo arithmetic statement" +} + +declare_lint_pass!(ModuloArithmetic => [MODULO_ARITHMETIC]); + +struct OperandInfo { + string_representation: Option, + is_negative: bool, + is_integral: bool, +} + +fn analyze_operand(operand: &Expr, cx: &LateContext<'_, '_>, expr: &Expr) -> Option { + match constant(cx, cx.tables, operand) { + Some((Constant::Int(v), _)) => match cx.tables.expr_ty(expr).kind { + ty::Int(ity) => { + let value = sext(cx.tcx, v, ity); + return Some(OperandInfo { + string_representation: Some(value.to_string()), + is_negative: value < 0, + is_integral: true, + }); + }, + ty::Uint(_) => { + return Some(OperandInfo { + string_representation: None, + is_negative: false, + is_integral: true, + }); + }, + _ => {}, + }, + Some((Constant::F32(f), _)) => { + return Some(floating_point_operand_info(&f)); + }, + Some((Constant::F64(f), _)) => { + return Some(floating_point_operand_info(&f)); + }, + _ => {}, + } + None +} + +fn floating_point_operand_info>(f: &T) -> OperandInfo { + OperandInfo { + string_representation: Some(format!("{:.3}", *f)), + is_negative: *f < 0.0.into(), + is_integral: false, + } +} + +fn might_have_negative_value(t: &ty::TyS<'_>) -> bool { + t.is_signed() || t.is_floating_point() +} + +fn check_const_operands<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx Expr, + lhs_operand: &OperandInfo, + rhs_operand: &OperandInfo, +) { + if lhs_operand.is_negative ^ rhs_operand.is_negative { + span_lint_and_then( + cx, + MODULO_ARITHMETIC, + expr.span, + &format!( + "you are using modulo operator on constants with different signs: `{} % {}`", + lhs_operand.string_representation.as_ref().unwrap(), + rhs_operand.string_representation.as_ref().unwrap() + ), + |db| { + db.note("double check for expected result especially when interoperating with different languages"); + if lhs_operand.is_integral { + db.note("or consider using `rem_euclid` or similar function"); + } + }, + ); + } +} + +fn check_non_const_operands<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, operand: &Expr) { + let operand_type = cx.tables.expr_ty(operand); + if might_have_negative_value(operand_type) { + span_lint_and_then( + cx, + MODULO_ARITHMETIC, + expr.span, + "you are using modulo operator on types that might have different signs", + |db| { + db.note("double check for expected result especially when interoperating with different languages"); + if operand_type.is_integral() { + db.note("or consider using `rem_euclid` or similar function"); + } + }, + ); + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ModuloArithmetic { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + match &expr.kind { + ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => { + if let BinOpKind::Rem = op.node { + let lhs_operand = analyze_operand(lhs, cx, expr); + let rhs_operand = analyze_operand(rhs, cx, expr); + if_chain! { + if let Some(lhs_operand) = lhs_operand; + if let Some(rhs_operand) = rhs_operand; + then { + check_const_operands(cx, expr, &lhs_operand, &rhs_operand); + } + else { + check_non_const_operands(cx, expr, lhs); + } + } + }; + }, + _ => {}, + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index bdbe06c5f27..08cbff40444 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 341] = [ +pub const ALL_LINTS: [Lint; 342] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1183,6 +1183,13 @@ pub const ALL_LINTS: [Lint; 341] = [ deprecation: None, module: "enum_variants", }, + Lint { + name: "modulo_arithmetic", + group: "restriction", + desc: "any modulo arithmetic statement", + deprecation: None, + module: "modulo_arithmetic", + }, Lint { name: "modulo_one", group: "correctness", From 6223391170de2ed0756e50d122039d1805510f0f Mon Sep 17 00:00:00 2001 From: mgr-inz-rafal Date: Thu, 26 Dec 2019 13:34:55 +0100 Subject: [PATCH 2/3] Add tests for new lint (modulo_arithmetic) --- tests/ui/modulo_arithmetic_float.rs | 36 ++++ tests/ui/modulo_arithmetic_float.stderr | 83 ++++++++++ tests/ui/modulo_arithmetic_integral.rs | 90 ++++++++++ tests/ui/modulo_arithmetic_integral.stderr | 156 ++++++++++++++++++ tests/ui/modulo_arithmetic_integral_const.rs | 44 +++++ .../modulo_arithmetic_integral_const.stderr | 156 ++++++++++++++++++ 6 files changed, 565 insertions(+) create mode 100644 tests/ui/modulo_arithmetic_float.rs create mode 100644 tests/ui/modulo_arithmetic_float.stderr create mode 100644 tests/ui/modulo_arithmetic_integral.rs create mode 100644 tests/ui/modulo_arithmetic_integral.stderr create mode 100644 tests/ui/modulo_arithmetic_integral_const.rs create mode 100644 tests/ui/modulo_arithmetic_integral_const.stderr diff --git a/tests/ui/modulo_arithmetic_float.rs b/tests/ui/modulo_arithmetic_float.rs new file mode 100644 index 00000000000..b010b0dbdfa --- /dev/null +++ b/tests/ui/modulo_arithmetic_float.rs @@ -0,0 +1,36 @@ +#![warn(clippy::modulo_arithmetic)] +#![allow( + unused, + clippy::shadow_reuse, + clippy::shadow_unrelated, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::modulo_one +)] + +fn main() { + // Lint when both sides are const and of the opposite sign + -1.6 % 2.1; + 1.6 % -2.1; + (1.1 - 2.3) % (1.1 + 2.3); + (1.1 + 2.3) % (1.1 - 2.3); + + // Lint on floating point numbers + let a_f32: f32 = -1.6; + let mut b_f32: f32 = 2.1; + a_f32 % b_f32; + b_f32 % a_f32; + b_f32 %= a_f32; + + let a_f64: f64 = -1.6; + let mut b_f64: f64 = 2.1; + a_f64 % b_f64; + b_f64 % a_f64; + b_f64 %= a_f64; + + // No lint when both sides are const and of the same sign + 1.6 % 2.1; + -1.6 % -2.1; + (1.1 + 2.3) % (-1.1 + 2.3); + (-1.1 - 2.3) % (1.1 - 2.3); +} diff --git a/tests/ui/modulo_arithmetic_float.stderr b/tests/ui/modulo_arithmetic_float.stderr new file mode 100644 index 00000000000..7bfdb0bde60 --- /dev/null +++ b/tests/ui/modulo_arithmetic_float.stderr @@ -0,0 +1,83 @@ +error: you are using modulo operator on constants with different signs: `-1.600 % 2.100` + --> $DIR/modulo_arithmetic_float.rs:13:5 + | +LL | -1.6 % 2.1; + | ^^^^^^^^^^ + | + = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on constants with different signs: `1.600 % -2.100` + --> $DIR/modulo_arithmetic_float.rs:14:5 + | +LL | 1.6 % -2.1; + | ^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on constants with different signs: `-1.200 % 3.400` + --> $DIR/modulo_arithmetic_float.rs:15:5 + | +LL | (1.1 - 2.3) % (1.1 + 2.3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on constants with different signs: `3.400 % -1.200` + --> $DIR/modulo_arithmetic_float.rs:16:5 + | +LL | (1.1 + 2.3) % (1.1 - 2.3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_float.rs:21:5 + | +LL | a_f32 % b_f32; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_float.rs:22:5 + | +LL | b_f32 % a_f32; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_float.rs:23:5 + | +LL | b_f32 %= a_f32; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_float.rs:27:5 + | +LL | a_f64 % b_f64; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_float.rs:28:5 + | +LL | b_f64 % a_f64; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_float.rs:29:5 + | +LL | b_f64 %= a_f64; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: aborting due to 10 previous errors + diff --git a/tests/ui/modulo_arithmetic_integral.rs b/tests/ui/modulo_arithmetic_integral.rs new file mode 100644 index 00000000000..779d035c5f8 --- /dev/null +++ b/tests/ui/modulo_arithmetic_integral.rs @@ -0,0 +1,90 @@ +#![warn(clippy::modulo_arithmetic)] +#![allow( + unused, + clippy::shadow_reuse, + clippy::shadow_unrelated, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::modulo_one +)] + +fn main() { + // Lint on signed integral numbers + let a = -1; + let mut b = 2; + a % b; + b % a; + b %= a; + + let a_i8: i8 = 1; + let mut b_i8: i8 = 2; + a_i8 % b_i8; + b_i8 %= a_i8; + + let a_i16: i16 = 1; + let mut b_i16: i16 = 2; + a_i16 % b_i16; + b_i16 %= a_i16; + + let a_i32: i32 = 1; + let mut b_i32: i32 = 2; + a_i32 % b_i32; + b_i32 %= a_i32; + + let a_i64: i64 = 1; + let mut b_i64: i64 = 2; + a_i64 % b_i64; + b_i64 %= a_i64; + + let a_i128: i128 = 1; + let mut b_i128: i128 = 2; + a_i128 % b_i128; + b_i128 %= a_i128; + + let a_isize: isize = 1; + let mut b_isize: isize = 2; + a_isize % b_isize; + b_isize %= a_isize; + + let a = 1; + let mut b = 2; + a % b; + b %= a; + + // No lint on unsigned integral value + let a_u8: u8 = 17; + let b_u8: u8 = 3; + a_u8 % b_u8; + let mut a_u8: u8 = 1; + a_u8 %= 2; + + let a_u16: u16 = 17; + let b_u16: u16 = 3; + a_u16 % b_u16; + let mut a_u16: u16 = 1; + a_u16 %= 2; + + let a_u32: u32 = 17; + let b_u32: u32 = 3; + a_u32 % b_u32; + let mut a_u32: u32 = 1; + a_u32 %= 2; + + let a_u64: u64 = 17; + let b_u64: u64 = 3; + a_u64 % b_u64; + let mut a_u64: u64 = 1; + a_u64 %= 2; + + let a_u128: u128 = 17; + let b_u128: u128 = 3; + a_u128 % b_u128; + let mut a_u128: u128 = 1; + a_u128 %= 2; + + let a_usize: usize = 17; + let b_usize: usize = 3; + a_usize % b_usize; + let mut a_usize: usize = 1; + a_usize %= 2; +} diff --git a/tests/ui/modulo_arithmetic_integral.stderr b/tests/ui/modulo_arithmetic_integral.stderr new file mode 100644 index 00000000000..e863b838699 --- /dev/null +++ b/tests/ui/modulo_arithmetic_integral.stderr @@ -0,0 +1,156 @@ +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:15:5 + | +LL | a % b; + | ^^^^^ + | + = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:16:5 + | +LL | b % a; + | ^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:17:5 + | +LL | b %= a; + | ^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:21:5 + | +LL | a_i8 % b_i8; + | ^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:22:5 + | +LL | b_i8 %= a_i8; + | ^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:26:5 + | +LL | a_i16 % b_i16; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:27:5 + | +LL | b_i16 %= a_i16; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:31:5 + | +LL | a_i32 % b_i32; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:32:5 + | +LL | b_i32 %= a_i32; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:36:5 + | +LL | a_i64 % b_i64; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:37:5 + | +LL | b_i64 %= a_i64; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:41:5 + | +LL | a_i128 % b_i128; + | ^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:42:5 + | +LL | b_i128 %= a_i128; + | ^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:46:5 + | +LL | a_isize % b_isize; + | ^^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:47:5 + | +LL | b_isize %= a_isize; + | ^^^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:51:5 + | +LL | a % b; + | ^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on types that might have different signs + --> $DIR/modulo_arithmetic_integral.rs:52:5 + | +LL | b %= a; + | ^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: aborting due to 17 previous errors + diff --git a/tests/ui/modulo_arithmetic_integral_const.rs b/tests/ui/modulo_arithmetic_integral_const.rs new file mode 100644 index 00000000000..57a96692c00 --- /dev/null +++ b/tests/ui/modulo_arithmetic_integral_const.rs @@ -0,0 +1,44 @@ +#![warn(clippy::modulo_arithmetic)] +#![allow( + unused, + clippy::shadow_reuse, + clippy::shadow_unrelated, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::modulo_one +)] + +fn main() { + // Lint when both sides are const and of the opposite sign + -1 % 2; + 1 % -2; + (1 - 2) % (1 + 2); + (1 + 2) % (1 - 2); + 35 * (7 - 4 * 2) % (-500 * -600); + + -1i8 % 2i8; + 1i8 % -2i8; + -1i16 % 2i16; + 1i16 % -2i16; + -1i32 % 2i32; + 1i32 % -2i32; + -1i64 % 2i64; + 1i64 % -2i64; + -1i128 % 2i128; + 1i128 % -2i128; + -1isize % 2isize; + 1isize % -2isize; + + // No lint when both sides are const and of the same sign + 1 % 2; + -1 % -2; + (1 + 2) % (-1 + 2); + (-1 - 2) % (1 - 2); + + 1u8 % 2u8; + 1u16 % 2u16; + 1u32 % 2u32; + 1u64 % 2u64; + 1u128 % 2u128; + 1usize % 2usize; +} diff --git a/tests/ui/modulo_arithmetic_integral_const.stderr b/tests/ui/modulo_arithmetic_integral_const.stderr new file mode 100644 index 00000000000..de328bb75fe --- /dev/null +++ b/tests/ui/modulo_arithmetic_integral_const.stderr @@ -0,0 +1,156 @@ +error: you are using modulo operator on constants with different signs: `-1 % 2` + --> $DIR/modulo_arithmetic_integral_const.rs:13:5 + | +LL | -1 % 2; + | ^^^^^^ + | + = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `1 % -2` + --> $DIR/modulo_arithmetic_integral_const.rs:14:5 + | +LL | 1 % -2; + | ^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-1 % 3` + --> $DIR/modulo_arithmetic_integral_const.rs:15:5 + | +LL | (1 - 2) % (1 + 2); + | ^^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `3 % -1` + --> $DIR/modulo_arithmetic_integral_const.rs:16:5 + | +LL | (1 + 2) % (1 - 2); + | ^^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-35 % 300000` + --> $DIR/modulo_arithmetic_integral_const.rs:17:5 + | +LL | 35 * (7 - 4 * 2) % (-500 * -600); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-1 % 2` + --> $DIR/modulo_arithmetic_integral_const.rs:19:5 + | +LL | -1i8 % 2i8; + | ^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `1 % -2` + --> $DIR/modulo_arithmetic_integral_const.rs:20:5 + | +LL | 1i8 % -2i8; + | ^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-1 % 2` + --> $DIR/modulo_arithmetic_integral_const.rs:21:5 + | +LL | -1i16 % 2i16; + | ^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `1 % -2` + --> $DIR/modulo_arithmetic_integral_const.rs:22:5 + | +LL | 1i16 % -2i16; + | ^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-1 % 2` + --> $DIR/modulo_arithmetic_integral_const.rs:23:5 + | +LL | -1i32 % 2i32; + | ^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `1 % -2` + --> $DIR/modulo_arithmetic_integral_const.rs:24:5 + | +LL | 1i32 % -2i32; + | ^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-1 % 2` + --> $DIR/modulo_arithmetic_integral_const.rs:25:5 + | +LL | -1i64 % 2i64; + | ^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `1 % -2` + --> $DIR/modulo_arithmetic_integral_const.rs:26:5 + | +LL | 1i64 % -2i64; + | ^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-1 % 2` + --> $DIR/modulo_arithmetic_integral_const.rs:27:5 + | +LL | -1i128 % 2i128; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `1 % -2` + --> $DIR/modulo_arithmetic_integral_const.rs:28:5 + | +LL | 1i128 % -2i128; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `-1 % 2` + --> $DIR/modulo_arithmetic_integral_const.rs:29:5 + | +LL | -1isize % 2isize; + | ^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: you are using modulo operator on constants with different signs: `1 % -2` + --> $DIR/modulo_arithmetic_integral_const.rs:30:5 + | +LL | 1isize % -2isize; + | ^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + = note: or consider using `rem_euclid` or similar function + +error: aborting due to 17 previous errors + From a208906afb950d26c6acd770b8650bc840ad35dc Mon Sep 17 00:00:00 2001 From: mgr-inz-rafal Date: Sat, 28 Dec 2019 17:14:19 +0100 Subject: [PATCH 3/3] Fixes for elided lifetimes --- clippy_lints/src/modulo_arithmetic.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 308bb00fe76..09c3ce8d028 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -37,7 +37,7 @@ struct OperandInfo { is_integral: bool, } -fn analyze_operand(operand: &Expr, cx: &LateContext<'_, '_>, expr: &Expr) -> Option { +fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option { match constant(cx, cx.tables, operand) { Some((Constant::Int(v), _)) => match cx.tables.expr_ty(expr).kind { ty::Int(ity) => { @@ -82,7 +82,7 @@ fn might_have_negative_value(t: &ty::TyS<'_>) -> bool { fn check_const_operands<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, - expr: &'tcx Expr, + expr: &'tcx Expr<'_>, lhs_operand: &OperandInfo, rhs_operand: &OperandInfo, ) { @@ -106,7 +106,7 @@ fn check_const_operands<'a, 'tcx>( } } -fn check_non_const_operands<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, operand: &Expr) { +fn check_non_const_operands<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, operand: &Expr<'_>) { let operand_type = cx.tables.expr_ty(operand); if might_have_negative_value(operand_type) { span_lint_and_then( @@ -125,7 +125,7 @@ fn check_non_const_operands<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Ex } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ModuloArithmetic { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { match &expr.kind { ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => { if let BinOpKind::Rem = op.node {