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