Skip to content

Commit

Permalink
Refactor, remove Constant::to_bits
Browse files Browse the repository at this point in the history
  • Loading branch information
Centri3 committed Jul 6, 2023
1 parent d2302eb commit fa31c15
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion book/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 33 additions & 16 deletions clippy_lints/src/manual_float_methods.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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`.
/// This should use the aforementioned dedicated method instead, `is_infinite`.
///
/// ### Example
/// ```rust
Expand All @@ -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`.
/// This should use the aforementioned dedicated method instead, `is_finite`.
///
/// ### 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,
Expand Down Expand Up @@ -84,18 +91,20 @@ 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))
// 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))
&& let Some(local_snippet) = snippet_opt(cx, first.span)
&& !is_from_proc_macro(cx, expr)
{
Expand Down Expand Up @@ -141,18 +150,26 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
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,
}
}
11 changes: 0 additions & 11 deletions clippy_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 8 additions & 1 deletion tests/ui/manual_float_methods.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -20,8 +21,14 @@ 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) {}
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 {}
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/manual_float_methods.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: manually checking if a float is infinite
--> $DIR/manual_float_methods.rs:13:8
--> $DIR/manual_float_methods.rs:14:8
|
LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
|
= 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:15:8
|
LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -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:16: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:17:8
|
LL | if x != INFINITE && x != NEG_INFINITE {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -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:19: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:20:8
|
LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down

0 comments on commit fa31c15

Please sign in to comment.