]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/arithmetic.rs
Merge pull request #3269 from rust-lang-nursery/relicense
[rust.git] / clippy_lints / src / arithmetic.rs
1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10
11 use crate::utils::span_lint;
12 use crate::rustc::hir;
13 use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
14 use crate::rustc::{declare_tool_lint, lint_array};
15 use crate::syntax::source_map::Span;
16
17 /// **What it does:** Checks for plain integer arithmetic.
18 ///
19 /// **Why is this bad?** This is only checked against overflow in debug builds.
20 /// In some applications one wants explicitly checked, wrapping or saturating
21 /// arithmetic.
22 ///
23 /// **Known problems:** None.
24 ///
25 /// **Example:**
26 /// ```rust
27 /// a + 1
28 /// ```
29 declare_clippy_lint! {
30     pub INTEGER_ARITHMETIC,
31     restriction,
32     "any integer arithmetic statement"
33 }
34
35 /// **What it does:** Checks for float arithmetic.
36 ///
37 /// **Why is this bad?** For some embedded systems or kernel development, it
38 /// can be useful to rule out floating-point numbers.
39 ///
40 /// **Known problems:** None.
41 ///
42 /// **Example:**
43 /// ```rust
44 /// a + 1.0
45 /// ```
46 declare_clippy_lint! {
47     pub FLOAT_ARITHMETIC,
48     restriction,
49     "any floating-point arithmetic statement"
50 }
51
52 #[derive(Copy, Clone, Default)]
53 pub struct Arithmetic {
54     span: Option<Span>,
55 }
56
57 impl LintPass for Arithmetic {
58     fn get_lints(&self) -> LintArray {
59         lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC)
60     }
61 }
62
63 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
64     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
65         if self.span.is_some() {
66             return;
67         }
68         match expr.node {
69             hir::ExprKind::Binary(ref op, ref l, ref r) => {
70                 match op.node {
71                     hir::BinOpKind::And
72                     | hir::BinOpKind::Or
73                     | hir::BinOpKind::BitAnd
74                     | hir::BinOpKind::BitOr
75                     | hir::BinOpKind::BitXor
76                     | hir::BinOpKind::Shl
77                     | hir::BinOpKind::Shr
78                     | hir::BinOpKind::Eq
79                     | hir::BinOpKind::Lt
80                     | hir::BinOpKind::Le
81                     | hir::BinOpKind::Ne
82                     | hir::BinOpKind::Ge
83                     | hir::BinOpKind::Gt => return,
84                     _ => (),
85                 }
86                 let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r));
87                 if l_ty.is_integral() && r_ty.is_integral() {
88                     span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
89                     self.span = Some(expr.span);
90                 } else if l_ty.is_floating_point() && r_ty.is_floating_point() {
91                     span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
92                     self.span = Some(expr.span);
93                 }
94             },
95             hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => {
96                 let ty = cx.tables.expr_ty(arg);
97                 if ty.is_integral() {
98                     span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
99                     self.span = Some(expr.span);
100                 } else if ty.is_floating_point() {
101                     span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
102                     self.span = Some(expr.span);
103                 }
104             },
105             _ => (),
106         }
107     }
108
109     fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
110         if Some(expr.span) == self.span {
111             self.span = None;
112         }
113     }
114 }