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_lang_ctor, path_to_local_id} ;
4
- use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
5
5
use rustc_hir:: LangItem :: OptionSome ;
6
- use rustc_hir:: { Arm , Block , BlockCheckMode , Expr , ExprKind , HirId , Pat , PatKind , UnsafeSource } ;
6
+ use rustc_hir:: { Arm , Expr , ExprKind , HirId , Pat , PatKind } ;
7
7
use rustc_lint:: LateContext ;
8
8
use rustc_span:: { sym, SyntaxContext } ;
9
9
10
- use super :: manual_map :: { check_with, SomeExpr } ;
10
+ use super :: manual_utils :: { check_with, SomeExpr } ;
11
11
use super :: MANUAL_FILTER ;
12
12
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>}`
13
+ // Function called on the <expr> of `[&+]Some((ref | ref mut) x) => <expr>`
14
+ // Need to check if it's of the form `<expr>=if <cond> {<then_expr>} else {<else_expr>}`
35
15
// AND that only one `then/else_expr` resolves to `Some(x)` while the other resolves to `None`
36
- // return `cond` if
16
+ // return the `cond` expression if so.
37
17
fn get_cond_expr < ' tcx > (
38
18
cx : & LateContext < ' tcx > ,
39
19
pat : & Pat < ' _ > ,
@@ -45,15 +25,13 @@ fn get_cond_expr<'tcx>(
45
25
if let ExprKind :: If ( cond, then_expr, Some ( else_expr) ) = block_expr. kind;
46
26
if let PatKind :: Binding ( _, target, ..) = pat. kind;
47
27
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) ) ;
28
+ = ( is_some_expr ( cx, target, ctxt, then_expr) ,
29
+ is_some_expr ( cx, target, ctxt, else_expr) ) ;
50
30
if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
51
31
then {
52
- let mut needs_unsafe_block = NeedsUnsafeBlock :: default ( ) ;
53
- needs_unsafe_block. visit_expr( expr) ;
54
32
return Some ( SomeExpr {
55
33
expr: peels_blocks_incl_unsafe( cond. peel_drop_temps( ) ) ,
56
- needs_unsafe_block: needs_unsafe_block . 0 ,
34
+ needs_unsafe_block: contains_unsafe_block ( cx , expr ) ,
57
35
needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
58
36
} )
59
37
}
@@ -63,7 +41,7 @@ fn get_cond_expr<'tcx>(
63
41
64
42
fn peels_blocks_incl_unsafe_opt < ' a > ( expr : & ' a Expr < ' a > ) -> Option < & ' a Expr < ' a > > {
65
43
// 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 `
44
+ // checked by `contains_unsafe_block `
67
45
if let ExprKind :: Block ( block, None ) = expr. kind {
68
46
if block. stmts . is_empty ( ) {
69
47
return block. expr ;
@@ -76,20 +54,15 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
76
54
peels_blocks_incl_unsafe_opt ( expr) . unwrap_or ( expr)
77
55
}
78
56
79
- // function called for each <ifelse > expression:
57
+ // function called for each <expr > expression:
80
58
// Some(x) => if <cond> {
81
- // <ifelse >
59
+ // <expr >
82
60
// } else {
83
- // <ifelse >
61
+ // <expr >
84
62
// }
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) {
63
+ // Returns true if <expr> resolves to `Some(x)`, `false` otherwise
64
+ fn is_some_expr < ' tcx > ( cx : & LateContext < ' _ > , target : HirId , ctxt : SyntaxContext , expr : & ' tcx Expr < ' _ > ) -> bool {
65
+ if let Some ( inner_expr) = peels_blocks_incl_unsafe_opt ( expr) {
93
66
// there can be not statements in the block as they would be removed when switching to `.filter`
94
67
if let ExprKind :: Call (
95
68
Expr {
@@ -99,9 +72,7 @@ fn handle_if_or_else_expr<'tcx>(
99
72
[ arg] ,
100
73
) = inner_expr. kind
101
74
{
102
- return ctxt == if_or_else_expr. span . ctxt ( )
103
- && is_lang_ctor ( cx, qpath, OptionSome )
104
- && path_to_local_id ( arg, target) ;
75
+ return ctxt == expr. span . ctxt ( ) && is_lang_ctor ( cx, qpath, OptionSome ) && path_to_local_id ( arg, target) ;
105
76
}
106
77
} ;
107
78
false
@@ -126,15 +97,13 @@ pub(super) fn check_match<'tcx>(
126
97
expr : & ' tcx Expr < ' _ > ,
127
98
) {
128
99
let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
129
- if_chain ! {
130
- if is_type_diagnostic_item( cx, ty, sym:: Option ) ;
131
- if arms. len( ) == 2 ;
132
- if arms[ 0 ] . guard. is_none( ) ;
133
- if arms[ 1 ] . guard. is_none( ) ;
134
- then {
135
- check( cx, expr, scrutinee, arms[ 0 ] . pat, arms[ 0 ] . body, Some ( arms[ 1 ] . pat) , arms[ 1 ] . body)
100
+ if is_type_diagnostic_item ( cx, ty, sym:: Option )
101
+ && let [ first_arm, second_arm] = arms
102
+ && first_arm. guard . is_none ( )
103
+ && second_arm. guard . is_none ( )
104
+ {
105
+ check ( cx, expr, scrutinee, first_arm. pat , first_arm. body , Some ( second_arm. pat ) , second_arm. body )
136
106
}
137
- }
138
107
}
139
108
140
109
pub ( super ) fn check_if_let < ' tcx > (
@@ -176,14 +145,11 @@ fn check<'tcx>(
176
145
"try this" ,
177
146
if sugg_info. needs_brackets {
178
147
format ! (
179
- "{{ {}{}.filter({}) }}" ,
180
- sugg_info. scrutinee_str, sugg_info. as_ref_str, body_str
148
+ "{{ {}{}.filter({body_str }) }}" ,
149
+ sugg_info. scrutinee_str, sugg_info. as_ref_str
181
150
)
182
151
} else {
183
- format ! (
184
- "{}{}.filter({})" ,
185
- sugg_info. scrutinee_str, sugg_info. as_ref_str, body_str
186
- )
152
+ format ! ( "{}{}.filter({body_str})" , sugg_info. scrutinee_str, sugg_info. as_ref_str)
187
153
} ,
188
154
sugg_info. app ,
189
155
) ;
0 commit comments