Skip to content

Commit 89f9644

Browse files
committed
and check for Result
1 parent 540b69c commit 89f9644

File tree

3 files changed

+39
-29
lines changed

3 files changed

+39
-29
lines changed

clippy_lints/src/option_if_let_else.rs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::sugg::Sugg;
3-
use clippy_utils::ty::is_type_diagnostic_item;
43
use clippy_utils::{
54
can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks,
65
peel_hir_expr_while, CaptureKind,
76
};
87
use if_chain::if_chain;
98
use rustc_errors::Applicability;
10-
use rustc_hir::LangItem::{OptionNone, OptionSome};
9+
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
1110
use rustc_hir::{
1211
def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp,
1312
};
1413
use rustc_lint::{LateContext, LateLintPass};
1514
use rustc_session::{declare_lint_pass, declare_tool_lint};
16-
use rustc_span::sym;
1715

1816
declare_clippy_lint! {
1917
/// ### What it does
@@ -74,16 +72,6 @@ declare_clippy_lint! {
7472

7573
declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
7674

77-
/// Returns true iff the given expression is the result of calling `Result::ok`
78-
fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
79-
if let ExprKind::MethodCall(path, &[ref receiver], _) = &expr.kind {
80-
path.ident.name.as_str() == "ok"
81-
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Result)
82-
} else {
83-
false
84-
}
85-
}
86-
8775
/// A struct containing information about occurrences of construct that this lint detects
8876
///
8977
/// Such as:
@@ -130,9 +118,8 @@ fn try_get_option_occurence<'tcx>(
130118
ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr,
131119
_ => expr,
132120
};
121+
let inner_pat = try_get_inner_pat(cx, pat)?;
133122
if_chain! {
134-
if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already
135-
let inner_pat = try_get_inner_pat(cx, pat)?;
136123
if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind;
137124
if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
138125
if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
@@ -185,7 +172,7 @@ fn try_get_option_occurence<'tcx>(
185172

186173
fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> {
187174
if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind {
188-
if is_lang_ctor(cx, qpath, OptionSome) {
175+
if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk) {
189176
return Some(inner_pat);
190177
}
191178
}
@@ -224,9 +211,9 @@ fn try_convert_match<'tcx>(
224211
arms: &[Arm<'tcx>],
225212
) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
226213
if arms.len() == 2 {
227-
return if is_none_arm(cx, &arms[1]) {
214+
return if is_none_or_err_arm(cx, &arms[1]) {
228215
Some((arms[0].pat, arms[0].body, arms[1].body))
229-
} else if is_none_arm(cx, &arms[0]) {
216+
} else if is_none_or_err_arm(cx, &arms[0]) {
230217
Some((arms[1].pat, arms[1].body, arms[0].body))
231218
} else {
232219
None
@@ -235,9 +222,12 @@ fn try_convert_match<'tcx>(
235222
None
236223
}
237224

238-
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
225+
fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
239226
match arm.pat.kind {
240227
PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
228+
PatKind::TupleStruct(ref qpath, [first_pat], _) => {
229+
is_lang_ctor(cx, qpath, ResultErr) && matches!(first_pat.kind, PatKind::Wild)
230+
},
241231
PatKind::Wild => true,
242232
_ => false,
243233
}

tests/ui/option_if_let_else.fixed

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,7 @@ fn main() {
184184
let _ = Some(10).map_or(5, |a| a + 1);
185185

186186
let res: Result<i32, i32> = Ok(5);
187-
let _ = match res {
188-
Ok(a) => a + 1,
189-
_ => 1,
190-
};
191-
let _ = match res {
192-
Err(_) => 1,
193-
Ok(a) => a + 1,
194-
};
195-
let _ = if let Ok(a) = res { a + 1 } else { 5 };
187+
let _ = res.map_or(1, |a| a + 1);
188+
let _ = res.map_or(1, |a| a + 1);
189+
let _ = res.map_or(5, |a| a + 1);
196190
}

tests/ui/option_if_let_else.stderr

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,5 +226,31 @@ LL | | None => 5,
226226
LL | | };
227227
| |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
228228

229-
error: aborting due to 17 previous errors
229+
error: use Option::map_or instead of an if let/else
230+
--> $DIR/option_if_let_else.rs:222:13
231+
|
232+
LL | let _ = match res {
233+
| _____________^
234+
LL | | Ok(a) => a + 1,
235+
LL | | _ => 1,
236+
LL | | };
237+
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
238+
239+
error: use Option::map_or instead of an if let/else
240+
--> $DIR/option_if_let_else.rs:226:13
241+
|
242+
LL | let _ = match res {
243+
| _____________^
244+
LL | | Err(_) => 1,
245+
LL | | Ok(a) => a + 1,
246+
LL | | };
247+
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
248+
249+
error: use Option::map_or instead of an if let/else
250+
--> $DIR/option_if_let_else.rs:230:13
251+
|
252+
LL | let _ = if let Ok(a) = res { a + 1 } else { 5 };
253+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
254+
255+
error: aborting due to 20 previous errors
230256

0 commit comments

Comments
 (0)