about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCatherine <114838443+Centri3@users.noreply.github.com>2023-07-04 12:49:15 -0500
committerCatherine <114838443+Centri3@users.noreply.github.com>2023-07-08 13:17:35 -0500
commit41438c2b90f0324494c6ca22d205bf0acec4c03c (patch)
tree6840156fa56d64b11206d2703e9363a987df15df
parent5949f762bfa15e62657771e556c160abe4caee8b (diff)
downloadrust-41438c2b90f0324494c6ca22d205bf0acec4c03c.tar.gz
rust-41438c2b90f0324494c6ca22d205bf0acec4c03c.zip
Refactor, remove `Constant::to_bits`
-rw-r--r--README.md2
-rw-r--r--book/src/README.md2
-rw-r--r--clippy_lints/src/manual_float_methods.rs59
-rw-r--r--clippy_utils/src/consts.rs11
-rw-r--r--tests/ui/manual_float_methods.rs21
-rw-r--r--tests/ui/manual_float_methods.stderr12
6 files changed, 66 insertions, 41 deletions
diff --git a/README.md b/README.md
index d712d3e6750..5d490645d89 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
 You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
diff --git a/book/src/README.md b/book/src/README.md
index 3b627096268..486ea3df704 100644
--- a/book/src/README.md
+++ b/book/src/README.md
@@ -6,7 +6,7 @@
 A collection of lints to catch common mistakes and improve your
 [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint
 level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs
index 0f488627b4e..09b39634333 100644
--- a/clippy_lints/src/manual_float_methods.rs
+++ b/clippy_lints/src/manual_float_methods.rs
@@ -1,5 +1,8 @@
 use clippy_utils::{
-    consts::constant, diagnostics::span_lint_and_then, is_from_proc_macro, path_to_local, source::snippet_opt,
+    consts::{constant, Constant},
+    diagnostics::span_lint_and_then,
+    is_from_proc_macro, path_to_local,
+    source::snippet_opt,
 };
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
@@ -9,10 +12,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `x == <float>::INFINITY || x == <float>::NEG_INFINITY`.
+    /// Checks for manual `is_infinite` reimplementations
+    /// (i.e., `x == <float>::INFINITY || x == <float>::NEG_INFINITY`).
     ///
     /// ### Why is this bad?
-    /// This should use the dedicated method instead, `is_infinite`.
+    /// The method `is_infinite` is shorter and more readable.
     ///
     /// ### Example
     /// ```rust
@@ -31,20 +35,23 @@ declare_clippy_lint! {
 }
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `x != <float>::INFINITY && x != <float>::NEG_INFINITY`.
+    /// Checks for manual `is_finite` reimplementations
+    /// (i.e., `x != <float>::INFINITY && x != <float>::NEG_INFINITY`).
     ///
     /// ### Why is this bad?
-    /// This should use the dedicated method instead, `is_finite`.
+    /// The method `is_finite` is shorter and more readable.
     ///
     /// ### Example
     /// ```rust
     /// # let x = 1.0f32;
     /// if x != f32::INFINITY && x != f32::NEG_INFINITY {}
+    /// if x.abs() < f32::INFINITY {}
     /// ```
     /// Use instead:
     /// ```rust
     /// # let x = 1.0f32;
     /// if x.is_finite() {}
+    /// if x.is_finite() {}
     /// ```
     #[clippy::version = "1.72.0"]
     pub MANUAL_IS_FINITE,
@@ -84,20 +91,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
             && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
             // Checking all possible scenarios using a function would be a hopeless task, as we have
             // 16 possible alignments of constants/operands. For now, let's use `partition`.
-            && let (operands, consts) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
+            && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
                 .into_iter()
                 .partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
             && let [first, second] = &*operands
-            && let Some([const_1, const_2]) = consts
+            && let Some([const_1, const_2]) = constants
                 .into_iter()
-                .map(|i| constant(cx, cx.typeck_results(), i).and_then(|c| c.to_bits()))
+                .map(|i| constant(cx, cx.typeck_results(), i))
                 .collect::<Option<Vec<_>>>()
                 .as_deref()
             && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
-            && (is_infinity(*const_1) && is_neg_infinity(*const_2)
-                || is_neg_infinity(*const_1) && is_infinity(*const_2))
-            && let Some(local_snippet) = snippet_opt(cx, first.span)
+            // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
+            // case somebody does that for some reason
+            && (is_infinity(const_1) && is_neg_infinity(const_2)
+                || is_neg_infinity(const_1) && is_infinity(const_2))
             && !is_from_proc_macro(cx, expr)
+            && let Some(local_snippet) = snippet_opt(cx, first.span)
         {
             let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
                 (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,
@@ -128,31 +137,39 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
                                 "use the dedicated method instead",
                                 format!("{local_snippet}.is_finite()"),
                                 Applicability::MaybeIncorrect,
-                            );
-                            diag.span_suggestion_verbose(
+                            )
+                            .span_suggestion_verbose(
                                 expr.span,
                                 "this will alter how it handles NaN; if that is a problem, use instead",
                                 format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"),
                                 Applicability::MaybeIncorrect,
-                            );
-                            diag.span_suggestion_verbose(
+                            )
+                            .span_suggestion_verbose(
                                 expr.span,
                                 "or, for conciseness",
                                 format!("!{local_snippet}.is_infinite()"),
                                 Applicability::MaybeIncorrect,
                             );
-                        }
+                        },
                     }
-                }
+                },
             );
         }
     }
 }
 
