about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/loops/mod.rs36
-rw-r--r--clippy_lints/src/loops/while_float.rs20
-rw-r--r--tests/ui/while_float.rs14
-rw-r--r--tests/ui/while_float.stderr20
6 files changed, 92 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e17d6b3cf27..d5115f70f66 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5911,6 +5911,7 @@ Released 2018-09-13
 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 [`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake
+[`while_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_float
 [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
 [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
 [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 6850ec821e8..df2ef465700 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -293,6 +293,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::loops::SAME_ITEM_PUSH_INFO,
     crate::loops::SINGLE_ELEMENT_LOOP_INFO,
     crate::loops::UNUSED_ENUMERATE_INDEX_INFO,
+    crate::loops::WHILE_FLOAT_INFO,
     crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
     crate::loops::WHILE_LET_LOOP_INFO,
     crate::loops::WHILE_LET_ON_ITERATOR_INFO,
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index b5e39b33c6a..3dcb050d77e 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -17,6 +17,7 @@ mod same_item_push;
 mod single_element_loop;
 mod unused_enumerate_index;
 mod utils;
+mod while_float;
 mod while_immutable_condition;
 mod while_let_loop;
 mod while_let_on_iterator;
@@ -418,6 +419,39 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for while loops comparing floating point values.
+    ///
+    /// ### Why is this bad?
+    /// If you increment floating point values, errors can compound,
+    /// so, use integers instead if possible.
+    ///
+    /// ### Known problems
+    /// The lint will catch all while loops comparing floating point
+    /// values without regarding the increment.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let mut x = 0.0;
+    /// while x < 42.0 {
+    ///     x += 1.0;
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// let mut x = 0;
+    /// while x < 42 {
+    ///     x += 1;
+    /// }
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub WHILE_FLOAT,
+    nursery,
+    "while loops comaparing floating point values"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks whether a for loop is being used to push a constant
     /// value into a Vec.
     ///
@@ -706,6 +740,7 @@ impl_lint_pass!(Loops => [
     NEVER_LOOP,
     MUT_RANGE_BOUND,
     WHILE_IMMUTABLE_CONDITION,
+    WHILE_FLOAT,
     SAME_ITEM_PUSH,
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
@@ -762,6 +797,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 
         if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
             while_immutable_condition::check(cx, condition, body);
+            while_float::check(cx, condition);
             missing_spin_loop::check(cx, condition, body);
             manual_while_let_some::check(cx, condition, body, span);
         }
diff --git a/clippy_lints/src/loops/while_float.rs b/clippy_lints/src/loops/while_float.rs
new file mode 100644
index 00000000000..cf62ce29f0c
--- /dev/null
+++ b/clippy_lints/src/loops/while_float.rs
@@ -0,0 +1,20 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_hir::ExprKind;
+
+pub(super) fn check(cx: &rustc_lint::LateContext<'_>, condition: &rustc_hir::Expr<'_>) {
+    if let ExprKind::Binary(_op, left, right) = condition.kind
+        && is_float_type(cx, left)
+        && is_float_type(cx, right)
+    {
+        span_lint(
+            cx,
+            super::WHILE_FLOAT,
+            condition.span,
+            "while condition comparing floats",
+        );
+    }
+}
+
+fn is_float_type(cx: &rustc_lint::LateContext<'_>, expr: &rustc_hir::Expr<'_>) -> bool {
+    cx.typeck_results().expr_ty(expr).is_floating_point()
+}
diff --git a/tests/ui/while_float.rs b/tests/ui/while_float.rs
new file mode 100644
index 00000000000..a3b0618948e
--- /dev/null
+++ b/tests/ui/while_float.rs
@@ -0,0 +1,14 @@
+#[deny(clippy::while_float)]
+fn main() {
+    let mut x = 0.0_f32;
+    while x < 42.0_f32 {
+        x += 0.5;
+    }
+    while x < 42.0 {
+        x += 1.0;
+    }
+    let mut x = 0;
+    while x < 42 {
+        x += 1;
+    }
+}
diff --git a/tests/ui/while_float.stderr b/tests/ui/while_float.stderr
new file mode 100644
index 00000000000..b8e934b97c6
--- /dev/null
+++ b/tests/ui/while_float.stderr
@@ -0,0 +1,20 @@
+error: while condition comparing floats
+  --> tests/ui/while_float.rs:4:11
+   |
+LL |     while x < 42.0_f32 {
+   |           ^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> tests/ui/while_float.rs:1:8
+   |
+LL | #[deny(clippy::while_float)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
+error: while condition comparing floats
+  --> tests/ui/while_float.rs:7:11
+   |
+LL |     while x < 42.0 {
+   |           ^^^^^^^^
+
+error: aborting due to 2 previous errors
+