@@ -3,9 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_then;
3
3
use clippy_utils:: source:: snippet_with_applicability;
4
4
use clippy_utils:: { def_path_def_ids, fn_def_id, is_lint_allowed} ;
5
5
use rustc_data_structures:: fx:: FxHashMap ;
6
- use rustc_errors:: { Applicability , Diagnostic } ;
6
+ use rustc_errors:: { Applicability , Diag } ;
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
- /// Map of resolved funtion def_id with suggestion string after checking crate
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,14 +135,12 @@ 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
144
- fn make_suggestion ( diag : & mut Diagnostic , cx : & LateContext < ' _ > , expr : & Expr < ' _ > , fn_span : Span , sugg_fn_path : & str ) {
143
+ fn make_suggestion ( diag : & mut Diag < ' _ , ( ) > , cx : & LateContext < ' _ > , expr : & Expr < ' _ > , fn_span : Span , sugg_fn_path : & str ) {
145
144
let mut applicability = Applicability :: Unspecified ;
146
145
let args_span = expr. span . with_lo ( fn_span. hi ( ) ) ;
147
146
let args_snippet = snippet_with_applicability ( cx, args_span, ".." , & mut applicability) ;
@@ -153,3 +152,33 @@ fn make_suggestion(diag: &mut Diagnostic, cx: &LateContext<'_>, expr: &Expr<'_>,
153
152
Applicability :: Unspecified ,
154
153
) ;
155
154
}
155
+
156
+ /// Check whether a body is from an async function/closure.
157
+ fn in_async_body ( cx : & LateContext < ' _ > , body_id : BodyId ) -> bool {
158
+ let parent_node = cx. tcx . parent_hir_node ( body_id. hir_id ) ;
159
+ match parent_node {
160
+ Node :: Expr ( expr) => matches ! (
161
+ expr. kind,
162
+ ExprKind :: Closure ( Closure {
163
+ kind: ClosureKind :: Coroutine ( CoroutineKind :: Desugared (
164
+ CoroutineDesugaring :: Async | CoroutineDesugaring :: AsyncGen ,
165
+ _
166
+ ) ) ,
167
+ ..
168
+ } )
169
+ ) ,
170
+ Node :: Item ( Item {
171
+ kind : ItemKind :: Fn ( fn_sig, ..) ,
172
+ ..
173
+ } )
174
+ | Node :: ImplItem ( ImplItem {
175
+ kind : ImplItemKind :: Fn ( fn_sig, _) ,
176
+ ..
177
+ } )
178
+ | Node :: TraitItem ( TraitItem {
179
+ kind : TraitItemKind :: Fn ( fn_sig, _) ,
180
+ ..
181
+ } ) => fn_sig. header . is_async ( ) ,
182
+ _ => false ,
183
+ }
184
+ }
0 commit comments