]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/overflow_check_conditional.rs
Merge branch 'feature/gh-pages-docs' of https://github.com/killercup/rust-clippy...
[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:** This lint finds classic underflow / overflow checks.
6 ///
7 /// **Why is this bad?** Most classic C underflow / overflow checks will fail in Rust. Users can
8 /// 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!(pub OVERFLOW_CHECK_CONDITIONAL, Warn,
18               "Using overflow checks which are likely to panic");
19
20 #[derive(Copy, Clone)]
21 pub struct OverflowCheckConditional;
22
23 impl LintPass for OverflowCheckConditional {
24     fn get_lints(&self) -> LintArray {
25         lint_array!(OVERFLOW_CHECK_CONDITIONAL)
26     }
27 }
28
29 impl LateLintPass for OverflowCheckConditional {
30     // a + b < a, a > a + b, a < a - b, a - b > a
31     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
32         if_let_chain! {[
33             let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
34             let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = first.node,
35             let Expr_::ExprPath(_,ref path1) = ident1.node,
36             let Expr_::ExprPath(_, ref path2) = ident2.node,
37             let Expr_::ExprPath(_, ref path3) = second.node,
38             &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0],
39             cx.tcx.expr_ty(ident1).is_integral(),
40             cx.tcx.expr_ty(ident2).is_integral()
41         ], {
42             if let BinOp_::BiLt = op.node {
43                 if let BinOp_::BiAdd = op2.node {
44                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditions that will fail in Rust.");
45                 }
46             }
47             if let BinOp_::BiGt = op.node {
48                 if let BinOp_::BiSub = op2.node {
49                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditions that will fail in Rust.");
50                 }
51             }
52         }}
53
54         if_let_chain! {[
55             let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
56             let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = second.node,
57             let Expr_::ExprPath(_,ref path1) = ident1.node,
58             let Expr_::ExprPath(_, ref path2) = ident2.node,
59             let Expr_::ExprPath(_, ref path3) = first.node,
60             &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0],
61             cx.tcx.expr_ty(ident1).is_integral(),
62             cx.tcx.expr_ty(ident2).is_integral()
63         ], {
64             if let BinOp_::BiGt = op.node {
65                 if let BinOp_::BiAdd = op2.node {
66                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditions that will fail in Rust.");
67                 }
68             }
69             if let BinOp_::BiLt = op.node {
70                 if let BinOp_::BiSub = op2.node {
71                     span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditions that will fail in Rust.");
72                 }
73             }
74         }}
75     }
76 }