Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion clippy_lints/src/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
&& args.iter().any(|a| a.hir_id == expr.hir_id)
&& let Res::Def(DefKind::AssocFn, def_id) = expr.res(cx)
&& cx.tcx.is_diagnostic_item(sym::to_string_method, def_id)
&& let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id)
&& args.type_at(0).is_str()
{
// Detected `ToString::to_string` passed as an argument (generic: any call or method call)
span_lint_and_sugg(
Expand All @@ -425,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
expr.span,
"`ToString::to_string` used as `&str` to `String` converter",
"try",
"ToOwned::to_owned".to_string(),
"str::to_owned".to_string(),
Applicability::MachineApplicable,
);
}
Expand Down
25 changes: 15 additions & 10 deletions tests/ui/str_to_string.fixed
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#![warn(clippy::str_to_string)]

fn main() {
let hello = "hello world".to_owned();
let hello: String = "hello world".to_owned();
//~^ str_to_string

let msg = &hello[..];
let msg: &str = &hello[..];
msg.to_owned();
//~^ str_to_string
}
Expand All @@ -19,7 +19,7 @@ fn issue16271(key: &[u8]) {
};
}

let _value = t!(str::from_utf8(key)).to_owned();
let _value: String = t!(str::from_utf8(key)).to_owned();
//~^ str_to_string
}

Expand All @@ -32,22 +32,27 @@ impl<T> GenericWrapper<T> {
}

fn issue16511(x: Option<&str>) {
let _ = x.map(ToOwned::to_owned);
let _: Option<String> = x.map(str::to_owned);
//~^ str_to_string

let _ = x.map(ToOwned::to_owned);
let _: Option<String> = x.map(str::to_owned);
//~^ str_to_string

let _ = ["a", "b"].iter().map(ToOwned::to_owned);
//~^ str_to_string
// This should not trigger the lint because ToOwned::to_owned would produce &str, not String.
let _: Vec<String> = ["a", "b"].iter().map(ToString::to_string).collect();

fn mapper<F: Fn(&str) -> String>(f: F) -> String {
f("hello")
}
let _ = mapper(ToOwned::to_owned);
let _: String = mapper(str::to_owned);
//~^ str_to_string

let w = GenericWrapper("hello");
let _ = w.mapper(ToOwned::to_owned);
let w: GenericWrapper<&str> = GenericWrapper("hello");
let _: String = w.mapper(str::to_owned);
//~^ str_to_string
}

// No lint: non-str types should not trigger str_to_string. See #16569
fn no_lint_non_str() {
let _: Vec<String> = [1, 2].iter().map(i32::to_string).collect();
}
25 changes: 15 additions & 10 deletions tests/ui/str_to_string.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#![warn(clippy::str_to_string)]

fn main() {
let hello = "hello world".to_string();
let hello: String = "hello world".to_string();
//~^ str_to_string

let msg = &hello[..];
let msg: &str = &hello[..];
msg.to_string();
//~^ str_to_string
}
Expand All @@ -19,7 +19,7 @@ fn issue16271(key: &[u8]) {
};
}

let _value = t!(str::from_utf8(key)).to_string();
let _value: String = t!(str::from_utf8(key)).to_string();
//~^ str_to_string
}

Expand All @@ -32,22 +32,27 @@ impl<T> GenericWrapper<T> {
}

fn issue16511(x: Option<&str>) {
let _ = x.map(ToString::to_string);
let _: Option<String> = x.map(ToString::to_string);
//~^ str_to_string

let _ = x.map(str::to_string);
let _: Option<String> = x.map(str::to_string);
//~^ str_to_string

let _ = ["a", "b"].iter().map(ToString::to_string);
//~^ str_to_string
// This should not trigger the lint because ToOwned::to_owned would produce &str, not String.
let _: Vec<String> = ["a", "b"].iter().map(ToString::to_string).collect();

fn mapper<F: Fn(&str) -> String>(f: F) -> String {
f("hello")
}
let _ = mapper(ToString::to_string);
let _: String = mapper(ToString::to_string);
//~^ str_to_string

let w = GenericWrapper("hello");
let _ = w.mapper(ToString::to_string);
let w: GenericWrapper<&str> = GenericWrapper("hello");
let _: String = w.mapper(ToString::to_string);
//~^ str_to_string
}

// No lint: non-str types should not trigger str_to_string. See #16569
fn no_lint_non_str() {
let _: Vec<String> = [1, 2].iter().map(i32::to_string).collect();
}
44 changes: 19 additions & 25 deletions tests/ui/str_to_string.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: `to_string()` called on a `&str`
--> tests/ui/str_to_string.rs:4:17
--> tests/ui/str_to_string.rs:4:25
|
LL | let hello = "hello world".to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()`
LL | let hello: String = "hello world".to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()`
|
= note: `-D clippy::str-to-string` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::str_to_string)]`
Expand All @@ -14,40 +14,34 @@ LL | msg.to_string();
| ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()`

error: `to_string()` called on a `&str`
--> tests/ui/str_to_string.rs:22:18
--> tests/ui/str_to_string.rs:22:26
|
LL | let _value = t!(str::from_utf8(key)).to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()`
LL | let _value: String = t!(str::from_utf8(key)).to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()`

error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:35:19
--> tests/ui/str_to_string.rs:35:35
|
LL | let _ = x.map(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: Option<String> = x.map(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned`

error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:38:19
--> tests/ui/str_to_string.rs:38:35
|
LL | let _ = x.map(str::to_string);
| ^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: Option<String> = x.map(str::to_string);
| ^^^^^^^^^^^^^^ help: try: `str::to_owned`

error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:41:35
--> tests/ui/str_to_string.rs:47:28
|
LL | let _ = ["a", "b"].iter().map(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: String = mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned`

error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:47:20
--> tests/ui/str_to_string.rs:51:30
|
LL | let _ = mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: String = w.mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned`

error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:51:22
|
LL | let _ = w.mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`

error: aborting due to 8 previous errors
error: aborting due to 7 previous errors