From d8a281ef735be327dceace003b36e14616023126 Mon Sep 17 00:00:00 2001 From: Micha White Date: Sat, 21 May 2022 17:02:00 -0400 Subject: [PATCH 1/3] Added an unused_rounding lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/unused_rounding.rs | 69 ++++++++++++++++++++++++ tests/ui/unused_rounding.fixed | 8 +++ tests/ui/unused_rounding.rs | 8 +++ tests/ui/unused_rounding.stderr | 22 ++++++++ 8 files changed, 112 insertions(+) create mode 100644 clippy_lints/src/unused_rounding.rs create mode 100644 tests/ui/unused_rounding.fixed create mode 100644 tests/ui/unused_rounding.rs create mode 100644 tests/ui/unused_rounding.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f6295a45f3..137fd793e75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3821,6 +3821,7 @@ Released 2018-09-13 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label +[`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 570d736518b..02171a0909e 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -546,6 +546,7 @@ store.register_lints(&[ unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unused_async::UNUSED_ASYNC, unused_io_amount::UNUSED_IO_AMOUNT, + unused_rounding::UNUSED_ROUNDING, unused_self::UNUSED_SELF, unused_unit::UNUSED_UNIT, unwrap::PANICKING_UNWRAP, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index ec187563b3f..10808af363d 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -32,5 +32,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS), LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::USELESS_TRANSMUTE), + LintId::of(unused_rounding::UNUSED_ROUNDING), LintId::of(use_self::USE_SELF), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5f636e5114b..09435b06d0a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -402,6 +402,7 @@ mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_async; mod unused_io_amount; +mod unused_rounding; mod unused_self; mod unused_unit; mod unwrap; @@ -906,6 +907,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); store.register_late_pass(|| Box::new(get_first::GetFirst)); + store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs new file mode 100644 index 00000000000..7706a338eb2 --- /dev/null +++ b/clippy_lints/src/unused_rounding.rs @@ -0,0 +1,69 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::{Expr, ExprKind, LitFloatType, LitKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// + /// Detects cases where a whole-number literal float is being rounded, using + /// the `floor`, `ceil`, or `round` methods. + /// + /// ### Why is this bad? + /// + /// This is unnecessary and confusing to the reader. Doing this is probably a mistake. + /// + /// ### Example + /// ```rust + /// let x = 1f32.ceil(); + /// ``` + /// Use instead: + /// ```rust + /// let x = 1f32; + /// ``` + #[clippy::version = "1.62.0"] + pub UNUSED_ROUNDING, + nursery, + "Rounding a whole number literal, which is useless" +} +declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); + +fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> { + if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind + && let method_name = name_ident.ident.name.as_str() + && (method_name == "ceil" || method_name == "round" || method_name == "floor") + && !args.is_empty() + && let ExprKind::Lit(spanned) = &args[0].kind + && let LitKind::Float(symbol, ty) = spanned.kind { + let f = symbol.as_str().parse::().unwrap(); + let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty { + ty.name_str() + } else { + "" + }; + if f.fract() < f64::EPSILON { + Some((method_name, f_str)) + } else { + None + } + } else { + None + } +} + +impl EarlyLintPass for UnusedRounding { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let Some((method_name, float)) = is_useless_rounding(expr) { + span_lint_and_sugg( + cx, + UNUSED_ROUNDING, + expr.span, + &format!("used the `{}` method with a whole number float", method_name), + &format!("remove the `{}` method call", method_name), + float, + Applicability::MachineApplicable, + ); + } + } +} diff --git a/tests/ui/unused_rounding.fixed b/tests/ui/unused_rounding.fixed new file mode 100644 index 00000000000..a1cb80413d2 --- /dev/null +++ b/tests/ui/unused_rounding.fixed @@ -0,0 +1,8 @@ +// run-rustfix +#![warn(clippy::unused_rounding)] + +fn main() { + let _ = 1f32; + let _ = 1.0f64; + let _ = 1.00f32; +} diff --git a/tests/ui/unused_rounding.rs b/tests/ui/unused_rounding.rs new file mode 100644 index 00000000000..90af8f19dd9 --- /dev/null +++ b/tests/ui/unused_rounding.rs @@ -0,0 +1,8 @@ +// run-rustfix +#![warn(clippy::unused_rounding)] + +fn main() { + let _ = 1f32.ceil(); + let _ = 1.0f64.floor(); + let _ = 1.00f32.round(); +} diff --git a/tests/ui/unused_rounding.stderr b/tests/ui/unused_rounding.stderr new file mode 100644 index 00000000000..6cfb02e0402 --- /dev/null +++ b/tests/ui/unused_rounding.stderr @@ -0,0 +1,22 @@ +error: used the `ceil` method with a whole number float + --> $DIR/unused_rounding.rs:5:13 + | +LL | let _ = 1f32.ceil(); + | ^^^^^^^^^^^ help: remove the `ceil` method call: `1f32` + | + = note: `-D clippy::unused-rounding` implied by `-D warnings` + +error: used the `floor` method with a whole number float + --> $DIR/unused_rounding.rs:6:13 + | +LL | let _ = 1.0f64.floor(); + | ^^^^^^^^^^^^^^ help: remove the `floor` method call: `1.0f64` + +error: used the `round` method with a whole number float + --> $DIR/unused_rounding.rs:7:13 + | +LL | let _ = 1.00f32.round(); + | ^^^^^^^^^^^^^^^ help: remove the `round` method call: `1.00f32` + +error: aborting due to 3 previous errors + From 4de301e394d99b391de6e449e4dbf44d771d0486 Mon Sep 17 00:00:00 2001 From: Micha White Date: Sun, 22 May 2022 17:21:04 -0400 Subject: [PATCH 2/3] Fixed the test to not use an epsilon --- clippy_lints/src/unused_rounding.rs | 2 +- tests/ui/unused_rounding.fixed | 1 + tests/ui/unused_rounding.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 7706a338eb2..3ee5d7a32a3 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -42,7 +42,7 @@ fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> { } else { "" }; - if f.fract() < f64::EPSILON { + if f.fract() == 0.0 { Some((method_name, f_str)) } else { None diff --git a/tests/ui/unused_rounding.fixed b/tests/ui/unused_rounding.fixed index a1cb80413d2..54f85806ac3 100644 --- a/tests/ui/unused_rounding.fixed +++ b/tests/ui/unused_rounding.fixed @@ -5,4 +5,5 @@ fn main() { let _ = 1f32; let _ = 1.0f64; let _ = 1.00f32; + let _ = 2e-54f64.floor(); } diff --git a/tests/ui/unused_rounding.rs b/tests/ui/unused_rounding.rs index 90af8f19dd9..8d007bc4a1d 100644 --- a/tests/ui/unused_rounding.rs +++ b/tests/ui/unused_rounding.rs @@ -5,4 +5,5 @@ fn main() { let _ = 1f32.ceil(); let _ = 1.0f64.floor(); let _ = 1.00f32.round(); + let _ = 2e-54f64.floor(); } From f489954e3e6c7b15fd243d33bdd9eabdf90161b6 Mon Sep 17 00:00:00 2001 From: Micha White Date: Sun, 22 May 2022 17:22:10 -0400 Subject: [PATCH 3/3] Changed the lint description --- clippy_lints/src/unused_rounding.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 3ee5d7a32a3..306afe44148 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { #[clippy::version = "1.62.0"] pub UNUSED_ROUNDING, nursery, - "Rounding a whole number literal, which is useless" + "Uselessly rounding a whole number floating-point literal" } declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);