1 use clippy_utils
::consts
::{constant_simple, Constant}
;
2 use clippy_utils
::diagnostics
::span_lint_and_help
;
3 use if_chain
::if_chain
;
4 use rustc_hir
::{BinOpKind, Expr, ExprKind}
;
5 use rustc_lint
::{LateContext, LateLintPass}
;
6 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
10 /// Checks for `0.0 / 0.0`.
12 /// ### Why is this bad?
13 /// It's less readable than `f32::NAN` or `f64::NAN`.
17 /// let nan = 0.0f32 / 0.0;
22 /// let nan = f32::NAN;
24 #[clippy::version = "pre 1.29.0"]
25 pub ZERO_DIVIDED_BY_ZERO
,
27 "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`"
30 declare_lint_pass
!(ZeroDiv
=> [ZERO_DIVIDED_BY_ZERO
]);
32 impl<'tcx
> LateLintPass
<'tcx
> for ZeroDiv
{
33 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) {
34 // check for instances of 0.0/0.0
36 if let ExprKind
::Binary(ref op
, left
, right
) = expr
.kind
;
37 if op
.node
== BinOpKind
::Div
;
38 // TODO - constant_simple does not fold many operations involving floats.
39 // That's probably fine for this lint - it's pretty unlikely that someone would
40 // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
41 if let Some(lhs_value
) = constant_simple(cx
, cx
.typeck_results(), left
);
42 if let Some(rhs_value
) = constant_simple(cx
, cx
.typeck_results(), right
);
43 if Constant
::F32(0.0) == lhs_value
|| Constant
::F64(0.0) == lhs_value
;
44 if Constant
::F32(0.0) == rhs_value
|| Constant
::F64(0.0) == rhs_value
;
46 // since we're about to suggest a use of f32::NAN or f64::NAN,
47 // match the precision of the literals that are given.
48 let float_type
= match (lhs_value
, rhs_value
) {
50 | (_
, Constant
::F64(_
)) => "f64",
57 "constant division of `0.0` with `0.0` will always result in NaN",
60 "consider using `{}::NAN` if you would like a constant representing NaN",