Auto merge of #12765 - yusufraji:while-float, r=llogiq

Add new lint `while_float`

This PR adds a nursery lint that checks for while loops comparing floating point values.

changelog:
```
changelog: [`while_float`]: Checks for while loops comparing floating point values.
```

Fixes #758
This commit is contained in:
bors 2024-05-21 11:36:31 +00:00
commit 2efebd2f0c
6 changed files with 92 additions and 0 deletions

View File

@ -5911,6 +5911,7 @@ Released 2018-09-13
[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads [`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 [`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 [`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_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_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 [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator

View File

@ -293,6 +293,7 @@
crate::loops::SAME_ITEM_PUSH_INFO, crate::loops::SAME_ITEM_PUSH_INFO,
crate::loops::SINGLE_ELEMENT_LOOP_INFO, crate::loops::SINGLE_ELEMENT_LOOP_INFO,
crate::loops::UNUSED_ENUMERATE_INDEX_INFO, crate::loops::UNUSED_ENUMERATE_INDEX_INFO,
crate::loops::WHILE_FLOAT_INFO,
crate::loops::WHILE_IMMUTABLE_CONDITION_INFO, crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
crate::loops::WHILE_LET_LOOP_INFO, crate::loops::WHILE_LET_LOOP_INFO,
crate::loops::WHILE_LET_ON_ITERATOR_INFO, crate::loops::WHILE_LET_ON_ITERATOR_INFO,

View File

@ -17,6 +17,7 @@
mod single_element_loop; mod single_element_loop;
mod unused_enumerate_index; mod unused_enumerate_index;
mod utils; mod utils;
mod while_float;
mod while_immutable_condition; mod while_immutable_condition;
mod while_let_loop; mod while_let_loop;
mod while_let_on_iterator; mod while_let_on_iterator;
@ -416,6 +417,39 @@
"variables used within while expression are not mutated in the body" "variables used within while expression are not mutated in the body"
} }
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! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Checks whether a for loop is being used to push a constant /// Checks whether a for loop is being used to push a constant
@ -706,6 +740,7 @@ pub fn new(msrv: Msrv, enforce_iter_loop_reborrow: bool) -> Self {
NEVER_LOOP, NEVER_LOOP,
MUT_RANGE_BOUND, MUT_RANGE_BOUND,
WHILE_IMMUTABLE_CONDITION, WHILE_IMMUTABLE_CONDITION,
WHILE_FLOAT,
SAME_ITEM_PUSH, SAME_ITEM_PUSH,
SINGLE_ELEMENT_LOOP, SINGLE_ELEMENT_LOOP,
MISSING_SPIN_LOOP, MISSING_SPIN_LOOP,
@ -762,6 +797,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) { if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
while_immutable_condition::check(cx, condition, body); while_immutable_condition::check(cx, condition, body);
while_float::check(cx, condition);
missing_spin_loop::check(cx, condition, body); missing_spin_loop::check(cx, condition, body);
manual_while_let_some::check(cx, condition, body, span); manual_while_let_some::check(cx, condition, body, span);
} }

View File

@ -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()
}

14
tests/ui/while_float.rs Normal file
View File

@ -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;
}
}

View File

@ -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