diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs deleted file mode 100644 index 3effba56826..00000000000 --- a/clippy_lints/src/integer_division.rs +++ /dev/null @@ -1,61 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use if_chain::if_chain; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for division of integers - /// - /// ### Why is this bad? - /// When outside of some very specific algorithms, - /// integer division is very often a mistake because it discards the - /// remainder. - /// - /// ### Example - /// ```rust - /// let x = 3 / 2; - /// println!("{}", x); - /// ``` - /// - /// Use instead: - /// ```rust - /// let x = 3f32 / 2f32; - /// println!("{}", x); - /// ``` - #[clippy::version = "1.37.0"] - pub INTEGER_DIVISION, - restriction, - "integer division may cause loss of precision" -} - -declare_lint_pass!(IntegerDivision => [INTEGER_DIVISION]); - -impl<'tcx> LateLintPass<'tcx> for IntegerDivision { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if is_integer_division(cx, expr) { - span_lint_and_help( - cx, - INTEGER_DIVISION, - expr.span, - "integer division", - None, - "division of integers may cause loss of precision. consider using floats", - ); - } - } -} - -fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { - if_chain! { - if let hir::ExprKind::Binary(binop, left, right) = &expr.kind; - if binop.node == hir::BinOpKind::Div; - then { - let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right)); - return left_ty.is_integral() && right_ty.is_integral(); - } - } - - false -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 946e8c76f17..7acfdf56840 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -194,7 +194,6 @@ store.register_lints(&[ init_numbered_fields::INIT_NUMBERED_FIELDS, inline_fn_without_body::INLINE_FN_WITHOUT_BODY, int_plus_one::INT_PLUS_ONE, - integer_division::INTEGER_DIVISION, invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, items_after_statements::ITEMS_AFTER_STATEMENTS, iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, @@ -434,6 +433,7 @@ store.register_lints(&[ operators::IDENTITY_OP, operators::INEFFECTIVE_BIT_MASK, operators::INTEGER_ARITHMETIC, + operators::INTEGER_DIVISION, operators::MISREFACTORED_ASSIGN_OP, operators::OP_REF, operators::VERBOSE_BIT_MASK, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index b7441385230..53d968c4710 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -25,7 +25,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(implicit_return::IMPLICIT_RETURN), LintId::of(indexing_slicing::INDEXING_SLICING), LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL), - LintId::of(integer_division::INTEGER_DIVISION), LintId::of(large_include_file::LARGE_INCLUDE_FILE), LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), @@ -52,6 +51,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), LintId::of(operators::FLOAT_ARITHMETIC), LintId::of(operators::INTEGER_ARITHMETIC), + LintId::of(operators::INTEGER_DIVISION), LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN), LintId::of(panic_unimplemented::PANIC), LintId::of(panic_unimplemented::TODO), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 327a1150952..4c4d149e177 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -254,7 +254,6 @@ mod inherent_to_string; mod init_numbered_fields; mod inline_fn_without_body; mod int_plus_one; -mod integer_division; mod invalid_upcast_comparisons; mod items_after_statements; mod iter_not_returning_iterator; @@ -734,7 +733,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite)); - store.register_late_pass(|| Box::new(integer_division::IntegerDivision)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); diff --git a/clippy_lints/src/operators/integer_division.rs b/clippy_lints/src/operators/integer_division.rs new file mode 100644 index 00000000000..631d10f4a72 --- /dev/null +++ b/clippy_lints/src/operators/integer_division.rs @@ -0,0 +1,27 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::INTEGER_DIVISION; + +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + op: hir::BinOpKind, + left: &'tcx hir::Expr<'_>, + right: &'tcx hir::Expr<'_>, +) { + if op == hir::BinOpKind::Div + && cx.typeck_results().expr_ty(left).is_integral() + && cx.typeck_results().expr_ty(right).is_integral() + { + span_lint_and_help( + cx, + INTEGER_DIVISION, + expr.span, + "integer division", + None, + "division of integers may cause loss of precision. consider using floats", + ); + } +} diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 91550e0e678..ea6a0083bc8 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -11,6 +11,7 @@ mod eq_op; mod erasing_op; mod float_equality_without_abs; mod identity_op; +mod integer_division; mod misrefactored_assign_op; mod numeric_arithmetic; mod op_ref; @@ -437,6 +438,32 @@ declare_clippy_lint! { "using identity operations, e.g., `x + 0` or `y / 1`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for division of integers + /// + /// ### Why is this bad? + /// When outside of some very specific algorithms, + /// integer division is very often a mistake because it discards the + /// remainder. + /// + /// ### Example + /// ```rust + /// let x = 3 / 2; + /// println!("{}", x); + /// ``` + /// + /// Use instead: + /// ```rust + /// let x = 3f32 / 2f32; + /// println!("{}", x); + /// ``` + #[clippy::version = "1.37.0"] + pub INTEGER_DIVISION, + restriction, + "integer division may cause loss of precision" +} + pub struct Operators { arithmetic_context: numeric_arithmetic::Context, verbose_bit_mask_threshold: u64, @@ -457,6 +484,7 @@ impl_lint_pass!(Operators => [ ERASING_OP, FLOAT_EQUALITY_WITHOUT_ABS, IDENTITY_OP, + INTEGER_DIVISION, ]); impl Operators { pub fn new(verbose_bit_mask_threshold: u64) -> Self { @@ -486,6 +514,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators { double_comparison::check(cx, op.node, lhs, rhs, e.span); duration_subsec::check(cx, e, op.node, lhs, rhs); float_equality_without_abs::check(cx, e, op.node, lhs, rhs); + integer_division::check(cx, e, op.node, lhs, rhs); }, ExprKind::AssignOp(op, lhs, rhs) => { self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);