@@ -9,6 +9,7 @@ mod double_comparison;
99mod duration_subsec;
1010mod eq_op;
1111mod erasing_op;
12+ mod float_equality_without_abs;
1213mod misrefactored_assign_op;
1314mod numeric_arithmetic;
1415mod 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+
386420pub 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] ) ;
405440impl 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