]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/unused_rounding.rs
Rollup merge of #105123 - BlackHoleFox:fixing-the-macos-deployment, r=oli-obk
[rust.git] / src / tools / clippy / clippy_lints / src / unused_rounding.rs
1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::snippet;
3 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
4 use rustc_errors::Applicability;
5 use rustc_lint::{EarlyContext, EarlyLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
7
8 declare_clippy_lint! {
9     /// ### What it does
10     ///
11     /// Detects cases where a whole-number literal float is being rounded, using
12     /// the `floor`, `ceil`, or `round` methods.
13     ///
14     /// ### Why is this bad?
15     ///
16     /// This is unnecessary and confusing to the reader. Doing this is probably a mistake.
17     ///
18     /// ### Example
19     /// ```rust
20     /// let x = 1f32.ceil();
21     /// ```
22     /// Use instead:
23     /// ```rust
24     /// let x = 1f32;
25     /// ```
26     #[clippy::version = "1.63.0"]
27     pub UNUSED_ROUNDING,
28     nursery,
29     "Uselessly rounding a whole number floating-point literal"
30 }
31 declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
32
33 fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> {
34     if let ExprKind::MethodCall(box MethodCall { seg:name_ident, receiver, .. }) = &expr.kind
35         && let method_name = name_ident.ident.name.as_str()
36         && (method_name == "ceil" || method_name == "round" || method_name == "floor")
37         && let ExprKind::Lit(token_lit) = &receiver.kind
38         && token_lit.is_semantic_float()
39         && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() {
40             (f.fract() == 0.0).then(||
41                 (method_name, snippet(cx, receiver.span, "..").to_string())
42             )
43         } else {
44             None
45         }
46 }
47
48 impl EarlyLintPass for UnusedRounding {
49     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
50         if let Some((method_name, float)) = is_useless_rounding(cx, expr) {
51             span_lint_and_sugg(
52                 cx,
53                 UNUSED_ROUNDING,
54                 expr.span,
55                 &format!("used the `{method_name}` method with a whole number float"),
56                 &format!("remove the `{method_name}` method call"),
57                 float,
58                 Applicability::MachineApplicable,
59             );
60         }
61     }
62 }