diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index 6c0ed93318e9..72bf7caee25f 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -60,19 +60,18 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { } // Don't emit a suggestion since the binding is used later - check(cx, expr, local.hir_id, false); + check(cx, expr, false); }, - Node::LetStmt(&LetStmt { pat, hir_id, .. }) if let PatKind::Wild = pat.kind => { + Node::LetStmt(&LetStmt { pat, .. }) if let PatKind::Wild = pat.kind => { // `let _ = child;`, also dropped immediately without `wait()`ing - check(cx, expr, hir_id, true); + check(cx, expr, true); }, Node::Stmt(&Stmt { kind: StmtKind::Semi(_), - hir_id, .. }) => { // Immediately dropped. E.g. `std::process::Command::new("echo").spawn().unwrap();` - check(cx, expr, hir_id, true); + check(cx, expr, true); }, _ => {}, } @@ -212,9 +211,8 @@ impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> { /// such as checking that the binding is not used in certain ways, which isn't necessary for /// `let _ = ;`. /// -/// This checks if the program doesn't unconditionally exit after the spawn expression and that it -/// isn't the last statement of the program. -fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, node_id: HirId, emit_suggestion: bool) { +/// This checks if the program doesn't unconditionally exit after the spawn expression. +fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, emit_suggestion: bool) { let Some(block) = get_enclosing_block(cx, spawn_expr.hir_id) else { return; }; @@ -228,12 +226,6 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, node_id: Hi return; } - // This might be the last effective node of the program (main function). - // There's no need to lint in that case either, as this is basically equivalent to calling `exit()` - if is_last_node_in_main(cx, node_id) { - return; - } - span_lint_and_then( cx, ZOMBIE_PROCESSES, @@ -257,26 +249,6 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, node_id: Hi ); } -/// The hir id id may either correspond to a `Local` or `Stmt`, depending on how we got here. -/// This function gets the enclosing function, checks if it's `main` and if so, -/// check if the last statement modulo blocks is the given id. -fn is_last_node_in_main(cx: &LateContext<'_>, id: HirId) -> bool { - let hir = cx.tcx.hir(); - let body_owner = hir.enclosing_body_owner(id); - let enclosing_body = hir.body_owned_by(body_owner); - - if let Some((main_def_id, _)) = cx.tcx.entry_fn(()) - && main_def_id == body_owner.to_def_id() - && let ExprKind::Block(block, _) = &enclosing_body.value.peel_blocks().kind - && let [.., stmt] = block.stmts - { - matches!(stmt.kind, StmtKind::Let(local) if local.hir_id == id) - || matches!(stmt.kind, StmtKind::Semi(..) if stmt.hir_id == id) - } else { - false - } -} - /// Checks if the given expression exits the process. fn is_exit_expression(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn_def_id(cx, expr).is_some_and(|fn_did| { diff --git a/tests/ui/zombie_processes.rs b/tests/ui/zombie_processes.rs index 2de5776fc84c..a2abc7fc3a17 100644 --- a/tests/ui/zombie_processes.rs +++ b/tests/ui/zombie_processes.rs @@ -131,15 +131,6 @@ fn main() { } x.wait().unwrap(); } - - // Checking that it won't lint if spawn is the last statement of a main function. - // IMPORTANT: this case must always be at the very end so it always tests the right thing. - // Don't move this. - { - { - Command::new("").spawn().unwrap(); - } - } } fn process_child(c: Child) { diff --git a/tests/ui/zombie_processes_fixable.fixed b/tests/ui/zombie_processes_fixable.fixed index bc2e82b330e1..6045262f519a 100644 --- a/tests/ui/zombie_processes_fixable.fixed +++ b/tests/ui/zombie_processes_fixable.fixed @@ -1,4 +1,5 @@ #![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] use std::process::{Child, Command}; @@ -19,3 +20,7 @@ fn not_main() { fn spawn_proc() -> Child { Command::new("").spawn().unwrap() } + +fn spawn_proc_2() -> Child { + return Command::new("").spawn().unwrap(); +} diff --git a/tests/ui/zombie_processes_fixable.rs b/tests/ui/zombie_processes_fixable.rs index c216d153c508..e1ecb771641e 100644 --- a/tests/ui/zombie_processes_fixable.rs +++ b/tests/ui/zombie_processes_fixable.rs @@ -1,4 +1,5 @@ #![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] use std::process::{Child, Command}; diff --git a/tests/ui/zombie_processes_fixable.stderr b/tests/ui/zombie_processes_fixable.stderr index 25039bcba2d7..e1c40472c325 100644 --- a/tests/ui/zombie_processes_fixable.stderr +++ b/tests/ui/zombie_processes_fixable.stderr @@ -1,5 +1,5 @@ error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes_fixable.rs:6:13 + --> tests/ui/zombie_processes_fixable.rs:7:13 | LL | let _ = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()` @@ -10,7 +10,7 @@ LL | let _ = Command::new("").spawn().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes_fixable.rs:8:5 + --> tests/ui/zombie_processes_fixable.rs:9:5 | LL | Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()` @@ -19,7 +19,7 @@ LL | Command::new("").spawn().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes_fixable.rs:10:5 + --> tests/ui/zombie_processes_fixable.rs:11:5 | LL | spawn_proc(); | ^^^^^^^^^^^^- help: try: `.wait()` @@ -28,7 +28,7 @@ LL | spawn_proc(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes_fixable.rs:16:5 + --> tests/ui/zombie_processes_fixable.rs:17:5 | LL | Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()`