@@ -2216,6 +2216,11 @@ impl HumanEmitter {
22162216 show_code_change
22172217 {
22182218 for part in parts {
2219+ let snippet = if let Ok ( snippet) = sm. span_to_snippet ( part. span ) {
2220+ snippet
2221+ } else {
2222+ String :: new ( )
2223+ } ;
22192224 let span_start_pos = sm. lookup_char_pos ( part. span . lo ( ) ) . col_display ;
22202225 let span_end_pos = sm. lookup_char_pos ( part. span . hi ( ) ) . col_display ;
22212226
@@ -2263,13 +2268,80 @@ impl HumanEmitter {
22632268 }
22642269 if let DisplaySuggestion :: Diff = show_code_change {
22652270 // Colorize removal with red in diff format.
2266- buffer. set_style_range (
2267- row_num - 2 ,
2268- ( padding as isize + span_start_pos as isize ) as usize ,
2269- ( padding as isize + span_end_pos as isize ) as usize ,
2270- Style :: Removal ,
2271- true ,
2272- ) ;
2271+
2272+ // Below, there's some tricky buffer indexing going on. `row_num` at this
2273+ // point corresponds to:
2274+ //
2275+ // |
2276+ // LL | CODE
2277+ // | ++++ <- `row_num`
2278+ //
2279+ // in the buffer. When we have a diff format output, we end up with
2280+ //
2281+ // |
2282+ // LL - OLDER <- row_num - 2
2283+ // LL + NEWER
2284+ // | <- row_num
2285+ //
2286+ // The `row_num - 2` is to select the buffer line that has the "old version
2287+ // of the diff" at that point. When the removal is a single line, `i` is
2288+ // `0`, `newlines` is `1` so `(newlines - i - 1)` ends up being `0`, so row
2289+ // points at `LL - OLDER`. When the removal corresponds to multiple lines,
2290+ // we end up with `newlines > 1` and `i` being `0..newlines - 1`.
2291+ //
2292+ // |
2293+ // LL - OLDER <- row_num - 2 - (newlines - last_i - 1)
2294+ // LL - CODE
2295+ // LL - BEING
2296+ // LL - REMOVED <- row_num - 2 - (newlines - first_i - 1)
2297+ // LL + NEWER
2298+ // | <- row_num
2299+
2300+ let newlines = snippet. lines ( ) . count ( ) ;
2301+ if newlines > 0 && row_num > newlines {
2302+ // Account for removals where the part being removed spans multiple
2303+ // lines.
2304+ // FIXME: We check the number of rows because in some cases, like in
2305+ // `tests/ui/lint/invalid-nan-comparison-suggestion.rs`, the rendered
2306+ // suggestion will only show the first line of code being replaced. The
2307+ // proper way of doing this would be to change the suggestion rendering
2308+ // logic to show the whole prior snippet, but the current output is not
2309+ // too bad to begin with, so we side-step that issue here.
2310+ for ( i, line) in snippet. lines ( ) . enumerate ( ) {
2311+ let line = normalize_whitespace ( line) ;
2312+ let row = row_num - 2 - ( newlines - i - 1 ) ;
2313+ // On the first line, we highlight between the start of the part
2314+ // span, and the end of that line.
2315+ // On the last line, we highlight between the start of the line, and
2316+ // the column of the part span end.
2317+ // On all others, we highlight the whole line.
2318+ let start = if i == 0 {
2319+ ( padding as isize + span_start_pos as isize ) as usize
2320+ } else {
2321+ padding
2322+ } ;
2323+ let end = if i == 0 {
2324+ ( padding as isize
2325+ + span_start_pos as isize
2326+ + line. len ( ) as isize )
2327+ as usize
2328+ } else if i == newlines - 1 {
2329+ ( padding as isize + span_end_pos as isize ) as usize
2330+ } else {
2331+ ( padding as isize + line. len ( ) as isize ) as usize
2332+ } ;
2333+ buffer. set_style_range ( row, start, end, Style :: Removal , true ) ;
2334+ }
2335+ } else {
2336+ // The removed code fits all in one line.
2337+ buffer. set_style_range (
2338+ row_num - 2 ,
2339+ ( padding as isize + span_start_pos as isize ) as usize ,
2340+ ( padding as isize + span_end_pos as isize ) as usize ,
2341+ Style :: Removal ,
2342+ true ,
2343+ ) ;
2344+ }
22732345 }
22742346
22752347 // length of the code after substitution
0 commit comments