]> git.lizzy.rs Git - rust.git/blob - src/arithmetic.rs
lint remainder, document test w/ half expr
[rust.git] / src / arithmetic.rs
1 use rustc::hir;
2 use rustc::lint::*;
3 use syntax::codemap::Span;
4 use utils::span_lint;
5
6 /// **What it does:** This lint checks for plain integer arithmetic
7 ///
8 /// **Why is this bad?** This is only checked against overflow in debug builds.
9 /// In some applications one wants explicitly checked, wrapping or saturating
10 /// arithmetic.
11 ///
12 /// **Known problems:** None
13 ///
14 /// **Example:**
15 /// ```
16 /// a + 1
17 /// ```
18 declare_lint! {
19     pub INTEGER_ARITHMETIC,
20     Allow,
21     "Any integer arithmetic statement"
22 }
23
24 /// **What it does:** This lint checks for float arithmetic
25 ///
26 /// **Why is this bad?** For some embedded systems or kernel development, it
27 /// can be useful to rule out floating-point numbers
28 ///
29 /// **Known problems:** None
30 ///
31 /// **Example:**
32 /// ```
33 /// a + 1.0
34 /// ```
35 declare_lint! {
36     pub FLOAT_ARITHMETIC,
37     Allow,
38     "Any floating-point arithmetic statement"
39 }
40
41 #[derive(Copy, Clone, Default)]
42 pub struct Arithmetic {
43     span: Option<Span>
44 }
45
46 impl LintPass for Arithmetic {
47     fn get_lints(&self) -> LintArray {
48         lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC)
49     }
50 }
51
52 impl LateLintPass for Arithmetic {
53     fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) {
54         if let Some(_) = self.span { return; }
55         match expr.node {
56             hir::ExprBinary(ref op, ref l, ref r) => {
57                 match op.node {
58                     hir::BiAnd | hir::BiOr | hir::BiBitAnd | 
59                     hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | 
60                     hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | 
61                     hir::BiGt => return,
62                     _ => ()
63                 }
64                 let (l_ty, r_ty) = (cx.tcx.expr_ty(l), cx.tcx.expr_ty(r));
65                 if l_ty.is_integral() && r_ty.is_integral() {
66                     span_lint(cx, 
67                               INTEGER_ARITHMETIC, 
68                               expr.span,
69                               "integer arithmetic detected");
70                     self.span = Some(expr.span);                    
71                 } else if l_ty.is_floating_point() && r_ty.is_floating_point() {
72                     span_lint(cx,
73                               FLOAT_ARITHMETIC,
74                               expr.span,
75                               "floating-point arithmetic detected");
76                     self.span = Some(expr.span);                    
77                 }
78             },
79             hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
80                 let ty = cx.tcx.expr_ty(arg);
81                 if ty.is_integral() {
82                     span_lint(cx, 
83                               INTEGER_ARITHMETIC, 
84                               expr.span,
85                               "integer arithmetic detected");
86                     self.span = Some(expr.span);
87                 } else if ty.is_floating_point() {
88                     span_lint(cx,
89                               FLOAT_ARITHMETIC,
90                               expr.span,
91                               "floating-point arithmetic detected");
92                     self.span = Some(expr.span);
93                 }
94             },
95             _ => ()
96         }
97     }
98     
99     fn check_expr_post(&mut self, _: &LateContext, expr: &hir::Expr) {
100         if Some(expr.span) == self.span {
101             self.span = None;
102         }
103     }
104 }