Skip to content

Commit 9035264

Browse files
committed
Add suggestion in if_let_some_result
1 parent 0a7003e commit 9035264

File tree

4 files changed

+101
-13
lines changed

4 files changed

+101
-13
lines changed

clippy_lints/src/ok_if_let.rs

+26-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint};
1+
use crate::utils::{match_type, method_chain_args, paths, snippet, snippet_with_applicability, span_lint_and_sugg};
22
use if_chain::if_chain;
3+
use rustc_errors::Applicability;
34
use rustc_hir::*;
45
use rustc_lint::{LateContext, LateLintPass};
56
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -40,18 +41,36 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet {
4041
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
4142
if_chain! { //begin checking variables
4243
if let ExprKind::Match(ref op, ref body, ref source) = expr.kind; //test if expr is a match
43-
if let MatchSource::IfLetDesugar { .. } = *source; //test if it is an If Let
44-
if let ExprKind::MethodCall(_, _, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok()
44+
if let MatchSource::IfLetDesugar { contains_else_clause } = *source; //test if it is an If Let
45+
if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok()
4546
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation
4647
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
4748

4849
then {
4950
let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
50-
let some_expr_string = snippet(cx, y[0].span, "");
51+
let mut applicability = Applicability::MachineApplicable;
52+
let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
53+
let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability);
54+
let mut sugg = format!(
55+
"if let Ok({}) = {} {}",
56+
some_expr_string,
57+
// FIXME(JohnTitor): this trimming is hacky, probably can improve it
58+
trimmed_ok.trim_matches('.'),
59+
snippet(cx, body[0].span, ".."),
60+
);
61+
if contains_else_clause {
62+
sugg = format!("{} else {}", sugg, snippet(cx, body[1].span, ".."));
63+
}
5164
if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type {
52-
span_help_and_lint(cx, IF_LET_SOME_RESULT, expr.span,
53-
"Matching on `Some` with `ok()` is redundant",
54-
&format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string));
65+
span_lint_and_sugg(
66+
cx,
67+
IF_LET_SOME_RESULT,
68+
expr.span,
69+
"Matching on `Some` with `ok()` is redundant",
70+
&format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
71+
sugg,
72+
applicability,
73+
);
5574
}
5675
}
5776
}

tests/ui/ok_if_let.fixed

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::if_let_some_result)]
4+
5+
fn str_to_int(x: &str) -> i32 {
6+
if let Ok(y) = x.parse() {
7+
y
8+
} else {
9+
0
10+
}
11+
}
12+
13+
fn str_to_int_ok(x: &str) -> i32 {
14+
if let Ok(y) = x.parse() {
15+
y
16+
} else {
17+
0
18+
}
19+
}
20+
21+
fn nested_some_no_else(x: &str) -> i32 {
22+
{
23+
if let Ok(y) = x.parse() {
24+
return y;
25+
};
26+
0
27+
}
28+
}
29+
30+
fn main() {
31+
let x = str_to_int("1");
32+
let y = str_to_int_ok("2");
33+
let z = nested_some_no_else("3");
34+
println!("{}{}{}", x, y, z);
35+
}

tests/ui/ok_if_let.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
13
#![warn(clippy::if_let_some_result)]
24

35
fn str_to_int(x: &str) -> i32 {
@@ -16,8 +18,18 @@ fn str_to_int_ok(x: &str) -> i32 {
1618
}
1719
}
1820

21+
fn nested_some_no_else(x: &str) -> i32 {
22+
{
23+
if let Some(y) = x.parse().ok() {
24+
return y;
25+
};
26+
0
27+
}
28+
}
29+
1930
fn main() {
20-
let y = str_to_int("1");
21-
let z = str_to_int_ok("2");
22-
println!("{}{}", y, z);
31+
let x = str_to_int("1");
32+
let y = str_to_int_ok("2");
33+
let z = nested_some_no_else("3");
34+
println!("{}{}{}", x, y, z);
2335
}

tests/ui/ok_if_let.stderr

+25-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: Matching on `Some` with `ok()` is redundant
2-
--> $DIR/ok_if_let.rs:4:5
2+
--> $DIR/ok_if_let.rs:6:5
33
|
44
LL | / if let Some(y) = x.parse().ok() {
55
LL | | y
@@ -9,7 +9,29 @@ LL | | }
99
| |_____^
1010
|
1111
= note: `-D clippy::if-let-some-result` implied by `-D warnings`
12-
= help: Consider matching on `Ok(y)` and removing the call to `ok` instead
12+
help: Consider matching on `Ok(y)` and removing the call to `ok` instead
13+
|
14+
LL | if let Ok(y) = x.parse() {
15+
LL | y
16+
LL | } else {
17+
LL | 0
18+
LL | }
19+
|
20+
21+
error: Matching on `Some` with `ok()` is redundant
22+
--> $DIR/ok_if_let.rs:23:9
23+
|
24+
LL | / if let Some(y) = x.parse().ok() {
25+
LL | | return y;
26+
LL | | };
27+
| |_________^
28+
|
29+
help: Consider matching on `Ok(y)` and removing the call to `ok` instead
30+
|
31+
LL | if let Ok(y) = x.parse() {
32+
LL | return y;
33+
LL | };
34+
|
1335

14-
error: aborting due to previous error
36+
error: aborting due to 2 previous errors
1537

0 commit comments

Comments
 (0)