use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty}; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds /// from other `Duration` methods. /// /// **Why is this bad?** It's more concise to call `Duration::subsec_micros()` or /// `Duration::subsec_millis()` than to calculate them. /// /// **Known problems:** None. /// /// **Example:** /// ```rust /// # use std::time::Duration; /// let dur = Duration::new(5, 0); /// /// // Bad /// let _micros = dur.subsec_nanos() / 1_000; /// let _millis = dur.subsec_nanos() / 1_000_000; /// /// // Good /// let _micros = dur.subsec_micros(); /// let _millis = dur.subsec_millis(); /// ``` pub DURATION_SUBSEC, complexity, "checks for calculation of subsecond microseconds or milliseconds" } declare_lint_pass!(DurationSubsec => [DURATION_SUBSEC]); impl<'tcx> LateLintPass<'tcx> for DurationSubsec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind; if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind; if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::DURATION); if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right); then { let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) { ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", ("subsec_nanos", 1_000) => "subsec_micros", _ => return, }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, DURATION_SUBSEC, expr.span, &format!("calling `{}()` is more concise than this calculation", suggested_fn), "try", format!( "{}.{}()", snippet_with_applicability(cx, args[0].span, "_", &mut applicability), suggested_fn ), applicability, ); } } } }