1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::snippet_with_applicability;
3 use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
4 use rustc_errors::Applicability;
5 use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
6 use rustc_lint::LateContext;
9 use super::MATCH_AS_REF;
11 pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
12 if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
13 let arm_ref_mut = if is_none_arm(cx, &arms[0]) {
14 is_ref_some_arm(cx, &arms[1])
15 } else if is_none_arm(cx, &arms[1]) {
16 is_ref_some_arm(cx, &arms[0])
20 if let Some(rb) = arm_ref_mut {
21 let suggestion = match rb {
22 Mutability::Not => "as_ref",
23 Mutability::Mut => "as_mut",
26 let output_ty = cx.typeck_results().expr_ty(expr);
27 let input_ty = cx.typeck_results().expr_ty(ex);
29 let cast = if_chain! {
30 if let ty::Adt(_, substs) = input_ty.kind();
31 let input_ty = substs.type_at(0);
32 if let ty::Adt(_, substs) = output_ty.kind();
33 let output_ty = substs.type_at(0);
34 if let ty::Ref(_, output_ty, _) = *output_ty.kind();
35 if input_ty != output_ty;
43 let mut applicability = Applicability::MachineApplicable;
48 &format!("use `{suggestion}()` instead"),
51 "{}.{suggestion}(){cast}",
52 snippet_with_applicability(cx, ex.span, "_", &mut applicability),
60 // Checks if arm has the form `None => None`
61 fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
64 PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
68 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
69 fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
71 if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
72 if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome);
73 if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind;
74 if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
75 if is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome);
76 if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
77 if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;