Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit caaba82

Browse files
committed
move clone_on_copy to its own module
1 parent 171c4c1 commit caaba82

File tree

2 files changed

+112
-103
lines changed

2 files changed

+112
-103
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use crate::utils::{is_copy, span_lint_and_then, sugg};
2+
use rustc_errors::Applicability;
3+
use rustc_hir as hir;
4+
use rustc_lint::LateContext;
5+
use rustc_middle::ty::{self, Ty};
6+
use std::iter;
7+
8+
use super::CLONE_DOUBLE_REF;
9+
use super::CLONE_ON_COPY;
10+
11+
/// Checks for the `CLONE_ON_COPY` lint.
12+
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
13+
let ty = cx.typeck_results().expr_ty(expr);
14+
if let ty::Ref(_, inner, _) = arg_ty.kind() {
15+
if let ty::Ref(_, innermost, _) = inner.kind() {
16+
span_lint_and_then(
17+
cx,
18+
CLONE_DOUBLE_REF,
19+
expr.span,
20+
&format!(
21+
"using `clone` on a double-reference; \
22+
this will copy the reference of type `{}` instead of cloning the inner type",
23+
ty
24+
),
25+
|diag| {
26+
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
27+
let mut ty = innermost;
28+
let mut n = 0;
29+
while let ty::Ref(_, inner, _) = ty.kind() {
30+
ty = inner;
31+
n += 1;
32+
}
33+
let refs: String = iter::repeat('&').take(n + 1).collect();
34+
let derefs: String = iter::repeat('*').take(n).collect();
35+
let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
36+
diag.span_suggestion(
37+
expr.span,
38+
"try dereferencing it",
39+
format!("{}({}{}).clone()", refs, derefs, snip.deref()),
40+
Applicability::MaybeIncorrect,
41+
);
42+
diag.span_suggestion(
43+
expr.span,
44+
"or try being explicit if you are sure, that you want to clone a reference",
45+
explicit,
46+
Applicability::MaybeIncorrect,
47+
);
48+
}
49+
},
50+
);
51+
return; // don't report clone_on_copy
52+
}
53+
}
54+
55+
if is_copy(cx, ty) {
56+
let snip;
57+
if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
58+
let parent = cx.tcx.hir().get_parent_node(expr.hir_id);
59+
match &cx.tcx.hir().get(parent) {
60+
hir::Node::Expr(parent) => match parent.kind {
61+
// &*x is a nop, &x.clone() is not
62+
hir::ExprKind::AddrOf(..) => return,
63+
// (*x).func() is useless, x.clone().func() can work in case func borrows mutably
64+
hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => {
65+
return;
66+
},
67+
68+
_ => {},
69+
},
70+
hir::Node::Stmt(stmt) => {
71+
if let hir::StmtKind::Local(ref loc) = stmt.kind {
72+
if let hir::PatKind::Ref(..) = loc.pat.kind {
73+
// let ref y = *x borrows x, let ref y = x.clone() does not
74+
return;
75+
}
76+
}
77+
},
78+
_ => {},
79+
}
80+
81+
// x.clone() might have dereferenced x, possibly through Deref impls
82+
if cx.typeck_results().expr_ty(arg) == ty {
83+
snip = Some(("try removing the `clone` call", format!("{}", snippet)));
84+
} else {
85+
let deref_count = cx
86+
.typeck_results()
87+
.expr_adjustments(arg)
88+
.iter()
89+
.filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
90+
.count();
91+
let derefs: String = iter::repeat('*').take(deref_count).collect();
92+
snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
93+
}
94+
} else {
95+
snip = None;
96+
}
97+
span_lint_and_then(
98+
cx,
99+
CLONE_ON_COPY,
100+
expr.span,
101+
&format!("using `clone` on type `{}` which implements the `Copy` trait", ty),
102+
|diag| {
103+
if let Some((text, snip)) = snip {
104+
diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
105+
}
106+
},
107+
);
108+
}
109+
}

clippy_lints/src/methods/mod.rs

Lines changed: 3 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod bind_instead_of_map;
22
mod bytes_nth;
3+
mod clone_on_copy;
34
mod clone_on_ref_ptr;
45
mod expect_used;
56
mod filetype_is_file;
@@ -45,7 +46,6 @@ mod wrong_self_convention;
4546
mod zst_offset;
4647

4748
use std::borrow::Cow;
48-
use std::iter;
4949

5050
use bind_instead_of_map::BindInsteadOfMap;
5151
use if_chain::if_chain;
@@ -69,7 +69,7 @@ use crate::utils::{
6969
is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method,
7070
match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, remove_blocks, return_ty,
7171
single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
72-
span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, SpanlessEq,
72+
span_lint_and_help, span_lint_and_sugg, strip_pat_refs, walk_ptrs_ty_depth, SpanlessEq,
7373
};
7474

