mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-21 17:52:12 +03:00
fix(str_to_string): false positive non-str types (#16571)
Fix rust-lang/rust-clippy#16569 bug introduced in rust-lang/rust-clippy#16512 changelog: [`str_to_string`]: fix false positive r? @samueltardieu
This commit is contained in:
@@ -417,6 +417,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
||||
&& 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(
|
||||
@@ -425,7 +427,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
||||
expr.span,
|
||||
"`ToString::to_string` used as `&str` to `String` converter",
|
||||
"try",
|
||||
"ToOwned::to_owned".to_string(),
|
||||
"str::to_owned".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+15
-10
@@ -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
|
||||
}
|
||||
@@ -19,7 +19,7 @@ macro_rules! t {
|
||||
};
|
||||
}
|
||||
|
||||
let _value = t!(str::from_utf8(key)).to_string();
|
||||
let _value: String = t!(str::from_utf8(key)).to_string();
|
||||
//~^ str_to_string
|
||||
}
|
||||
|
||||
@@ -32,22 +32,27 @@ fn mapper<U, F: FnOnce(T) -> U>(self, f: F) -> U {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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)]`
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user