Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 56f50d3

Browse files
committed
Move FloatEqualityWithoutAbs into Operators lint pass
1 parent 3de70a4 commit 56f50d3

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
@@ -64,7 +64,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
6464
LintId::of(escape::BOXED_LOCAL),
6565
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
6666
LintId::of(explicit_write::EXPLICIT_WRITE),
67-
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
6867
LintId::of(float_literal::EXCESSIVE_PRECISION),
6968
LintId::of(format::USELESS_FORMAT),
7069
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
@@ -257,6 +256,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
257256
LintId::of(operators::DURATION_SUBSEC),
258257
LintId::of(operators::EQ_OP),
259258
LintId::of(operators::ERASING_OP),
259+
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
260260
LintId::of(operators::INEFFECTIVE_BIT_MASK),
261261
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
262262
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
@@ -151,7 +151,6 @@ store.register_lints(&[
151151
exit::EXIT,
152152
explicit_write::EXPLICIT_WRITE,
153153
fallible_impl_from::FALLIBLE_IMPL_FROM,
154-
float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
155154
float_literal::EXCESSIVE_PRECISION,
156155
float_literal::LOSSY_FLOAT_LITERAL,
157156
floating_point_arithmetic::IMPRECISE_FLOPS,
@@ -432,6 +431,7 @@ store.register_lints(&[
432431
operators::EQ_OP,
433432
operators::ERASING_OP,
434433
operators::FLOAT_ARITHMETIC,
434+
operators::FLOAT_EQUALITY_WITHOUT_ABS,
435435
operators::INEFFECTIVE_BIT_MASK,
436436
operators::INTEGER_ARITHMETIC,
437437
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),
@@ -28,6 +27,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
2827
LintId::of(methods::SUSPICIOUS_MAP),
2928
LintId::of(mut_key::MUTABLE_KEY_TYPE),
3029
LintId::of(octal_escapes::OCTAL_ESCAPES),
30+
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
3131
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
3232
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
3333
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ mod exhaustive_items;
227227
mod exit;
228228
mod explicit_write;
229229
mod fallible_impl_from;
230-
mod float_equality_without_abs;
231230
mod float_literal;
232231
mod floating_point_arithmetic;
233232
mod format;
@@ -842,7 +841,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
842841
store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
843842
store.register_late_pass(|| Box::new(self_assignment::SelfAssignment));
844843
store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
845-
store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
846844
store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
847845
store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
848846
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
@@ -9,6 +9,7 @@ mod double_comparison;
99
mod duration_subsec;
1010
mod eq_op;
1111
mod erasing_op;
12+
mod float_equality_without_abs;
1213
mod misrefactored_assign_op;
1314
mod numeric_arithmetic;
1415
mod op_ref;
@@ -383,6 +384,39 @@ declare_clippy_lint! {
383384
"using erasing operations, e.g., `x * 0` or `y & 0`"
384385
}
385386

387+
declare_clippy_lint! {
388+
/// ### What it does
389+
/// Checks for statements of the form `(a - b) < f32::EPSILON` or
390+
/// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
391+
///
392+
/// ### Why is this bad?
393+
/// The code without `.abs()` is more likely to have a bug.
394+
///
395+
/// ### Known problems
396+
/// If the user can ensure that b is larger than a, the `.abs()` is
397+
/// technically unnecessary. However, it will make the code more robust and doesn't have any
398+
/// large performance implications. If the abs call was deliberately left out for performance
399+
/// reasons, it is probably better to state this explicitly in the code, which then can be done
400+
/// with an allow.
401+
///
402+
/// ### Example
403+
/// ```rust
404+
/// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
405+
/// (a - b) < f32::EPSILON
406+
/// }
407+
/// ```
408+
/// Use instead:
409+
/// ```rust
410+
/// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
411+
/// (a - b).abs() < f32::EPSILON
412+
/// }
413+
/// ```
414+
#[clippy::version = "1.48.0"]
415+
pub FLOAT_EQUALITY_WITHOUT_ABS,
416+
suspicious,
417+
"float equality check without `.abs()`"
418+
}
419+
386420
pub struct Operators {
387421
arithmetic_context: numeric_arithmetic::Context,
388422
verbose_bit_mask_threshold: u64,
@@ -401,6 +435,7 @@ impl_lint_pass!(Operators => [
401435
EQ_OP,
402436
OP_REF,
403437
ERASING_OP,
438+
FLOAT_EQUALITY_WITHOUT_ABS,
404439
]);
405440
impl Operators {
406441
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
@@ -428,6 +463,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
428463
verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
429464
double_comparison::check(cx, op.node, lhs, rhs, e.span);
430465
duration_subsec::check(cx, e, op.node, lhs, rhs);
466+
float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
431467
},
432468
ExprKind::AssignOp(op, lhs, rhs) => {
433469
self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);

0 commit comments

Comments
 (0)