7575
declare_clippy_lint! {
@@ -1781,7 +1781,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
17811781

17821782
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
17831783
if args.len() == 1 && method_call.ident.name == sym::clone {
1784-
lint_clone_on_copy(cx, expr, &args[0], self_ty);
1784+
clone_on_copy::check(cx, expr, &args[0], self_ty);
17851785
clone_on_ref_ptr::check(cx, expr, &args[0]);
17861786
}
17871787
if args.len() == 1 && method_call.ident.name == sym!(to_string) {
@@ -2323,106 +2323,6 @@ fn lint_expect_fun_call(
23232323
);
23242324
}
23252325

2326-
/// Checks for the `CLONE_ON_COPY` lint.
2327-
fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
2328-
let ty = cx.typeck_results().expr_ty(expr);
2329-
if let ty::Ref(_, inner, _) = arg_ty.kind() {
2330-
if let ty::Ref(_, innermost, _) = inner.kind() {
2331-
span_lint_and_then(
2332-
cx,
2333-
CLONE_DOUBLE_REF,
2334-
expr.span,
2335-
&format!(
2336-
"using `clone` on a double-reference; \
2337-
this will copy the reference of type `{}` instead of cloning the inner type",
2338-
ty
2339-
),
2340-
|diag| {
2341-
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
2342-
let mut ty = innermost;
2343-
let mut n = 0;
2344-
while let ty::Ref(_, inner, _) = ty.kind() {
2345-
ty = inner;
2346-
n += 1;
2347-
}
2348-
let refs: String = iter::repeat('&').take(n + 1).collect();
2349-
let derefs: String = iter::repeat('*').take(n).collect();
2350-
let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
2351-
diag.span_suggestion(
2352-
expr.span,
2353-
"try dereferencing it",
2354-
format!("{}({}{}).clone()", refs, derefs, snip.deref()),
2355-
Applicability::MaybeIncorrect,
2356-
);
2357-
diag.span_suggestion(
2358-
expr.span,
2359-
"or try being explicit if you are sure, that you want to clone a reference",
2360-
explicit,
2361-
Applicability::MaybeIncorrect,
2362-
);
2363-
}
2364-
},
2365-
);
2366-
return; // don't report clone_on_copy
2367-
}
2368-
}
2369-
2370-
if is_copy(cx, ty) {
2371-
let snip;
2372-
if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
2373-
let parent = cx.tcx.hir().get_parent_node(expr.hir_id);
2374-
match &cx.tcx.hir().get(parent) {
2375-
hir::Node::Expr(parent) => match parent.kind {
2376-
// &*x is a nop, &x.clone() is not
2377-
hir::ExprKind::AddrOf(..) => return,
2378-
// (*x).func() is useless, x.clone().func() can work in case func borrows mutably
2379-
hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => {
2380-
return;
2381-
},
2382-
2383-
_ => {},
2384-
},
2385-
hir::Node::Stmt(stmt) => {
2386-
if let hir::StmtKind::Local(ref loc) = stmt.kind {
2387-
if let hir::PatKind::Ref(..) = loc.pat.kind {
2388-
// let ref y = *x borrows x, let ref y = x.clone() does not
2389-
return;
2390-
}
2391-
}
2392-
},
2393-
_ => {},
2394-
}
2395-
2396-
// x.clone() might have dereferenced x, possibly through Deref impls
2397-
if cx.typeck_results().expr_ty(arg) == ty {
2398-
snip = Some(("try removing the `clone` call", format!("{}", snippet)));
2399-
} else {
2400-
let deref_count = cx
2401-
.typeck_results()
2402-
.expr_adjustments(arg)
2403-
.iter()
2404-
.filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
2405-
.count();
2406-
let derefs: String = iter::repeat('*').take(deref_count).collect();
2407-
snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
2408-
}
2409-
} else {
2410-
snip = None;
2411-
}
2412-
span_lint_and_then(
2413-
cx,
2414-
CLONE_ON_COPY,
2415-
expr.span,
2416-
&format!("using `clone` on type `{}` which implements the `Copy` trait", ty),
2417-
|diag| {
2418-
if let Some((text, snip)) = snip {
2419-
diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
2420-
}
2421-
},
2422-
);
2423-
}
2424-
}
2425-
24262326
fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) {
24272327
fn check_fold_with_op(
24282328
cx: &LateContext<'_>,

0 commit comments

Comments
 (0)