Move DurationSubsec into Operators lint pass

This commit is contained in:
Jason Newcomb 2022-05-31 22:48:17 -04:00
parent 4ac3626f2e
commit 732d7162ab
7 changed files with 80 additions and 80 deletions

View File

@ -1,75 +0,0 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
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 rustc_span::sym;
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.
///
/// ### Example
/// ```rust
/// # use std::time::Duration;
/// # let duration = Duration::new(5, 0);
/// let micros = duration.subsec_nanos() / 1_000;
/// let millis = duration.subsec_nanos() / 1_000_000;
/// ```
///
/// Use instead:
/// ```rust
/// # use std::time::Duration;
/// # let duration = Duration::new(5, 0);
/// let micros = duration.subsec_micros();
/// let millis = duration.subsec_millis();
/// ```
#[clippy::version = "pre 1.29.0"]
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, .. }, left, right) = expr.kind;
if let ExprKind::MethodCall(method_path, args, _) = left.kind;
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::Duration);
if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right);
then {
let suggested_fn = match (method_path.ident.as_str(), 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,
);
}
}
}
}

View File

@ -57,7 +57,6 @@
LintId::of(drop_forget_ref::FORGET_REF),
LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
LintId::of(duplicate_mod::DUPLICATE_MOD),
LintId::of(duration_subsec::DURATION_SUBSEC),
LintId::of(entry::MAP_ENTRY),
LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
@ -258,6 +257,7 @@
LintId::of(operators::ASSIGN_OP_PATTERN),
LintId::of(operators::BAD_BIT_MASK),
LintId::of(operators::DOUBLE_COMPARISONS),
LintId::of(operators::DURATION_SUBSEC),
LintId::of(operators::INEFFECTIVE_BIT_MASK),
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),

View File

@ -11,7 +11,6 @@
LintId::of(casts::UNNECESSARY_CAST),
LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(double_parens::DOUBLE_PARENS),
LintId::of(duration_subsec::DURATION_SUBSEC),
LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(format::USELESS_FORMAT),
LintId::of(functions::TOO_MANY_ARGUMENTS),
@ -71,6 +70,7 @@
LintId::of(no_effect::NO_EFFECT),
LintId::of(no_effect::UNNECESSARY_OPERATION),
LintId::of(operators::DOUBLE_COMPARISONS),
LintId::of(operators::DURATION_SUBSEC),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(precedence::PRECEDENCE),

View File

@ -131,7 +131,6 @@
drop_forget_ref::FORGET_REF,
drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
duplicate_mod::DUPLICATE_MOD,
duration_subsec::DURATION_SUBSEC,
else_if_without_else::ELSE_IF_WITHOUT_ELSE,
empty_drop::EMPTY_DROP,
empty_enum::EMPTY_ENUM,
@ -432,6 +431,7 @@
operators::ASSIGN_OP_PATTERN,
operators::BAD_BIT_MASK,
operators::DOUBLE_COMPARISONS,
operators::DURATION_SUBSEC,
operators::FLOAT_ARITHMETIC,
operators::INEFFECTIVE_BIT_MASK,
operators::INTEGER_ARITHMETIC,

View File

@ -212,7 +212,6 @@ macro_rules! declare_clippy_lint {
mod double_parens;
mod drop_forget_ref;
mod duplicate_mod;
mod duration_subsec;
mod else_if_without_else;
mod empty_drop;
mod empty_enum;
@ -732,7 +731,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl));
store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
store.register_late_pass(|| Box::new(unwrap::Unwrap));
store.register_late_pass(|| Box::new(duration_subsec::DurationSubsec));
store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing));
store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst));
store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));

View File

@ -0,0 +1,44 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::sym;
use super::DURATION_SUBSEC;
pub(crate) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
op: BinOpKind,
left: &'tcx Expr<'_>,
right: &'tcx Expr<'_>,
) {
if op == BinOpKind::Div
&& let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
&& let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right)
{
let suggested_fn = match (method_path.ident.as_str(), 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, self_arg.span, "_", &mut applicability),
suggested_fn
),
applicability,
);
}
}

View File

@ -6,6 +6,7 @@
mod assign_op_pattern;
mod bit_mask;
mod double_comparison;
mod duration_subsec;
mod misrefactored_assign_op;
mod numeric_arithmetic;
mod verbose_bit_mask;
@ -271,6 +272,36 @@
"unnecessary double comparisons that can be simplified"
}
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.
///
/// ### Example
/// ```rust
/// # use std::time::Duration;
/// # let duration = Duration::new(5, 0);
/// let micros = duration.subsec_nanos() / 1_000;
/// let millis = duration.subsec_nanos() / 1_000_000;
/// ```
///
/// Use instead:
/// ```rust
/// # use std::time::Duration;
/// # let duration = Duration::new(5, 0);
/// let micros = duration.subsec_micros();
/// let millis = duration.subsec_millis();
/// ```
#[clippy::version = "pre 1.29.0"]
pub DURATION_SUBSEC,
complexity,
"checks for calculation of subsecond microseconds or milliseconds"
}
pub struct Operators {
arithmetic_context: numeric_arithmetic::Context,
verbose_bit_mask_threshold: u64,
@ -285,6 +316,7 @@ pub struct Operators {
INEFFECTIVE_BIT_MASK,
VERBOSE_BIT_MASK,
DOUBLE_COMPARISONS,
DURATION_SUBSEC,
]);
impl Operators {
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
@ -305,6 +337,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
bit_mask::check(cx, e, op.node, lhs, rhs);
verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
double_comparison::check(cx, op.node, lhs, rhs, e.span);
duration_subsec::check(cx, e, op.node, lhs, rhs);
},
ExprKind::AssignOp(op, lhs, rhs) => {
self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);