|
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}; |
2 | 2 | use if_chain::if_chain;
|
| 3 | +use rustc_errors::Applicability; |
3 | 4 | use rustc_hir::*;
|
4 | 5 | use rustc_lint::{LateContext, LateLintPass};
|
5 | 6 | use rustc_session::{declare_lint_pass, declare_tool_lint};
|
@@ -40,18 +41,36 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet {
|
40 | 41 | fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
|
41 | 42 | if_chain! { //begin checking variables
|
42 | 43 | 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() |
45 | 46 | if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation
|
46 | 47 | if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
|
47 | 48 |
|
48 | 49 | then {
|
49 | 50 | 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 | + } |
51 | 64 | 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 | + ); |
55 | 74 | }
|
56 | 75 | }
|
57 | 76 | }
|
|
0 commit comments