Skip to content

Commit fdc6240

Browse files
committed
fix: don't ICE on LineOverflow when the line contains multibyte characters
1 parent 7991944 commit fdc6240

6 files changed

Lines changed: 71 additions & 10 deletions

File tree

src/format_report_formatter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ fn annotation(error: &FormattingError) -> Option<Annotation<'_>> {
106106

107107
fn error_kind_to_snippet_annotation_level(error_kind: &ErrorKind) -> Level {
108108
match error_kind {
109-
ErrorKind::LineOverflow(..)
109+
ErrorKind::LineOverflow { .. }
110110
| ErrorKind::TrailingWhitespace
111111
| ErrorKind::IoError(_)
112112
| ErrorKind::ModuleResolutionError(_)

src/formatting.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ impl FormattingError {
333333

334334
pub(crate) fn is_internal(&self) -> bool {
335335
match self.kind {
336-
ErrorKind::LineOverflow(..)
336+
ErrorKind::LineOverflow { .. }
337337
| ErrorKind::TrailingWhitespace
338338
| ErrorKind::IoError(_)
339339
| ErrorKind::ParseError
@@ -354,7 +354,13 @@ impl FormattingError {
354354
// (space, target)
355355
pub(crate) fn format_len(&self) -> (usize, usize) {
356356
match self.kind {
357-
ErrorKind::LineOverflow(found, max) => (max, found - max),
357+
ErrorKind::LineOverflow {
358+
overflow_start_byte,
359+
..
360+
} => (
361+
overflow_start_byte,
362+
self.line_buffer.len() - overflow_start_byte,
363+
),
358364
ErrorKind::TrailingWhitespace
359365
| ErrorKind::DeprecatedAttr
360366
| ErrorKind::BadAttr
@@ -564,8 +570,13 @@ impl<'a> FormatLines<'a> {
564570
}
565571

566572
// Check for any line width errors we couldn't correct.
567-
let error_kind = ErrorKind::LineOverflow(self.line_len, self.config.max_width());
568-
if self.line_len > self.config.max_width()
573+
let max_width = self.config.max_width();
574+
let error_kind = ErrorKind::LineOverflow {
575+
total_line_width: self.line_len,
576+
max_width,
577+
overflow_start_byte: self.byte_offset_at_col(max_width),
578+
};
579+
if self.line_len > max_width
569580
&& !self.is_skipped_line()
570581
&& self.should_report_error(kind, &error_kind)
571582
{
@@ -600,6 +611,22 @@ impl<'a> FormatLines<'a> {
600611
}
601612
}
602613

614+
/// Inverse of `Self::char`'s column accounting: walk `line_buffer` with
615+
/// the same rule (tab = `tab_spaces` cols, every other char = 1 col) and
616+
/// return the byte offset where the accumulated column count first reaches
617+
/// `target_col`. Returns `line_buffer.len()` if the line is shorter.
618+
fn byte_offset_at_col(&self, target_col: usize) -> usize {
619+
let tab_spaces = self.config.tab_spaces();
620+
let mut col = 0;
621+
for (idx, ch) in self.line_buffer.char_indices() {
622+
if col >= target_col {
623+
return idx;
624+
}
625+
col += if ch == '\t' { tab_spaces } else { 1 };
626+
}
627+
self.line_buffer.len()
628+
}
629+
603630
fn push_err(&mut self, kind: ErrorKind, is_comment: bool, is_string: bool) {
604631
self.errors.push(FormattingError {
605632
line: self.cur_line,
@@ -621,7 +648,7 @@ impl<'a> FormatLines<'a> {
621648
};
622649

623650
match error_kind {
624-
ErrorKind::LineOverflow(..) => {
651+
ErrorKind::LineOverflow { .. } => {
625652
self.config.error_on_line_overflow() && allow_error_report
626653
}
627654
ErrorKind::TrailingWhitespace | ErrorKind::LostComment => allow_error_report,

src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,16 @@ pub(crate) mod visitor;
106106
/// these can currently be propagated to clients.
107107
#[derive(Error, Debug)]
108108
pub enum ErrorKind {
109-
/// Line has exceeded character limit (found, maximum).
109+
/// A line exceeded the configured maximum width.
110110
#[error(
111111
"line formatted, but exceeded maximum width \
112-
(maximum: {1} (see `max_width` option), found: {0})"
112+
(maximum: {max_width} (see `max_width` option), found: {total_line_width})"
113113
)]
114-
LineOverflow(usize, usize),
114+
LineOverflow {
115+
total_line_width: usize,
116+
max_width: usize,
117+
overflow_start_byte: usize,
118+
},
115119
/// Line ends in whitespace.
116120
#[error("left behind trailing whitespace")]
117121
TrailingWhitespace,
@@ -225,7 +229,7 @@ impl FormatReport {
225229
}
226230
for err in new_errors {
227231
match err.kind {
228-
ErrorKind::LineOverflow(..) => {
232+
ErrorKind::LineOverflow { .. } => {
229233
errs.has_operational_errors = true;
230234
}
231235
ErrorKind::TrailingWhitespace => {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "issue_6850"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
"☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"
3+
}

tests/rustfmt/main.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,27 @@ fn dont_emit_ICE() {
203203
}
204204
}
205205

206+
#[test]
207+
fn dont_panic_on_line_overflow_with_multibyte_chars() {
208+
// See also https://github.com/rust-lang/rustfmt/issues/6850
209+
let args = [
210+
"--config",
211+
"error_on_line_overflow=true,error_on_unformatted=true",
212+
"tests/cargo-fmt/source/issue_6850/src/main.rs",
213+
];
214+
215+
let (_stdout, stderr) = rustfmt(&args);
216+
assert!(stderr.contains(
217+
"line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option), found: 126)"
218+
));
219+
220+
let panic_re = regex::Regex::new("thread.*panicked").unwrap();
221+
assert!(
222+
!panic_re.is_match(&stderr),
223+
"rustfmt panicked instead of reporting line overflow:\n{stderr}"
224+
);
225+
}
226+
206227
#[test]
207228
fn rustfmt_emits_error_when_control_brace_style_is_always_next_line() {
208229
// See also https://github.com/rust-lang/rustfmt/issues/5912

0 commit comments

Comments
 (0)