11use clippy_utils:: diagnostics:: { multispan_sugg, span_lint_and_help, span_lint_and_sugg, span_lint_and_then} ;
2- use clippy_utils:: source:: { indent_of , snippet, snippet_block , snippet_opt , snippet_with_applicability} ;
2+ use clippy_utils:: source:: { snippet, snippet_with_applicability} ;
33use clippy_utils:: sugg:: Sugg ;
4- use clippy_utils:: {
5- get_parent_expr, is_refutable, is_wild, meets_msrv, msrvs, path_to_local_id, peel_blocks, strip_pat_refs,
6- } ;
4+ use clippy_utils:: { is_wild, meets_msrv, msrvs, path_to_local_id, peel_blocks, strip_pat_refs} ;
75use core:: iter:: once;
86use if_chain:: if_chain;
97use rustc_errors:: Applicability ;
10- use rustc_hir:: { Arm , BorrowKind , Expr , ExprKind , Local , MatchSource , Mutability , Node , Pat , PatKind , QPath } ;
8+ use rustc_hir:: { Arm , BorrowKind , Expr , ExprKind , Local , MatchSource , Mutability , Pat , PatKind , QPath } ;
119use rustc_lint:: { LateContext , LateLintPass } ;
1210use rustc_middle:: ty;
1311use rustc_semver:: RustcVersion ;
@@ -17,6 +15,7 @@ mod match_as_ref;
1715mod match_bool;
1816mod match_like_matches;
1917mod match_same_arms;
18+ mod match_single_binding;
2019mod match_wild_enum;
2120mod match_wild_err_arm;
2221mod overlapping_arms;
@@ -630,7 +629,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
630629 if self . infallible_destructuring_match_linted {
631630 self . infallible_destructuring_match_linted = false ;
632631 } else {
633- check_match_single_binding ( cx, ex, arms, expr) ;
632+ match_single_binding :: check ( cx, ex, arms, expr) ;
634633 }
635634 }
636635 if let ExprKind :: Match ( ex, arms, _) = expr. kind {
@@ -753,163 +752,6 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
753752 }
754753}
755754
756- #[ allow( clippy:: too_many_lines) ]
757- fn check_match_single_binding < ' a > ( cx : & LateContext < ' a > , ex : & Expr < ' a > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
758- if expr. span . from_expansion ( ) || arms. len ( ) != 1 || is_refutable ( cx, arms[ 0 ] . pat ) {
759- return ;
760- }
761-
762- // HACK:
763- // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
764- // to prevent false positives as there is currently no better way to detect if code was excluded by
765- // a macro. See PR #6435
766- if_chain ! {
767- if let Some ( match_snippet) = snippet_opt( cx, expr. span) ;
768- if let Some ( arm_snippet) = snippet_opt( cx, arms[ 0 ] . span) ;
769- if let Some ( ex_snippet) = snippet_opt( cx, ex. span) ;
770- let rest_snippet = match_snippet. replace( & arm_snippet, "" ) . replace( & ex_snippet, "" ) ;
771- if rest_snippet. contains( "=>" ) ;
772- then {
773- // The code it self contains another thick arrow "=>"
774- // -> Either another arm or a comment
775- return ;
776- }
777- }
778-
779- let matched_vars = ex. span ;
780- let bind_names = arms[ 0 ] . pat . span ;
781- let match_body = peel_blocks ( arms[ 0 ] . body ) ;
782- let mut snippet_body = if match_body. span . from_expansion ( ) {
783- Sugg :: hir_with_macro_callsite ( cx, match_body, ".." ) . to_string ( )
784- } else {
785- snippet_block ( cx, match_body. span , ".." , Some ( expr. span ) ) . to_string ( )
786- } ;
787-
788- // Do we need to add ';' to suggestion ?
789- match match_body. kind {
790- ExprKind :: Block ( block, _) => {
791- // macro + expr_ty(body) == ()
792- if block. span . from_expansion ( ) && cx. typeck_results ( ) . expr_ty ( match_body) . is_unit ( ) {
793- snippet_body. push ( ';' ) ;
794- }
795- } ,
796- _ => {
797- // expr_ty(body) == ()
798- if cx. typeck_results ( ) . expr_ty ( match_body) . is_unit ( ) {
799- snippet_body. push ( ';' ) ;
800- }
801- } ,
802- }
803-
804- let mut applicability = Applicability :: MaybeIncorrect ;
805- match arms[ 0 ] . pat . kind {
806- PatKind :: Binding ( ..) | PatKind :: Tuple ( _, _) | PatKind :: Struct ( ..) => {
807- // If this match is in a local (`let`) stmt
808- let ( target_span, sugg) = if let Some ( parent_let_node) = opt_parent_let ( cx, ex) {
809- (
810- parent_let_node. span ,
811- format ! (
812- "let {} = {};\n {}let {} = {};" ,
813- snippet_with_applicability( cx, bind_names, ".." , & mut applicability) ,
814- snippet_with_applicability( cx, matched_vars, ".." , & mut applicability) ,
815- " " . repeat( indent_of( cx, expr. span) . unwrap_or( 0 ) ) ,
816- snippet_with_applicability( cx, parent_let_node. pat. span, ".." , & mut applicability) ,
817- snippet_body
818- ) ,
819- )
820- } else {
821- // If we are in closure, we need curly braces around suggestion
822- let mut indent = " " . repeat ( indent_of ( cx, ex. span ) . unwrap_or ( 0 ) ) ;
823- let ( mut cbrace_start, mut cbrace_end) = ( "" . to_string ( ) , "" . to_string ( ) ) ;
824- if let Some ( parent_expr) = get_parent_expr ( cx, expr) {
825- if let ExprKind :: Closure ( ..) = parent_expr. kind {
826- cbrace_end = format ! ( "\n {}}}" , indent) ;
827- // Fix body indent due to the closure
828- indent = " " . repeat ( indent_of ( cx, bind_names) . unwrap_or ( 0 ) ) ;
829- cbrace_start = format ! ( "{{\n {}" , indent) ;
830- }
831- }
832- // If the parent is already an arm, and the body is another match statement,
833- // we need curly braces around suggestion
834- let parent_node_id = cx. tcx . hir ( ) . get_parent_node ( expr. hir_id ) ;
835- if let Node :: Arm ( arm) = & cx. tcx . hir ( ) . get ( parent_node_id) {
836- if let ExprKind :: Match ( ..) = arm. body . kind {
837- cbrace_end = format ! ( "\n {}}}" , indent) ;
838- // Fix body indent due to the match
839- indent = " " . repeat ( indent_of ( cx, bind_names) . unwrap_or ( 0 ) ) ;
840- cbrace_start = format ! ( "{{\n {}" , indent) ;
841- }
842- }
843- (
844- expr. span ,
845- format ! (
846- "{}let {} = {};\n {}{}{}" ,
847- cbrace_start,
848- snippet_with_applicability( cx, bind_names, ".." , & mut applicability) ,
849- snippet_with_applicability( cx, matched_vars, ".." , & mut applicability) ,
850- indent,
851- snippet_body,
852- cbrace_end
853- ) ,
854- )
855- } ;
856- span_lint_and_sugg (
857- cx,
858- MATCH_SINGLE_BINDING ,
859- target_span,
860- "this match could be written as a `let` statement" ,
861- "consider using `let` statement" ,
862- sugg,
863- applicability,
864- ) ;
865- } ,
866- PatKind :: Wild => {
867- if ex. can_have_side_effects ( ) {
868- let indent = " " . repeat ( indent_of ( cx, expr. span ) . unwrap_or ( 0 ) ) ;
869- let sugg = format ! (
870- "{};\n {}{}" ,
871- snippet_with_applicability( cx, ex. span, ".." , & mut applicability) ,
872- indent,
873- snippet_body
874- ) ;
875- span_lint_and_sugg (
876- cx,
877- MATCH_SINGLE_BINDING ,
878- expr. span ,
879- "this match could be replaced by its scrutinee and body" ,
880- "consider using the scrutinee and body instead" ,
881- sugg,
882- applicability,
883- ) ;
884- } else {
885- span_lint_and_sugg (
886- cx,
887- MATCH_SINGLE_BINDING ,
888- expr. span ,
889- "this match could be replaced by its body itself" ,
890- "consider using the match body instead" ,
891- snippet_body,
892- Applicability :: MachineApplicable ,
893- ) ;
894- }
895- } ,
896- _ => ( ) ,
897- }
898- }
899-
900- /// Returns true if the `ex` match expression is in a local (`let`) statement
901- fn opt_parent_let < ' a > ( cx : & LateContext < ' a > , ex : & Expr < ' a > ) -> Option < & ' a Local < ' a > > {
902- let map = & cx. tcx . hir ( ) ;
903- if_chain ! {
904- if let Some ( Node :: Expr ( parent_arm_expr) ) = map. find( map. get_parent_node( ex. hir_id) ) ;
905- if let Some ( Node :: Local ( parent_let_expr) ) = map. find( map. get_parent_node( parent_arm_expr. hir_id) ) ;
906- then {
907- return Some ( parent_let_expr) ;
908- }
909- }
910- None
911- }
912-
913755fn has_multiple_ref_pats < ' a , ' b , I > ( pats : I ) -> bool
914756where
915757 ' b : ' a ,
0 commit comments