Skip to content

Commit 269b913

Browse files
Better handle blocks with just one expression
1 parent 0e4b6c8 commit 269b913

File tree

6 files changed

+33
-12
lines changed

6 files changed

+33
-12
lines changed

clippy_lints/src/strings.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use rustc_session::declare_lint_pass;
1414
use rustc_span::source_map::Spanned;
1515
use rustc_span::sym;
1616

17+
use std::ops::ControlFlow;
18+
1719
declare_clippy_lint! {
1820
/// ### What it does
1921
/// Checks for string appends of the form `x = x + y` (without
@@ -454,13 +456,21 @@ fn is_parent_map_like(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<rustc_spa
454456
}
455457

456458
fn is_called_from_map_like(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<rustc_span::Span> {
457-
let parent = get_parent_expr(cx, expr)?;
458-
459-
if matches!(parent.kind, ExprKind::Closure(_)) {
460-
is_parent_map_like(cx, parent)
461-
} else {
462-
None
463-
}
459+
// Look for a closure as parent of `expr`, discarding simple blocks
460+
let parent_closure = cx
461+
.tcx
462+
.hir_parent_iter(expr.hir_id)
463+
.try_fold(expr.hir_id, |child_hir_id, (_, node)| match node {
464+
// Check that the child expression is the only expression in the block
465+
Node::Block(block) if block.stmts.is_empty() && block.expr.map(|e| e.hir_id) == Some(child_hir_id) => {
466+
ControlFlow::Continue(block.hir_id)
467+
},
468+
Node::Expr(expr) if matches!(expr.kind, ExprKind::Block(..)) => ControlFlow::Continue(expr.hir_id),
469+
Node::Expr(expr) if matches!(expr.kind, ExprKind::Closure(_)) => ControlFlow::Break(Some(expr)),
470+
_ => ControlFlow::Break(None),
471+
})
472+
.break_value()?;
473+
is_parent_map_like(cx, parent_closure?)
464474
}
465475

466476
fn suggest_cloned_string_to_string(cx: &LateContext<'_>, span: rustc_span::Span) {

tests/ui/string_to_string.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ fn main() {
1515
});
1616
//~^^ string_to_string
1717

18-
// Should not lint.
1918
let x = Some(String::new());
2019
let _ = x.unwrap_or_else(|| v.to_string());
2120
//~^ string_to_string

tests/ui/string_to_string.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ LL | x.to_string()
1717
= help: consider using `.clone()`
1818

1919
error: `to_string()` called on a `String`
20-
--> tests/ui/string_to_string.rs:20:33
20+
--> tests/ui/string_to_string.rs:19:33
2121
|
2222
LL | let _ = x.unwrap_or_else(|| v.to_string());
2323
| ^^^^^^^^^^^^^

tests/ui/string_to_string_in_map.fixed

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ fn main() {
99
//~^ string_to_string
1010
let _ = variable2.cloned();
1111
//~^ string_to_string
12+
#[rustfmt::skip]
13+
let _ = variable2.cloned();
14+
//~^ string_to_string
1215

1316
let _ = vec![String::new()].iter().cloned().collect::<Vec<_>>();
1417
//~^ string_to_string

tests/ui/string_to_string_in_map.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ fn main() {
99
//~^ string_to_string
1010
let _ = variable2.map(|x| x.to_string());
1111
//~^ string_to_string
12+
#[rustfmt::skip]
13+
let _ = variable2.map(|x| { x.to_string() });
14+
//~^ string_to_string
1215

1316
let _ = vec![String::new()].iter().map(String::to_string).collect::<Vec<_>>();
1417
//~^ string_to_string

tests/ui/string_to_string_in_map.stderr

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,22 @@ LL | let _ = variable2.map(|x| x.to_string());
1717
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
1818

1919
error: `to_string()` called on a `String`
20-
--> tests/ui/string_to_string_in_map.rs:13:40
20+
--> tests/ui/string_to_string_in_map.rs:13:23
21+
|
22+
LL | let _ = variable2.map(|x| { x.to_string() });
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
24+
25+
error: `to_string()` called on a `String`
26+
--> tests/ui/string_to_string_in_map.rs:16:40
2127
|
2228
LL | let _ = vec![String::new()].iter().map(String::to_string).collect::<Vec<_>>();
2329
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
2430

2531
error: `to_string()` called on a `String`
26-
--> tests/ui/string_to_string_in_map.rs:15:40
32+
--> tests/ui/string_to_string_in_map.rs:18:40
2733
|
2834
LL | let _ = vec![String::new()].iter().map(|x| x.to_string()).collect::<Vec<_>>();
2935
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
3036

31-
error: aborting due to 4 previous errors
37+
error: aborting due to 5 previous errors
3238

0 commit comments

Comments
 (0)