1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
2
use clippy_utils:: ty:: is_type_diagnostic_item;
3
+ use clippy_utils:: visitors:: contains_unsafe_block;
3
4
use clippy_utils:: { is_res_lang_ctor, path_res, path_to_local_id} ;
4
- use rustc_hir :: intravisit :: { walk_expr , Visitor } ;
5
+
5
6
use 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 } ;
7
8
use rustc_lint:: LateContext ;
8
9
use rustc_span:: { sym, SyntaxContext } ;
9
10
10
- use super :: manual_map :: { check_with, SomeExpr } ;
11
+ use super :: manual_utils :: { check_with, SomeExpr } ;
11
12
use super :: MANUAL_FILTER ;
12
13
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>}`
35
16
// 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.
37
18
fn get_cond_expr < ' tcx > (
38
19
cx : & LateContext < ' tcx > ,
39
20
pat : & Pat < ' _ > ,
@@ -45,15 +26,13 @@ fn get_cond_expr<'tcx>(
45
26
if let ExprKind :: If ( cond, then_expr, Some ( else_expr) ) = block_expr. kind;
46
27
if let PatKind :: Binding ( _, target, ..) = pat. kind;
47
28
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) ) ;
50
31
if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
51
32
then {
52
- let mut needs_unsafe_block = NeedsUnsafeBlock :: default ( ) ;
53
- needs_unsafe_block. visit_expr( expr) ;
54
33
return Some ( SomeExpr {
55
34
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 ) ,
57
36
needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
58
37
} )
59
38
}
@@ -63,7 +42,7 @@ fn get_cond_expr<'tcx>(
63
42
64
43
fn peels_blocks_incl_unsafe_opt < ' a > ( expr : & ' a Expr < ' a > ) -> Option < & ' a Expr < ' a > > {
65
44
// 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 `
67
46
if let ExprKind :: Block ( block, None ) = expr. kind {
68
47
if block. stmts . is_empty ( ) {
69
48
return block. expr ;
@@ -76,23 +55,18 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
76
55
peels_blocks_incl_unsafe_opt ( expr) . unwrap_or ( expr)
77
56
}
78
57
79
- // function called for each <ifelse > expression:
58
+ // function called for each <expr > expression:
80
59
// Some(x) => if <cond> {
81
- // <ifelse >
60
+ // <expr >
82
61
// } else {
83
- // <ifelse >
62
+ // <expr >
84
63
// }
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) {
93
67
// there can be not statements in the block as they would be removed when switching to `.filter`
94
68
if let ExprKind :: Call ( callee, [ arg] ) = inner_expr. kind {
95
- return ctxt == if_or_else_expr . span . ctxt ( )
69
+ return ctxt == expr . span . ctxt ( )
96
70
&& is_res_lang_ctor ( cx, path_res ( cx, callee) , OptionSome )
97
71
&& path_to_local_id ( arg, target) ;
98
72
}
@@ -119,15 +93,13 @@ pub(super) fn check_match<'tcx>(
119
93
expr : & ' tcx Expr < ' _ > ,
120
94
) {
121
95
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 ) ;
129
102
}
130
- }
131
103
}
132
104
133
105
pub ( super ) fn check_if_let < ' tcx > (
0 commit comments