summaryrefslogtreecommitdiff
path: root/compiler/rustc_lint/src/noop_method_call.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint/src/noop_method_call.rs')
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs81
1 files changed, 63 insertions, 18 deletions
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index d67a00619dd..d054966459d 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -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 => "borrow",
+ sym::noop_method_clone => "clone",
+ sym::noop_method_deref => "deref",
+ _ => 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 },
+ )
+ }
}
}