]>
Commit | Line | Data |
---|---|---|
abe05a73 | 1 | use consts::{constant_simple, Constant, FloatWidth}; |
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 | /// ``` | |
17 | declare_lint! { | |
18 | pub ZERO_DIVIDED_BY_ZERO, | |
19 | Warn, | |
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. | |
abe05a73 XL |
40 | if let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(cx, left); |
41 | if let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(cx, right); | |
42 | if Ok(0.0) == lhs_value.parse(); | |
43 | if Ok(0.0) == rhs_value.parse(); | |
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. | |
47 | let float_type = match (lhs_width, rhs_width) { | |
48 | (FloatWidth::F64, _) | |
49 | | (_, FloatWidth::F64) => "f64", | |
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 | } |