-fn is_infinity(bits: u128) -> bool {
-    bits == 0x7f80_0000 || bits == 0x7ff0_0000_0000_0000
+fn is_infinity(constant: &Constant<'_>) -> bool {
+    match constant {
+        Constant::F32(float) => *float == f32::INFINITY,
+        Constant::F64(float) => *float == f64::INFINITY,
+        _ => false,
+    }
 }
 
-fn is_neg_infinity(bits: u128) -> bool {
-    bits == 0xff80_0000 || bits == 0xfff0_0000_0000_0000
+fn is_neg_infinity(constant: &Constant<'_>) -> bool {
+    match constant {
+        Constant::F32(float) => *float == f32::NEG_INFINITY,
+        Constant::F64(float) => *float == f64::NEG_INFINITY,
+        _ => false,
+    }
 }
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index b9f8eefeb8e..87d85d742ce 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -190,17 +190,6 @@ impl<'tcx> Constant<'tcx> {
         }
     }
 
-    /// Returns the bit representation if `self` is a bool, integer, or float.
-    pub fn to_bits(&self) -> Option<u128> {
-        match self {
-            Constant::Int(int) => Some(*int),
-            Constant::F32(float) => Some(u128::from(float.to_bits())),
-            Constant::F64(float) => Some(u128::from(float.to_bits())),
-            Constant::Bool(bool) => Some(u128::from(*bool)),
-            _ => None,
-        }
-    }
-
     /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
     pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
         if let Constant::Int(const_int) = *self {
diff --git a/tests/ui/manual_float_methods.rs b/tests/ui/manual_float_methods.rs
index b772202c003..af9076cfb71 100644
--- a/tests/ui/manual_float_methods.rs
+++ b/tests/ui/manual_float_methods.rs
@@ -1,6 +1,7 @@
 //@aux-build:proc_macros.rs:proc-macro
 #![allow(clippy::needless_if, unused)]
 #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)]
+#![feature(inline_const)]
 
 #[macro_use]
 extern crate proc_macros;
@@ -8,6 +9,14 @@ extern crate proc_macros;
 const INFINITE: f32 = f32::INFINITY;
 const NEG_INFINITE: f32 = f32::NEG_INFINITY;
 
+fn fn_test() -> f64 {
+    f64::NEG_INFINITY
+}
+
+fn fn_test_not_inf() -> f64 {
+    112.0
+}
+
 fn main() {
     let x = 1.0f32;
     if x == f32::INFINITY || x == f32::NEG_INFINITY {}
@@ -20,8 +29,18 @@ fn main() {
     // Don't lint
     if x.is_infinite() {}
     if x.is_finite() {}
-    // If they're doing it this way, they probably know what they're doing
     if x.abs() < f64::INFINITY {}
+    if f64::INFINITY > x.abs() {}
+    if f64::abs(x) < f64::INFINITY {}
+    if f64::INFINITY > f64::abs(x) {}
+    // Is not evaluated by `clippy_utils::constant`
+    if x != f64::INFINITY && x != fn_test() {}
+    // Not -inf
+    if x != f64::INFINITY && x != fn_test_not_inf() {}
+    const X: f64 = 1.0f64;
+    // Will be linted if `const_float_classify` is enabled
+    if const { X == f64::INFINITY || X == f64::NEG_INFINITY } {}
+    if const { X != f64::INFINITY && X != f64::NEG_INFINITY } {}
     external! {
         let x = 1.0;
         if x == f32::INFINITY || x == f32::NEG_INFINITY {}
diff --git a/tests/ui/manual_float_methods.stderr b/tests/ui/manual_float_methods.stderr
index 7f4a4d2e95b..a56118b316a 100644
--- a/tests/ui/manual_float_methods.stderr
+++ b/tests/ui/manual_float_methods.stderr
@@ -1,5 +1,5 @@
 error: manually checking if a float is infinite
-  --> $DIR/manual_float_methods.rs:13:8
+  --> $DIR/manual_float_methods.rs:22:8
    |
 LL |     if x == f32::INFINITY || x == f32::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
@@ -7,7 +7,7 @@ LL |     if x == f32::INFINITY || x == f32::NEG_INFINITY {}
    = note: `-D clippy::manual-is-infinite` implied by `-D warnings`
 
 error: manually checking if a float is finite
-  --> $DIR/manual_float_methods.rs:14:8
+  --> $DIR/manual_float_methods.rs:23:8
    |
 LL |     if x != f32::INFINITY && x != f32::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -27,13 +27,13 @@ LL |     if !x.is_infinite() {}
    |        ~~~~~~~~~~~~~~~~
 
 error: manually checking if a float is infinite
-  --> $DIR/manual_float_methods.rs:15:8
+  --> $DIR/manual_float_methods.rs:24:8
    |
 LL |     if x == INFINITE || x == NEG_INFINITE {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
 
 error: manually checking if a float is finite
-  --> $DIR/manual_float_methods.rs:16:8
+  --> $DIR/manual_float_methods.rs:25:8
    |
 LL |     if x != INFINITE && x != NEG_INFINITE {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,13 +52,13 @@ LL |     if !x.is_infinite() {}
    |        ~~~~~~~~~~~~~~~~
 
 error: manually checking if a float is infinite
-  --> $DIR/manual_float_methods.rs:18:8
+  --> $DIR/manual_float_methods.rs:27:8
    |
 LL |     if x == f64::INFINITY || x == f64::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
 
 error: manually checking if a float is finite
-  --> $DIR/manual_float_methods.rs:19:8
+  --> $DIR/manual_float_methods.rs:28:8
    |
 LL |     if x != f64::INFINITY && x != f64::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^