Skip to content

Commit 0e4b6c8

Browse files
Make string_to_string emit a suggestion when cloned can be used
1 parent 0ffc6cf commit 0e4b6c8

File tree

6 files changed

+66
-49
lines changed

6 files changed

+66
-49
lines changed

clippy_lints/src/strings.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
1+
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
22
use clippy_utils::source::{snippet, snippet_with_applicability};
33
use clippy_utils::ty::is_type_lang_item;
44
use clippy_utils::{
@@ -440,14 +440,14 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]);
440440

441441
fn is_parent_map_like(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<rustc_span::Span> {
442442
if let Some(parent_expr) = get_parent_expr(cx, expr)
443-
&& let ExprKind::MethodCall(name, ..) = parent_expr.kind
443+
&& let ExprKind::MethodCall(name, _, _, parent_span) = parent_expr.kind
444444
&& name.ident.name == sym::map
445445
&& let Some(caller_def_id) = cx.typeck_results().type_dependent_def_id(parent_expr.hir_id)
446446
&& (clippy_utils::is_diag_item_method(cx, caller_def_id, sym::Result)
447447
|| clippy_utils::is_diag_item_method(cx, caller_def_id, sym::Option)
448448
|| clippy_utils::is_diag_trait_item(cx, caller_def_id, sym::Iterator))
449449
{
450-
Some(parent_expr.span)
450+
Some(parent_span)
451451
} else {
452452
None
453453
}
@@ -464,13 +464,14 @@ fn is_called_from_map_like(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<rust
464464
}
465465

466466
fn suggest_cloned_string_to_string(cx: &LateContext<'_>, span: rustc_span::Span) {
467-
span_lint_and_help(
467+
span_lint_and_sugg(
468468
cx,
469469
STRING_TO_STRING,
470470
span,
471471
"`to_string()` called on a `String`",
472-
None,
473-
"consider using `.cloned()`",
472+
"try",
473+
"cloned()".to_string(),
474+
Applicability::MachineApplicable,
474475
);
475476
}
476477

tests/ui/string_to_string.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
#![warn(clippy::string_to_string)]
2-
#![allow(clippy::redundant_clone)]
2+
#![allow(clippy::redundant_clone, clippy::unnecessary_literal_unwrap)]
33

44
fn main() {
55
let mut message = String::from("Hello");
66
let mut v = message.to_string();
77
//~^ string_to_string
8+
9+
let variable1 = String::new();
10+
let v = &variable1;
11+
let variable2 = Some(v);
12+
let _ = variable2.map(|x| {
13+
println!();
14+
x.to_string()
15+
});
16+
//~^^ string_to_string
17+
18+
// Should not lint.
19+
let x = Some(String::new());
20+
let _ = x.unwrap_or_else(|| v.to_string());
21+
//~^ string_to_string
822
}

tests/ui/string_to_string.stderr

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,21 @@ LL | let mut v = message.to_string();
88
= note: `-D clippy::string-to-string` implied by `-D warnings`
99
= help: to override `-D warnings` add `#[allow(clippy::string_to_string)]`
1010

11-
error: aborting due to 1 previous error
11+
error: `to_string()` called on a `String`
12+
--> tests/ui/string_to_string.rs:14:9
13+
|
14+
LL | x.to_string()
15+
| ^^^^^^^^^^^^^
16+
|
17+
= help: consider using `.clone()`
18+
19+
error: `to_string()` called on a `String`
20+
--> tests/ui/string_to_string.rs:20:33
21+
|
22+
LL | let _ = x.unwrap_or_else(|| v.to_string());
23+
| ^^^^^^^^^^^^^
24+
|
25+
= help: consider using `.clone()`
26+
27+
error: aborting due to 3 previous errors
1228

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![deny(clippy::string_to_string)]
2+
#![allow(clippy::unnecessary_literal_unwrap, clippy::useless_vec, clippy::iter_cloned_collect)]
3+
4+
fn main() {
5+
let variable1 = String::new();
6+
let v = &variable1;
7+
let variable2 = Some(v);
8+
let _ = variable2.cloned();
9+
//~^ string_to_string
10+
let _ = variable2.cloned();
11+
//~^ string_to_string
12+
13+
let _ = vec![String::new()].iter().cloned().collect::<Vec<_>>();
14+
//~^ string_to_string
15+
let _ = vec![String::new()].iter().cloned().collect::<Vec<_>>();
16+
//~^ string_to_string
17+
}

tests/ui/string_to_string_in_map.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
#![deny(clippy::string_to_string)]
2-
#![allow(clippy::unnecessary_literal_unwrap, clippy::useless_vec)]
2+
#![allow(clippy::unnecessary_literal_unwrap, clippy::useless_vec, clippy::iter_cloned_collect)]
33

44
fn main() {
55
let variable1 = String::new();
66
let v = &variable1;
77
let variable2 = Some(v);
88
let _ = variable2.map(String::to_string);
99
//~^ string_to_string
10-
let _ = variable2.map(|x| {
11-
println!();
12-
x.to_string()
13-
});
14-
//~^^ string_to_string
1510
let _ = variable2.map(|x| x.to_string());
1611
//~^ string_to_string
17-
let x = Some(String::new());
18-
let _ = x.unwrap_or_else(|| v.to_string());
19-
//~^ string_to_string
2012

2113
let _ = vec![String::new()].iter().map(String::to_string).collect::<Vec<_>>();
2214
//~^ string_to_string
Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,32 @@
11
error: `to_string()` called on a `String`
2-
--> tests/ui/string_to_string_in_map.rs:8:13
2+
--> tests/ui/string_to_string_in_map.rs:8:23
33
|
44
LL | let _ = variable2.map(String::to_string);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
66
|
7-
= help: consider using `.cloned()`
87
note: the lint level is defined here
98
--> tests/ui/string_to_string_in_map.rs:1:9
109
|
1110
LL | #![deny(clippy::string_to_string)]
1211
| ^^^^^^^^^^^^^^^^^^^^^^^^
1312

1413
error: `to_string()` called on a `String`
15-
--> tests/ui/string_to_string_in_map.rs:12:9
16-
|
17-
LL | x.to_string()
18-
| ^^^^^^^^^^^^^
19-
|
20-
= help: consider using `.clone()`
21-
22-
error: `to_string()` called on a `String`
23-
--> tests/ui/string_to_string_in_map.rs:15:13
14+
--> tests/ui/string_to_string_in_map.rs:10:23
2415
|
2516
LL | let _ = variable2.map(|x| x.to_string());
26-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27-
|
28-
= help: consider using `.cloned()`
17+
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
2918

3019
error: `to_string()` called on a `String`
31-
--> tests/ui/string_to_string_in_map.rs:18:33
32-
|
33-
LL | let _ = x.unwrap_or_else(|| v.to_string());
34-
| ^^^^^^^^^^^^^
35-
|
36-
= help: consider using `.clone()`
37-
38-
error: `to_string()` called on a `String`
39-
--> tests/ui/string_to_string_in_map.rs:21:13
20+
--> tests/ui/string_to_string_in_map.rs:13:40
4021
|
4122
LL | let _ = vec![String::new()].iter().map(String::to_string).collect::<Vec<_>>();
42-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43-
|
44-
= help: consider using `.cloned()`
23+
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
4524

4625
error: `to_string()` called on a `String`
47-
--> tests/ui/string_to_string_in_map.rs:23:13
26+
--> tests/ui/string_to_string_in_map.rs:15:40
4827
|
4928
LL | let _ = vec![String::new()].iter().map(|x| x.to_string()).collect::<Vec<_>>();
50-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
51-
|
52-
= help: consider using `.cloned()`
29+
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
5330

54-
error: aborting due to 6 previous errors
31+
error: aborting due to 4 previous errors
5532

0 commit comments

Comments
 (0)