diff options
| author | Oliver S̶c̶h̶n̶e̶i̶d̶e̶r Scherer <github35764891676564198441@oli-obk.de> | 2018-10-12 15:07:12 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-12 15:07:12 +0200 |
| commit | d445dbfe162212f90efbe2df9795a257a347a767 (patch) | |
| tree | c1e19eeaaf1df6a66f6861456abb6f5cab9bb4fd | |
| parent | 7557269db2ca3d891d31470cbf7982df15827ae2 (diff) | |
| parent | 352863065cb644a4f59fa5655601960e34bf77e7 (diff) | |
| download | rust-d445dbfe162212f90efbe2df9795a257a347a767.tar.gz rust-d445dbfe162212f90efbe2df9795a257a347a767.zip | |
Merge pull request #3291 from JoshMcguigan/cmp_owned-3289
cmp_owned wording and false positive
| -rw-r--r-- | clippy_lints/src/misc.rs | 49 | ||||
| -rw-r--r-- | tests/ui/cmp_owned.rs | 20 | ||||
| -rw-r--r-- | tests/ui/cmp_owned.stderr | 20 |
3 files changed, 63 insertions, 26 deletions
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 4e6d5b72efc..1cf7345e8df 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -21,7 +21,7 @@ use crate::utils::{get_item_name, get_parent_expr, implements_trait, in_constant iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, walk_ptrs_ty, SpanlessEq}; use crate::utils::sugg::Sugg; -use crate::syntax::ast::{LitKind, CRATE_NODE_ID}; +use crate::syntax::ast::LitKind; use crate::consts::{constant, Constant}; use crate::rustc_errors::Applicability; @@ -535,34 +535,39 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) { return; } + let other_gets_derefed = match other.node { + ExprKind::Unary(UnDeref, _) => true, + _ => false, + }; + + let lint_span = if other_gets_derefed { + expr.span.to(other.span) + } else { + expr.span + }; + span_lint_and_then( cx, CMP_OWNED, - expr.span, + lint_span, "this creates an owned instance just for comparison", |db| { - // this is as good as our recursion check can get, we can't prove that the - // current function is - // called by - // PartialEq::eq, but we can at least ensure that this code is not part of it - let parent_fn = cx.tcx.hir.get_parent(expr.id); - let parent_impl = cx.tcx.hir.get_parent(parent_fn); - if parent_impl != CRATE_NODE_ID { - if let Node::Item(item) = cx.tcx.hir.get(parent_impl) { - if let ItemKind::Impl(.., Some(ref trait_ref), _, _) = item.node { - if trait_ref.path.def.def_id() == partial_eq_trait_id { - // we are implementing PartialEq, don't suggest not doing `to_owned`, otherwise - // we go into - // recursion - db.span_label(expr.span, "try calling implementing the comparison without allocating"); - return; - } - } - } + // this also catches PartialEq implementations that call to_owned + if other_gets_derefed { + db.span_label(lint_span, "try implementing the comparison without allocating"); + return; } - let try_hint = if deref_arg_impl_partial_eq_other { format!("*{}", snip) } else { snip.to_string() }; + + let try_hint = if deref_arg_impl_partial_eq_other { + // suggest deref on the left + format!("*{}", snip) + } else { + // suggest dropping the to_owned on the left + snip.to_string() + }; + db.span_suggestion_with_applicability( - expr.span, + lint_span, "try", try_hint, Applicability::MachineApplicable, // snippet diff --git a/tests/ui/cmp_owned.rs b/tests/ui/cmp_owned.rs index 978e919ff43..dc3d62ddfa6 100644 --- a/tests/ui/cmp_owned.rs +++ b/tests/ui/cmp_owned.rs @@ -35,6 +35,16 @@ fn main() { "abc".chars().filter(|c| c.to_owned() != 'X'); "abc".chars().filter(|c| *c != 'X'); + + let x = &Baz; + let y = &Baz; + + y.to_owned() == *x; + + let x = &&Baz; + let y = &Baz; + + y.to_owned() == **x; } struct Foo; @@ -67,3 +77,13 @@ impl std::borrow::Borrow<Foo> for Bar { &FOO } } + +#[derive(PartialEq)] +struct Baz; + +impl ToOwned for Baz { + type Owned = Baz; + fn to_owned(&self) -> Baz { + Baz + } +} diff --git a/tests/ui/cmp_owned.stderr b/tests/ui/cmp_owned.stderr index 5434b68de9f..a7371ab4b6c 100644 --- a/tests/ui/cmp_owned.stderr +++ b/tests/ui/cmp_owned.stderr @@ -37,10 +37,22 @@ error: this creates an owned instance just for comparison | ^^^^^^^^^^^^ help: try: `*c` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:44:9 + --> $DIR/cmp_owned.rs:42:5 | -44 | self.to_owned() == *other - | ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating +42 | y.to_owned() == *x; + | ^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating -error: aborting due to 7 previous errors +error: this creates an owned instance just for comparison + --> $DIR/cmp_owned.rs:47:5 + | +47 | y.to_owned() == **x; + | ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating + +error: this creates an owned instance just for comparison + --> $DIR/cmp_owned.rs:54:9 + | +54 | self.to_owned() == *other + | ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating + +error: aborting due to 9 previous errors |
