Skip to content

Commit 9f2d0a6

Browse files
committed
Merge branch 'master' into manual_memcpy_with_counter
2 parents 0fbcd7a + 88fec89 commit 9f2d0a6

11 files changed

+421
-104
lines changed

clippy_lints/src/await_holding_lock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ declare_clippy_lint! {
1111
/// non-async-aware MutexGuard.
1212
///
1313
/// **Why is this bad?** The Mutex types found in syd::sync and parking_lot
14-
/// are not designed to operator in an async context across await points.
14+
/// are not designed to operate in an async context across await points.
1515
///
1616
/// There are two potential solutions. One is to use an asynx-aware Mutex
1717
/// type. Many asynchronous foundation crates provide such a Mutex type. The

clippy_lints/src/methods/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir:
20412041
}
20422042
span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| {
20432043
if let Some((text, snip)) = snip {
2044-
diag.span_suggestion(expr.span, text, snip, Applicability::Unspecified);
2044+
diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
20452045
}
20462046
});
20472047
}

clippy_lints/src/misc.rs

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind;
33
use rustc_errors::Applicability;
44
use rustc_hir::intravisit::FnKind;
55
use rustc_hir::{
6-
def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, StmtKind, Ty,
7-
TyKind, UnOp,
6+
self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
7+
StmtKind, TyKind, UnOp,
88
};
99
use rustc_lint::{LateContext, LateLintPass};
10-
use rustc_middle::ty;
10+
use rustc_middle::ty::{self, Ty};
1111
use rustc_session::{declare_lint_pass, declare_tool_lint};
1212
use rustc_span::hygiene::DesugaringKind;
1313
use rustc_span::source_map::{ExpnKind, Span};
@@ -371,8 +371,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
371371
if op.is_comparison() {
372372
check_nan(cx, left, expr);
373373
check_nan(cx, right, expr);
374-
check_to_owned(cx, left, right);
375-
check_to_owned(cx, right, left);
374+
check_to_owned(cx, left, right, true);
375+
check_to_owned(cx, right, left, false);
376376
}
377377
if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) {
378378
if is_allowed(cx, left) || is_allowed(cx, right) {
@@ -570,19 +570,38 @@ fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
570570
matches!(&walk_ptrs_ty(cx.tables.expr_ty(expr)).kind, ty::Array(_, _))
571571
}
572572

573-
fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
573+
fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
574+
#[derive(Default)]
575+
struct EqImpl {
576+
ty_eq_other: bool,
577+
other_eq_ty: bool,
578+
}
579+
580+
impl EqImpl {
581+
fn is_implemented(&self) -> bool {
582+
self.ty_eq_other || self.other_eq_ty
583+
}
584+
}
585+
586+
fn symmetric_partial_eq<'tcx>(cx: &LateContext<'_, 'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option<EqImpl> {
587+
cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl {
588+
ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]),
589+
other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]),
590+
})
591+
}
592+
574593
let (arg_ty, snip) = match expr.kind {
575594
ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
576595
if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
577-
(cx.tables.expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
596+
(cx.tables.expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
578597
} else {
579598
return;
580599
}
581600
},
582601
ExprKind::Call(ref path, ref v) if v.len() == 1 => {
583602
if let ExprKind::Path(ref path) = path.kind {
584603
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
585-
(cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
604+
(cx.tables.expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
586605
} else {
587606
return;
588607
}
@@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
593612
_ => return,
594613
};
595614

596-
let other_ty = cx.tables.expr_ty_adjusted(other);
597-
let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() {
598-
Some(id) => id,
599-
None => return,
600-
};
615+
let other_ty = cx.tables.expr_ty(other);
601616

602-
let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| {
603-
implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])
604-
});
605-
let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| {
606-
implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])
607-
});
608-
let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]);
617+
let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
618+
let with_deref = arg_ty
619+
.builtin_deref(true)
620+
.and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty))
621+
.unwrap_or_default();
609622

610-
if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
623+
if !with_deref.is_implemented() && !without_deref.is_implemented() {
611624
return;
612625
}
613626

