Skip to content

Commit 71ecbc4

Browse files
committed
Auto merge of rust-lang#8509 - smoelius:fix-8507, r=giraffate
Fix `unncessary_to_owned` false positive Fix rust-lang#8507 changelog: none
2 parents 9a1f6a9 + 1a95590 commit 71ecbc4

File tree

4 files changed

+126
-24
lines changed

4 files changed

+126
-24
lines changed

clippy_lints/src/methods/unnecessary_to_owned.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use super::implicit_clone::is_clone_like;
22
use super::unnecessary_iter_cloned::{self, is_into_iter};
33
use clippy_utils::diagnostics::span_lint_and_sugg;
44
use clippy_utils::source::snippet_opt;
5-
use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
5+
use clippy_utils::ty::{
6+
contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs,
7+
};
68
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
79
use rustc_errors::Applicability;
810
use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
@@ -114,7 +116,12 @@ fn check_addr_of_expr(
114116
parent.span,
115117
&format!("unnecessary use of `{}`", method_name),
116118
"use",
117-
format!("{:&>width$}{}", "", receiver_snippet, width = n_target_refs - n_receiver_refs),
119+
format!(
120+
"{:&>width$}{}",
121+
"",
122+
receiver_snippet,
123+
width = n_target_refs - n_receiver_refs
124+
),
118125
Applicability::MachineApplicable,
119126
);
120127
return true;
@@ -182,20 +189,10 @@ fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name:
182189
if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty);
183190
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
184191
then {
185-
if unnecessary_iter_cloned::check_for_loop_iter(
186-
cx,
187-
parent,
188-
method_name,
189-
receiver,
190-
true,
191-
) {
192+
if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) {
192193
return true;
193194
}
194-
let cloned_or_copied = if is_copy(cx, item_ty) {
195-
"copied"
196-
} else {
197-
"cloned"
198-
};
195+
let cloned_or_copied = if is_copy(cx, item_ty) { "copied" } else { "cloned" };
199196
// The next suggestion may be incorrect because the removal of the `to_owned`-like
200197
// function could cause the iterator to hold a reference to a resource that is used
201198
// mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.
@@ -243,18 +240,19 @@ fn check_other_call_arg<'tcx>(
243240
if if trait_predicate.def_id() == deref_trait_id {
244241
if let [projection_predicate] = projection_predicates[..] {
245242
let normalized_ty =
246-
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
243+
cx.tcx
244+
.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
247245
implements_trait(cx, receiver_ty, deref_trait_id, &[])
248-
&& get_associated_type(cx, receiver_ty, deref_trait_id,
249-
"Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
246+
&& get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
247+
.map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
250248
} else {
251249
false
252250
}
253251
} else if trait_predicate.def_id() == as_ref_trait_id {
254252
let composed_substs = compose_substs(
255253
cx,
256254
&trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
257-
call_substs
255+
call_substs,
258256
);
259257
implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
260258
} else {
@@ -264,6 +262,12 @@ fn check_other_call_arg<'tcx>(
264262
// `Target = T`.
265263
if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
266264
let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
265+
// If the trait is `AsRef` and the input type variable `T` occurs in the output type, then
266+
// `T` must not be instantiated with a reference
267+
// (https://github.com/rust-lang/rust-clippy/issues/8507).
268+
if (n_refs == 0 && !receiver_ty.is_ref())
269+
|| trait_predicate.def_id() != as_ref_trait_id
270+
|| !contains_ty(fn_sig.output(), input);
267271
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
268272
then {
269273
span_lint_and_sugg(
@@ -339,11 +343,7 @@ fn get_input_traits_and_projections<'tcx>(
339343
if let Some(arg) = substs.iter().next();
340344
if let GenericArgKind::Type(arg_ty) = arg.unpack();
341345
if arg_ty == input;
342-
then {
343-
true
344-
} else {
345-
false
346-
}
346+
then { true } else { false }
347347
}
348348
};
349349
match predicate.kind().skip_binder() {

tests/ui/unnecessary_to_owned.fixed

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,51 @@ fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::E
212212
}
213213

214214
fn require_string(_: &String) {}
215+
216+
// https://github.com/rust-lang/rust-clippy/issues/8507
217+
mod issue_8507 {
218+
#![allow(dead_code)]
219+
220+
struct Opaque<P>(P);
221+
222+
pub trait Abstracted {}
223+
224+
impl<P> Abstracted for Opaque<P> {}
225+
226+
fn build<P>(p: P) -> Opaque<P>
227+
where
228+
P: AsRef<str>,
229+
{
230+
Opaque(p)
231+
}
232+
233+
// Should not lint.
234+
fn test_str(s: &str) -> Box<dyn Abstracted> {
235+
Box::new(build(s.to_string()))
236+
}
237+
238+
// Should not lint.
239+
fn test_x(x: super::X) -> Box<dyn Abstracted> {
240+
Box::new(build(x))
241+
}
242+
243+
#[derive(Clone, Copy)]
244+
struct Y(&'static str);
245+
246+
impl AsRef<str> for Y {
247+
fn as_ref(&self) -> &str {
248+
self.0
249+
}
250+
}
251+
252+
impl ToString for Y {
253+
fn to_string(&self) -> String {
254+
self.0.to_string()
255+
}
256+
}
257+
258+
// Should lint because Y is copy.
259+
fn test_y(y: Y) -> Box<dyn Abstracted> {
260+
Box::new(build(y))
261+
}
262+
}

tests/ui/unnecessary_to_owned.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,51 @@ fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::E
212212
}
213213

214214
fn require_string(_: &String) {}
215+
216+
// https://github.com/rust-lang/rust-clippy/issues/8507
217+
mod issue_8507 {
218+
#![allow(dead_code)]
219+
220+
struct Opaque<P>(P);
221+
222+
pub trait Abstracted {}
223+
224+
impl<P> Abstracted for Opaque<P> {}
225+
226+
fn build<P>(p: P) -> Opaque<P>
227+
where
228+
P: AsRef<str>,
229+
{
230+
Opaque(p)
231+
}
232+
233+
// Should not lint.
234+
fn test_str(s: &str) -> Box<dyn Abstracted> {
235+
Box::new(build(s.to_string()))
236+
}
237+
238+
// Should not lint.
239+
fn test_x(x: super::X) -> Box<dyn Abstracted> {
240+
Box::new(build(x))
241+
}
242+
243+
#[derive(Clone, Copy)]
244+
struct Y(&'static str);
245+
246+
impl AsRef<str> for Y {
247+
fn as_ref(&self) -> &str {
248+
self.0
249+
}
250+
}
251+
252+
impl ToString for Y {
253+
fn to_string(&self) -> String {
254+
self.0.to_string()
255+
}
256+
}
257+
258+
// Should lint because Y is copy.
259+
fn test_y(y: Y) -> Box<dyn Abstracted> {
260+
Box::new(build(y.to_string()))
261+
}
262+
}

tests/ui/unnecessary_to_owned.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,5 +491,11 @@ LL - let path = match get_file_path(&t) {
491491
LL + let path = match get_file_path(t) {
492492
|
493493

494-
error: aborting due to 76 previous errors
494+
error: unnecessary use of `to_string`
495+
--> $DIR/unnecessary_to_owned.rs:260:24
496+
|
497+
LL | Box::new(build(y.to_string()))
498+
| ^^^^^^^^^^^^^ help: use: `y`
499+
500+
error: aborting due to 77 previous errors
495501

0 commit comments

Comments
 (0)