]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | use rustc::hir; |
2 | use rustc::lint::*; | |
3 | use syntax::codemap::Span; | |
4 | use utils::span_lint; | |
5 | ||
6 | /// **What it does:** 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 | /// ```rust | |
16 | /// a + 1 | |
17 | /// ``` | |
18 | declare_restriction_lint! { | |
19 | pub INTEGER_ARITHMETIC, | |
20 | "any integer arithmetic statement" | |
21 | } | |
22 | ||
23 | /// **What it does:** Checks for float arithmetic. | |
24 | /// | |
25 | /// **Why is this bad?** For some embedded systems or kernel development, it | |
26 | /// can be useful to rule out floating-point numbers. | |
27 | /// | |
28 | /// **Known problems:** None. | |
29 | /// | |
30 | /// **Example:** | |
31 | /// ```rust | |
32 | /// a + 1.0 | |
33 | /// ``` | |
34 | declare_restriction_lint! { | |
35 | pub FLOAT_ARITHMETIC, | |
36 | "any floating-point arithmetic statement" | |
37 | } | |
38 | ||
39 | #[derive(Copy, Clone, Default)] | |
40 | pub struct Arithmetic { | |
41 | span: Option<Span>, | |
42 | } | |
43 | ||
44 | impl LintPass for Arithmetic { | |
45 | fn get_lints(&self) -> LintArray { | |
46 | lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC) | |
47 | } | |
48 | } | |
49 | ||
50 | impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic { | |
51 | fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { | |
52 | if self.span.is_some() { | |
53 | return; | |
54 | } | |
55 | match expr.node { | |
56 | hir::ExprBinary(ref op, ref l, ref r) => { | |
57 | match op.node { | |
abe05a73 XL |
58 | hir::BiAnd | |
59 | hir::BiOr | | |
60 | hir::BiBitAnd | | |
61 | hir::BiBitOr | | |
62 | hir::BiBitXor | | |
63 | hir::BiShl | | |
64 | hir::BiShr | | |
65 | hir::BiEq | | |
66 | hir::BiLt | | |
67 | hir::BiLe | | |
68 | hir::BiNe | | |
69 | hir::BiGe | | |
70 | hir::BiGt => return, | |
ea8adc8c XL |
71 | _ => (), |
72 | } | |
73 | let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r)); | |
74 | if l_ty.is_integral() && r_ty.is_integral() { | |
75 | span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); | |
76 | self.span = Some(expr.span); | |
77 | } else if l_ty.is_floating_point() && r_ty.is_floating_point() { | |
78 | span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); | |
79 | self.span = Some(expr.span); | |
80 | } | |
81 | }, | |
82 | hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { | |
83 | let ty = cx.tables.expr_ty(arg); | |
84 | if ty.is_integral() { | |
85 | span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); | |
86 | self.span = Some(expr.span); | |
87 | } else if ty.is_floating_point() { | |
88 | span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); | |
89 | self.span = Some(expr.span); | |
90 | } | |
91 | }, | |
92 | _ => (), | |
93 | } | |
94 | } | |
95 | ||
96 | fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { | |
97 | if Some(expr.span) == self.span { | |
98 | self.span = None; | |
99 | } | |
100 | } | |
101 | } |