614-
let other_gets_derefed = match other.kind {
615-
ExprKind::Unary(UnOp::UnDeref, _) => true,
616-
_ => false,
617-
};
627+
let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _));
618628

619629
let lint_span = if other_gets_derefed {
620630
expr.span.to(other.span)
@@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
634644
return;
635645
}
636646

637-
let try_hint = if deref_arg_impl_partial_eq_other {
638-
// suggest deref on the left
639-
format!("*{}", snip)
647+
let expr_snip;
648+
let eq_impl;
649+
if with_deref.is_implemented() {
650+
expr_snip = format!("*{}", snip);
651+
eq_impl = with_deref;
640652
} else {
641-
// suggest dropping the to_owned on the left
642-
snip.to_string()
653+
expr_snip = snip.to_string();
654+
eq_impl = without_deref;
643655
};
644656

657+
let span;
658+
let hint;
659+
if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) {
660+
span = expr.span;
661+
hint = expr_snip;
662+
} else {
663+
span = expr.span.to(other.span);
664+
if eq_impl.ty_eq_other {
665+
hint = format!("{} == {}", expr_snip, snippet(cx, other.span, ".."));
666+
} else {
667+
hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip);
668+
}
669+
}
670+
645671
diag.span_suggestion(
646-
lint_span,
672+
span,
647673
"try",
648-
try_hint,
674+
hint,
649675
Applicability::MachineApplicable, // snippet
650676
);
651677
},
@@ -694,7 +720,7 @@ fn non_macro_local(cx: &LateContext<'_, '_>, res: def::Res) -> bool {
694720
}
695721
}
696722

697-
fn check_cast(cx: &LateContext<'_, '_>, span: Span, e: &Expr<'_>, ty: &Ty<'_>) {
723+
fn check_cast(cx: &LateContext<'_, '_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
698724
if_chain! {
699725
if let TyKind::Ptr(ref mut_ty) = ty.kind;
700726
if let ExprKind::Lit(ref lit) = e.kind;

tests/ui/clone_on_copy.fixed

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// run-rustfix
2+
3+
#![allow(
4+
unused,
5+
clippy::redundant_clone,
6+
clippy::deref_addrof,
7+
clippy::no_effect,
8+
clippy::unnecessary_operation
9+
)]
10+
11+
use std::cell::RefCell;
12+
use std::rc::{self, Rc};
13+
use std::sync::{self, Arc};
14+
15+
fn main() {}
16+
17+
fn is_ascii(ch: char) -> bool {
18+
ch.is_ascii()
19+
}
20+
21+
fn clone_on_copy() {
22+
42;
23+
24+
vec![1].clone(); // ok, not a Copy type
25+
Some(vec![1]).clone(); // ok, not a Copy type
26+
*(&42);
27+
28+
let rc = RefCell::new(0);
29+
*rc.borrow();
30+
31+
// Issue #4348
32+
let mut x = 43;
33+
let _ = &x.clone(); // ok, getting a ref
34+
'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
35+
is_ascii('z');
36+
37+
// Issue #5436
38+
let mut vec = Vec::new();
39+
vec.push(42);
40+
}

tests/ui/clone_on_copy.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// run-rustfix
2+
3+
#![allow(
4+
unused,
5+
clippy::redundant_clone,
6+
clippy::deref_addrof,
7+
clippy::no_effect,
8+
clippy::unnecessary_operation
9+
)]
10+
11+
use std::cell::RefCell;
12+
use std::rc::{self, Rc};
13+
use std::sync::{self, Arc};
14+
15+
fn main() {}
16+
17+
fn is_ascii(ch: char) -> bool {
18+
ch.is_ascii()
19+
}
20+
21+
fn clone_on_copy() {
22+
42.clone();
23+
24+
vec![1].clone(); // ok, not a Copy type
25+
Some(vec![1]).clone(); // ok, not a Copy type
26+
(&42).clone();
27+
28+
let rc = RefCell::new(0);
29+
rc.borrow().clone();
30+
31+
// Issue #4348
32+
let mut x = 43;
33+
let _ = &x.clone(); // ok, getting a ref
34+
'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
35+
is_ascii('z'.clone());
36+
37+
// Issue #5436
38+
let mut vec = Vec::new();
39+
vec.push(42.clone());
40+
}

