Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit dfb4ff8

Browse files
committed
[question_mark]: also trigger on return statements
1 parent dd857f8 commit dfb4ff8

7 files changed

+59
-15
lines changed

clippy_lints/src/matches/manual_utils.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ where
6363
return None;
6464
}
6565

66-
let Some(some_expr) = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt) else {
67-
return None;
68-
};
66+
let some_expr = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt)?;
6967

7068
// These two lints will go back and forth with each other.
7169
if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit

clippy_lints/src/matches/redundant_pattern_match.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,7 @@ fn find_method_and_type<'tcx>(
128128

129129
if is_wildcard || is_rest {
130130
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
131-
let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else {
132-
return None;
133-
};
131+
let id = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id))?;
134132
let lang_items = cx.tcx.lang_items();
135133
if Some(id) == lang_items.result_ok_variant() {
136134
Some(("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)))

clippy_lints/src/question_mark.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,32 @@ enum IfBlockType<'hir> {
9696
),
9797
}
9898

99+
fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir Expr<'hir>> {
100+
if let Block {
101+
stmts: &[],
102+
expr: Some(els),
103+
..
104+
} = block
105+
{
106+
Some(els)
107+
} else if let [stmt] = block.stmts
108+
&& let StmtKind::Semi(expr) = stmt.kind
109+
&& let ExprKind::Ret(..) = expr.kind
110+
{
111+
Some(expr)
112+
} else {
113+
None
114+
}
115+
}
116+
99117
fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
100118
if let StmtKind::Local(Local {
101119
pat,
102120
init: Some(init_expr),
103121
els: Some(els),
104122
..
105123
}) = stmt.kind
106-
&& let Block {
107-
stmts: &[],
108-
expr: Some(els),
109-
..
110-
} = els
124+
&& let Some(els) = find_let_else_ret_expression(els)
111125
&& let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els)
112126
{
113127
let mut applicability = Applicability::MaybeIncorrect;

clippy_lints/src/undocumented_unsafe_blocks.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos
680680
})
681681
.filter(|(_, text)| !text.is_empty());
682682

683-
let Some((line_start, line)) = lines.next() else {
684-
return None;
685-
};
683+
let (line_start, line) = lines.next()?;
686684
// Check for a sequence of line comments.
687685
if line.starts_with("//") {
688686
let (mut line, mut line_start) = (line, line_start);

tests/ui/manual_let_else_question_mark.fixed

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,16 @@ fn foo() -> Option<()> {
6060

6161
Some(())
6262
}
63+
64+
// lint not just `return None`, but also `return None;` (note the semicolon)
65+
fn issue11993(y: Option<i32>) -> Option<i32> {
66+
let x = y?;
67+
68+
// don't lint: more than one statement in the else body
69+
let Some(x) = y else {
70+
todo!();
71+
return None;
72+
};
73+
74+
None
75+
}

tests/ui/manual_let_else_question_mark.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,18 @@ fn foo() -> Option<()> {
6565

6666
Some(())
6767
}
68+
69+
// lint not just `return None`, but also `return None;` (note the semicolon)
70+
fn issue11993(y: Option<i32>) -> Option<i32> {
71+
let Some(x) = y else {
72+
return None;
73+
};
74+
75+
// don't lint: more than one statement in the else body
76+
let Some(x) = y else {
77+
todo!();
78+
return None;
79+
};
80+
81+
None
82+
}

tests/ui/manual_let_else_question_mark.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,13 @@ error: this could be rewritten as `let...else`
5353
LL | let v = if let Some(v_some) = g() { v_some } else { return None };
5454
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return None };`
5555

56-
error: aborting due to 6 previous errors
56+
error: this `let...else` may be rewritten with the `?` operator
57+
--> $DIR/manual_let_else_question_mark.rs:71:5
58+
|
59+
LL | / let Some(x) = y else {
60+
LL | | return None;
61+
LL | | };
62+
| |______^ help: replace it with: `let x = y?;`
63+
64+
error: aborting due to 7 previous errors
5765

0 commit comments

Comments
 (0)