Skip to content

Commit d445dbf

Browse files
authored
Merge pull request #3291 from JoshMcguigan/cmp_owned-3289
cmp_owned wording and false positive
2 parents 7557269 + 3528630 commit d445dbf

File tree

3 files changed

+63
-26
lines changed

3 files changed

+63
-26
lines changed

clippy_lints/src/misc.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::utils::{get_item_name, get_parent_expr, implements_trait, in_constant
2121
iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint,
2222
span_lint_and_then, walk_ptrs_ty, SpanlessEq};
2323
use crate::utils::sugg::Sugg;
24-
use crate::syntax::ast::{LitKind, CRATE_NODE_ID};
24+
use crate::syntax::ast::LitKind;
2525
use crate::consts::{constant, Constant};
2626
use crate::rustc_errors::Applicability;
2727

@@ -535,34 +535,39 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
535535
return;
536536
}
537537

538+
let other_gets_derefed = match other.node {
539+
ExprKind::Unary(UnDeref, _) => true,
540+
_ => false,
541+
};
542+
543+
let lint_span = if other_gets_derefed {
544+
expr.span.to(other.span)
545+
} else {
546+
expr.span
547+
};
548+
538549
span_lint_and_then(
539550
cx,
540551
CMP_OWNED,
541-
expr.span,
552+
lint_span,
542553
"this creates an owned instance just for comparison",
543554
|db| {
544-
// this is as good as our recursion check can get, we can't prove that the
545-
// current function is
546-
// called by
547-
// PartialEq::eq, but we can at least ensure that this code is not part of it
548-
let parent_fn = cx.tcx.hir.get_parent(expr.id);
549-
let parent_impl = cx.tcx.hir.get_parent(parent_fn);
550-
if parent_impl != CRATE_NODE_ID {
551-
if let Node::Item(item) = cx.tcx.hir.get(parent_impl) {
552-
if let ItemKind::Impl(.., Some(ref trait_ref), _, _) = item.node {
553-
if trait_ref.path.def.def_id() == partial_eq_trait_id {
554-
// we are implementing PartialEq, don't suggest not doing `to_owned`, otherwise
555-
// we go into
556-
// recursion
557-
db.span_label(expr.span, "try calling implementing the comparison without allocating");
558-
return;
559-
}
560-
}
561-
}
555+
// this also catches PartialEq implementations that call to_owned
556+
if other_gets_derefed {
557+
db.span_label(lint_span, "try implementing the comparison without allocating");
558+
return;
562559
}
563-
let try_hint = if deref_arg_impl_partial_eq_other { format!("*{}", snip) } else { snip.to_string() };
560+
561+
let try_hint = if deref_arg_impl_partial_eq_other {
562+
// suggest deref on the left
563+
format!("*{}", snip)
564+
} else {
565+
// suggest dropping the to_owned on the left
566+
snip.to_string()
567+
};
568+
564569
db.span_suggestion_with_applicability(
565-
expr.span,
570+
lint_span,
566571
"try",
567572
try_hint,
568573
Applicability::MachineApplicable, // snippet

tests/ui/cmp_owned.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ fn main() {
3535
"abc".chars().filter(|c| c.to_owned() != 'X');
3636

3737
"abc".chars().filter(|c| *c != 'X');
38+
39+
let x = &Baz;
40+
let y = &Baz;
41+
42+
y.to_owned() == *x;
43+
44+
let x = &&Baz;
45+
let y = &Baz;
46+
47+
y.to_owned() == **x;
3848
}
3949

4050
struct Foo;
@@ -67,3 +77,13 @@ impl std::borrow::Borrow<Foo> for Bar {
6777
&FOO
6878
}
6979
}
80+
81+
#[derive(PartialEq)]
82+
struct Baz;
83+
84+
impl ToOwned for Baz {
85+
type Owned = Baz;
86+
fn to_owned(&self) -> Baz {
87+
Baz
88+
}
89+
}

tests/ui/cmp_owned.stderr

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,22 @@ error: this creates an owned instance just for comparison
3737
| ^^^^^^^^^^^^ help: try: `*c`
3838

3939
error: this creates an owned instance just for comparison
40-
--> $DIR/cmp_owned.rs:44:9
40+
--> $DIR/cmp_owned.rs:42:5
4141
|
42-
44 | self.to_owned() == *other
43-
| ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating
42+
42 | y.to_owned() == *x;
43+
| ^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
4444

45-
error: aborting due to 7 previous errors
45+
error: this creates an owned instance just for comparison
46+
--> $DIR/cmp_owned.rs:47:5
47+
|
48+
47 | y.to_owned() == **x;
49+
| ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
50+
51+
error: this creates an owned instance just for comparison
52+
--> $DIR/cmp_owned.rs:54:9
53+
|
54+
54 | self.to_owned() == *other
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
56+
57+
error: aborting due to 9 previous errors
4658

0 commit comments

Comments
 (0)