Skip to content

Commit 0dbc32d

Browse files
committed
merge clone_double_ref with noop_method_call
1 parent 8a919eb commit 0dbc32d

14 files changed

+119
-165
lines changed

compiler/rustc_lint/messages.ftl

+1-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ lint_array_into_iter =
66
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
77
88
lint_clone_double_ref =
9-
using `clone` on a double-reference, which copies the reference of type `{$ty}` instead of cloning the inner type
10-
11-
lint_clone_double_ref_try_deref = try dereferencing it
12-
13-
lint_clone_double_ref_sugg_explicit = or try being explicit if you are sure, that you want to clone a reference
9+
using `.{$call}()` on a double reference, which copies `{$ty}` instead of {$op} the inner type
1410
1511
lint_enum_intrinsics_mem_discriminant =
1612
the return value of `mem::discriminant` is unspecified when called with a non-enum type

compiler/rustc_lint/src/clone_double_ref.rs

-86
This file was deleted.

compiler/rustc_lint/src/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ extern crate tracing;
5050

5151
mod array_into_iter;
5252
pub mod builtin;
53-
mod clone_double_ref;
5453
mod context;
5554
mod deref_into_dyn_supertrait;
5655
mod early;
@@ -96,7 +95,6 @@ use rustc_span::Span;
9695

9796
use array_into_iter::ArrayIntoIter;
9897
use builtin::*;
99-
use clone_double_ref::CloneDoubleRef;
10098
use deref_into_dyn_supertrait::*;
10199
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
102100
use for_loops_over_fallibles::*;
@@ -201,7 +199,6 @@ late_lint_methods!(
201199
[
202200
BuiltinCombinedModuleLateLintPass,
203201
[
204-
CloneDoubleRef: CloneDoubleRef,
205202
ForLoopsOverFallibles: ForLoopsOverFallibles,
206203
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
207204
HardwiredLints: HardwiredLints,

compiler/rustc_lint/src/lints.rs

+2-26
Original file line numberDiff line numberDiff line change
@@ -567,33 +567,9 @@ pub struct BuiltinUnexpectedCliConfigValue {
567567
#[derive(LintDiagnostic)]
568568
#[diag(lint_clone_double_ref)]
569569
pub struct CloneDoubleRef<'a> {
570+
pub call: Symbol,
570571
pub ty: Ty<'a>,
571-
#[subdiagnostic]
572-
pub try_deref: CloneDoubleRefTryDeref,
573-
#[subdiagnostic]
574-
pub explicit: CloneDoubleRefExplicit<'a>,
575-
}
576-
577-
#[derive(Subdiagnostic)]
578-
#[multipart_suggestion(lint_clone_double_ref_sugg_explicit, applicability = "maybe-incorrect")]
579-
pub struct CloneDoubleRefExplicit<'a> {
580-
#[suggestion_part(code = "<{refs}{ty}>::clone(")]
581-
pub start: Span,
582-
#[suggestion_part(code = ")")]
583-
pub end: Span,
584-
pub refs: String,
585-
pub ty: Ty<'a>,
586-
}
587-
588-
#[derive(Subdiagnostic)]
589-
#[multipart_suggestion(lint_clone_double_ref_try_deref, applicability = "maybe-incorrect")]
590-
pub struct CloneDoubleRefTryDeref {
591-
#[suggestion_part(code = "{refs}({derefs}")]
592-
pub start: Span,
593-
#[suggestion_part(code = ").clone()")]
594-
pub end: Span,
595-
pub refs: String,
596-
pub derefs: String,
572+
pub op: &'static str,
597573
}
598574

599575
// deref_into_dyn_supertrait.rs

compiler/rustc_lint/src/noop_method_call.rs

+49-19
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::{CloneDoubleRef, NoopMethodCallDiag};
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! {
@@ -31,18 +32,32 @@ declare_lint! {
3132
/// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything
3233
/// as references are copy. This lint detects these calls and warns the user about them.
3334
pub NOOP_METHOD_CALL,
34-
Allow,
35+
Warn,
3536
"detects the use of well-known noop methods"
3637
}
3738

38-
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
39+
declare_lint! {
40+
/// The `clone_double_ref` lint checks for usage of `.clone()` on an `&&T`,
41+
/// which copies the inner `&T`, instead of cloning the underlying `T` and
42+
/// can be confusing.
43+
pub CLONE_DOUBLE_REF,
44+
Warn,
45+
"using `clone` on `&&T`"
46+
}
47+
48+
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL, CLONE_DOUBLE_REF]);
3949

4050
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
4151
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
4252
// We only care about method calls.
43-
let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
44-
return
53+
let ExprKind::MethodCall(call, receiver, _, call_span) = &expr.kind else {
54+
return;
4555
};
56+
57+
if call_span.from_expansion() {
58+
return;
59+
}
60+
4661
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
4762
// traits and ignore any other method call.
4863
let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
@@ -70,25 +85,40 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
7085
};
7186
// (Re)check that it implements the noop diagnostic.
7287
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-
}
88+
89+
let op = match name {
90+
sym::noop_method_borrow => "borrowing",
91+
sym::noop_method_clone => "cloning",
92+
sym::noop_method_deref => "dereferencing",
93+
_ => return,
94+
};
95+
7996
let receiver_ty = cx.typeck_results().expr_ty(receiver);
8097
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.
98+
99+
let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
100+
101+
// If there is any user defined auto-deref step, then we don't want to warn.
102+
// https://github.com/rust-lang/rust-clippy/issues/9272
103+
if arg_adjustments.iter().any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) {
84104
return;
85105
}
106+
86107
let expr_span = expr.span;
87108
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-
);
109+
110+
if receiver_ty == expr_ty {
111+
cx.emit_spanned_lint(
112+
NOOP_METHOD_CALL,
113+
span,
114+
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
115+
);
116+
} else {
117+
cx.emit_spanned_lint(
118+
CLONE_DOUBLE_REF,
119+
span,
120+
CloneDoubleRef { call: call.ident.name, ty: expr_ty, op },
121+
)
122+
}
93123
}
94124
}

