11use clippy_utils:: diagnostics:: span_lint_and_sugg;
22use clippy_utils:: ty:: is_type_diagnostic_item;
3+ use clippy_utils:: visitors:: contains_unsafe_block;
34use clippy_utils:: { is_res_lang_ctor, path_res, path_to_local_id} ;
4- use rustc_hir :: intravisit :: { walk_expr , Visitor } ;
5+
56use rustc_hir:: LangItem :: OptionSome ;
6- use rustc_hir:: { Arm , Block , BlockCheckMode , Expr , ExprKind , HirId , Pat , PatKind , UnsafeSource } ;
7+ use rustc_hir:: { Arm , Expr , ExprKind , HirId , Pat , PatKind } ;
78use rustc_lint:: LateContext ;
89use rustc_span:: { sym, SyntaxContext } ;
910
10- use super :: manual_map :: { check_with, SomeExpr } ;
11+ use super :: manual_utils :: { check_with, SomeExpr } ;
1112use super :: MANUAL_FILTER ;
1213
13- #[ derive( Default ) ]
14- struct NeedsUnsafeBlock ( pub bool ) ;
15-
16- impl < ' tcx > Visitor < ' tcx > for NeedsUnsafeBlock {
17- fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
18- match expr. kind {
19- ExprKind :: Block (
20- Block {
21- rules : BlockCheckMode :: UnsafeBlock ( UnsafeSource :: UserProvided ) ,
22- ..
23- } ,
24- _,
25- ) => {
26- self . 0 = true ;
27- } ,
28- _ => walk_expr ( self , expr) ,
29- }
30- }
31- }
32-
33- // Function called on the `expr` of `[&+]Some((ref | ref mut) x) => <expr>`
34- // Need to check if it's of the `if <cond> {<then_expr>} else {<else_expr>}`
14+ // Function called on the <expr> of `[&+]Some((ref | ref mut) x) => <expr>`
15+ // Need to check if it's of the form `<expr>=if <cond> {<then_expr>} else {<else_expr>}`
3516// AND that only one `then/else_expr` resolves to `Some(x)` while the other resolves to `None`
36- // return `cond` if
17+ // return the `cond` expression if so.
3718fn get_cond_expr < ' tcx > (
3819 cx : & LateContext < ' tcx > ,
3920 pat : & Pat < ' _ > ,
@@ -45,15 +26,13 @@ fn get_cond_expr<'tcx>(
4526 if let ExprKind :: If ( cond, then_expr, Some ( else_expr) ) = block_expr. kind;
4627 if let PatKind :: Binding ( _, target, ..) = pat. kind;
4728 if let ( then_visitor, else_visitor)
48- = ( handle_if_or_else_expr ( cx, target, ctxt, then_expr) ,
49- handle_if_or_else_expr ( cx, target, ctxt, else_expr) ) ;
29+ = ( is_some_expr ( cx, target, ctxt, then_expr) ,
30+ is_some_expr ( cx, target, ctxt, else_expr) ) ;
5031 if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
5132 then {
52- let mut needs_unsafe_block = NeedsUnsafeBlock :: default ( ) ;
53- needs_unsafe_block. visit_expr( expr) ;
5433 return Some ( SomeExpr {
5534 expr: peels_blocks_incl_unsafe( cond. peel_drop_temps( ) ) ,
56- needs_unsafe_block: needs_unsafe_block . 0 ,
35+ needs_unsafe_block: contains_unsafe_block ( cx , expr ) ,
5736 needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
5837 } )
5938 }
@@ -63,7 +42,7 @@ fn get_cond_expr<'tcx>(
6342
6443fn peels_blocks_incl_unsafe_opt < ' a > ( expr : & ' a Expr < ' a > ) -> Option < & ' a Expr < ' a > > {
6544 // we don't want to use `peel_blocks` here because we don't care if the block is unsafe, it's
66- // checked by `NeedsUnsafeBlock `
45+ // checked by `contains_unsafe_block `
6746 if let ExprKind :: Block ( block, None ) = expr. kind {
6847 if block. stmts . is_empty ( ) {
6948 return block. expr ;
@@ -76,23 +55,18 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
7655 peels_blocks_incl_unsafe_opt ( expr) . unwrap_or ( expr)
7756}
7857
79- // function called for each <ifelse > expression:
58+ // function called for each <expr > expression:
8059// Some(x) => if <cond> {
81- // <ifelse >
60+ // <expr >
8261// } else {
83- // <ifelse >
62+ // <expr >
8463// }
85- // Returns true if <ifelse> resolves to `Some(x)`, `false` otherwise
86- fn handle_if_or_else_expr < ' tcx > (
87- cx : & LateContext < ' _ > ,
88- target : HirId ,
89- ctxt : SyntaxContext ,
90- if_or_else_expr : & ' tcx Expr < ' _ > ,
91- ) -> bool {
92- if let Some ( inner_expr) = peels_blocks_incl_unsafe_opt ( if_or_else_expr) {
64+ // Returns true if <expr> resolves to `Some(x)`, `false` otherwise
65+ fn is_some_expr < ' tcx > ( cx : & LateContext < ' _ > , target : HirId , ctxt : SyntaxContext , expr : & ' tcx Expr < ' _ > ) -> bool {
66+ if let Some ( inner_expr) = peels_blocks_incl_unsafe_opt ( expr) {
9367 // there can be not statements in the block as they would be removed when switching to `.filter`
9468 if let ExprKind :: Call ( callee, [ arg] ) = inner_expr. kind {
95- return ctxt == if_or_else_expr . span . ctxt ( )
69+ return ctxt == expr . span . ctxt ( )
9670 && is_res_lang_ctor ( cx, path_res ( cx, callee) , OptionSome )
9771 && path_to_local_id ( arg, target) ;
9872 }
@@ -119,15 +93,13 @@ pub(super) fn check_match<'tcx>(
11993 expr : & ' tcx Expr < ' _ > ,
12094) {
12195 let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
122- if_chain ! {
123- if is_type_diagnostic_item( cx, ty, sym:: Option ) ;
124- if arms. len( ) == 2 ;
125- if arms[ 0 ] . guard. is_none( ) ;
126- if arms[ 1 ] . guard. is_none( ) ;
127- then {
128- check( cx, expr, scrutinee, arms[ 0 ] . pat, arms[ 0 ] . body, Some ( arms[ 1 ] . pat) , arms[ 1 ] . body)
96+ if is_type_diagnostic_item ( cx, ty, sym:: Option )
97+ && let [ first_arm, second_arm] = arms
98+ && first_arm. guard . is_none ( )
99+ && second_arm. guard . is_none ( )
100+ {
101+ check ( cx, expr, scrutinee, first_arm. pat , first_arm. body , Some ( second_arm. pat ) , second_arm. body ) ;
129102 }
130- }
131103}
132104
133105pub ( super ) fn check_if_let < ' tcx > (
0 commit comments