uplift clippy::clone_double_ref
as suspicious_double_ref_op
This commit is contained in:
parent
1a6ae3d692
commit
5c99175a9e
19 changed files with 230 additions and 199 deletions
|
@ -1,10 +1,11 @@
|
|||
use crate::context::LintContext;
|
||||
use crate::lints::NoopMethodCallDiag;
|
||||
use crate::lints::{NoopMethodCallDiag, SuspiciousDoubleRefDiag};
|
||||
use crate::LateContext;
|
||||
use crate::LateLintPass;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_lint! {
|
||||
|
@ -35,14 +36,44 @@ declare_lint! {
|
|||
"detects the use of well-known noop methods"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
|
||||
declare_lint! {
|
||||
/// The `suspicious_double_ref_op` lint checks for usage of `.clone()`/`.borrow()`/`.deref()`
|
||||
/// on an `&&T` when `T: !Deref/Borrow/Clone`, which means the call will return the inner `&T`,
|
||||
/// instead of performing the operation on the underlying `T` and can be confusing.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(unused)]
|
||||
/// struct Foo;
|
||||
/// let foo = &&Foo;
|
||||
/// let clone: &Foo = foo.clone();
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Since `Foo` doesn't implement `Clone`, running `.clone()` only dereferences the double
|
||||
/// reference, instead of cloning the inner type which should be what was intended.
|
||||
pub SUSPICIOUS_DOUBLE_REF_OP,
|
||||
Warn,
|
||||
"suspicious call of trait method on `&&T`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL, SUSPICIOUS_DOUBLE_REF_OP]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// We only care about method calls.
|
||||
let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
|
||||
return
|
||||
let ExprKind::MethodCall(call, receiver, _, call_span) = &expr.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
if call_span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
|
||||
// traits and ignore any other method call.
|
||||
let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
|
||||
|
@ -70,25 +101,39 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
|||
};
|
||||
// (Re)check that it implements the noop diagnostic.
|
||||
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
|
||||
if !matches!(
|
||||
name,
|
||||
sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let op = match name {
|
||||
sym::noop_method_borrow => "borrowing",
|
||||
sym::noop_method_clone => "cloning",
|
||||
sym::noop_method_deref => "dereferencing",
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
|
||||
if receiver_ty != expr_ty {
|
||||
// This lint will only trigger if the receiver type and resulting expression \
|
||||
// type are the same, implying that the method call is unnecessary.
|
||||
let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
|
||||
|
||||
// If there is any user defined auto-deref step, then we don't want to warn.
|
||||
// https://github.com/rust-lang/rust-clippy/issues/9272
|
||||
if arg_adjustments.iter().any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
let expr_span = expr.span;
|
||||
let span = expr_span.with_lo(receiver.span.hi());
|
||||
cx.emit_spanned_lint(
|
||||
NOOP_METHOD_CALL,
|
||||
span,
|
||||
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
|
||||
);
|
||||
|
||||
if receiver_ty == expr_ty {
|
||||
cx.emit_spanned_lint(
|
||||
NOOP_METHOD_CALL,
|
||||
span,
|
||||
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
|
||||
);
|
||||
} else {
|
||||
cx.emit_spanned_lint(
|
||||
SUSPICIOUS_DOUBLE_REF_OP,
|
||||
span,
|
||||
SuspiciousDoubleRefDiag { call: call.ident.name, ty: expr_ty, op },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue