Skip to content

Commit dd08494

Browse files
committed
check that the adjusted receiver type matches target
1 parent 60258b0 commit dd08494

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

clippy_lints/src/methods/unnecessary_to_owned.rs

+5
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ fn check_addr_of_expr(
144144
if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
145145
if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
146146
if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty);
147+
// Make sure that it's actually calling the right `.to_string()`, (#10033)
148+
// *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
149+
// but that's ok for Cow::into_owned specifically)
150+
if cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty
151+
|| is_cow_into_owned(cx, method_name, method_def_id);
147152
then {
148153
if n_receiver_refs > 0 {
149154
span_lint_and_sugg(

tests/ui/unnecessary_to_owned.fixed

+33
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,36 @@ mod issue_10021 {
474474
Ok(())
475475
}
476476
}
477+
478+
mod issue_10033 {
479+
#![allow(dead_code)]
480+
use std::{fmt::Display, ops::Deref};
481+
482+
fn _main() {
483+
let f = Foo;
484+
485+
// Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does
486+
// deref to `str`)
487+
foo(&f.to_string());
488+
}
489+
490+
fn foo(s: &str) {
491+
println!("{}", s);
492+
}
493+
494+
struct Foo;
495+
496+
impl Deref for Foo {
497+
type Target = str;
498+
499+
fn deref(&self) -> &Self::Target {
500+
"str"
501+
}
502+
}
503+
504+
impl Display for Foo {
505+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
506+
write!(f, "Foo")
507+
}
508+
}
509+
}

tests/ui/unnecessary_to_owned.rs

+33
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,36 @@ mod issue_10021 {
474474
Ok(())
475475
}
476476
}
477+
478+
mod issue_10033 {
479+
#![allow(dead_code)]
480+
use std::{fmt::Display, ops::Deref};
481+
482+
fn _main() {
483+
let f = Foo;
484+
485+
// Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does
486+
// deref to `str`)
487+
foo(&f.to_string());
488+
}
489+
490+
fn foo(s: &str) {
491+
println!("{}", s);
492+
}
493+
494+
struct Foo;
495+
496+
impl Deref for Foo {
497+
type Target = str;
498+
499+
fn deref(&self) -> &Self::Target {
500+
"str"
501+
}
502+
}
503+
504+
impl Display for Foo {
505+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
506+
write!(f, "Foo")
507+
}
508+
}
509+
}

0 commit comments

Comments
 (0)