diff --git a/crates/oxc_linter/src/rules/eslint/no_unreachable.rs b/crates/oxc_linter/src/rules/eslint/no_unreachable.rs index 7e406372e..da24a6215 100644 --- a/crates/oxc_linter/src/rules/eslint/no_unreachable.rs +++ b/crates/oxc_linter/src/rules/eslint/no_unreachable.rs @@ -50,25 +50,18 @@ impl Rule for NoUnreachable { // In our first path we first check if each block is definitely unreachable, If it is then // we set it as such, If we encounter an infinite loop we keep its end block since it can // prevent other reachable blocks from ever getting executed. - let _: Control<()> = depth_first_search(graph, Some(root.cfg_id()), |event| match event { - DfsEvent::Finish(node, _) => { - let bb = cfg.basic_block(node); - let unreachable = if bb.unreachable { - true - } else { - graph - .edges_directed(node, Direction::Incoming) - .any(|edge| matches!(edge.weight(), EdgeType::Join)) - }; + let _: Control<()> = depth_first_search(graph, Some(root.cfg_id()), |event| { + if let DfsEvent::Finish(node, _) = event { + let unreachable = cfg.basic_block(node).unreachable; unreachables[node.index()] = unreachable; - if let Some(it) = cfg.is_infinite_loop_start(node, nodes) { - infinite_loops.push(it); + if !unreachable { + if let Some(it) = cfg.is_infinite_loop_start(node, nodes) { + infinite_loops.push(it); + } } - - Control::Continue } - _ => Control::Continue, + Control::Continue }); // In the second path we go for each infinite loop end block and follow it marking all @@ -255,6 +248,14 @@ fn test() { b(); } ", + " + try { + a(); + } finally { + b(); + } + c(); + ", ]; let fail = vec![ diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 093e5cae8..354b570f1 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -1248,7 +1248,11 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { self.cfg.add_edge( finally_block_end_ix, after_try_statement_block_ix, - EdgeType::Join, + if self.cfg.basic_block(after_try_block_graph_ix).unreachable { + EdgeType::Unreachable + } else { + EdgeType::Join + }, ); } } diff --git a/crates/oxc_semantic/src/control_flow/builder/mod.rs b/crates/oxc_semantic/src/control_flow/builder/mod.rs index f2ecd8a7c..dc8f7c112 100644 --- a/crates/oxc_semantic/src/control_flow/builder/mod.rs +++ b/crates/oxc_semantic/src/control_flow/builder/mod.rs @@ -91,7 +91,7 @@ impl<'a> ControlFlowGraphBuilder<'a> { pub fn add_edge(&mut self, a: BasicBlockId, b: BasicBlockId, weight: EdgeType) { if matches!(weight, EdgeType::NewFunction) { self.basic_block_mut(b).unreachable = false; - } else if self.basic_block(a).unreachable { + } else if matches!(weight, EdgeType::Unreachable) || self.basic_block(a).unreachable { if self.graph.edges_directed(b, Direction::Incoming).count() == 0 { self.basic_block_mut(b).unreachable = true; } diff --git a/crates/oxc_semantic/tests/integration/snapshots/integration__cfg__cfg_files@labelled_try_break.js-2.snap b/crates/oxc_semantic/tests/integration/snapshots/integration__cfg__cfg_files@labelled_try_break.js-2.snap index afd46db9d..fe0f39b32 100644 --- a/crates/oxc_semantic/tests/integration/snapshots/integration__cfg__cfg_files@labelled_try_break.js-2.snap +++ b/crates/oxc_semantic/tests/integration/snapshots/integration__cfg__cfg_files@labelled_try_break.js-2.snap @@ -31,7 +31,7 @@ digraph { 7 -> 8 [ label = "Unreachable" , style = "dotted" ] 9 -> 2 [ label = "Error(Implicit)" , style = "dotted" ] 3 -> 5 [ label = "Normal" ] - 8 -> 9 [ label = "Join" , style = "dotted" ] + 8 -> 9 [ label = "Unreachable" , style = "dotted" ] 10 -> 2 [ label = "Error(Implicit)" ] 9 -> 10 [ label = "Normal" , style = "dotted" ] 7 -> 10 [ label = "Jump" ]