]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/match_result_ok.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / match_result_ok.rs
CommitLineData
cdc7bbd5 1use clippy_utils::diagnostics::span_lint_and_sugg;
94222f64 2use clippy_utils::higher;
cdc7bbd5
XL
3use clippy_utils::method_chain_args;
4use clippy_utils::source::snippet_with_applicability;
5use clippy_utils::ty::is_type_diagnostic_item;
f20569fa
XL
6use if_chain::if_chain;
7use rustc_errors::Applicability;
94222f64 8use rustc_hir::{Expr, ExprKind, PatKind, QPath};
f20569fa
XL
9use rustc_lint::{LateContext, LateLintPass};
10use rustc_session::{declare_lint_pass, declare_tool_lint};
11use rustc_span::sym;
12
13declare_clippy_lint! {
94222f64 14 /// ### What it does
c295e0f8 15 /// Checks for unnecessary `ok()` in `while let`.
f20569fa 16 ///
94222f64 17 /// ### Why is this bad?
c295e0f8 18 /// Calling `ok()` in `while let` is unnecessary, instead match
f20569fa
XL
19 /// on `Ok(pat)`
20 ///
94222f64 21 /// ### Example
f20569fa 22 /// ```ignore
c295e0f8
XL
23 /// while let Some(value) = iter.next().ok() {
24 /// vec.push(value)
f20569fa 25 /// }
f20569fa 26 ///
c295e0f8
XL
27 /// if let Some(valie) = iter.next().ok() {
28 /// vec.push(value)
29 /// }
30 /// ```
31 /// Use instead:
f20569fa 32 /// ```ignore
c295e0f8
XL
33 /// while let Ok(value) = iter.next() {
34 /// vec.push(value)
35 /// }
36 ///
37 /// if let Ok(value) = iter.next() {
3c0e092e 38 /// vec.push(value)
f20569fa
XL
39 /// }
40 /// ```
a2a8927a 41 #[clippy::version = "1.57.0"]
c295e0f8 42 pub MATCH_RESULT_OK,
f20569fa 43 style,
c295e0f8 44 "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
f20569fa
XL
45}
46
c295e0f8 47declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]);
f20569fa 48
c295e0f8 49impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
f20569fa 50 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
c295e0f8
XL
51 let (let_pat, let_expr, ifwhile) =
52 if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
53 (let_pat, let_expr, "if")
54 } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
55 (let_pat, let_expr, "while")
56 } else {
57 return;
58 };
59
60 if_chain! {
5099ac24 61 if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
c295e0f8 62 if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
94222f64 63 if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
c295e0f8 64 if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
f20569fa
XL
65 if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
66
67 then {
c295e0f8 68
f20569fa
XL
69 let mut applicability = Applicability::MachineApplicable;
70 let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
5099ac24 71 let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_path.ident.span), "", &mut applicability);
f20569fa 72 let sugg = format!(
c295e0f8
XL
73 "{} let Ok({}) = {}",
74 ifwhile,
f20569fa
XL
75 some_expr_string,
76 trimmed_ok.trim().trim_end_matches('.'),
77 );
78 span_lint_and_sugg(
79 cx,
c295e0f8 80 MATCH_RESULT_OK,
94222f64 81 expr.span.with_hi(let_expr.span.hi()),
f20569fa
XL
82 "matching on `Some` with `ok()` is redundant",
83 &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
84 sugg,
85 applicability,
86 );
87 }
88 }
89 }
90}