Skip to content

Commit 091fd03

Browse files
committed
Auto merge of #3555 - daxpedda:master, r=oli-obk
Fix `implicit_return` false positives. Fixing some false positives on the `implicit_return` lint. Basically it should only check for missing return statements in `block.stmts.last()` if it's a `break`, otherwise it should skip because it would either be an error, or a false positive in the case of a `loop` (which I'm trying to fix with this PR). **Question:** - I say "we" inside of comments ([`// make sure it's a break, otherwise we want to skip`](https://github.com/rust-lang/rust-clippy/pull/3555/files#diff-11d233fe8c8414214c2b8732b8c9877aR71)). Any alternatives or is that okay? - I named a test [`test_loop_with_nests()`](https://github.com/rust-lang/rust-clippy/blob/6870638c3fb66c2abb20633bf40cc09ccc760047/tests/ui/implicit_return.rs#L54-L64), any better suggestions?
2 parents a416c5e + 6870638 commit 091fd03

File tree

3 files changed

+61
-26
lines changed

3 files changed

+61
-26
lines changed

clippy_lints/src/implicit_return.rs

+21-21
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ declare_clippy_lint! {
4545
pub struct Pass;
4646

4747
impl Pass {
48+
fn lint(cx: &LateContext<'_, '_>, outer_span: syntax_pos::Span, inner_span: syntax_pos::Span, msg: &str) {
49+
span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing return statement", |db| {
50+
if let Some(snippet) = snippet_opt(cx, inner_span) {
51+
db.span_suggestion_with_applicability(
52+
outer_span,
53+
msg,
54+
format!("return {}", snippet),
55+
Applicability::MachineApplicable,
56+
);
57+
}
58+
});
59+
}
60+
4861
fn expr_match(cx: &LateContext<'_, '_>, expr: &rustc::hir::Expr) {
4962
match &expr.node {
5063
// loops could be using `break` instead of `return`
@@ -55,23 +68,19 @@ impl Pass {
5568
// only needed in the case of `break` with `;` at the end
5669
else if let Some(stmt) = block.stmts.last() {
5770
if let rustc::hir::StmtKind::Semi(expr, ..) = &stmt.node {
58-
Self::expr_match(cx, expr);
71+
// make sure it's a break, otherwise we want to skip
72+
if let ExprKind::Break(.., break_expr) = &expr.node {
73+
if let Some(break_expr) = break_expr {
74+
Self::lint(cx, expr.span, break_expr.span, "change `break` to `return` as shown");
75+
}
76+
}
5977
}
6078
}
6179
},
6280
// use `return` instead of `break`
6381
ExprKind::Break(.., break_expr) => {
6482
if let Some(break_expr) = break_expr {
65-
span_lint_and_then(cx, IMPLICIT_RETURN, expr.span, "missing return statement", |db| {
66-
if let Some(snippet) = snippet_opt(cx, break_expr.span) {
67-
db.span_suggestion_with_applicability(
68-
expr.span,
69-
"change `break` to `return` as shown",
70-
format!("return {}", snippet),
71-
Applicability::MachineApplicable,
72-
);
73-
}
74-
});
83+
Self::lint(cx, expr.span, break_expr.span, "change `break` to `return` as shown");
7584
}
7685
},
7786
ExprKind::If(.., if_expr, else_expr) => {
@@ -89,16 +98,7 @@ impl Pass {
8998
// skip if it already has a return statement
9099
ExprKind::Ret(..) => (),
91100
// everything else is missing `return`
92-
_ => span_lint_and_then(cx, IMPLICIT_RETURN, expr.span, "missing return statement", |db| {
93-
if let Some(snippet) = snippet_opt(cx, expr.span) {
94-
db.span_suggestion_with_applicability(
95-
expr.span,
96-
"add `return` as shown",
97-
format!("return {}", snippet),
98-
Applicability::MachineApplicable,
99-
);
100-
}
101-
}),
101+
_ => Self::lint(cx, expr.span, expr.span, "add `return` as shown"),
102102
}
103103
}
104104
}

tests/ui/implicit_return.rs

+23
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,27 @@ fn test_loop() -> bool {
4242
}
4343
}
4444

45+
#[allow(clippy::never_loop)]
46+
fn test_loop_with_block() -> bool {
47+
loop {
48+
{
49+
break true;
50+
}
51+
}
52+
}
53+
54+
#[allow(clippy::never_loop)]
55+
fn test_loop_with_nests() -> bool {
56+
loop {
57+
if true {
58+
break true;
59+
}
60+
else {
61+
let _ = true;
62+
}
63+
}
64+
}
65+
4566
fn test_closure() {
4667
#[rustfmt::skip]
4768
let _ = || { true };
@@ -53,5 +74,7 @@ fn main() {
5374
let _ = test_if_block();
5475
let _ = test_match(true);
5576
let _ = test_loop();
77+
let _ = test_loop_with_block();
78+
let _ = test_loop_with_nests();
5679
test_closure();
5780
}

tests/ui/implicit_return.stderr

+17-5
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,28 @@ error: missing return statement
3737
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
3838

3939
error: missing return statement
40-
--> $DIR/implicit_return.rs:47:18
40+
--> $DIR/implicit_return.rs:49:13
4141
|
42-
47 | let _ = || { true };
42+
49 | break true;
43+
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
44+
45+
error: missing return statement
46+
--> $DIR/implicit_return.rs:58:13
47+
|
48+
58 | break true;
49+
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
50+
51+
error: missing return statement
52+
--> $DIR/implicit_return.rs:68:18
53+
|
54+
68 | let _ = || { true };
4355
| ^^^^ help: add `return` as shown: `return true`
4456

4557
error: missing return statement
46-
--> $DIR/implicit_return.rs:48:16
58+
--> $DIR/implicit_return.rs:69:16
4759
|
48-
48 | let _ = || true;
60+
69 | let _ = || true;
4961
| ^^^^ help: add `return` as shown: `return true`
5062

51-
error: aborting due to 8 previous errors
63+
error: aborting due to 10 previous errors
5264

0 commit comments

Comments
 (0)