@@ -14,8 +14,8 @@ use rustc_ast::ast::LitKind;
14
14
use rustc_errors:: Applicability ;
15
15
use rustc_hir:: def:: CtorKind ;
16
16
use rustc_hir:: {
17
- print, Arm , BindingAnnotation , Block , BorrowKind , Expr , ExprKind , Local , MatchSource , Mutability , Pat , PatKind ,
18
- QPath , RangeEnd ,
17
+ print, Arm , BindingAnnotation , Block , BorrowKind , Expr , ExprKind , Local , MatchSource , Mutability , Node , Pat ,
18
+ PatKind , QPath , RangeEnd ,
19
19
} ;
20
20
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
21
21
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -882,7 +882,7 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
882
882
}
883
883
}
884
884
885
- fn check_match_single_binding ( cx : & LateContext < ' _ , ' _ > , ex : & Expr < ' _ > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
885
+ fn check_match_single_binding < ' a > ( cx : & LateContext < ' _ , ' a > , ex : & Expr < ' a > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
886
886
if in_macro ( expr. span ) || arms. len ( ) != 1 || is_refutable ( cx, arms[ 0 ] . pat ) {
887
887
return ;
888
888
}
@@ -914,19 +914,38 @@ fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[A
914
914
let mut applicability = Applicability :: MaybeIncorrect ;
915
915
match arms[ 0 ] . pat . kind {
916
916
PatKind :: Binding ( ..) | PatKind :: Tuple ( _, _) | PatKind :: Struct ( ..) => {
917
+ // If this match is in a local (`let`) stmt
918
+ let ( target_span, sugg) = if let Some ( parent_let_node) = opt_parent_let ( cx, ex) {
919
+ (
920
+ parent_let_node. span ,
921
+ format ! (
922
+ "let {} = {};\n {}let {} = {};" ,
923
+ snippet_with_applicability( cx, bind_names, ".." , & mut applicability) ,
924
+ snippet_with_applicability( cx, matched_vars, ".." , & mut applicability) ,
925
+ " " . repeat( indent_of( cx, expr. span) . unwrap_or( 0 ) ) ,
926
+ snippet_with_applicability( cx, parent_let_node. pat. span, ".." , & mut applicability) ,
927
+ snippet_body
928
+ ) ,
929
+ )
930
+ } else {
931
+ (
932
+ expr. span ,
933
+ format ! (
934
+ "let {} = {};\n {}{}" ,
935
+ snippet_with_applicability( cx, bind_names, ".." , & mut applicability) ,
936
+ snippet_with_applicability( cx, matched_vars, ".." , & mut applicability) ,
937
+ " " . repeat( indent_of( cx, expr. span) . unwrap_or( 0 ) ) ,
938
+ snippet_body
939
+ ) ,
940
+ )
941
+ } ;
917
942
span_lint_and_sugg (
918
943
cx,
919
944
MATCH_SINGLE_BINDING ,
920
- expr . span ,
945
+ target_span ,
921
946
"this match could be written as a `let` statement" ,
922
947
"consider using `let` statement" ,
923
- format ! (
924
- "let {} = {};\n {}{}" ,
925
- snippet_with_applicability( cx, bind_names, ".." , & mut applicability) ,
926
- snippet_with_applicability( cx, matched_vars, ".." , & mut applicability) ,
927
- " " . repeat( indent_of( cx, expr. span) . unwrap_or( 0 ) ) ,
928
- snippet_body,
929
- ) ,
948
+ sugg,
930
949
applicability,
931
950
) ;
932
951
} ,
@@ -945,6 +964,19 @@ fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[A
945
964
}
946
965
}
947
966
967
+ /// Returns true if the `ex` match expression is in a local (`let`) statement
968
+ fn opt_parent_let < ' a > ( cx : & LateContext < ' _ , ' a > , ex : & Expr < ' a > ) -> Option < & ' a Local < ' a > > {
969
+ if_chain ! {
970
+ let map = & cx. tcx. hir( ) ;
971
+ if let Some ( Node :: Expr ( parent_arm_expr) ) = map. find( map. get_parent_node( ex. hir_id) ) ;
972
+ if let Some ( Node :: Local ( parent_let_expr) ) = map. find( map. get_parent_node( parent_arm_expr. hir_id) ) ;
973
+ then {
974
+ return Some ( parent_let_expr) ;
975
+ }
976
+ }
977
+ None
978
+ }
979
+
948
980
/// Gets all arms that are unbounded `PatRange`s.
949
981
fn all_ranges < ' a , ' tcx > (
950
982
cx : & LateContext < ' a , ' tcx > ,
0 commit comments