]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
Merge branch 'master' of http://localhost:8000/rust-lang/rust.git:at_commit=75dd959a3...
[rust.git] / src / tools / clippy / clippy_lints / src / operators / float_equality_without_abs.rs
1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::{match_def_path, paths, sugg};
3 use if_chain::if_chain;
4 use rustc_ast::util::parser::AssocOp;
5 use rustc_errors::Applicability;
6 use rustc_hir::def::{DefKind, Res};
7 use rustc_hir::{BinOpKind, Expr, ExprKind};
8 use rustc_lint::LateContext;
9 use rustc_middle::ty;
10 use rustc_span::source_map::Spanned;
11
12 use super::FLOAT_EQUALITY_WITHOUT_ABS;
13
14 pub(crate) fn check<'tcx>(
15     cx: &LateContext<'tcx>,
16     expr: &'tcx Expr<'_>,
17     op: BinOpKind,
18     lhs: &'tcx Expr<'_>,
19     rhs: &'tcx Expr<'_>,
20 ) {
21     let (lhs, rhs) = match op {
22         BinOpKind::Lt => (lhs, rhs),
23         BinOpKind::Gt => (rhs, lhs),
24         _ => return,
25     };
26
27     if_chain! {
28         // left hand side is a subtraction
29         if let ExprKind::Binary(
30             Spanned {
31                 node: BinOpKind::Sub,
32                 ..
33             },
34             val_l,
35             val_r,
36         ) = lhs.kind;
37
38         // right hand side matches either f32::EPSILON or f64::EPSILON
39         if let ExprKind::Path(ref epsilon_path) = rhs.kind;
40         if let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id);
41         if match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON);
42
43         // values of the subtractions on the left hand side are of the type float
44         let t_val_l = cx.typeck_results().expr_ty(val_l);
45         let t_val_r = cx.typeck_results().expr_ty(val_r);
46         if let ty::Float(_) = t_val_l.kind();
47         if let ty::Float(_) = t_val_r.kind();
48
49         then {
50             let sug_l = sugg::Sugg::hir(cx, val_l, "..");
51             let sug_r = sugg::Sugg::hir(cx, val_r, "..");
52             // format the suggestion
53             let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par());
54             // spans the lint
55             span_lint_and_then(
56                 cx,
57                 FLOAT_EQUALITY_WITHOUT_ABS,
58                 expr.span,
59                 "float equality check without `.abs()`",
60                 | diag | {
61                     diag.span_suggestion(
62                         lhs.span,
63                         "add `.abs()`",
64                         suggestion,
65                         Applicability::MaybeIncorrect,
66                     );
67                 }
68             );
69         }
70     }
71 }