Skip to content

Commit 5eaaa8e

Browse files
ityuanycamc314
andauthored
fix(linter): prevent underflow in count_comment_lines for JSX files (#15026)
When processing JSX inline comments like `{/* comment */}` with the eslint/max-lines rule using skipComments: true, the count_comment_lines function would calculate start_line > end_line, causing integer underflow. This resulted in: - Debug mode: panic with "attempt to subtract with overflow" - Release mode: wrapping to usize::MAX, incorrect line count Fix by using saturating_sub which: - Prevents panic in all build modes - Returns 0 for inline comments (logically correct) - Maintains correct behavior for multi-line comments Added test case to prevent regression. --------- Co-authored-by: Cameron Clark <[email protected]>
1 parent 8d8d508 commit 5eaaa8e

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

crates/oxc_linter/src/utils/comment.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,92 @@ pub fn count_comment_lines(comment: &Comment, source_text: &str) -> usize {
2323
if line_has_just_comment(comment_end_line, "*/") {
2424
end_line += 1;
2525
}
26-
end_line - start_line
26+
end_line.saturating_sub(start_line)
27+
}
28+
}
29+
30+
#[cfg(test)]
31+
mod test {
32+
use super::*;
33+
use oxc_allocator::Allocator;
34+
use oxc_parser::Parser;
35+
use oxc_semantic::SemanticBuilder;
36+
use oxc_span::SourceType;
37+
38+
#[test]
39+
fn test_count_comment_lines() {
40+
let cases: Vec<(&str, SourceType, Vec<usize>)> = vec![
41+
// Line comments - standalone
42+
("// This is a comment\nlet x = 1;", SourceType::default(), vec![1]),
43+
(" // This is a comment\nlet x = 1;", SourceType::default(), vec![1]),
44+
// Line comments - with code on same line
45+
("let x = 1; // comment", SourceType::default(), vec![0]),
46+
// Multiple line comments
47+
(
48+
"// Comment 1\n// Comment 2\n// Comment 3\nlet x = 1;",
49+
SourceType::default(),
50+
vec![1, 1, 1],
51+
),
52+
// Block comments - single line standalone
53+
("/* comment */\nlet x = 1;", SourceType::default(), vec![1]),
54+
// Block comments - single line with code
55+
("let x = /* comment */ 1;", SourceType::default(), vec![0]),
56+
// Block comments - empty
57+
("/**/\nlet x = 1;", SourceType::default(), vec![1]),
58+
// Block comments - multiline with delimiters on own lines
59+
(
60+
"/*\n * This is a\n * multi-line comment\n */\nlet x = 1;",
61+
SourceType::default(),
62+
vec![4],
63+
),
64+
// Block comments - multiline with leading whitespace
65+
(" /*\n * Comment\n */\nlet x = 1;", SourceType::default(), vec![3]),
66+
// Block comments - multiline with start delimiter sharing line with code
67+
("let y = 2; /*\n * Comment\n */\nlet x = 1;", SourceType::default(), vec![2]),
68+
// Block comments - multiline with end delimiter sharing line with code
69+
("/*\n * Comment\n */ let x = 1;", SourceType::default(), vec![2]),
70+
// Block comments - multiline with both delimiters sharing lines with code
71+
("let y = 2; /*\n * Comment\n */ let x = 1;", SourceType::default(), vec![1]),
72+
// JSX comments
73+
(
74+
r"export function Component() {
75+
// hello
76+
/*
77+
cons
78+
*/
79+
return (
80+
<div>
81+
{/* hello */}
82+
<span>content</span>
83+
</div>
84+
);
85+
}",
86+
SourceType::tsx(),
87+
vec![1, 3, 0],
88+
),
89+
];
90+
91+
for (source, source_type, expected_counts) in cases {
92+
let allocator = Allocator::default();
93+
let ret = Parser::new(&allocator, source, source_type).parse();
94+
let semantic = SemanticBuilder::new().build(&ret.program).semantic;
95+
let comments = semantic.comments();
96+
97+
assert_eq!(
98+
comments.len(),
99+
expected_counts.len(),
100+
"Expected {} comments in source: {:?}",
101+
expected_counts.len(),
102+
source
103+
);
104+
105+
for (i, expected_count) in expected_counts.iter().enumerate() {
106+
let actual_count = count_comment_lines(&comments[i], source);
107+
assert_eq!(
108+
actual_count, *expected_count,
109+
"Comment {i} in source {source:?} expected {expected_count} lines but got {actual_count}",
110+
);
111+
}
112+
}
27113
}
28114
}

0 commit comments

Comments
 (0)