1- use clippy_utils:: diagnostics:: span_lint_and_sugg ;
1+ use clippy_utils:: diagnostics:: span_lint_and_then ;
22use clippy_utils:: res:: { MaybeDef , MaybeQPath } ;
3- use clippy_utils:: source:: snippet_with_applicability;
3+ use clippy_utils:: sugg:: Sugg ;
4+ use clippy_utils:: ty:: option_arg_ty;
45use clippy_utils:: { is_none_arm, peel_blocks} ;
56use rustc_errors:: Applicability ;
67use rustc_hir:: { Arm , BindingMode , ByRef , Expr , ExprKind , LangItem , Mutability , PatKind , QPath } ;
@@ -10,54 +11,58 @@ use rustc_middle::ty;
1011use super :: MATCH_AS_REF ;
1112
1213pub ( crate ) fn check ( cx : & LateContext < ' _ > , ex : & Expr < ' _ > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
13- if arms. len ( ) == 2 && arms[ 0 ] . guard . is_none ( ) && arms[ 1 ] . guard . is_none ( ) {
14- let arm_ref_mut = if is_none_arm ( cx, & arms[ 0 ] ) {
15- is_ref_some_arm ( cx, & arms[ 1 ] )
16- } else if is_none_arm ( cx, & arms[ 1 ] ) {
17- is_ref_some_arm ( cx, & arms[ 0 ] )
14+ if let [ arm1, arm2] = arms
15+ && arm1. guard . is_none ( )
16+ && arm2. guard . is_none ( )
17+ && let Some ( arm_ref_mutbl) = if is_none_arm ( cx, arm1) {
18+ as_ref_some_arm ( cx, arm2)
19+ } else if is_none_arm ( cx, arm2) {
20+ as_ref_some_arm ( cx, arm1)
1821 } else {
1922 None
23+ }
24+ {
25+ let method = match arm_ref_mutbl {
26+ Mutability :: Not => "as_ref" ,
27+ Mutability :: Mut => "as_mut" ,
2028 } ;
21- if let Some ( rb) = arm_ref_mut {
22- let suggestion = match rb {
23- Mutability :: Not => "as_ref" ,
24- Mutability :: Mut => "as_mut" ,
25- } ;
2629
27- let output_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
28- let input_ty = cx. typeck_results ( ) . expr_ty ( ex) ;
30+ let output_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
31+ let input_ty = cx. typeck_results ( ) . expr_ty ( ex) ;
2932
30- let cast = if let ty:: Adt ( _, args) = input_ty. kind ( )
31- && let input_ty = args. type_at ( 0 )
32- && let ty:: Adt ( _, args) = output_ty. kind ( )
33- && let output_ty = args. type_at ( 0 )
34- && let ty:: Ref ( _, output_ty, _) = * output_ty. kind ( )
35- && input_ty != output_ty
36- {
37- ".map(|x| x as _)"
38- } else {
39- ""
40- } ;
33+ let cast = if let Some ( input_ty) = option_arg_ty ( cx, input_ty)
34+ && let Some ( output_ty) = option_arg_ty ( cx, output_ty)
35+ && let ty:: Ref ( _, output_ty, _) = * output_ty. kind ( )
36+ && input_ty != output_ty
37+ {
38+ ".map(|x| x as _)"
39+ } else {
40+ ""
41+ } ;
4142
42- let mut applicability = Applicability :: MachineApplicable ;
43- span_lint_and_sugg (
44- cx,
45- MATCH_AS_REF ,
46- expr. span ,
47- format ! ( "use `{suggestion}()` instead" ) ,
48- "try" ,
49- format ! (
50- "{}.{suggestion}(){cast}" ,
51- snippet_with_applicability( cx, ex. span, "_" , & mut applicability) ,
52- ) ,
53- applicability,
54- ) ;
55- }
43+ let mut applicability = Applicability :: MachineApplicable ;
44+ span_lint_and_then (
45+ cx,
46+ MATCH_AS_REF ,
47+ expr. span ,
48+ format ! ( "manual implementation of `Option::{method}`" ) ,
49+ |diag| {
50+ diag. span_suggestion_verbose (
51+ expr. span ,
52+ format ! ( "use `Option::{method}()` directly" ) ,
53+ format ! (
54+ "{}.{method}(){cast}" ,
55+ Sugg :: hir_with_applicability( cx, ex, "_" , & mut applicability) . maybe_paren( ) ,
56+ ) ,
57+ applicability,
58+ ) ;
59+ } ,
60+ ) ;
5661 }
5762}
5863
5964// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
60- fn is_ref_some_arm ( cx : & LateContext < ' _ > , arm : & Arm < ' _ > ) -> Option < Mutability > {
65+ fn as_ref_some_arm ( cx : & LateContext < ' _ > , arm : & Arm < ' _ > ) -> Option < Mutability > {
6166 if let PatKind :: TupleStruct ( ref qpath, [ first_pat, ..] , _) = arm. pat . kind
6267 && cx
6368 . qpath_res ( qpath, arm. pat . hir_id )
0 commit comments