@@ -1874,6 +1874,7 @@ impl Renderer {
18741874 show_code_change
18751875 {
18761876 for part in parts {
1877+ let snippet = sm. span_to_snippet ( part. span . clone ( ) ) . unwrap_or_default ( ) ;
18771878 let ( span_start, span_end) = sm. span_to_locations ( part. span . clone ( ) ) ;
18781879 let span_start_pos = span_start. display ;
18791880 let span_end_pos = span_end. display ;
@@ -1932,13 +1933,86 @@ impl Renderer {
19321933 }
19331934 if let DisplaySuggestion :: Diff = show_code_change {
19341935 // Colorize removal with red in diff format.
1935- buffer. set_style_range (
1936- row_num - 2 ,
1937- ( padding as isize + span_start_pos as isize ) as usize ,
1938- ( padding as isize + span_end_pos as isize ) as usize ,
1939- ElementStyle :: Removal ,
1940- true ,
1941- ) ;
1936+
1937+ // Below, there's some tricky buffer indexing going on. `row_num` at this
1938+ // point corresponds to:
1939+ //
1940+ // |
1941+ // LL | CODE
1942+ // | ++++ <- `row_num`
1943+ //
1944+ // in the buffer. When we have a diff format output, we end up with
1945+ //
1946+ // |
1947+ // LL - OLDER <- row_num - 2
1948+ // LL + NEWER
1949+ // | <- row_num
1950+ //
1951+ // The `row_num - 2` is to select the buffer line that has the "old version
1952+ // of the diff" at that point. When the removal is a single line, `i` is
1953+ // `0`, `newlines` is `1` so `(newlines - i - 1)` ends up being `0`, so row
1954+ // points at `LL - OLDER`. When the removal corresponds to multiple lines,
1955+ // we end up with `newlines > 1` and `i` being `0..newlines - 1`.
1956+ //
1957+ // |
1958+ // LL - OLDER <- row_num - 2 - (newlines - last_i - 1)
1959+ // LL - CODE
1960+ // LL - BEING
1961+ // LL - REMOVED <- row_num - 2 - (newlines - first_i - 1)
1962+ // LL + NEWER
1963+ // | <- row_num
1964+
1965+ let newlines = snippet. lines ( ) . count ( ) ;
1966+ if newlines > 0 && row_num > newlines {
1967+ // Account for removals where the part being removed spans multiple
1968+ // lines.
1969+ // FIXME: We check the number of rows because in some cases, like in
1970+ // `tests/ui/lint/invalid-nan-comparison-suggestion.rs`, the rendered
1971+ // suggestion will only show the first line of code being replaced. The
1972+ // proper way of doing this would be to change the suggestion rendering
1973+ // logic to show the whole prior snippet, but the current output is not
1974+ // too bad to begin with, so we side-step that issue here.
1975+ for ( i, line) in snippet. lines ( ) . enumerate ( ) {
1976+ let line = normalize_whitespace ( line) ;
1977+ let row = row_num - 2 - ( newlines - i - 1 ) ;
1978+ // On the first line, we highlight between the start of the part
1979+ // span, and the end of that line.
1980+ // On the last line, we highlight between the start of the line, and
1981+ // the column of the part span end.
1982+ // On all others, we highlight the whole line.
1983+ let start = if i == 0 {
1984+ ( padding as isize + span_start_pos as isize ) as usize
1985+ } else {
1986+ padding
1987+ } ;
1988+ let end = if i == 0 {
1989+ ( padding as isize
1990+ + span_start_pos as isize
1991+ + line. len ( ) as isize )
1992+ as usize
1993+ } else if i == newlines - 1 {
1994+ ( padding as isize + span_end_pos as isize ) as usize
1995+ } else {
1996+ ( padding as isize + line. len ( ) as isize ) as usize
1997+ } ;
1998+ buffer. set_style_range (
1999+ row,
2000+ start,
2001+ end,
2002+ ElementStyle :: Removal ,
2003+ true ,
2004+ ) ;
2005+ }
2006+ } else {
2007+ // The removed code fits all in one line.
2008+ buffer. set_style_range (
2009+ row_num - 2 ,
2010+ ( padding as isize + span_start_pos as isize ) as usize ,
2011+ ( padding as isize + span_end_pos as isize ) as usize ,
2012+ ElementStyle :: Removal ,
2013+ true ,
2014+ ) ;
2015+ }
19422016 }
19432017
19442018 // length of the code after substitution
0 commit comments