From c854ce1e4999c62700d7b68da23bd60c46fc41eb Mon Sep 17 00:00:00 2001 From: l3ops Date: Thu, 6 Oct 2022 11:00:50 +0200 Subject: [PATCH] fix(rome_js_analyze): improve the diagnostics emitted by `noUnreachable` (#3348) * fix(rome_js_analyze): improve the range merging logic in `noDeadCode` * fix the order and wording of advices --- .../main_check/upgrade_severity.snap | 11 +- .../src/analyzers/nursery/no_unreachable.rs | 338 +++++++++++++++--- .../src/control_flow/nodes/switch_stmt.rs | 3 + .../noUnreachable/JsBreakStatement.js.snap | 12 +- .../noUnreachable/JsContinueStatement.js.snap | 12 +- .../noUnreachable/JsDoWhileStatement.js.snap | 12 +- .../noUnreachable/JsForInStatement.js.snap | 12 +- .../noUnreachable/JsForOfStatement.js.snap | 12 +- .../noUnreachable/JsForStatement.js.snap | 2 - .../noUnreachable/JsIfStatement.js.snap | 8 +- .../noUnreachable/JsLabeledStatement.js.snap | 14 +- .../noUnreachable/JsReturnStatement.js.snap | 12 +- .../noUnreachable/JsSwitchStatement.js | 5 + .../noUnreachable/JsSwitchStatement.js.snap | 34 +- .../noUnreachable/JsThrowStatement.js.snap | 6 +- .../JsTryFinallyStatement.js.snap | 124 ++----- .../noUnreachable/JsTryStatement.js.snap | 62 ++-- .../noUnreachable/JsVariableStatement.js.snap | 65 +--- .../noUnreachable/JsWhileStatement.js.snap | 6 +- .../nursery/noUnreachable/MergeRanges.js | 108 ++++++ .../nursery/noUnreachable/MergeRanges.js.snap | 233 ++++++++++++ .../noUnreachable/SuppressionComments.js.snap | 6 +- .../noUnreachable/TerminatorsPlurals.js.snap | 30 +- website/src/docs/lint/rules/noUnreachable.md | 14 +- 24 files changed, 797 insertions(+), 344 deletions(-) create mode 100644 crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js create mode 100644 crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js.snap diff --git a/crates/rome_cli/tests/snapshots/main_check/upgrade_severity.snap b/crates/rome_cli/tests/snapshots/main_check/upgrade_severity.snap index 45c1cf5004b..d06c05de805 100644 --- a/crates/rome_cli/tests/snapshots/main_check/upgrade_severity.snap +++ b/crates/rome_cli/tests/snapshots/main_check/upgrade_severity.snap @@ -39,18 +39,19 @@ errors where emitted while running checks # Emitted Messages ```block -file.js:3:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +file.js:2:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ × This code is unreachable 1 │ function f() { - 2 │ for (;;) { + > 2 │ for (;;) { + │ ^^^^^^^^^^ > 3 │ continue; - │ ^^^^^^^^^ > 4 │ break; - │ ^^^^^^ - 5 │ } + > 5 │ } + │ ^ 6 │ } + 7 │ ``` diff --git a/crates/rome_js_analyze/src/analyzers/nursery/no_unreachable.rs b/crates/rome_js_analyze/src/analyzers/nursery/no_unreachable.rs index 874b578eed0..ef0bfe8dacf 100644 --- a/crates/rome_js_analyze/src/analyzers/nursery/no_unreachable.rs +++ b/crates/rome_js_analyze/src/analyzers/nursery/no_unreachable.rs @@ -2,10 +2,14 @@ use std::{cmp::Ordering, collections::VecDeque, num::NonZeroU32, vec::IntoIter}; use roaring::bitmap::RoaringBitmap; use rome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic}; -use rome_console::markup; use rome_control_flow::{builder::BlockId, ExceptionHandler, Instruction, InstructionKind}; -use rome_js_syntax::{JsLanguage, JsReturnStatement, JsSyntaxElement, JsSyntaxKind, TextRange}; -use rome_rowan::AstNode; +use rome_js_syntax::{ + JsBlockStatement, JsCaseClause, JsDefaultClause, JsDoWhileStatement, JsForInStatement, + JsForOfStatement, JsForStatement, JsFunctionBody, JsIfStatement, JsLabeledStatement, + JsLanguage, JsReturnStatement, JsSwitchStatement, JsSyntaxElement, JsSyntaxKind, JsSyntaxNode, + JsTryFinallyStatement, JsTryStatement, JsVariableStatement, JsWhileStatement, TextRange, +}; +use rome_rowan::{declare_node_union, AstNode}; use rustc_hash::FxHashMap; use crate::control_flow::ControlFlowGraph; @@ -70,17 +74,15 @@ impl Rule for NoUnreachable { let mut diagnostic = RuleDiagnostic::new( rule_category!(), state.text_trimmed_range, - markup! { + if state.terminators.is_empty() { "This code is unreachable" + } else { + "This code will never be reached ..." }, ) + .summary("This code is unreachable") .unnecessary(); - /// Primary label of the diagnostic if it comes earlier in the source than its secondary labels - const PRIMARY_LABEL_BEFORE: &str = "This code will never be reached ..."; - /// Primary label of the diagnostic if it comes later in the source than its secondary labels - const PRIMARY_LABEL_AFTER: &str = "... before it can reach this code"; - // Pluralize and adapt the error message accordingly based on the // number and position of secondary labels match state.terminators.as_slice() { @@ -89,44 +91,42 @@ impl Rule for NoUnreachable { [] => {} // A single node is responsible for this range being unreachable [node] => { - if node.range.start() < state.text_trimmed_range.start() { - diagnostic = diagnostic - .secondary( - node.range, - format_args!("This statement will {} ...", node.reason()), - ) - .primary(PRIMARY_LABEL_AFTER); - } else { - diagnostic = diagnostic.primary(PRIMARY_LABEL_BEFORE).secondary( - node.range, - format_args!( - "... because this statement will {} beforehand", - node.reason() - ), - ); - } + diagnostic = diagnostic.secondary( + node.range, + format_args!( + "... because this statement will {} beforehand", + node.reason() + ), + ); } // The range has two dominating terminator instructions [node_a, node_b] => { if node_a.kind == node_b.kind { diagnostic = diagnostic - .secondary(node_a.range, "Either this statement ...") + .secondary(node_a.range, "... because either this statement ...") .secondary( node_b.range, - format_args!("... or this statement will {} ...", node_b.reason()), - ) - .primary(PRIMARY_LABEL_AFTER); + format_args!( + "... or this statement will {} beforehand", + node_b.reason() + ), + ); } else { diagnostic = diagnostic .secondary( node_a.range, - format_args!("Either this statement will {} ...", node_a.reason()), + format_args!( + "... because either this statement will {} ...", + node_a.reason() + ), ) .secondary( node_b.range, - format_args!("... or this statement will {} ...", node_b.reason()), - ) - .primary(PRIMARY_LABEL_AFTER); + format_args!( + "... or this statement will {} beforehand", + node_b.reason() + ), + ); } } // The range has three or more dominating terminator instructions @@ -148,15 +148,18 @@ impl Rule for NoUnreachable { if has_homogeneous_kind { for (index, node) in terminators.iter().enumerate() { if index == 0 { - diagnostic = - diagnostic.secondary(node.range, "Either this statement, ..."); + diagnostic = diagnostic + .secondary(node.range, "... because either this statement, ..."); } else if index < last { diagnostic = diagnostic.secondary(node.range, "... this statement, ..."); } else { diagnostic = diagnostic.secondary( node.range, - format_args!("... or this statement will {} ...", node.reason()), + format_args!( + "... or this statement will {} beforehand", + node.reason() + ), ); } } @@ -165,7 +168,10 @@ impl Rule for NoUnreachable { if index == 0 { diagnostic = diagnostic.secondary( node.range, - format_args!("Either this statement will {}, ...", node.reason()), + format_args!( + "... because either this statement will {}, ...", + node.reason() + ), ); } else if index < last { diagnostic = diagnostic.secondary( @@ -175,13 +181,14 @@ impl Rule for NoUnreachable { } else { diagnostic = diagnostic.secondary( node.range, - format_args!("... or this statement will {} ...", node.reason()), + format_args!( + "... or this statement will {} beforehand", + node.reason() + ), ); } } } - - diagnostic = diagnostic.primary(PRIMARY_LABEL_AFTER); } } @@ -617,7 +624,7 @@ impl UnreachableRanges { } }); - match insertion { + let index = match insertion { // The search returned an existing overlapping range, extend it to // cover the incoming range Ok(index) => { @@ -637,6 +644,8 @@ impl UnreachableRanges { entry.terminators.insert(index, terminator); } } + + index } // No overlapping range was found, insert at the appropriate // position to preserve the ordering instead @@ -649,11 +658,258 @@ impl UnreachableRanges { terminators: terminator.into_iter().collect(), }, ); + + index + } + }; + + let node = match node.parent() { + Some(parent) => parent, + None => return, + }; + + self.propagate_ranges(node, index); + } + + /// Propagate unreachable ranges upward in the tree by detecting and + /// merging disjoint ranges that cover all the fields of a certain node + /// type. This requires specialized logic for each control flow node type, + /// for instance an if-statement is considered fully unreachable if its + /// test expression, consequent statement and optional else clause are all + /// fully unreachable. + fn propagate_ranges(&mut self, mut node: JsSyntaxNode, mut index: usize) -> Option<()> { + while let Some(parent) = node.ancestors().find_map(JsControlFlowNode::cast) { + // Merge the adjacent and overlapping ranges + self.merge_adjacent_ranges(); + + let fields = match &parent { + JsControlFlowNode::JsFunctionBody(_) => break, + + JsControlFlowNode::JsBlockStatement(stmt) => { + let statements = stmt.statements().into_syntax(); + if statements.text_trimmed_range().is_empty() { + vec![] + } else { + vec![statements.text_range()] + } + } + + JsControlFlowNode::JsVariableStatement(stmt) => { + let declaration = stmt.declaration().ok()?; + declaration + .declarators() + .into_iter() + .filter_map(|declarator| match declarator { + Ok(declarator) => match declarator.initializer()?.expression() { + Ok(expression) => Some(Ok(expression.syntax().text_range())), + Err(err) => Some(Err(err)), + }, + Err(err) => Some(Err(err)), + }) + .collect::, _>>() + .ok()? + } + JsControlFlowNode::JsLabeledStatement(stmt) => { + vec![stmt.body().ok()?.syntax().text_range()] + } + JsControlFlowNode::JsDoWhileStatement(stmt) => vec![ + stmt.body().ok()?.syntax().text_range(), + stmt.test().ok()?.syntax().text_range(), + ], + JsControlFlowNode::JsForInStatement(stmt) => vec![ + stmt.initializer().ok()?.syntax().text_range(), + stmt.body().ok()?.syntax().text_range(), + ], + JsControlFlowNode::JsForOfStatement(stmt) => vec![ + stmt.initializer().ok()?.syntax().text_range(), + stmt.body().ok()?.syntax().text_range(), + ], + JsControlFlowNode::JsForStatement(stmt) => { + let mut res = Vec::new(); + + if let Some(initializer) = stmt.initializer() { + res.push(initializer.syntax().text_range()); + } + + if let Some(test) = stmt.test() { + res.push(test.syntax().text_range()); + } + + if let Some(update) = stmt.update() { + res.push(update.syntax().text_range()); + } + + res.push(stmt.body().ok()?.syntax().text_range()); + res + } + JsControlFlowNode::JsIfStatement(stmt) => { + let mut res = vec![ + stmt.test().ok()?.syntax().text_range(), + stmt.consequent().ok()?.syntax().text_range(), + ]; + + if let Some(else_clause) = stmt.else_clause() { + res.push(else_clause.alternate().ok()?.syntax().text_range()); + } + + res + } + JsControlFlowNode::JsSwitchStatement(stmt) => { + let mut res = vec![stmt.discriminant().ok()?.syntax().text_range()]; + + let cases = stmt.cases().into_syntax(); + if !cases.text_trimmed_range().is_empty() { + res.push(cases.text_range()); + } + + res + } + JsControlFlowNode::JsTryStatement(stmt) => vec![ + stmt.body().ok()?.syntax().text_range(), + stmt.catch_clause().ok()?.body().ok()?.syntax().text_range(), + ], + JsControlFlowNode::JsTryFinallyStatement(stmt) => { + let mut res = vec![stmt.body().ok()?.syntax().text_range()]; + + if let Some(catch_clause) = stmt.catch_clause() { + res.push(catch_clause.body().ok()?.syntax().text_range()); + } + + res.push( + stmt.finally_clause() + .ok()? + .body() + .ok()? + .syntax() + .text_range(), + ); + + res + } + JsControlFlowNode::JsWhileStatement(stmt) => vec![ + stmt.test().ok()?.syntax().text_range(), + stmt.body().ok()?.syntax().text_range(), + ], + JsControlFlowNode::JsCaseClause(stmt) => { + let mut res = vec![stmt.test().ok()?.syntax().text_range()]; + + let consequent = stmt.consequent().into_syntax(); + if !consequent.text_trimmed_range().is_empty() { + res.push(consequent.text_range()); + } + + res + } + JsControlFlowNode::JsDefaultClause(stmt) => { + let mut res = vec![stmt.default_token().ok()?.text_range()]; + + let consequent = stmt.consequent().into_syntax(); + if !consequent.text_trimmed_range().is_empty() { + res.push(consequent.text_range()); + } + + res + } + }; + + let next_index = check_neighbors(&self.ranges, index, &fields)?; + + // Extend the range at the specific index to cover the whole parent node + let entry = &mut self.ranges[next_index]; + entry.text_range = entry.text_range.cover(parent.syntax().text_range()); + entry.text_trimmed_range = entry + .text_trimmed_range + .cover(parent.syntax().text_trimmed_range()); + + index = next_index; + node = parent.syntax().parent()?; + } + + // Merge the adjacent and overlapping ranges + self.merge_adjacent_ranges(); + + Some(()) + } + + /// Merge adjacent unreachable ranges into a single entry + fn merge_adjacent_ranges(&mut self) { + let mut index = 0; + while index < self.ranges.len().saturating_sub(1) { + let text_range = self.ranges[index].text_range; + + if self.ranges[index + 1].text_range.start() <= text_range.end() { + let prev_entry = self.ranges.remove(index + 1); + + let entry = &mut self.ranges[index]; + entry.text_range = entry.text_range.cover(prev_entry.text_range); + entry.text_trimmed_range = entry + .text_trimmed_range + .cover(prev_entry.text_trimmed_range); + + continue; } + + index += 1; } } } +declare_node_union! { + JsControlFlowNode = + JsFunctionBody | + JsVariableStatement | + JsLabeledStatement | + JsBlockStatement | + JsDoWhileStatement | + JsForInStatement | + JsForOfStatement | + JsForStatement | + JsIfStatement | + JsSwitchStatement | + JsTryStatement | + JsTryFinallyStatement | + JsWhileStatement | + JsCaseClause | + JsDefaultClause +} + +/// Try to find a section of `ranges` that matches `fields`, and returns an +/// index `i` into `ranges` such that the ranges from `i` to `i + fields.len()` +/// cover the corresponding entry in `fields`. +/// +/// To avoid having to iterate over the whole length of `ranges`, the search is +/// guided using `index` to only try ranges starting between +/// `index - fields.len()` and `index`, clamped within the limits of `ranges`. +fn check_neighbors( + ranges: &[UnreachableRange], + index: usize, + fields: &[TextRange], +) -> Option { + if fields.len() > ranges.len() { + return None; + } + + let fields_end = fields.len().saturating_sub(1); + let min_start = index.saturating_sub(fields_end); + let max_start = (min_start + fields.len()).min(ranges.len().saturating_sub(fields_end)); + + for start in min_start..max_start { + let end = start + fields.len(); + let slice = &ranges[start..end]; + + let is_matching = slice + .iter() + .zip(fields.iter().filter(|field| !field.is_empty())) + .all(|(range, field)| range.text_range.contains_range(*field)); + + if is_matching { + return Some(start); + } + } + + None +} + impl IntoIterator for UnreachableRanges { type Item = UnreachableRange; type IntoIter = IntoIter; diff --git a/crates/rome_js_analyze/src/control_flow/nodes/switch_stmt.rs b/crates/rome_js_analyze/src/control_flow/nodes/switch_stmt.rs index 6edc61aef7b..422f1ee49ec 100644 --- a/crates/rome_js_analyze/src/control_flow/nodes/switch_stmt.rs +++ b/crates/rome_js_analyze/src/control_flow/nodes/switch_stmt.rs @@ -26,6 +26,9 @@ impl NodeVisitor for SwitchVisitor { builder: &mut FunctionBuilder, _: StatementStack, ) -> SyntaxResult { + // Execute the discriminant expression as a side-effect + builder.append_statement().with_node(node.discriminant()?); + let entry_block = builder.cursor(); let break_block = builder.append_block(); diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsBreakStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsBreakStatement.js.snap index 47b1a449c8e..648174d2876 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsBreakStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsBreakStatement.js.snap @@ -24,9 +24,7 @@ function JsBreakStatement2() { ``` JsBreakStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 2 │ while (true) { 3 │ break; @@ -35,7 +33,7 @@ JsBreakStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━ 5 │ } 6 │ } - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 1 │ function JsBreakStatement1() { 2 │ while (true) { @@ -50,9 +48,7 @@ JsBreakStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━ ``` JsBreakStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 9 │ while (true) { 10 │ break; @@ -61,7 +57,7 @@ JsBreakStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━━ 12 │ } 13 │ } - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 8 │ function JsBreakStatement2() { 9 │ while (true) { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsContinueStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsContinueStatement.js.snap index 6c4c19f202c..f15876943f4 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsContinueStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsContinueStatement.js.snap @@ -24,9 +24,7 @@ function JsContinueStatement2() { ``` JsContinueStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 2 │ while (true) { 3 │ continue; @@ -35,7 +33,7 @@ JsContinueStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━ 5 │ } 6 │ } - i This statement will continue the loop ... + i ... because this statement will continue the loop beforehand 1 │ function JsContinueStatement1() { 2 │ while (true) { @@ -50,9 +48,7 @@ JsContinueStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━ ``` JsContinueStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 9 │ while (true) { 10 │ continue; @@ -61,7 +57,7 @@ JsContinueStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━ 12 │ } 13 │ } - i This statement will continue the loop ... + i ... because this statement will continue the loop beforehand 8 │ function JsContinueStatement2() { 9 │ while (true) { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsDoWhileStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsDoWhileStatement.js.snap index 2c2bea478f0..effcb5c32bd 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsDoWhileStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsDoWhileStatement.js.snap @@ -23,9 +23,7 @@ function JsDoWhileStatement2() { ``` JsDoWhileStatement.js:4:14 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 2 │ do { 3 │ break; @@ -34,7 +32,7 @@ JsDoWhileStatement.js:4:14 lint/nursery/noUnreachable ━━━━━━━━ 5 │ } 6 │ - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 1 │ function JsDoWhileStatement1() { 2 │ do { @@ -49,9 +47,7 @@ JsDoWhileStatement.js:4:14 lint/nursery/noUnreachable ━━━━━━━━ ``` JsDoWhileStatement.js:10:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 8 │ do { 9 │ continue; @@ -60,7 +56,7 @@ JsDoWhileStatement.js:10:9 lint/nursery/noUnreachable ━━━━━━━━ 11 │ } while (true); 12 │ } - i This statement will continue the loop ... + i ... because this statement will continue the loop beforehand 7 │ function JsDoWhileStatement2() { 8 │ do { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForInStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForInStatement.js.snap index 15a2c56bc8c..0a7c21d930b 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForInStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForInStatement.js.snap @@ -24,9 +24,7 @@ function JsForInStatement2() { ``` JsForInStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 2 │ for (const key in value) { 3 │ break; @@ -35,7 +33,7 @@ JsForInStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━ 5 │ } 6 │ } - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 1 │ function JsForInStatement1() { 2 │ for (const key in value) { @@ -50,9 +48,7 @@ JsForInStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━ ``` JsForInStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 9 │ for (const key in value) { 10 │ continue; @@ -61,7 +57,7 @@ JsForInStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━━ 12 │ } 13 │ } - i This statement will continue the loop ... + i ... because this statement will continue the loop beforehand 8 │ function JsForInStatement2() { 9 │ for (const key in value) { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForOfStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForOfStatement.js.snap index 0b2368bfc1f..97b03e79990 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForOfStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForOfStatement.js.snap @@ -24,9 +24,7 @@ function JsForOfStatement2() { ``` JsForOfStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 2 │ for (const key of value) { 3 │ break; @@ -35,7 +33,7 @@ JsForOfStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━ 5 │ } 6 │ } - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 1 │ function JsForOfStatement1() { 2 │ for (const key of value) { @@ -50,9 +48,7 @@ JsForOfStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━ ``` JsForOfStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 9 │ for (const key of value) { 10 │ continue; @@ -61,7 +57,7 @@ JsForOfStatement.js:11:9 lint/nursery/noUnreachable ━━━━━━━━━ 12 │ } 13 │ } - i This statement will continue the loop ... + i ... because this statement will continue the loop beforehand 8 │ function JsForOfStatement2() { 9 │ for (const key of value) { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForStatement.js.snap index 4fbce3f2813..7985f64d8d3 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsForStatement.js.snap @@ -16,8 +16,6 @@ function JsForStatement1() { ``` JsForStatement.js:2:29 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - ! This code will never be reached ... 1 │ function JsForStatement1() { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsIfStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsIfStatement.js.snap index 6e9ebd071fd..0e14174d613 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsIfStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsIfStatement.js.snap @@ -20,9 +20,7 @@ function JsIfStatement1() { ``` JsIfStatement.js:8:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 6 │ } 7 │ @@ -31,7 +29,7 @@ JsIfStatement.js:8:5 lint/nursery/noUnreachable ━━━━━━━━━━ 9 │ } 10 │ - i Either this statement ... + i ... because either this statement ... 1 │ function JsIfStatement1() { 2 │ if (true) { @@ -40,7 +38,7 @@ JsIfStatement.js:8:5 lint/nursery/noUnreachable ━━━━━━━━━━ 4 │ } else { 5 │ return; - i ... or this statement will return from the function ... + i ... or this statement will return from the function beforehand 3 │ return; 4 │ } else { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsLabeledStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsLabeledStatement.js.snap index 5078ce52839..d3ba9d12fa4 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsLabeledStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsLabeledStatement.js.snap @@ -32,9 +32,7 @@ function JsLabeledStatement2() { ``` JsLabeledStatement.js:9:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 7 │ } 8 │ @@ -43,7 +41,7 @@ JsLabeledStatement.js:9:9 lint/nursery/noUnreachable ━━━━━━━━━ 10 │ } 11 │ } - i Either this statement will continue the loop ... + i ... because either this statement will continue the loop ... 2 │ label: while (true) { 3 │ if (true) { @@ -52,7 +50,7 @@ JsLabeledStatement.js:9:9 lint/nursery/noUnreachable ━━━━━━━━━ 5 │ } else { 6 │ break label; - i ... or this statement will break the flow of the code ... + i ... or this statement will break the flow of the code beforehand 4 │ continue label; 5 │ } else { @@ -67,9 +65,7 @@ JsLabeledStatement.js:9:9 lint/nursery/noUnreachable ━━━━━━━━━ ``` JsLabeledStatement.js:17:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 15 │ beforeBreak(); 16 │ break label; @@ -78,7 +74,7 @@ JsLabeledStatement.js:17:9 lint/nursery/noUnreachable ━━━━━━━━ 18 │ } 19 │ - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 14 │ label: { 15 │ beforeBreak(); diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsReturnStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsReturnStatement.js.snap index c39176add31..558cbd34c3a 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsReturnStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsReturnStatement.js.snap @@ -20,9 +20,7 @@ function JsReturnStatement2() { ``` JsReturnStatement.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 1 │ function JsReturnStatement1() { 2 │ return; @@ -31,7 +29,7 @@ JsReturnStatement.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━ 4 │ } 5 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 1 │ function JsReturnStatement1() { > 2 │ return; @@ -45,9 +43,7 @@ JsReturnStatement.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━ ``` JsReturnStatement.js:8:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 6 │ function JsReturnStatement2() { 7 │ return; @@ -56,7 +52,7 @@ JsReturnStatement.js:8:5 lint/nursery/noUnreachable ━━━━━━━━━ 9 │ } 10 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 6 │ function JsReturnStatement2() { > 7 │ return; diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js index 008ff076cc4..8353f3832a2 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js @@ -18,3 +18,8 @@ function JsSwitchStatement2() { afterBreak(); } } + +function JsSwitchStatement3() { + return; + switch (value) {} +} diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js.snap index 1f12ef0b26a..a51123d54f0 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsSwitchStatement.js.snap @@ -25,15 +25,18 @@ function JsSwitchStatement2() { } } +function JsSwitchStatement3() { + return; + switch (value) {} +} + ``` # Diagnostics ``` JsSwitchStatement.js:18:13 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 16 │ case 0: 17 │ break; @@ -42,7 +45,7 @@ JsSwitchStatement.js:18:13 lint/nursery/noUnreachable ━━━━━━━━ 19 │ } 20 │ } - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 15 │ switch (value) { 16 │ case 0: @@ -54,4 +57,27 @@ JsSwitchStatement.js:18:13 lint/nursery/noUnreachable ━━━━━━━━ ``` +``` +JsSwitchStatement.js:24:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This code will never be reached ... + + 22 │ function JsSwitchStatement3() { + 23 │ return; + > 24 │ switch (value) {} + │ ^^^^^^^^^^^^^^^^^ + 25 │ } + 26 │ + + i ... because this statement will return from the function beforehand + + 22 │ function JsSwitchStatement3() { + > 23 │ return; + │ ^^^^^^^ + 24 │ switch (value) {} + 25 │ } + + +``` + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsThrowStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsThrowStatement.js.snap index 57543290edd..f1c6e64063a 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsThrowStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsThrowStatement.js.snap @@ -15,9 +15,7 @@ function JsThrowStatement1() { ``` JsThrowStatement.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 1 │ function JsThrowStatement1() { 2 │ throw new Error(); @@ -26,7 +24,7 @@ JsThrowStatement.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━ 4 │ } 5 │ - i This statement will throw an exception ... + i ... because this statement will throw an exception beforehand 1 │ function JsThrowStatement1() { > 2 │ throw new Error(); diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryFinallyStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryFinallyStatement.js.snap index 75659c4187b..73a6b73161a 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryFinallyStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryFinallyStatement.js.snap @@ -71,9 +71,7 @@ function JsTryFinallyStatement4() { ``` JsTryFinallyStatement.js:11:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 9 │ } 10 │ @@ -82,7 +80,7 @@ JsTryFinallyStatement.js:11:5 lint/nursery/noUnreachable ━━━━━━━ 12 │ } 13 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 6 │ } finally { 7 │ finallyClause(); @@ -95,69 +93,23 @@ JsTryFinallyStatement.js:11:5 lint/nursery/noUnreachable ━━━━━━━ ``` ``` -JsTryFinallyStatement.js:18:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsTryFinallyStatement.js:17:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... - 17 │ try { - > 18 │ tryBlock(); - │ ^^^^^^^^^^^ - 19 │ } catch (err) { - 20 │ catchClause(); - - i This statement will return from the function ... - - 14 │ function JsTryFinallyStatement2() { - > 15 │ return; - │ ^^^^^^^ + 15 │ return; 16 │ - 17 │ try { - - -``` - -``` -JsTryFinallyStatement.js:20:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This code is unreachable - - ! ... before it can reach this code - - 18 │ tryBlock(); - 19 │ } catch (err) { - > 20 │ catchClause(); - │ ^^^^^^^^^^^^^^ - 21 │ } finally { - 22 │ finallyClause(); - - i This statement will return from the function ... - - 14 │ function JsTryFinallyStatement2() { - > 15 │ return; - │ ^^^^^^^ - 16 │ - 17 │ try { - - -``` - -``` -JsTryFinallyStatement.js:22:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This code is unreachable - - ! ... before it can reach this code - - 20 │ catchClause(); - 21 │ } finally { + > 17 │ try { + │ ^^^^^ + > 18 │ tryBlock(); + ... > 22 │ finallyClause(); - │ ^^^^^^^^^^^^^^^^ - 23 │ } + > 23 │ } + │ ^ 24 │ } + 25 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 14 │ function JsTryFinallyStatement2() { > 15 │ return; @@ -171,9 +123,7 @@ JsTryFinallyStatement.js:22:9 lint/nursery/noUnreachable ━━━━━━━ ``` JsTryFinallyStatement.js:35:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 33 │ } 34 │ @@ -182,7 +132,7 @@ JsTryFinallyStatement.js:35:9 lint/nursery/noUnreachable ━━━━━━━ 36 │ } catch (err) { 37 │ catchClause2(); - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 30 │ } catch { 31 │ } finally { @@ -195,46 +145,22 @@ JsTryFinallyStatement.js:35:9 lint/nursery/noUnreachable ━━━━━━━ ``` ``` -JsTryFinallyStatement.js:37:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsTryFinallyStatement.js:36:19 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 35 │ afterTryStatement1(); - 36 │ } catch (err) { + > 36 │ } catch (err) { + │ ^ > 37 │ catchClause2(); - │ ^^^^^^^^^^^^^^^ - 38 │ } - 39 │ - - i This statement will return from the function ... - - 30 │ } catch { - 31 │ } finally { - > 32 │ return; - │ ^^^^^^^ - 33 │ } - 34 │ - - -``` - -``` -JsTryFinallyStatement.js:40:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This code is unreachable - - ! ... before it can reach this code - - 38 │ } - 39 │ + > 38 │ } + > 39 │ > 40 │ afterTryStatement2(); │ ^^^^^^^^^^^^^^^^^^^^^ 41 │ } 42 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 30 │ } catch { 31 │ } finally { @@ -249,9 +175,7 @@ JsTryFinallyStatement.js:40:5 lint/nursery/noUnreachable ━━━━━━━ ``` JsTryFinallyStatement.js:59:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 57 │ } 58 │ @@ -260,7 +184,7 @@ JsTryFinallyStatement.js:59:5 lint/nursery/noUnreachable ━━━━━━━ 60 │ } 61 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 44 │ try { 45 │ tryBlock1(); diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryStatement.js.snap index 1108402e370..4d4d2b60ee6 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsTryStatement.js.snap @@ -50,9 +50,7 @@ function JsTryStatement4() { ``` JsTryStatement.js:10:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 8 │ } 9 │ @@ -61,7 +59,7 @@ JsTryStatement.js:10:5 lint/nursery/noUnreachable ━━━━━━━━━━ 11 │ } 12 │ - i Either this statement ... + i ... because either this statement ... 2 │ try { 3 │ tryBlock(); @@ -70,7 +68,7 @@ JsTryStatement.js:10:5 lint/nursery/noUnreachable ━━━━━━━━━━ 5 │ } catch (err) { 6 │ catchClause(); - i ... or this statement will return from the function ... + i ... or this statement will return from the function beforehand 5 │ } catch (err) { 6 │ catchClause(); @@ -83,44 +81,23 @@ JsTryStatement.js:10:5 lint/nursery/noUnreachable ━━━━━━━━━━ ``` ``` -JsTryStatement.js:28:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsTryStatement.js:27:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable + ! This code will never be reached ... - ! ... before it can reach this code - - 27 │ try { - > 28 │ tryBlock(); - │ ^^^^^^^^^^^ - 29 │ } catch (err) { - 30 │ catchClause(); - - i This statement will return from the function ... - - 24 │ function JsTryStatement3() { - > 25 │ return; - │ ^^^^^^^ + 25 │ return; 26 │ - 27 │ try { - - -``` - -``` -JsTryStatement.js:30:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This code is unreachable - - ! ... before it can reach this code - - 28 │ tryBlock(); - 29 │ } catch (err) { + > 27 │ try { + │ ^^^^^ + > 28 │ tryBlock(); + > 29 │ } catch (err) { > 30 │ catchClause(); - │ ^^^^^^^^^^^^^^ - 31 │ } + > 31 │ } + │ ^ 32 │ } + 33 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 24 │ function JsTryStatement3() { > 25 │ return; @@ -132,16 +109,19 @@ JsTryStatement.js:30:9 lint/nursery/noUnreachable ━━━━━━━━━━ ``` ``` -JsTryStatement.js:37:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsTryStatement.js:36:19 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This code is unreachable + 34 │ function JsTryStatement4() { 35 │ try { - 36 │ } catch (err) { + > 36 │ } catch (err) { + │ ^ > 37 │ catchClause(); - │ ^^^^^^^^^^^^^^ - 38 │ } + > 38 │ } + │ ^ 39 │ } + 40 │ ``` diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsVariableStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsVariableStatement.js.snap index b9afed50f4a..a6434f55d93 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsVariableStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsVariableStatement.js.snap @@ -39,20 +39,18 @@ function JsVariableStatement6() { # Diagnostics ``` -JsVariableStatement.js:8:20 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsVariableStatement.js:8:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 6 │ function JsVariableStatement2() { 7 │ return; > 8 │ var variable = initializer(); - │ ^^^^^^^^^^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9 │ } 10 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 6 │ function JsVariableStatement2() { > 7 │ return; @@ -64,20 +62,18 @@ JsVariableStatement.js:8:20 lint/nursery/noUnreachable ━━━━━━━━ ``` ``` -JsVariableStatement.js:18:20 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsVariableStatement.js:18:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 16 │ function JsVariableStatement4() { 17 │ return; > 18 │ let variable = initializer(); - │ ^^^^^^^^^^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 │ } 20 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 16 │ function JsVariableStatement4() { > 17 │ return; @@ -89,20 +85,18 @@ JsVariableStatement.js:18:20 lint/nursery/noUnreachable ━━━━━━━━ ``` ``` -JsVariableStatement.js:23:22 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsVariableStatement.js:23:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 21 │ function JsVariableStatement5() { 22 │ return; > 23 │ const variable = initializer(); - │ ^^^^^^^^^^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 24 │ } 25 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 21 │ function JsVariableStatement5() { > 22 │ return; @@ -114,45 +108,20 @@ JsVariableStatement.js:23:22 lint/nursery/noUnreachable ━━━━━━━━ ``` ``` -JsVariableStatement.js:28:21 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +JsVariableStatement.js:28:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 26 │ function JsVariableStatement6() { 27 │ return; > 28 │ var variable1 = initializer(), - │ ^^^^^^^^^^^^^ - 29 │ variable2 = initializer(); - 30 │ } - - i This statement will return from the function ... - - 26 │ function JsVariableStatement6() { - > 27 │ return; - │ ^^^^^^^ - 28 │ var variable1 = initializer(), - 29 │ variable2 = initializer(); - - -``` - -``` -JsVariableStatement.js:29:21 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This code is unreachable - - ! ... before it can reach this code - - 27 │ return; - 28 │ var variable1 = initializer(), + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > 29 │ variable2 = initializer(); - │ ^^^^^^^^^^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ 30 │ } 31 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 26 │ function JsVariableStatement6() { > 27 │ return; diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsWhileStatement.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsWhileStatement.js.snap index 7a4d886c1c2..d832f9fec3b 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsWhileStatement.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/JsWhileStatement.js.snap @@ -17,9 +17,7 @@ function JsWhileStatement1() { ``` JsWhileStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 2 │ while (true) { 3 │ break; @@ -28,7 +26,7 @@ JsWhileStatement.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━ 5 │ } 6 │ } - i This statement will break the flow of the code ... + i ... because this statement will break the flow of the code beforehand 1 │ function JsWhileStatement1() { 2 │ while (true) { diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js new file mode 100644 index 00000000000..6ab00a628da --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js @@ -0,0 +1,108 @@ +function MergeRanges1() { + return; + + const var1 = statement1(); + const var2 = statement2(); + + label: { + statement1(); + statement2(); + }; + + do { + statement1(); + statement2(); + } while (test); + + for (const a of b) { + statement1(); + statement2(); + } + + for (const a in b) { + statement1(); + statement2(); + } + + for (let i = 0; i < 10; i++) { + statement1(); + statement2(); + } + + if (a) { + statement1(); + statement2(); + } else if (b) { + statement1(); + statement2(); + } else { + statement1(); + statement2(); + } + + switch (value) { + case 1: + statement1(); + statement2(); + break; + default: + statement1(); + statement2(); + break; + } + + try { + statement1(); + statement2(); + } catch (err) { + statement1(); + statement2(); + } + + try { + statement1(); + statement2(); + } catch (err) { + statement1(); + statement2(); + } finally { + statement1(); + statement2(); + } + + while (cond) { + statement1(); + statement2(); + } +} + +function MergeRanges2() { + while (true) { + if (expr) { + return; + afterReturn(); + } else { + continue; + afterContinue(); + } + + const var1 = statement1(); + const var2 = statement2(); + + if (a) { + statement1(); + statement2(); + } else if (b) { + statement1(); + statement2(); + } else { + statement1(); + statement2(); + } + + label: { + statement1(); + statement2(); + }; + } +} diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js.snap new file mode 100644 index 00000000000..8ea268e0883 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/MergeRanges.js.snap @@ -0,0 +1,233 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +expression: MergeRanges.js +--- +# Input +```js +function MergeRanges1() { + return; + + const var1 = statement1(); + const var2 = statement2(); + + label: { + statement1(); + statement2(); + }; + + do { + statement1(); + statement2(); + } while (test); + + for (const a of b) { + statement1(); + statement2(); + } + + for (const a in b) { + statement1(); + statement2(); + } + + for (let i = 0; i < 10; i++) { + statement1(); + statement2(); + } + + if (a) { + statement1(); + statement2(); + } else if (b) { + statement1(); + statement2(); + } else { + statement1(); + statement2(); + } + + switch (value) { + case 1: + statement1(); + statement2(); + break; + default: + statement1(); + statement2(); + break; + } + + try { + statement1(); + statement2(); + } catch (err) { + statement1(); + statement2(); + } + + try { + statement1(); + statement2(); + } catch (err) { + statement1(); + statement2(); + } finally { + statement1(); + statement2(); + } + + while (cond) { + statement1(); + statement2(); + } +} + +function MergeRanges2() { + while (true) { + if (expr) { + return; + afterReturn(); + } else { + continue; + afterContinue(); + } + + const var1 = statement1(); + const var2 = statement2(); + + if (a) { + statement1(); + statement2(); + } else if (b) { + statement1(); + statement2(); + } else { + statement1(); + statement2(); + } + + label: { + statement1(); + statement2(); + }; + } +} + +``` + +# Diagnostics +``` +MergeRanges.js:4:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This code will never be reached ... + + 2 │ return; + 3 │ + > 4 │ const var1 = statement1(); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + > 5 │ const var2 = statement2(); + ... + > 75 │ statement2(); + > 76 │ } + │ ^ + 77 │ } + 78 │ + + i ... because this statement will return from the function beforehand + + 1 │ function MergeRanges1() { + > 2 │ return; + │ ^^^^^^^ + 3 │ + 4 │ const var1 = statement1(); + + +``` + +``` +MergeRanges.js:83:13 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This code will never be reached ... + + 81 │ if (expr) { + 82 │ return; + > 83 │ afterReturn(); + │ ^^^^^^^^^^^^^^ + 84 │ } else { + 85 │ continue; + + i ... because this statement will return from the function beforehand + + 80 │ while (true) { + 81 │ if (expr) { + > 82 │ return; + │ ^^^^^^^ + 83 │ afterReturn(); + 84 │ } else { + + +``` + +``` +MergeRanges.js:86:13 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This code will never be reached ... + + 84 │ } else { + 85 │ continue; + > 86 │ afterContinue(); + │ ^^^^^^^^^^^^^^^^ + 87 │ } + 88 │ + + i ... because this statement will continue the loop beforehand + + 83 │ afterReturn(); + 84 │ } else { + > 85 │ continue; + │ ^^^^^^^^^ + 86 │ afterContinue(); + 87 │ } + + +``` + +``` +MergeRanges.js:89:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This code will never be reached ... + + 87 │ } + 88 │ + > 89 │ const var1 = statement1(); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + > 90 │ const var2 = statement2(); + ... + > 105 │ statement2(); + > 106 │ }; + │ ^^ + 107 │ } + 108 │ } + + i ... because either this statement will return from the function ... + + 80 │ while (true) { + 81 │ if (expr) { + > 82 │ return; + │ ^^^^^^^ + 83 │ afterReturn(); + 84 │ } else { + + i ... or this statement will continue the loop beforehand + + 83 │ afterReturn(); + 84 │ } else { + > 85 │ continue; + │ ^^^^^^^^^ + 86 │ afterContinue(); + 87 │ } + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/SuppressionComments.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/SuppressionComments.js.snap index 2799095f768..39370c82693 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/SuppressionComments.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/SuppressionComments.js.snap @@ -24,9 +24,7 @@ function SuppressionComments2() { ``` SuppressionComments.js:5:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 3 │ beforeReturn(); 4 │ return; @@ -35,7 +33,7 @@ SuppressionComments.js:5:5 lint/nursery/noUnreachable ━━━━━━━━ 6 │ } 7 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 2 │ function SuppressionComments1() { 3 │ beforeReturn(); diff --git a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/TerminatorsPlurals.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/TerminatorsPlurals.js.snap index 1afbcd97ec0..5627bdf4b87 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/TerminatorsPlurals.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noUnreachable/TerminatorsPlurals.js.snap @@ -63,9 +63,7 @@ function TerminatorsPlural4() { ``` TerminatorsPlurals.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 1 │ function TerminatorsPlural1() { 2 │ return; @@ -78,7 +76,7 @@ TerminatorsPlurals.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━ 7 │ } 8 │ - i This statement will return from the function ... + i ... because this statement will return from the function beforehand 1 │ function TerminatorsPlural1() { > 2 │ return; @@ -92,9 +90,7 @@ TerminatorsPlurals.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━ ``` TerminatorsPlurals.js:16:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 14 │ } 15 │ @@ -107,7 +103,7 @@ TerminatorsPlurals.js:16:5 lint/nursery/noUnreachable ━━━━━━━━ 20 │ } 21 │ - i Either this statement ... + i ... because either this statement ... 9 │ function TerminatorsPlural2() { 10 │ if (a) { @@ -116,7 +112,7 @@ TerminatorsPlurals.js:16:5 lint/nursery/noUnreachable ━━━━━━━━ 12 │ } else { 13 │ return; - i ... or this statement will return from the function ... + i ... or this statement will return from the function beforehand 11 │ return; 12 │ } else { @@ -131,9 +127,7 @@ TerminatorsPlurals.js:16:5 lint/nursery/noUnreachable ━━━━━━━━ ``` TerminatorsPlurals.js:31:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 29 │ } 30 │ @@ -146,7 +140,7 @@ TerminatorsPlurals.js:31:5 lint/nursery/noUnreachable ━━━━━━━━ 35 │ } 36 │ - i Either this statement, ... + i ... because either this statement, ... 22 │ function TerminatorsPlural3() { 23 │ if (a) { @@ -164,7 +158,7 @@ TerminatorsPlurals.js:31:5 lint/nursery/noUnreachable ━━━━━━━━ 27 │ } else { 28 │ return; - i ... or this statement will return from the function ... + i ... or this statement will return from the function beforehand 26 │ return; 27 │ } else { @@ -179,9 +173,7 @@ TerminatorsPlurals.js:31:5 lint/nursery/noUnreachable ━━━━━━━━ ``` TerminatorsPlurals.js:48:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! This code is unreachable - - ! ... before it can reach this code + ! This code will never be reached ... 46 │ } 47 │ @@ -194,7 +186,7 @@ TerminatorsPlurals.js:48:5 lint/nursery/noUnreachable ━━━━━━━━ 52 │ } 53 │ - i Either this statement, ... + i ... because either this statement, ... 37 │ function TerminatorsPlural4() { 38 │ if (a) { @@ -221,7 +213,7 @@ TerminatorsPlurals.js:48:5 lint/nursery/noUnreachable ━━━━━━━━ 44 │ } else { 45 │ return; - i ... or this statement will return from the function ... + i ... or this statement will return from the function beforehand 43 │ return; 44 │ } else { diff --git a/website/src/docs/lint/rules/noUnreachable.md b/website/src/docs/lint/rules/noUnreachable.md index a7658e154a8..fb337377e95 100644 --- a/website/src/docs/lint/rules/noUnreachable.md +++ b/website/src/docs/lint/rules/noUnreachable.md @@ -20,9 +20,7 @@ function example() { {% raw %}
nursery/noUnreachable.js:3:5 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-   This code is unreachable
-  
-   ... before it can reach this code
+   This code will never be reached ...
   
     1 │ function example() {
     2 │     return;
@@ -31,7 +29,7 @@ function example() {
     4 │ }
     5 │ 
   
-   This statement will return from the function ...
+   ... because this statement will return from the function beforehand
   
     1 │ function example() {
   > 2 │     return;
@@ -51,8 +49,6 @@ function example() {
 
 {% raw %}
nursery/noUnreachable.js:2:28 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-   This code is unreachable
-  
    This code will never be reached ...
   
     1 │ function example() {
@@ -83,9 +79,7 @@ function example() {
 
 {% raw %}
nursery/noUnreachable.js:4:9 lint/nursery/noUnreachable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-   This code is unreachable
-  
-   ... before it can reach this code
+   This code will never be reached ...
   
     2 │     for(const key in value) {
     3 │         continue;
@@ -94,7 +88,7 @@ function example() {
     5 │     }
     6 │ }
   
-   This statement will continue the loop ...
+   ... because this statement will continue the loop beforehand
   
     1 │ function example() {
     2 │     for(const key in value) {