Skip to content

Commit 40c4ed4

Browse files
authored
Rollup merge of #110955 - fee1-dead-contrib:sus-operation, r=compiler-errors
uplift `clippy::clone_double_ref` as `suspicious_double_ref_op` Split from #109842. r? ``@compiler-errors``
2 parents f47a63c + 475378f commit 40c4ed4

21 files changed

+237
-200
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ use regex::Regex;
4040
use tempfile::Builder as TempFileBuilder;
4141

4242
use itertools::Itertools;
43-
use std::borrow::Borrow;
4443
use std::cell::OnceCell;
4544
use std::collections::BTreeSet;
4645
use std::ffi::OsString;
@@ -576,17 +575,17 @@ fn link_dwarf_object<'a>(
576575

577576
impl<Relocations> ThorinSession<Relocations> {
578577
fn alloc_mmap(&self, data: Mmap) -> &Mmap {
579-
(*self.arena_mmap.alloc(data)).borrow()
578+
&*self.arena_mmap.alloc(data)
580579
}
581580
}
582581

583582
impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
584583
fn alloc_data(&self, data: Vec<u8>) -> &[u8] {
585-
(*self.arena_data.alloc(data)).borrow()
584+
&*self.arena_data.alloc(data)
586585
}
587586

588587
fn alloc_relocation(&self, data: Relocations) -> &Relocations {
589-
(*self.arena_relocations.alloc(data)).borrow()
588+
&*self.arena_relocations.alloc(data)
590589
}
591590

592591
fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {

compiler/rustc_lint/messages.ftl

+8
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ lint_deprecated_lint_name =
5050
lint_renamed_or_removed_lint = {$msg}
5151
.suggestion = use the new name
5252
53+
lint_suspicious_double_ref_op =
54+
using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op ->
55+
*[should_not_happen] [{$op}]
56+
[deref] dereferencing
57+
[borrow] borrowing
58+
[clone] cloning
59+
} the inner type
60+
5361
lint_unknown_lint =
5462
unknown lint: `{$name}`
5563
.suggestion = did you mean

compiler/rustc_lint/src/lints.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,14 @@ pub struct NoopMethodCallDiag<'a> {
11501150
pub label: Span,
11511151
}
11521152

1153+
#[derive(LintDiagnostic)]
1154+
#[diag(lint_suspicious_double_ref_op)]
1155+
pub struct SuspiciousDoubleRefDiag<'a> {
1156+
pub call: Symbol,
1157+
pub ty: Ty<'a>,
1158+
pub op: &'static str,
1159+
}
1160+
11531161
// pass_by_value.rs
11541162
#[derive(LintDiagnostic)]
11551163
#[diag(lint_pass_by_value)]

compiler/rustc_lint/src/noop_method_call.rs

+63-18
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use crate::context::LintContext;
2-
use crate::lints::NoopMethodCallDiag;
2+
use crate::lints::{NoopMethodCallDiag, SuspiciousDoubleRefDiag};
33
use crate::LateContext;
44
use crate::LateLintPass;
55
use rustc_hir::def::DefKind;
66
use rustc_hir::{Expr, ExprKind};
77
use rustc_middle::ty;
8+
use rustc_middle::ty::adjustment::Adjust;
89
use rustc_span::symbol::sym;
910

1011
declare_lint! {
@@ -35,14 +36,44 @@ declare_lint! {
3536
"detects the use of well-known noop methods"
3637
}
3738

38-
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
39+
declare_lint! {
40+
/// The `suspicious_double_ref_op` lint checks for usage of `.clone()`/`.borrow()`/`.deref()`
41+
/// on an `&&T` when `T: !Deref/Borrow/Clone`, which means the call will return the inner `&T`,
42+
/// instead of performing the operation on the underlying `T` and can be confusing.
43+
///
44+
/// ### Example
45+
///
46+
/// ```rust
47+
/// # #![allow(unused)]
48+
/// struct Foo;
49+
/// let foo = &&Foo;
50+
/// let clone: &Foo = foo.clone();
51+
/// ```
52+
///
53+
/// {{produces}}
54+
///
55+
/// ### Explanation
56+
///
57+
/// Since `Foo` doesn't implement `Clone`, running `.clone()` only dereferences the double
58+
/// reference, instead of cloning the inner type which should be what was intended.
59+
pub SUSPICIOUS_DOUBLE_REF_OP,
60+
Warn,
61+
"suspicious call of trait method on `&&T`"
62+
}
63+
64+
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL, SUSPICIOUS_DOUBLE_REF_OP]);
3965

