Skip to content

Commit a90bcc0

Browse files
committed
fix the loop issue
1 parent c5dbd1d commit a90bcc0

File tree

3 files changed

+136
-1
lines changed

3 files changed

+136
-1
lines changed

clippy_lints/src/loops/infinite_loop.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ pub(super) fn check<'tcx>(
2929
return;
3030
}
3131

32+
if is_inside_unawaited_async_block(cx, expr) {
33+
return;
34+
}
35+
3236
if expr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, expr) {
3337
return;
3438
}
@@ -60,6 +64,43 @@ pub(super) fn check<'tcx>(
6064
}
6165
}
6266

67+
/// Check if the given expression is inside an async block that is not being awaited.
68+
/// This helps avoid false positives when async blocks are spawned or assigned to variables.
69+
fn is_inside_unawaited_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
70+
let current_hir_id = expr.hir_id;
71+
for (_, parent_node) in cx.tcx.hir_parent_iter(current_hir_id) {
72+
match parent_node {
73+
Node::Expr(Expr {
74+
kind: ExprKind::Closure(hir::Closure {
75+
kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
76+
hir::CoroutineDesugaring::Async,
77+
_,
78+
)),
79+
..
80+
}),
81+
..
82+
}) => {
83+
return !is_async_block_awaited(cx, expr);
84+
},
85+
_ => {},
86+
}
87+
}
88+
false
89+
}
90+
91+
fn is_async_block_awaited<'tcx>(cx: &LateContext<'tcx>, async_expr: &Expr<'_>) -> bool {
92+
for (_, parent_node) in cx.tcx.hir_parent_iter(async_expr.hir_id) {
93+
match parent_node {
94+
Node::Expr(Expr {
95+
kind: ExprKind::Match(_, _, hir::MatchSource::AwaitDesugar),
96+
..
97+
}) => return true,
98+
_ => (),
99+
}
100+
}
101+
false
102+
}
103+
63104
fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> {
64105
for (_, parent_node) in cx.tcx.hir_parent_iter(expr.hir_id) {
65106
match parent_node {

tests/ui/infinite_loops.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,4 +450,76 @@ mod issue_12338 {
450450
}
451451
}
452452

453+
#[allow(clippy::let_underscore_future, clippy::empty_loop)]
454+
mod issue_14000 {
455+
use super::do_something;
456+
457+
async fn foo() {
458+
let _ = async move {
459+
loop {
460+
//~^ infinite_loop
461+
do_something();
462+
}
463+
}
464+
.await;
465+
let _ = async move {
466+
loop {
467+
//~^ infinite_loop
468+
continue;
469+
}
470+
}
471+
.await;
472+
}
473+
474+
fn bar() {
475+
let _ = async move {
476+
loop {
477+
do_something();
478+
}
479+
};
480+
481+
let _ = async move {
482+
loop {
483+
continue;
484+
}
485+
};
486+
}
487+
}
488+
489+
#[allow(clippy::let_underscore_future)]
490+
mod tokio_spawn_test {
491+
use super::do_something;
492+
493+
fn install_ticker() {
494+
let mut schedule = std::time::Duration::from_secs(5);
495+
// This should NOT trigger the lint because the async block is spawned, not awaited
496+
std::thread::spawn(move || {
497+
async move {
498+
loop {
499+
// This loop should not trigger infinite_loop lint
500+
do_something();
501+
}
502+
}
503+
});
504+
}
505+
506+
fn spawn_async_block() {
507+
// This should NOT trigger the lint because the async block is not awaited
508+
let _handle = async move {
509+
loop {
510+
do_something();
511+
}
512+
};
513+
}
514+
515+
fn await_async_block() {
516+
// This SHOULD trigger the lint because the async block is awaited
517+
let _ = async move {
518+
loop {
519+
do_something();
520+
}
521+
};
522+
}
523+
}
524+
453525
fn main() {}

tests/ui/infinite_loops.stderr

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,5 +311,27 @@ help: if this is intentional, consider specifying `!` as function return
311311
LL | fn continue_outer() -> ! {
312312
| ++++
313313

314-
error: aborting due to 21 previous errors
314+
error: infinite loop detected
315+
--> tests/ui/infinite_loops.rs:459:13
316+
|
317+
LL | / loop {
318+
LL | |
319+
LL | | do_something();
320+
LL | | }
321+
| |_____________^
322+
|
323+
= help: if this is not intended, try adding a `break` or `return` condition in the loop
324+
325+
error: infinite loop detected
326+
--> tests/ui/infinite_loops.rs:466:13
327+
|
328+
LL | / loop {
329+
LL | |
330+
LL | | continue;
331+
LL | | }
332+
| |_____________^
333+
|
334+
= help: if this is not intended, try adding a `break` or `return` condition in the loop
335+
336+
error: aborting due to 23 previous errors
315337

0 commit comments

Comments
 (0)