@@ -3,9 +3,9 @@ use crate::utils::paths;
33use crate :: utils:: sugg:: Sugg ;
44use crate :: utils:: usage:: is_unused;
55use crate :: utils:: {
6- span_lint_and_help , span_lint_and_note ,
7- expr_block , in_macro , is_allowed , is_expn_of , is_wild , match_qpath , match_type , multispan_sugg , remove_blocks ,
8- snippet , snippet_block , snippet_with_applicability , span_lint_and_sugg, span_lint_and_then,
6+ expr_block , get_arg_name , in_macro , is_allowed , is_expn_of , is_refutable , is_wild , match_qpath , match_type ,
7+ match_var , multispan_sugg , remove_blocks , snippet , snippet_block , snippet_with_applicability , span_lint_and_help ,
8+ span_lint_and_note , span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty ,
99} ;
1010use if_chain:: if_chain;
1111use rustc:: lint:: in_external_macro;
@@ -822,36 +822,66 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
822822}
823823
824824fn check_match_single_binding ( cx : & LateContext < ' _ , ' _ > , ex : & Expr < ' _ > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
825- if in_macro ( expr. span ) {
825+ if in_macro ( expr. span ) || arms . len ( ) != 1 || is_refutable ( cx , arms [ 0 ] . pat ) {
826826 return ;
827827 }
828- if arms. len ( ) == 1 {
829- if is_refutable ( cx, arms[ 0 ] . pat ) {
830- return ;
831- }
832- match arms[ 0 ] . pat . kind {
833- PatKind :: Binding ( ..) | PatKind :: Tuple ( _, _) => {
834- let bind_names = arms[ 0 ] . pat . span ;
835- let matched_vars = ex. span ;
836- let match_body = remove_blocks ( & arms[ 0 ] . body ) ;
837- span_lint_and_sugg (
838- cx,
839- MATCH_SINGLE_BINDING ,
840- expr. span ,
841- "this match could be written as a `let` statement" ,
842- "consider using `let` statement" ,
843- format ! (
844- "let {} = {};\n {}" ,
845- snippet( cx, bind_names, ".." ) ,
846- snippet( cx, matched_vars, ".." ) ,
847- snippet_block( cx, match_body. span, ".." )
848- ) ,
849- Applicability :: MachineApplicable ,
850- ) ;
851- } ,
852- _ => ( ) ,
828+ let matched_vars = ex. span ;
829+ let bind_names = arms[ 0 ] . pat . span ;
830+ let match_body = remove_blocks ( & arms[ 0 ] . body ) ;
831+ let mut snippet_body = if match_body. span . from_expansion ( ) {
832+ Sugg :: hir_with_macro_callsite ( cx, match_body, ".." ) . to_string ( )
833+ } else {
834+ snippet_block ( cx, match_body. span , ".." ) . to_owned ( ) . to_string ( )
835+ } ;
836+
837+ // Do we need to add ';' to suggestion ?
838+ if_chain ! {
839+ if let ExprKind :: Block ( block, _) = & arms[ 0 ] . body. kind;
840+ if block. stmts. len( ) == 1 ;
841+ if let StmtKind :: Semi ( s) = block. stmts. get( 0 ) . unwrap( ) . kind;
842+ then {
843+ match s. kind {
844+ ExprKind :: Block ( _, _) => ( ) ,
845+ _ => {
846+ // expr_ty(body) == ()
847+ if cx. tables. expr_ty( & arms[ 0 ] . body) . is_unit( ) {
848+ snippet_body. push( ';' ) ;
849+ }
850+ }
851+ }
853852 }
854853 }
854+
855+ match arms[ 0 ] . pat . kind {
856+ PatKind :: Binding ( ..) | PatKind :: Tuple ( _, _) | PatKind :: Struct ( ..) => {
857+ span_lint_and_sugg (
858+ cx,
859+ MATCH_SINGLE_BINDING ,
860+ expr. span ,
861+ "this match could be written as a `let` statement" ,
862+ "consider using `let` statement" ,
863+ format ! (
864+ "let {} = {};\n {}" ,
865+ snippet( cx, bind_names, ".." ) ,
866+ snippet( cx, matched_vars, ".." ) ,
867+ snippet_body
868+ ) ,
869+ Applicability :: MachineApplicable ,
870+ ) ;
871+ } ,
872+ PatKind :: Wild => {
873+ span_lint_and_sugg (
874+ cx,
875+ MATCH_SINGLE_BINDING ,
876+ expr. span ,
877+ "this match could be replaced by its body itself" ,
878+ "consider using the match body instead" ,
879+ snippet_body,
880+ Applicability :: MachineApplicable ,
881+ ) ;
882+ } ,
883+ _ => ( ) ,
884+ }
855885}
856886
857887/// Gets all arms that are unbounded `PatRange`s.
0 commit comments