4066
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
4167
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
4268
// We only care about method calls.
43-
let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
44-
return
69+
let ExprKind::MethodCall(call, receiver, _, call_span) = &expr.kind else {
70+
return;
4571
};
72+
73+
if call_span.from_expansion() {
74+
return;
75+
}
76+
4677
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
4778
// traits and ignore any other method call.
4879
let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
@@ -70,25 +101,39 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
70101
};
71102
// (Re)check that it implements the noop diagnostic.
72103
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
73-
if !matches!(
74-
name,
75-
sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
76-
) {
77-
return;
78-
}
104+
105+
let op = match name {
106+
sym::noop_method_borrow => "borrow",
107+
sym::noop_method_clone => "clone",
108+
sym::noop_method_deref => "deref",
109+
_ => return,
110+
};
111+
79112
let receiver_ty = cx.typeck_results().expr_ty(receiver);
80113
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
81-
if receiver_ty != expr_ty {
82-
// This lint will only trigger if the receiver type and resulting expression \
83-
// type are the same, implying that the method call is unnecessary.
114+
let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
115+
116+
// If there is any user defined auto-deref step, then we don't want to warn.
117+
// https://github.com/rust-lang/rust-clippy/issues/9272
118+
if arg_adjustments.iter().any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) {
84119
return;
85120
}
121+
86122
let expr_span = expr.span;
87123
let span = expr_span.with_lo(receiver.span.hi());
88-
cx.emit_spanned_lint(
89-
NOOP_METHOD_CALL,
90-
span,
91-
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
92-
);
124+
125+
if receiver_ty == expr_ty {
126+
cx.emit_spanned_lint(
127+
NOOP_METHOD_CALL,
128+
span,
129+
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
130+
);
131+
} else {
132+
cx.emit_spanned_lint(
133+
SUSPICIOUS_DOUBLE_REF_OP,
134+
span,
135+
SuspiciousDoubleRefDiag { call: call.ident.name, ty: expr_ty, op },
136+
)
137+
}
93138
}
94139
}

library/core/tests/clone.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#[test]
2+
#[cfg_attr(not(bootstrap), allow(suspicious_double_ref_op))]
23
fn test_borrowed_clone() {
34
let x = 5;
45
let y: &i32 = &x;

src/librustdoc/html/format.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
167167
display_fn(move |f| {
168168
let mut bounds_dup = FxHashSet::default();
169169

170-
for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.clone())).enumerate() {
170+
for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(*b)).enumerate() {
171171
if i > 0 {
172172
f.write_str(" + ")?;
173173
}

src/tools/clippy/clippy_lints/src/declared_lints.rs

-1
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
313313
crate::methods::CHARS_NEXT_CMP_INFO,
314314
crate::methods::CLEAR_WITH_DRAIN_INFO,
315315
crate::methods::CLONED_INSTEAD_OF_COPIED_INFO,
316-
crate::methods::CLONE_DOUBLE_REF_INFO,
317316
crate::methods::CLONE_ON_COPY_INFO,
318317
crate::methods::CLONE_ON_REF_PTR_INFO,
319318
crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,

src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs

+2-38
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::get_parent_node;
33
use clippy_utils::source::snippet_with_context;
4-
use clippy_utils::sugg;
54
use clippy_utils::ty::is_copy;
65
use rustc_errors::Applicability;
76
use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
87
use rustc_lint::LateContext;
98
use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths};
109
use rustc_span::symbol::{sym, Symbol};
1110

12-
use super::CLONE_DOUBLE_REF;
1311
use super::CLONE_ON_COPY;
1412

1513
/// Checks for the `CLONE_ON_COPY` lint.
@@ -42,41 +40,7 @@ pub(super) fn check(
4240

4341
let ty = cx.typeck_results().expr_ty(expr);
4442
if let ty::Ref(_, inner, _) = arg_ty.kind() {
45-
if let ty::Ref(_, innermost, _) = inner.kind() {
46-
span_lint_and_then(
47-
cx,
48-
CLONE_DOUBLE_REF,
49-
expr.span,
50-
&with_forced_trimmed_paths!(format!(
51-
"using `clone` on a double-reference; \
52-
this will copy the reference of type `{ty}` instead of cloning the inner type"
53-
)),
54-
|diag| {
55-
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
56-
let mut ty = innermost;
57-
let mut n = 0;
58-
while let ty::Ref(_, inner, _) = ty.kind() {
59-
ty = inner;
60-
n += 1;
61-
}
62-
let refs = "&".repeat(n + 1);
63-
let derefs = "*".repeat(n);
64-
let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})"));
65-
diag.span_suggestion(
66-
expr.span,
67-
"try dereferencing it",
68-
with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())),
69-
Applicability::MaybeIncorrect,
70-
);
71-
diag.span_suggestion(
72-
expr.span,
73-
"or try being explicit if you are sure, that you want to clone a reference",
74-
explicit,
75-
Applicability::MaybeIncorrect,
76-
);
77-
}
78-
},
79-
);
43+
if let ty::Ref(..) = inner.kind() {
8044
return; // don't report clone_on_copy
8145
}
8246
}

