Skip to content

Commit 830f1c5

Browse files
committed
Auto merge of #11994 - y21:issue11993-fn, r=xFrednet
[`question_mark`]: also trigger on `return` statements This fixes the false negative mentioned in #11993: the lint only used to check for `return` expressions, and not a statement containing a `return` expression (doesn't close the issue tho since there's still a useful suggestion that we could make, which is to suggest `.ok_or()?`/`.ok_or_else()?` for `else { return Err(..) }`) changelog: [`question_mark`]: also trigger on `return` statements
2 parents 618fd4b + e44caea commit 830f1c5

7 files changed

+78
-17
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: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
88
use clippy_utils::{
99
eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
1010
is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
11-
peel_blocks_with_stmt,
11+
peel_blocks_with_stmt, span_contains_comment,
1212
};
1313
use rustc_errors::Applicability;
1414
use rustc_hir::def::Res;
@@ -96,19 +96,34 @@ 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
111-
&& let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els)
124+
&& let Some(ret) = find_let_else_ret_expression(els)
125+
&& let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret)
126+
&& !span_contains_comment(cx.tcx.sess.source_map(), els.span)
112127
{
113128
let mut applicability = Applicability::MaybeIncorrect;
114129
let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability);

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: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,24 @@ 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+
let Some(x) = y else {
75+
// Roses are red,
76+
// violets are blue,
77+
// please keep this comment,
78+
// it's art, you know?
79+
return None;
80+
};
81+
82+
None
83+
}

tests/ui/manual_let_else_question_mark.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,26 @@ 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+
let Some(x) = y else {
82+
// Roses are red,
83+
// violets are blue,
84+
// please keep this comment,
85+
// it's art, you know?
86+
return None;
87+
};
88+
89+
None
90+
}

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)