1 use super::utils::make_iterator_snippet;
2 use super::MANUAL_FLATTEN;
3 use clippy_utils::diagnostics::span_lint_and_then;
4 use clippy_utils::{is_ok_ctor, is_some_ctor, path_to_local_id};
5 use if_chain::if_chain;
6 use rustc_errors::Applicability;
7 use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, StmtKind};
8 use rustc_lint::LateContext;
10 use rustc_span::source_map::Span;
12 /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the
13 /// iterator element is used.
14 pub(super) fn check<'tcx>(
15 cx: &LateContext<'tcx>,
21 if let ExprKind::Block(ref block, _) = body.kind {
22 // Ensure the `if let` statement is the only expression or statement in the for-loop
23 let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() {
24 let match_stmt = &block.stmts[0];
25 if let StmtKind::Semi(inner_expr) = match_stmt.kind {
30 } else if block.stmts.is_empty() {
37 if let Some(inner_expr) = inner_expr;
38 if let ExprKind::Match(
39 ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false }
41 // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
42 if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
43 if path_to_local_id(match_expr, pat_hir_id);
44 // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
45 if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind;
46 let some_ctor = is_some_ctor(cx, path.res);
47 let ok_ctor = is_ok_ctor(cx, path.res);
48 if some_ctor || ok_ctor;
50 let if_let_type = if some_ctor { "Some" } else { "Ok" };
51 // Prepare the error message
52 let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
54 // Prepare the help message
55 let mut applicability = Applicability::MaybeIncorrect;
56 let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
57 let copied = match cx.typeck_results().expr_ty(match_expr).kind() {
58 ty::Ref(_, inner, _) => match inner.kind() {
59 ty::Ref(..) => ".copied()",
71 let sugg = format!("{}{}.flatten()", arg_snippet, copied);
76 Applicability::MaybeIncorrect,
80 "...and remove the `if let` statement in the for loop",