tests/ui/clone_on_copy.stderr

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: using `clone` on a `Copy` type
2+
--> $DIR/clone_on_copy.rs:22:5
3+
|
4+
LL | 42.clone();
5+
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
6+
|
7+
= note: `-D clippy::clone-on-copy` implied by `-D warnings`
8+
9+
error: using `clone` on a `Copy` type
10+
--> $DIR/clone_on_copy.rs:26:5
11+
|
12+
LL | (&42).clone();
13+
| ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
14+
15+
error: using `clone` on a `Copy` type
16+
--> $DIR/clone_on_copy.rs:29:5
17+
|
18+
LL | rc.borrow().clone();
19+
| ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
20+
21+
error: using `clone` on a `Copy` type
22+
--> $DIR/clone_on_copy.rs:35:14
23+
|
24+
LL | is_ascii('z'.clone());
25+
| ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
26+
27+
error: using `clone` on a `Copy` type
28+
--> $DIR/clone_on_copy.rs:39:14
29+
|
30+
LL | vec.push(42.clone());
31+
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
32+
33+
error: aborting due to 5 previous errors
34+
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// run-rustfix
2+
#![allow(unused, clippy::redundant_clone)] // See #5700
3+
4+
// Define the types in each module to avoid trait impls leaking between modules.
5+
macro_rules! impl_types {
6+
() => {
7+
#[derive(PartialEq)]
8+
pub struct Owned;
9+
10+
pub struct Borrowed;
11+
12+
impl ToOwned for Borrowed {
13+
type Owned = Owned;
14+
fn to_owned(&self) -> Owned {
15+
Owned {}
16+
}
17+
}
18+
19+
impl std::borrow::Borrow<Borrowed> for Owned {
20+
fn borrow(&self) -> &Borrowed {
21+
static VALUE: Borrowed = Borrowed {};
22+
&VALUE
23+
}
24+
}
25+
};
26+
}
27+
28+
// Only Borrowed == Owned is implemented
29+
mod borrowed_eq_owned {
30+
impl_types!();
31+
32+
impl PartialEq<Owned> for Borrowed {
33+
fn eq(&self, _: &Owned) -> bool {
34+
true
35+
}
36+
}
37+
38+
pub fn compare() {
39+
let owned = Owned {};
40+
let borrowed = Borrowed {};
41+
42+
if borrowed == owned {}
43+
if borrowed == owned {}
44+
}
45+
}
46+
47+
// Only Owned == Borrowed is implemented
48+
mod owned_eq_borrowed {
49+
impl_types!();
50+
51+
impl PartialEq<Borrowed> for Owned {
52+
fn eq(&self, _: &Borrowed) -> bool {
53+
true
54+
}
55+
}
56+
57+
fn compare() {
58+
let owned = Owned {};
59+
let borrowed = Borrowed {};
60+
61+
if owned == borrowed {}
62+
if owned == borrowed {}
63+
}
64+
}
65+
66+
mod issue_4874 {
67+
impl_types!();
68+
69+
// NOTE: PartialEq<Borrowed> for T can't be implemented due to the orphan rules
70+
impl<T> PartialEq<T> for Borrowed
71+
where
72+
T: AsRef<str> + ?Sized,
73+
{
74+
fn eq(&self, _: &T) -> bool {
75+
true
76+
}
77+
}
78+
79+
impl std::fmt::Display for Borrowed {
80+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81+
write!(f, "borrowed")
82+
}
83+
}
84+
85+
fn compare() {
86+
let borrowed = Borrowed {};
87+
88+
if borrowed == "Hi" {}
89+
if borrowed == "Hi" {}
90+
}
91+
}
92+
93+
fn main() {}

0 commit comments

Comments
 (0)