]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/loops/manual_flatten.rs
Auto merge of #88163 - camsteffen:collapsible-match-fix, r=Manishearth
[rust.git] / clippy_lints / src / loops / manual_flatten.rs
index 3d3ae6f3152a3b9b183403ad4bbefc49acc1cb7e..5852674da578067661fcf961501aa890cd531d02 100644 (file)
@@ -1,10 +1,14 @@
 use super::utils::make_iterator_snippet;
 use super::MANUAL_FLATTEN;
-use crate::utils::{is_ok_ctor, is_some_ctor, path_to_local_id, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher;
+use clippy_utils::{is_lang_ctor, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, StmtKind};
+use rustc_hir::LangItem::{OptionSome, ResultOk};
+use rustc_hir::{Expr, ExprKind, Pat, PatKind, StmtKind};
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 use rustc_span::source_map::Span;
 
 /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the
@@ -16,7 +20,7 @@ pub(super) fn check<'tcx>(
     body: &'tcx Expr<'_>,
     span: Span,
 ) {
-    if let ExprKind::Block(ref block, _) = body.kind {
+    if let ExprKind::Block(block, _) = body.kind {
         // Ensure the `if let` statement is the only expression or statement in the for-loop
         let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() {
             let match_stmt = &block.stmts[0];
@@ -33,26 +37,30 @@ pub(super) fn check<'tcx>(
 
         if_chain! {
             if let Some(inner_expr) = inner_expr;
-            if let ExprKind::Match(
-                ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false }
-            ) = inner_expr.kind;
+            if let Some(higher::IfLet { let_pat, let_expr, if_else: None, .. }) = higher::IfLet::hir(cx, inner_expr);
             // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
             if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
-            if path_to_local_id(match_expr, pat_hir_id);
+            if path_to_local_id(let_expr, pat_hir_id);
             // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
-            if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind;
-            let some_ctor = is_some_ctor(cx, path.res);
-            let ok_ctor = is_ok_ctor(cx, path.res);
+            if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
+            let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
+            let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
             if some_ctor || ok_ctor;
-            let if_let_type = if some_ctor { "Some" } else { "Ok" };
-
             then {
+                let if_let_type = if some_ctor { "Some" } else { "Ok" };
                 // Prepare the error message
                 let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
 
                 // Prepare the help message
                 let mut applicability = Applicability::MaybeIncorrect;
                 let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
+                let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
+                    ty::Ref(_, inner, _) => match inner.kind() {
+                        ty::Ref(..) => ".copied()",
+                        _ => ""
+                    }
+                    _ => ""
+                };
 
                 span_lint_and_then(
                     cx,
@@ -60,7 +68,7 @@ pub(super) fn check<'tcx>(
                     span,
                     &msg,
                     |diag| {
-                        let sugg = format!("{}.flatten()", arg_snippet);
+                        let sugg = format!("{}{}.flatten()", arg_snippet, copied);
                         diag.span_suggestion(
                             arg.span,
                             "try",