]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/overflow_check_conditional.rs
Make lint descriptions short and to the point; always fitting the column "triggers...
[rust.git] / clippy_lints / src / overflow_check_conditional.rs
1 use rustc::lint::*;
2 use rustc::hir::*;
3 use utils::span_lint;
4
5 /// **What it does:** Detects classic underflow/overflow checks.
6 ///
7 /// **Why is this bad?** Most classic C underflow/overflow checks will fail in
8 /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
9 ///
10 /// **Known problems:** None.
11 ///
12 /// **Example:**
13 /// ```rust
14 /// a + b < a
15 /// ```
16
17 declare_lint! {
18     pub OVERFLOW_CHECK_CONDITIONAL,
19     Warn,
20     "overflow checks inspired by C which are likely to panic"
21 }
22
23 #[derive(Copy, Clone)]
24 pub struct OverflowCheckConditional;
25
26 impl LintPass for OverflowCheckConditional {
27     fn get_lints(&self) -> LintArray {
28         lint_array!(OVERFLOW_CHECK_CONDITIONAL)
29     }
30 }
31
32 impl LateLintPass for OverflowCheckConditional {
33     // a + b < a, a > a + b, a < a - b, a - b > a
34     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
35         if_let_chain! {[
36             let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
37             let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = first.node,
38             let Expr_::ExprPath(_,ref path1) = ident1.node,
39             let Expr_::ExprPath(_, ref path2) = ident2.node,
40             let Expr_::ExprPath(_, ref path3) = second.node,
41             &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0],
42             cx.tcx.expr_ty(ident1).is_integral(),
43             cx.tcx.expr_ty(ident2).is_integral()
44         ], {
45             if let BinOp_::BiLt = op.node {
46                 if let BinOp_::BiAdd = op2.node {
47                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditions that will fail in Rust.");
48                 }
49             }
50             if let BinOp_::BiGt = op.node {
51                 if let BinOp_::BiSub = op2.node {
52                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditions that will fail in Rust.");
53                 }
54             }
55         }}
56
57         if_let_chain! {[
58             let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
59             let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = second.node,
60             let Expr_::ExprPath(_,ref path1) = ident1.node,
61             let Expr_::ExprPath(_, ref path2) = ident2.node,
62             let Expr_::ExprPath(_, ref path3) = first.node,
63             &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0],
64             cx.tcx.expr_ty(ident1).is_integral(),
65             cx.tcx.expr_ty(ident2).is_integral()
66         ], {
67             if let BinOp_::BiGt = op.node {
68                 if let BinOp_::BiAdd = op2.node {
69                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditions that will fail in Rust.");
70                 }
71             }
72             if let BinOp_::BiLt = op.node {
73                 if let BinOp_::BiSub = op2.node {
74                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditions that will fail in Rust.");
75                 }
76             }
77         }}
78     }
79 }