1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::higher
;
3 use clippy_utils
::is_res_lang_ctor
;
4 use clippy_utils
::source
::snippet_with_context
;
5 use clippy_utils
::ty
::is_type_diagnostic_item
;
6 use if_chain
::if_chain
;
7 use rustc_errors
::Applicability
;
8 use rustc_hir
::{Expr, ExprKind, LangItem, PatKind}
;
9 use rustc_lint
::{LateContext, LateLintPass}
;
10 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
13 declare_clippy_lint
! {
15 /// Checks for unnecessary `ok()` in `while let`.
17 /// ### Why is this bad?
18 /// Calling `ok()` in `while let` is unnecessary, instead match
23 /// while let Some(value) = iter.next().ok() {
27 /// if let Some(value) = iter.next().ok() {
33 /// while let Ok(value) = iter.next() {
37 /// if let Ok(value) = iter.next() {
41 #[clippy::version = "1.57.0"]
44 "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
47 declare_lint_pass
!(MatchResultOk
=> [MATCH_RESULT_OK
]);
49 impl<'tcx
> LateLintPass
<'tcx
> for MatchResultOk
{
50 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) {
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")
61 if let ExprKind
::MethodCall(ok_path
, recv
, [], ..) = let_expr
.kind
; //check is expr.ok() has type Result<T,E>.ok(, _)
62 if let PatKind
::TupleStruct(ref pat_path
, [ok_pat
], _
) = let_pat
.kind
; //get operation
63 if ok_path
.ident
.as_str() == "ok";
64 if is_type_diagnostic_item(cx
, cx
.typeck_results().expr_ty(recv
), sym
::Result
);
65 if is_res_lang_ctor(cx
, cx
.qpath_res(pat_path
, let_pat
.hir_id
), LangItem
::OptionSome
);
66 let ctxt
= expr
.span
.ctxt();
67 if let_expr
.span
.ctxt() == ctxt
;
68 if let_pat
.span
.ctxt() == ctxt
;
70 let mut applicability
= Applicability
::MachineApplicable
;
71 let some_expr_string
= snippet_with_context(cx
, ok_pat
.span
, ctxt
, "", &mut applicability
).0;
72 let trimmed_ok
= snippet_with_context(cx
, recv
.span
, ctxt
, "", &mut applicability
).0;
74 "{ifwhile} let Ok({some_expr_string}) = {}",
75 trimmed_ok
.trim().trim_end_matches('
.'
),
80 expr
.span
.with_hi(let_expr
.span
.hi()),
81 "matching on `Some` with `ok()` is redundant",
82 &format
!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"),