Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/format_report_formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fn annotation(error: &FormattingError) -> Option<Annotation<'_>> {

fn error_kind_to_snippet_annotation_level(error_kind: &ErrorKind) -> Level {
match error_kind {
ErrorKind::LineOverflow(..)
ErrorKind::LineOverflow { .. }
| ErrorKind::TrailingWhitespace
| ErrorKind::IoError(_)
| ErrorKind::ModuleResolutionError(_)
Expand Down
37 changes: 32 additions & 5 deletions src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ impl FormattingError {

pub(crate) fn is_internal(&self) -> bool {
match self.kind {
ErrorKind::LineOverflow(..)
ErrorKind::LineOverflow { .. }
| ErrorKind::TrailingWhitespace
| ErrorKind::IoError(_)
| ErrorKind::ParseError
Expand All @@ -354,7 +354,13 @@ impl FormattingError {
// (space, target)
pub(crate) fn format_len(&self) -> (usize, usize) {
match self.kind {
ErrorKind::LineOverflow(found, max) => (max, found - max),
ErrorKind::LineOverflow {
overflow_start_byte,
..
} => (
overflow_start_byte,
self.line_buffer.len() - overflow_start_byte,
),
ErrorKind::TrailingWhitespace
| ErrorKind::DeprecatedAttr
| ErrorKind::BadAttr
Expand Down Expand Up @@ -564,8 +570,13 @@ impl<'a> FormatLines<'a> {
}

// Check for any line width errors we couldn't correct.
let error_kind = ErrorKind::LineOverflow(self.line_len, self.config.max_width());
if self.line_len > self.config.max_width()
let max_width = self.config.max_width();
let error_kind = ErrorKind::LineOverflow {
total_line_width: self.line_len,
max_width,
overflow_start_byte: self.byte_offset_at_col(max_width),
};
if self.line_len > max_width
&& !self.is_skipped_line()
&& self.should_report_error(kind, &error_kind)
{
Expand Down Expand Up @@ -600,6 +611,22 @@ impl<'a> FormatLines<'a> {
}
}

/// Inverse of `Self::char`'s column accounting: walk `line_buffer` with
/// the same rule (tab = `tab_spaces` cols, every other char = 1 col) and
/// return the byte offset where the accumulated column count first reaches
/// `target_col`. Returns `line_buffer.len()` if the line is shorter.
fn byte_offset_at_col(&self, target_col: usize) -> usize {
let tab_spaces = self.config.tab_spaces();
let mut col = 0;
for (idx, ch) in self.line_buffer.char_indices() {
if col >= target_col {
return idx;
}
col += if ch == '\t' { tab_spaces } else { 1 };
Copy link
Copy Markdown
Contributor

@ytmimi ytmimi May 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily something we need to address in this PR since you're trying to follow the existing logic, but the rendered width of any \t characters isn't going to be fixed to config.tab_spaces(). It'll vary depending on where the \t is in the line.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a PR #6904 to track it

}
self.line_buffer.len()
}

fn push_err(&mut self, kind: ErrorKind, is_comment: bool, is_string: bool) {
self.errors.push(FormattingError {
line: self.cur_line,
Expand All @@ -621,7 +648,7 @@ impl<'a> FormatLines<'a> {
};

match error_kind {
ErrorKind::LineOverflow(..) => {
ErrorKind::LineOverflow { .. } => {
self.config.error_on_line_overflow() && allow_error_report
}
ErrorKind::TrailingWhitespace | ErrorKind::LostComment => allow_error_report,
Expand Down
12 changes: 8 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,16 @@ pub(crate) mod visitor;
/// these can currently be propagated to clients.
#[derive(Error, Debug)]
pub enum ErrorKind {
/// Line has exceeded character limit (found, maximum).
/// A line exceeded the configured maximum width.
#[error(
"line formatted, but exceeded maximum width \
(maximum: {1} (see `max_width` option), found: {0})"
(maximum: {max_width} (see `max_width` option), found: {total_line_width})"
)]
LineOverflow(usize, usize),
LineOverflow {
total_line_width: usize,
max_width: usize,
overflow_start_byte: usize,
},
/// Line ends in whitespace.
#[error("left behind trailing whitespace")]
TrailingWhitespace,
Expand Down Expand Up @@ -225,7 +229,7 @@ impl FormatReport {
}
for err in new_errors {
match err.kind {
ErrorKind::LineOverflow(..) => {
ErrorKind::LineOverflow { .. } => {
errs.has_operational_errors = true;
}
ErrorKind::TrailingWhitespace => {
Expand Down
6 changes: 6 additions & 0 deletions tests/cargo-fmt/source/issue_6850/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "issue_6850"
version = "0.1.0"
edition = "2021"

[dependencies]
3 changes: 3 additions & 0 deletions tests/cargo-fmt/source/issue_6850/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
"☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"
}
21 changes: 21 additions & 0 deletions tests/rustfmt/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,27 @@ fn dont_emit_ICE() {
}
}

#[test]
fn dont_panic_on_line_overflow_with_multibyte_chars() {
// See also https://github.com/rust-lang/rustfmt/issues/6850
let args = [
"--config",
"error_on_line_overflow=true,error_on_unformatted=true",
"tests/cargo-fmt/source/issue_6850/src/main.rs",
];

let (_stdout, stderr) = rustfmt(&args);
assert!(stderr.contains(
"line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option), found: 126)"
));

let panic_re = regex::Regex::new("thread.*panicked").unwrap();
assert!(
!panic_re.is_match(&stderr),
"rustfmt panicked instead of reporting line overflow:\n{stderr}"
);
}

#[test]
fn rustfmt_emits_error_when_control_brace_style_is_always_next_line() {
// See also https://github.com/rust-lang/rustfmt/issues/5912
Expand Down
Loading