]>
Commit | Line | Data |
---|---|---|
0531ce1d | 1 | use consts::{constant_simple, Constant}; |
ea8adc8c XL |
2 | use rustc::lint::*; |
3 | use rustc::hir::*; | |
4 | use utils::span_help_and_lint; | |
5 | ||
6 | /// **What it does:** Checks for `0.0 / 0.0`. | |
7 | /// | |
8 | /// **Why is this bad?** It's less readable than `std::f32::NAN` or | |
9 | /// `std::f64::NAN`. | |
10 | /// | |
11 | /// **Known problems:** None. | |
12 | /// | |
13 | /// **Example:** | |
14 | /// ```rust | |
15 | /// 0.0f32 / 0.0 | |
16 | /// ``` | |
0531ce1d | 17 | declare_clippy_lint! { |
ea8adc8c | 18 | pub ZERO_DIVIDED_BY_ZERO, |
0531ce1d | 19 | complexity, |
ea8adc8c XL |
20 | "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN" |
21 | } | |
22 | ||
23 | pub struct Pass; | |
24 | ||
25 | impl LintPass for Pass { | |
26 | fn get_lints(&self) -> LintArray { | |
27 | lint_array!(ZERO_DIVIDED_BY_ZERO) | |
28 | } | |
29 | } | |
30 | ||
31 | impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { | |
32 | fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { | |
33 | // check for instances of 0.0/0.0 | |
abe05a73 XL |
34 | if_chain! { |
35 | if let ExprBinary(ref op, ref left, ref right) = expr.node; | |
36 | if let BinOp_::BiDiv = op.node; | |
ea8adc8c XL |
37 | // TODO - constant_simple does not fold many operations involving floats. |
38 | // That's probably fine for this lint - it's pretty unlikely that someone would | |
39 | // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. | |
94b46f34 XL |
40 | if let Some(lhs_value) = constant_simple(cx, cx.tables, left); |
41 | if let Some(rhs_value) = constant_simple(cx, cx.tables, right); | |
0531ce1d XL |
42 | if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value; |
43 | if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value; | |
abe05a73 XL |
44 | then { |
45 | // since we're about to suggest a use of std::f32::NaN or std::f64::NaN, | |
46 | // match the precision of the literals that are given. | |
0531ce1d XL |
47 | let float_type = match (lhs_value, rhs_value) { |
48 | (Constant::F64(_), _) | |
49 | | (_, Constant::F64(_)) => "f64", | |
abe05a73 XL |
50 | _ => "f32" |
51 | }; | |
52 | span_help_and_lint( | |
53 | cx, | |
54 | ZERO_DIVIDED_BY_ZERO, | |
55 | expr.span, | |
56 | "constant division of 0.0 with 0.0 will always result in NaN", | |
57 | &format!( | |
58 | "Consider using `std::{}::NAN` if you would like a constant representing NaN", | |
59 | float_type, | |
60 | ), | |
61 | ); | |
62 | } | |
63 | } | |
ea8adc8c XL |
64 | } |
65 | } |