@@ -5,7 +5,10 @@ use clippy_utils::{def_path_def_ids, fn_def_id, is_lint_allowed};
5
5
use rustc_data_structures:: fx:: FxHashMap ;
6
6
use rustc_errors:: { Applicability , Diagnostic } ;
7
7
use rustc_hir:: def_id:: DefId ;
8
- use rustc_hir:: { Body , CoroutineKind , Expr , ExprKind } ;
8
+ use rustc_hir:: {
9
+ Body , BodyId , Closure , ClosureKind , CoroutineDesugaring , CoroutineKind , Expr , ExprKind , ImplItem , ImplItemKind ,
10
+ Item , ItemKind , Node , TraitItem , TraitItemKind ,
11
+ } ;
9
12
use rustc_lint:: { LateContext , LateLintPass } ;
10
13
use rustc_session:: impl_lint_pass;
11
14
use rustc_span:: Span ;
@@ -40,23 +43,24 @@ declare_clippy_lint! {
40
43
/// ```
41
44
#[ clippy:: version = "1.74.0" ]
42
45
pub UNNECESSARY_BLOCKING_OPS ,
43
- nursery ,
46
+ pedantic ,
44
47
"blocking operations in an async context"
45
48
}
46
49
47
50
pub ( crate ) struct UnnecessaryBlockingOps {
48
51
blocking_ops : Vec < DisallowedPath > ,
49
52
/// Map of resolved funtion def_id with suggestion string after checking crate
50
53
id_with_suggs : FxHashMap < DefId , Option < String > > ,
51
- is_in_async : bool ,
54
+ /// Tracking whether a body is async after entering it.
55
+ body_asyncness : Vec < bool > ,
52
56
}
53
57
54
58
impl UnnecessaryBlockingOps {
55
59
pub ( crate ) fn new ( blocking_ops : Vec < DisallowedPath > ) -> Self {
56
60
Self {
57
61
blocking_ops,
58
62
id_with_suggs : FxHashMap :: default ( ) ,
59
- is_in_async : false ,
63
+ body_asyncness : vec ! [ ] ,
60
64
}
61
65
}
62
66
}
@@ -108,14 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryBlockingOps {
108
112
if is_lint_allowed ( cx, UNNECESSARY_BLOCKING_OPS , body. value . hir_id ) {
109
113
return ;
110
114
}
111
-
112
- if let Some ( CoroutineKind :: Async ( _) ) = body. coroutine_kind ( ) {
113
- self . is_in_async = true ;
114
- }
115
+ self . body_asyncness . push ( in_async_body ( cx, body. id ( ) ) ) ;
115
116
}
116
117
117
118
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
118
- if self . is_in_async
119
+ if matches ! ( self . body_asyncness . last ( ) , Some ( true ) )
119
120
&& let ExprKind :: Call ( call, _) = & expr. kind
120
121
&& let Some ( call_did) = fn_def_id ( cx, expr)
121
122
&& let Some ( maybe_sugg) = self . id_with_suggs . get ( & call_did)
@@ -134,10 +135,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryBlockingOps {
134
135
}
135
136
}
136
137
137
- fn check_body_post ( & mut self , _: & LateContext < ' tcx > , body : & ' tcx Body < ' tcx > ) {
138
- if !matches ! ( body. coroutine_kind( ) , Some ( CoroutineKind :: Async ( _) ) ) {
139
- self . is_in_async = false ;
140
- }
138
+ fn check_body_post ( & mut self , _: & LateContext < ' tcx > , _: & ' tcx Body < ' tcx > ) {
139
+ self . body_asyncness . pop ( ) ;
141
140
}
142
141
}
143
142
@@ -153,3 +152,31 @@ fn make_suggestion(diag: &mut Diagnostic, cx: &LateContext<'_>, expr: &Expr<'_>,
153
152
Applicability :: Unspecified ,
154
153
) ;
155
154
}
155
+
156
+ fn in_async_body ( cx : & LateContext < ' _ > , body_id : BodyId ) -> bool {
157
+ let Some ( parent_node) = cx. tcx . hir ( ) . find_parent ( body_id. hir_id ) else {
158
+ return false ;
159
+ } ;
160
+ match parent_node {
161
+ Node :: Expr ( expr) => matches ! (
162
+ expr. kind,
163
+ ExprKind :: Closure ( Closure {
164
+ kind: ClosureKind :: Coroutine ( CoroutineKind :: Desugared ( CoroutineDesugaring :: Async , _) ) ,
165
+ ..
166
+ } )
167
+ ) ,
168
+ Node :: Item ( Item {
169
+ kind : ItemKind :: Fn ( fn_sig, ..) ,
170
+ ..
171
+ } )
172
+ | Node :: ImplItem ( ImplItem {
173
+ kind : ImplItemKind :: Fn ( fn_sig, _) ,
174
+ ..
175
+ } )
176
+ | Node :: TraitItem ( TraitItem {
177
+ kind : TraitItemKind :: Fn ( fn_sig, _) ,
178
+ ..
179
+ } ) => fn_sig. header . is_async ( ) ,
180
+ _ => false ,
181
+ }
182
+ }
0 commit comments