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};
11 /// Detects cases where a whole-number literal float is being rounded, using
12 /// the `floor`, `ceil`, or `round` methods.
14 /// ### Why is this bad?
16 /// This is unnecessary and confusing to the reader. Doing this is probably a mistake.
20 /// let x = 1f32.ceil();
26 #[clippy::version = "1.63.0"]
29 "Uselessly rounding a whole number floating-point literal"
31 declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
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())
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) {
55 &format!("used the `{method_name}` method with a whole number float"),
56 &format!("remove the `{method_name}` method call"),
58 Applicability::MachineApplicable,