]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/integer_division.rs
rustup https://github.com/rust-lang/rust/pull/67455
[rust.git] / clippy_lints / src / integer_division.rs
1 use crate::utils::span_help_and_lint;
2 use if_chain::if_chain;
3 use rustc::declare_lint_pass;
4 use rustc::hir;
5 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
6 use rustc_session::declare_tool_lint;
7
8 declare_clippy_lint! {
9     /// **What it does:** Checks for division of integers
10     ///
11     /// **Why is this bad?** When outside of some very specific algorithms,
12     /// integer division is very often a mistake because it discards the
13     /// remainder.
14     ///
15     /// **Known problems:** None.
16     ///
17     /// **Example:**
18     /// ```rust
19     /// fn main() {
20     ///     let x = 3 / 2;
21     ///     println!("{}", x);
22     /// }
23     /// ```
24     pub INTEGER_DIVISION,
25     restriction,
26     "integer division may cause loss of precision"
27 }
28
29 declare_lint_pass!(IntegerDivision => [INTEGER_DIVISION]);
30
31 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IntegerDivision {
32     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
33         if is_integer_division(cx, expr) {
34             span_help_and_lint(
35                 cx,
36                 INTEGER_DIVISION,
37                 expr.span,
38                 "integer division",
39                 "division of integers may cause loss of precision. consider using floats.",
40             );
41         }
42     }
43 }
44
45 fn is_integer_division<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) -> bool {
46     if_chain! {
47         if let hir::ExprKind::Binary(binop, left, right) = &expr.kind;
48         if let hir::BinOpKind::Div = &binop.node;
49         then {
50             let (left_ty, right_ty) = (cx.tables.expr_ty(left), cx.tables.expr_ty(right));
51             return left_ty.is_integral() && right_ty.is_integral();
52         }
53     }
54
55     false
56 }