1
1
use 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} ;
3
3
use 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} ;
7
5
use core:: iter:: once;
8
6
use if_chain:: if_chain;
9
7
use 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 } ;
11
9
use rustc_lint:: { LateContext , LateLintPass } ;
12
10
use rustc_middle:: ty;
13
11
use rustc_semver:: RustcVersion ;
@@ -17,6 +15,7 @@ mod match_as_ref;
17
15
mod match_bool;
18
16
mod match_like_matches;
19
17
mod match_same_arms;
18
+ mod match_single_binding;
20
19
mod match_wild_enum;
21
20
mod match_wild_err_arm;
22
21
mod overlapping_arms;
@@ -630,7 +629,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
630
629
if self . infallible_destructuring_match_linted {
631
630
self . infallible_destructuring_match_linted = false ;
632
631
} else {
633
- check_match_single_binding ( cx, ex, arms, expr) ;
632
+ match_single_binding :: check ( cx, ex, arms, expr) ;
634
633
}
635
634
}
636
635
if let ExprKind :: Match ( ex, arms, _) = expr. kind {
@@ -753,163 +752,6 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
753
752
}
754
753
}
755
754
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
-
913
755
fn has_multiple_ref_pats < ' a , ' b , I > ( pats : I ) -> bool
914
756
where
915
757
' b : ' a ,
0 commit comments