From 0194dbd79d44c43bfc878ce6cc355b81b47b75c6 Mon Sep 17 00:00:00 2001 From: Cameron Date: Mon, 30 Oct 2023 01:52:46 +0000 Subject: [PATCH] fix(linter) Fix panic when using ban ts comment on conformace tests (#1097) ``` RUST_BACKTRACE=full cargo run --bin=oxc_cli lint -D=suspicious -D=style -D=restriction -D=pedantic -D=nursery -D=correctness ./tasks/coverage/typescript/tests/cases/conformance/directives/ts-expect-error.ts --threads=1 ``` currently panics, entering unreachable code --- .../src/rules/typescript/ban_ts_comment.rs | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs b/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs index 8b2b750b8..45b4dc69c 100644 --- a/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs +++ b/crates/oxc_linter/src/rules/typescript/ban_ts_comment.rs @@ -178,16 +178,31 @@ impl BanTsComment { "check" => &self.ts_check, "nocheck" => &self.ts_nocheck, "expect-error" => &self.ts_expect_error, - _ => unreachable!(), + _ => { + unreachable!( + "Expected one of ignore/check/nocheck/expect-error, got {}.", + directive, + ); + } } } } pub fn find_ts_comment_directive(raw: &str, single_line: bool) -> Option<(&str, &str)> { let prefix = "@ts-"; - // For multi-line comments, get the last line - let mut lines = raw.lines(); - let line = lines.next_back()?; + + let mut last_line_start = None; + let mut char_indices = raw.char_indices().peekable(); + while let Some((_, c)) = char_indices.next() { + if c == '\n' { + last_line_start = char_indices.peek().map(|(i, _)| *i); + } + } + + let multi_len = last_line_start.unwrap_or(0); + let line = &raw[multi_len..]; + + // Check the content before the prefix let index = line.find(prefix)?; if !line[..index] .chars() @@ -195,13 +210,20 @@ pub fn find_ts_comment_directive(raw: &str, single_line: bool) -> Option<(&str, { return None; } - let multi_len = lines.map(|line| line.len() + 1).sum::(); + let start = index + prefix.len(); for directive in ["expect-error", "ignore", "nocheck", "check"] { if line.get(start..start + directive.len()) == Some(directive) { let start = multi_len + index + prefix.len(); let end = start + directive.len(); - return Some((&raw[start..end], &raw[end..])); + let (directive, description) = (&raw[start..end], &raw[end..]); + + debug_assert!( + matches!(directive, "expect-error" | "ignore" | "nocheck" | "check"), + "Expected one of ignore/check/nocheck/expect-error, got {directive}", + ); + + return Some((directive, description)); } } None