Refactor, remove Constant::to_bits
This commit is contained in:
parent
5949f762bf
commit
41438c2b90
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
|
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).
|
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.
|
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
A collection of lints to catch common mistakes and improve your
|
A collection of lints to catch common mistakes and improve your
|
||||||
[Rust](https://github.com/rust-lang/rust) code.
|
[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
|
Lints are divided into categories, each with a default [lint
|
||||||
level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
|
level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use clippy_utils::{
|
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_errors::Applicability;
|
||||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||||
@ -9,10 +12,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
|||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### 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?
|
/// ### Why is this bad?
|
||||||
/// This should use the dedicated method instead, `is_infinite`.
|
/// The method `is_infinite` is shorter and more readable.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -31,20 +35,23 @@ declare_clippy_lint! {
|
|||||||
}
|
}
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### 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?
|
/// ### Why is this bad?
|
||||||
/// This should use the dedicated method instead, `is_finite`.
|
/// The method `is_finite` is shorter and more readable.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # let x = 1.0f32;
|
/// # let x = 1.0f32;
|
||||||
/// if x != f32::INFINITY && x != f32::NEG_INFINITY {}
|
/// if x != f32::INFINITY && x != f32::NEG_INFINITY {}
|
||||||
|
/// if x.abs() < f32::INFINITY {}
|
||||||
/// ```
|
/// ```
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # let x = 1.0f32;
|
/// # let x = 1.0f32;
|
||||||
/// if x.is_finite() {}
|
/// if x.is_finite() {}
|
||||||
|
/// if x.is_finite() {}
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.72.0"]
|
#[clippy::version = "1.72.0"]
|
||||||
pub MANUAL_IS_FINITE,
|
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
|
&& 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
|
// 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`.
|
// 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()
|
.into_iter()
|
||||||
.partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
|
.partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
|
||||||
&& let [first, second] = &*operands
|
&& let [first, second] = &*operands
|
||||||
&& let Some([const_1, const_2]) = consts
|
&& let Some([const_1, const_2]) = constants
|
||||||
.into_iter()
|
.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<_>>>()
|
.collect::<Option<Vec<_>>>()
|
||||||
.as_deref()
|
.as_deref()
|
||||||
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
|
&& 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)
|
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
|
||||||
|| is_neg_infinity(*const_1) && is_infinity(*const_2))
|
// case somebody does that for some reason
|
||||||
&& let Some(local_snippet) = snippet_opt(cx, first.span)
|
&& (is_infinity(const_1) && is_neg_infinity(const_2)
|
||||||
|
|| is_neg_infinity(const_1) && is_infinity(const_2))
|
||||||
&& !is_from_proc_macro(cx, expr)
|
&& !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) {
|
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
|
||||||
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,
|
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,
|
||||||
@ -128,31 +137,39 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
|||||||
"use the dedicated method instead",
|
"use the dedicated method instead",
|
||||||
format!("{local_snippet}.is_finite()"),
|
format!("{local_snippet}.is_finite()"),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
)
|
||||||
diag.span_suggestion_verbose(
|
.span_suggestion_verbose(
|
||||||
expr.span,
|
expr.span,
|
||||||
"this will alter how it handles NaN; if that is a problem, use instead",
|
"this will alter how it handles NaN; if that is a problem, use instead",
|
||||||
format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"),
|
format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
)
|
||||||
diag.span_suggestion_verbose(
|
.span_suggestion_verbose(
|
||||||
expr.span,
|
expr.span,
|
||||||
"or, for conciseness",
|
"or, for conciseness",
|
||||||
format!("!{local_snippet}.is_infinite()"),
|
format!("!{local_snippet}.is_infinite()"),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_infinity(bits: u128) -> bool {
|
fn is_infinity(constant: &Constant<'_>) -> bool {
|
||||||
bits == 0x7f80_0000 || bits == 0x7ff0_0000_0000_0000
|
match constant {
|
||||||
|
Constant::F32(float) => *float == f32::INFINITY,
|
||||||
|
Constant::F64(float) => *float == f64::INFINITY,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_neg_infinity(bits: u128) -> bool {
|
fn is_neg_infinity(constant: &Constant<'_>) -> bool {
|
||||||
bits == 0xff80_0000 || bits == 0xfff0_0000_0000_0000
|
match constant {
|
||||||
|
Constant::F32(float) => *float == f32::NEG_INFINITY,
|
||||||
|
Constant::F64(float) => *float == f64::NEG_INFINITY,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
/// 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> {
|
pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
|
||||||
if let Constant::Int(const_int) = *self {
|
if let Constant::Int(const_int) = *self {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//@aux-build:proc_macros.rs:proc-macro
|
//@aux-build:proc_macros.rs:proc-macro
|
||||||
#![allow(clippy::needless_if, unused)]
|
#![allow(clippy::needless_if, unused)]
|
||||||
#![warn(clippy::manual_is_infinite, clippy::manual_is_finite)]
|
#![warn(clippy::manual_is_infinite, clippy::manual_is_finite)]
|
||||||
|
#![feature(inline_const)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate proc_macros;
|
extern crate proc_macros;
|
||||||
@ -8,6 +9,14 @@ extern crate proc_macros;
|
|||||||
const INFINITE: f32 = f32::INFINITY;
|
const INFINITE: f32 = f32::INFINITY;
|
||||||
const NEG_INFINITE: f32 = f32::NEG_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() {
|
fn main() {
|
||||||
let x = 1.0f32;
|
let x = 1.0f32;
|
||||||
if x == f32::INFINITY || x == f32::NEG_INFINITY {}
|
if x == f32::INFINITY || x == f32::NEG_INFINITY {}
|
||||||
@ -20,8 +29,18 @@ fn main() {
|
|||||||
// Don't lint
|
// Don't lint
|
||||||
if x.is_infinite() {}
|
if x.is_infinite() {}
|
||||||
if x.is_finite() {}
|
if x.is_finite() {}
|
||||||
// If they're doing it this way, they probably know what they're doing
|
|
||||||
if x.abs() < f64::INFINITY {}
|
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! {
|
external! {
|
||||||
let x = 1.0;
|
let x = 1.0;
|
||||||
if x == f32::INFINITY || x == f32::NEG_INFINITY {}
|
if x == f32::INFINITY || x == f32::NEG_INFINITY {}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: manually checking if a float is infinite
|
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 {}
|
LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
|
= note: `-D clippy::manual-is-infinite` implied by `-D warnings`
|
||||||
|
|
||||||
error: manually checking if a float is finite
|
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 {}
|
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
|
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 {}
|
LL | if x == INFINITE || x == NEG_INFINITE {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
|
||||||
|
|
||||||
error: manually checking if a float is finite
|
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 {}
|
LL | if x != INFINITE && x != NEG_INFINITE {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -52,13 +52,13 @@ LL | if !x.is_infinite() {}
|
|||||||
| ~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: manually checking if a float 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 {}
|
LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
|
||||||
|
|
||||||
error: manually checking if a float is finite
|
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 {}
|
LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Loading…
x
Reference in New Issue
Block a user