src/tools/clippy/clippy_lints/src/methods/mod.rs

-24
Original file line numberDiff line numberDiff line change
@@ -984,29 +984,6 @@ declare_clippy_lint! {
984984
"using 'clone' on a ref-counted pointer"
985985
}
986986

987-
declare_clippy_lint! {
988-
/// ### What it does
989-
/// Checks for usage of `.clone()` on an `&&T`.
990-
///
991-
/// ### Why is this bad?
992-
/// Cloning an `&&T` copies the inner `&T`, instead of
993-
/// cloning the underlying `T`.
994-
///
995-
/// ### Example
996-
/// ```rust
997-
/// fn main() {
998-
/// let x = vec![1];
999-
/// let y = &&x;
1000-
/// let z = y.clone();
1001-
/// println!("{:p} {:p}", *y, z); // prints out the same pointer
1002-
/// }
1003-
/// ```
1004-
#[clippy::version = "pre 1.29.0"]
1005-
pub CLONE_DOUBLE_REF,
1006-
correctness,
1007-
"using `clone` on `&&T`"
1008-
}
1009-
1010987
declare_clippy_lint! {
1011988
/// ### What it does
1012989
/// Checks for usage of `.to_string()` on an `&&T` where
@@ -3258,7 +3235,6 @@ impl_lint_pass!(Methods => [
32583235
CHARS_LAST_CMP,
32593236
CLONE_ON_COPY,
32603237
CLONE_ON_REF_PTR,
3261-
CLONE_DOUBLE_REF,
32623238
COLLAPSIBLE_STR_REPLACE,
32633239
ITER_OVEREAGER_CLONED,
32643240
CLONED_INSTEAD_OF_COPIED,

src/tools/clippy/clippy_lints/src/renamed_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
3030
("clippy::stutter", "clippy::module_name_repetitions"),
3131
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
3232
("clippy::zero_width_space", "clippy::invisible_characters"),
33+
("clippy::clone_double_ref", "suspicious_double_ref_op"),
3334
("clippy::drop_bounds", "drop_bounds"),
3435
("clippy::for_loop_over_option", "for_loops_over_fallibles"),
3536
("clippy::for_loop_over_result", "for_loops_over_fallibles"),

src/tools/clippy/tests/ui/explicit_deref_methods.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![allow(unused_variables)]
44
#![allow(
55
clippy::borrow_deref_ref,
6-
clippy::clone_double_ref,
6+
suspicious_double_ref_op,
77
clippy::explicit_auto_deref,
88
clippy::needless_borrow,
99
clippy::uninlined_format_args

src/tools/clippy/tests/ui/explicit_deref_methods.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![allow(unused_variables)]
44
#![allow(
55
clippy::borrow_deref_ref,
6-
clippy::clone_double_ref,
6+
suspicious_double_ref_op,
77
clippy::explicit_auto_deref,
88
clippy::needless_borrow,
99
clippy::uninlined_format_args

src/tools/clippy/tests/ui/rename.fixed

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#![allow(enum_intrinsics_non_enums)]
3737
#![allow(non_fmt_panics)]
3838
#![allow(named_arguments_used_positionally)]
39+
#![allow(suspicious_double_ref_op)]
3940
#![allow(temporary_cstring_as_ptr)]
4041
#![allow(unknown_lints)]
4142
#![allow(unused_labels)]
@@ -67,6 +68,7 @@
6768
#![warn(clippy::module_name_repetitions)]
6869
#![warn(clippy::recursive_format_impl)]
6970
#![warn(clippy::invisible_characters)]
71+
#![warn(suspicious_double_ref_op)]
7072
#![warn(drop_bounds)]
7173
#![warn(for_loops_over_fallibles)]
7274
#![warn(for_loops_over_fallibles)]

src/tools/clippy/tests/ui/rename.rs

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#![allow(enum_intrinsics_non_enums)]
3737
#![allow(non_fmt_panics)]
3838
#![allow(named_arguments_used_positionally)]
39+
#![allow(suspicious_double_ref_op)]
3940
#![allow(temporary_cstring_as_ptr)]
4041
#![allow(unknown_lints)]
4142
#![allow(unused_labels)]
@@ -67,6 +68,7 @@
6768
#![warn(clippy::stutter)]
6869
#![warn(clippy::to_string_in_display)]
6970
#![warn(clippy::zero_width_space)]
71+
#![warn(clippy::clone_double_ref)]
7072
#![warn(clippy::drop_bounds)]
7173
#![warn(clippy::for_loop_over_option)]
7274
#![warn(clippy::for_loop_over_result)]

0 commit comments

Comments
 (0)