library/alloc/src/str.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ macro_rules! specialize_for_lengths {
8989
$num => {
9090
for s in iter {
9191
copy_slice_and_advance!(target, sep_bytes);
92-
let content_bytes = s.borrow().as_ref();
92+
let content_bytes = s.as_ref();
9393
copy_slice_and_advance!(target, content_bytes);
9494
}
9595
},
@@ -98,7 +98,7 @@ macro_rules! specialize_for_lengths {
9898
// arbitrary non-zero size fallback
9999
for s in iter {
100100
copy_slice_and_advance!(target, sep_bytes);
101-
let content_bytes = s.borrow().as_ref();
101+
let content_bytes = s.as_ref();
102102
copy_slice_and_advance!(target, content_bytes);
103103
}
104104
}

tests/ui/issues/issue-11820.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// run-pass
22
// pretty-expanded FIXME #23616
33

4+
#![allow(noop_method_call)]
5+
46
struct NoClone;
57

68
fn main() {

tests/ui/lint/clone-double-ref.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
#![feature(once_cell)]
2-
#![deny(clone_double_ref)]
1+
#![feature(lazy_cell)]
2+
#![deny(clone_double_ref, noop_method_call)]
33

44
pub fn clone_on_double_ref() {
55
let x = vec![1];
66
let y = &&x;
77
let z: &Vec<_> = y.clone();
8-
//~^ ERROR using `clone` on a double-reference, which copies the reference of type `Vec<i32>`
8+
//~^ ERROR using `.clone()` on a double reference, which copies `&Vec<i32>`
99

1010
println!("{:p} {:p}", *y, z);
1111
}
@@ -22,7 +22,9 @@ fn rust_clippy_issue_9272() {
2222

2323
fn check(mut encoded: &[u8]) {
2424
let _ = &mut encoded.clone();
25+
//~^ ERROR call to `.clone()` on a reference in this situation does nothing
2526
let _ = &encoded.clone();
27+
//~^ ERROR call to `.clone()` on a reference in this situation does nothing
2628
}
2729

2830
fn main() {}

tests/ui/lint/clone-double-ref.stderr

+24-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
1-
error: using `clone` on a double-reference, which copies the reference of type `Vec<i32>` instead of cloning the inner type
2-
--> $DIR/clone-double-ref.rs:7:22
1+
error: using `.clone()` on a double reference, which copies `&Vec<i32>` instead of cloning the inner type
2+
--> $DIR/clone-double-ref.rs:7:23
33
|
44
LL | let z: &Vec<_> = y.clone();
5-
| ^^^^^^^^^
5+
| ^^^^^^^^
66
|
77
note: the lint level is defined here
88
--> $DIR/clone-double-ref.rs:2:9
99
|
10-
LL | #![deny(clone_double_ref)]
10+
LL | #![deny(clone_double_ref, noop_method_call)]
1111
| ^^^^^^^^^^^^^^^^
12-
help: try dereferencing it
12+
13+
error: call to `.clone()` on a reference in this situation does nothing
14+
--> $DIR/clone-double-ref.rs:24:25
15+
|
16+
LL | let _ = &mut encoded.clone();
17+
| ^^^^^^^^ unnecessary method call
18+
|
19+
= note: the type `&[u8]` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
20+
note: the lint level is defined here
21+
--> $DIR/clone-double-ref.rs:2:27
22+
|
23+
LL | #![deny(clone_double_ref, noop_method_call)]
24+
| ^^^^^^^^^^^^^^^^
25+
26+
error: call to `.clone()` on a reference in this situation does nothing
27+
--> $DIR/clone-double-ref.rs:26:21
1328
|
14-
LL | let z: &Vec<_> = &(*y).clone();
15-
| +++ ~~~~~~~~~
16-
help: or try being explicit if you are sure, that you want to clone a reference
29+
LL | let _ = &encoded.clone();
30+
| ^^^^^^^^ unnecessary method call
1731
|
18-
LL | let z: &Vec<_> = <&Vec<i32>>::clone(y);
19-
| +++++++++++++++++++ ~
32+
= note: the type `&[u8]` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
2033

21-
error: aborting due to previous error
34+
error: aborting due to 3 previous errors
2235

tests/ui/lint/noop-method-call.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,21 @@ fn main() {
1515
let non_clone_type_ref = &PlainType(1u32);
1616
let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
1717
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
18-
//~| WARNING using `clone` on a double-reference, which copies the reference of type `PlainType<u32>`
1918

2019
let clone_type_ref = &CloneType(1u32);
2120
let clone_type_ref_clone: CloneType<u32> = clone_type_ref.clone();
2221

23-
// Calling clone on a double reference doesn't warn since the method call itself
24-
// peels the outer reference off
2522
let clone_type_ref = &&CloneType(1u32);
2623
let clone_type_ref_clone: &CloneType<u32> = clone_type_ref.clone();
27-
//~^ WARNING using `clone` on a double-reference, which copies the reference of type `CloneType<u32>`
24+
//~^ WARNING using `.clone()` on a double reference, which copies `&CloneType<u32>`
2825

2926
let non_deref_type = &PlainType(1u32);
3027
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
3128
//~^ WARNING call to `.deref()` on a reference in this situation does nothing
3229

33-
// Dereferencing a &&T does not warn since it has collapsed the double reference
3430
let non_deref_type = &&PlainType(1u32);
3531
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
32+
//~^ WARNING using `.deref()` on a double reference, which copies `&PlainType<u32>`
3633

3734
let non_borrow_type = &PlainType(1u32);
3835
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
@@ -44,7 +41,7 @@ fn main() {
4441

4542
let xs = ["a", "b", "c"];
4643
let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead
47-
//~^ WARNING using `clone` on a double-reference, which copies the reference of type `str`
44+
//~^ WARNING using `.clone()` on a double reference, which copies `&str`
4845
}
4946

5047
fn generic<T>(non_clone_type: &PlainType<T>) {

0 commit comments

Comments
 (0)