Skip to content

Commit 3bd75b5

Browse files
committed
Move FloatEqualityWithoutAbs into Operators lint pass
1 parent af5b276 commit 3bd75b5

File tree

7 files changed

+110
-121
lines changed

7 files changed

+110
-121
lines changed

clippy_lints/src/float_equality_without_abs.rs

Lines changed: 0 additions & 116 deletions
This file was deleted.

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
6363
LintId::of(escape::BOXED_LOCAL),
6464
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
6565
LintId::of(explicit_write::EXPLICIT_WRITE),
66-
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
6766
LintId::of(float_literal::EXCESSIVE_PRECISION),
6867
LintId::of(format::USELESS_FORMAT),
6968
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
@@ -250,6 +249,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
250249
LintId::of(operators::DURATION_SUBSEC),
251250
LintId::of(operators::EQ_OP),
252251
LintId::of(operators::ERASING_OP),
252+
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
253253
LintId::of(operators::INEFFECTIVE_BIT_MASK),
254254
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
255255
LintId::of(operators::OP_REF),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ store.register_lints(&[
147147
exit::EXIT,
148148
explicit_write::EXPLICIT_WRITE,
149149
fallible_impl_from::FALLIBLE_IMPL_FROM,
150-
float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
151150
float_literal::EXCESSIVE_PRECISION,
152151
float_literal::LOSSY_FLOAT_LITERAL,
153152
floating_point_arithmetic::IMPRECISE_FLOPS,
@@ -420,6 +419,7 @@ store.register_lints(&[
420419
operators::EQ_OP,
421420
operators::ERASING_OP,
422421
operators::FLOAT_ARITHMETIC,
422+
operators::FLOAT_EQUALITY_WITHOUT_ABS,
423423
operators::INEFFECTIVE_BIT_MASK,
424424
operators::INTEGER_ARITHMETIC,
425425
operators::MISREFACTORED_ASSIGN_OP,

clippy_lints/src/lib.register_suspicious.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
1515
LintId::of(drop_forget_ref::DROP_NON_DROP),
1616
LintId::of(drop_forget_ref::FORGET_NON_DROP),
1717
LintId::of(duplicate_mod::DUPLICATE_MOD),
18-
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
1918
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
2019
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
2120
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
@@ -27,6 +26,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
2726
LintId::of(methods::SUSPICIOUS_MAP),
2827
LintId::of(mut_key::MUTABLE_KEY_TYPE),
2928
LintId::of(octal_escapes::OCTAL_ESCAPES),
29+
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
3030
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
3131
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
3232
LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ mod exhaustive_items;
224224
mod exit;
225225
mod explicit_write;
226226
mod fallible_impl_from;
227-
mod float_equality_without_abs;
228227
mod float_literal;
229228
mod floating_point_arithmetic;
230229
mod format;
@@ -819,7 +818,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
819818
store.register_late_pass(|| Box::new(self_assignment::SelfAssignment));
820819
store.register_late_pass(|| Box::new(manual_unwrap_or::ManualUnwrapOr));
821820
store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
822-
store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
823821
store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
824822
store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
825823
let disallowed_methods = conf.disallowed_methods.clone();
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
}

clippy_lints/src/operators/mod.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod double_comparison;
1010
mod duration_subsec;
1111
mod eq_op;
1212
mod erasing_op;
13+
mod float_equality_without_abs;
1314
mod misrefactored_assign_op;
1415
mod op_ref;
1516
mod verbose_bit_mask;
@@ -377,6 +378,39 @@ declare_clippy_lint! {
377378
"using erasing operations, e.g., `x * 0` or `y & 0`"
378379
}
379380

381+
declare_clippy_lint! {
382+
/// ### What it does
383+
/// Checks for statements of the form `(a - b) < f32::EPSILON` or
384+
/// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
385+
///
386+
/// ### Why is this bad?
387+
/// The code without `.abs()` is more likely to have a bug.
388+
///
389+
/// ### Known problems
390+
/// If the user can ensure that b is larger than a, the `.abs()` is
391+
/// technically unnecessary. However, it will make the code more robust and doesn't have any
392+
/// large performance implications. If the abs call was deliberately left out for performance
393+
/// reasons, it is probably better to state this explicitly in the code, which then can be done
394+
/// with an allow.
395+
///
396+
/// ### Example
397+
/// ```rust
398+
/// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
399+
/// (a - b) < f32::EPSILON
400+
/// }
401+
/// ```
402+
/// Use instead:
403+
/// ```rust
404+
/// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
405+
/// (a - b).abs() < f32::EPSILON
406+
/// }
407+
/// ```
408+
#[clippy::version = "1.48.0"]
409+
pub FLOAT_EQUALITY_WITHOUT_ABS,
410+
suspicious,
411+
"float equality check without `.abs()`"
412+
}
413+
380414
pub struct Operators {
381415
arithmetic_context: arithmetic::Context,
382416
verbose_bit_mask_threshold: u64,
@@ -395,6 +429,7 @@ impl_lint_pass!(Operators => [
395429
EQ_OP,
396430
OP_REF,
397431
ERASING_OP,
432+
FLOAT_EQUALITY_WITHOUT_ABS,
398433
]);
399434
impl Operators {
400435
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
@@ -422,6 +457,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
422457
verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
423458
double_comparison::check(cx, op.node, lhs, rhs, e.span);
424459
duration_subsec::check(cx, e, op.node, lhs, rhs);
460+
float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
425461
},
426462
ExprKind::AssignOp(op, lhs, rhs) => {
427463
self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);

0 commit comments

Comments
 (0)