about summary refs log tree commit diff
path: root/compiler/rustc_errors/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors/src')
-rw-r--r--compiler/rustc_errors/src/emitter.rs39
-rw-r--r--compiler/rustc_errors/src/lib.rs44
2 files changed, 57 insertions, 26 deletions
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 07c864c93a1..25777f4133b 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1623,7 +1623,7 @@ impl EmitterWriter {
             let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
             draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
             let mut lines = complete.lines();
-            for (line_pos, (line, parts)) in
+            for (line_pos, (line, highlight_parts)) in
                 lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
             {
                 // Print the span column to avoid confusion
@@ -1658,7 +1658,7 @@ impl EmitterWriter {
                     );
                     buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
                 } else if is_multiline {
-                    match &parts[..] {
+                    match &highlight_parts[..] {
                         [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
                             buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
                         }
@@ -1676,16 +1676,24 @@ impl EmitterWriter {
                 // print the suggestion
                 buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
 
-                if is_multiline {
-                    for SubstitutionHighlight { start, end } in parts {
-                        buffer.set_style_range(
-                            row_num,
-                            max_line_num_len + 3 + start,
-                            max_line_num_len + 3 + end,
-                            Style::Addition,
-                            true,
-                        );
-                    }
+                // Colorize addition/replacements with green.
+                for &SubstitutionHighlight { start, end } in highlight_parts {
+                    // Account for tabs when highlighting (#87972).
+                    let tabs: usize = line
+                        .chars()
+                        .take(start)
+                        .map(|ch| match ch {
+                            '\t' => 3,
+                            _ => 0,
+                        })
+                        .sum();
+                    buffer.set_style_range(
+                        row_num,
+                        max_line_num_len + 3 + start + tabs,
+                        max_line_num_len + 3 + end + tabs,
+                        Style::Addition,
+                        true,
+                    );
                 }
                 row_num += 1;
             }
@@ -1723,13 +1731,6 @@ impl EmitterWriter {
                     assert!(underline_start >= 0 && underline_end >= 0);
                     let padding: usize = max_line_num_len + 3;
                     for p in underline_start..underline_end {
-                        // Colorize addition/replacements with green.
-                        buffer.set_style(
-                            row_num - 1,
-                            (padding as isize + p) as usize,
-                            Style::Addition,
-                            true,
-                        );
                         if !show_diff {
                             // If this is a replacement, underline with `^`, if this is an addition
                             // underline with `+`.
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index ec29d8016dd..a48d4fe8bb5 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -283,6 +283,9 @@ impl CodeSuggestion {
                 let mut buf = String::new();
 
                 let mut line_highlight = vec![];
+                // We need to keep track of the difference between the existing code and the added
+                // or deleted code in order to point at the correct column *after* substitution.
+                let mut acc = 0;
                 for part in &substitution.parts {
                     let cur_lo = sm.lookup_char_pos(part.span.lo());
                     if prev_hi.line == cur_lo.line {
@@ -290,9 +293,11 @@ impl CodeSuggestion {
                             push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
                         while count > 0 {
                             highlights.push(std::mem::take(&mut line_highlight));
+                            acc = 0;
                             count -= 1;
                         }
                     } else {
+                        acc = 0;
                         highlights.push(std::mem::take(&mut line_highlight));
                         let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
                         while count > 0 {
@@ -316,18 +321,43 @@ impl CodeSuggestion {
                         }
                     }
                     // Add a whole line highlight per line in the snippet.
+                    let len: isize = part
+                        .snippet
+                        .split('\n')
+                        .next()
+                        .unwrap_or(&part.snippet)
+                        .chars()
+                        .map(|c| match c {
+                            '\t' => 4,
+                            _ => 1,
+                        })
+                        .sum();
                     line_highlight.push(SubstitutionHighlight {
-                        start: cur_lo.col.0,
-                        end: cur_lo.col.0
-                            + part.snippet.split('\n').next().unwrap_or(&part.snippet).len(),
+                        start: (cur_lo.col.0 as isize + acc) as usize,
+                        end: (cur_lo.col.0 as isize + acc + len) as usize,
                     });
+                    buf.push_str(&part.snippet);
+                    let cur_hi = sm.lookup_char_pos(part.span.hi());
+                    if prev_hi.line == cur_lo.line {
+                        // Account for the difference between the width of the current code and the
+                        // snippet being suggested, so that the *later* suggestions are correctly
+                        // aligned on the screen.
+                        acc += len as isize - (cur_hi.col.0 - cur_lo.col.0) as isize;
+                    }
+                    prev_hi = cur_hi;
+                    prev_line = sf.get_line(prev_hi.line - 1);
                     for line in part.snippet.split('\n').skip(1) {
+                        acc = 0;
                         highlights.push(std::mem::take(&mut line_highlight));
-                        line_highlight.push(SubstitutionHighlight { start: 0, end: line.len() });
+                        let end: usize = line
+                            .chars()
+                            .map(|c| match c {
+                                '\t' => 4,
+                                _ => 1,
+                            })
+                            .sum();
+                        line_highlight.push(SubstitutionHighlight { start: 0, end });
                     }
-                    buf.push_str(&part.snippet);
-                    prev_hi = sm.lookup_char_pos(part.span.hi());
-                    prev_line = sf.get_line(prev_hi.line - 1);
                 }
                 highlights.push(std::mem::take(&mut line_highlight));
                 let only_capitalization = is_case_difference(sm, &buf, bounding_span);