X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmissed_spans.rs;h=a957d3b3e30256524c4df2e510094e98707cec27;hb=160c3aafc53912352988887ed764ed4c862a14b2;hp=237a31e86b8838cfe2c05d0b23d70434063f1bea;hpb=6efc96324556d9d2bd0a60b652831e655f335d58;p=rust.git diff --git a/src/missed_spans.rs b/src/missed_spans.rs index 237a31e86b8..a957d3b3e30 100644 --- a/src/missed_spans.rs +++ b/src/missed_spans.rs @@ -1,23 +1,14 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::borrow::Cow; - use syntax::source_map::{BytePos, Pos, Span}; -use comment::{rewrite_comment, CodeCharKind, CommentCodeSlices}; -use config::{EmitMode, FileName}; -use shape::{Indent, Shape}; -use source_map::LineRangeUtils; -use utils::{count_newlines, last_line_width, mk_sp}; -use visitor::FmtVisitor; +use crate::comment::{is_last_comment_block, rewrite_comment, CodeCharKind, CommentCodeSlices}; +use crate::config::file_lines::FileLines; +use crate::config::FileName; +use crate::config::Version; +use crate::coverage::transform_missing_snippet; +use crate::shape::{Indent, Shape}; +use crate::source_map::LineRangeUtils; +use crate::utils::{count_lf_crlf, count_newlines, last_line_width, mk_sp}; +use crate::visitor::FmtVisitor; struct SnippetStatus { /// An offset to the current line from the beginning of the original snippet. @@ -43,10 +34,9 @@ fn output_at_start(&self) -> bool { self.buffer.is_empty() } - pub fn format_missing(&mut self, end: BytePos) { - // HACK(topecongiro) - // We use `format_missing()` to extract a missing comment between a macro - // (or alike) and a trailing semicolon. Here we just try to avoid calling + pub(crate) fn format_missing(&mut self, end: BytePos) { + // HACK(topecongiro): we use `format_missing()` to extract a missing comment between + // a macro (or similar) and a trailing semicolon. Here we just try to avoid calling // `format_missing_inner` in the common case where there is no such comment. // This is a hack, ideally we should fix a possible bug in `format_missing_inner` // or refactor `visit_mac` and `rewrite_macro`, but this should suffice to fix the @@ -60,10 +50,10 @@ pub fn format_missing(&mut self, end: BytePos) { self.format_missing_inner(end, |this, last_snippet, _| this.push_str(last_snippet)) } - pub fn format_missing_with_indent(&mut self, end: BytePos) { + pub(crate) fn format_missing_with_indent(&mut self, end: BytePos) { let config = self.config; self.format_missing_inner(end, |this, last_snippet, snippet| { - this.push_str(last_snippet.trim_right()); + this.push_str(last_snippet.trim_end()); if last_snippet == snippet && !this.output_at_start() { // No new lines in the snippet. this.push_str("\n"); @@ -73,13 +63,13 @@ pub fn format_missing_with_indent(&mut self, end: BytePos) { }) } - pub fn format_missing_no_indent(&mut self, end: BytePos) { + pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) { self.format_missing_inner(end, |this, last_snippet, _| { - this.push_str(last_snippet.trim_right()); + this.push_str(last_snippet.trim_end()); }) } - fn format_missing_inner( + fn format_missing_inner, &str, &str)>( &mut self, end: BytePos, process_last_snippet: F, @@ -144,7 +134,7 @@ fn push_vertical_spaces(&mut self, mut newline_count: usize) { fn write_snippet(&mut self, span: Span, process_last_snippet: F) where - F: Fn(&mut FmtVisitor, &str, &str), + F: Fn(&mut FmtVisitor<'_>, &str, &str), { // Get a snippet from the file start to the span's hi without allocating. // We need it to determine what precedes the current comment. If the comment @@ -172,7 +162,7 @@ fn write_snippet_inner( span: Span, process_last_snippet: F, ) where - F: Fn(&mut FmtVisitor, &str, &str), + F: Fn(&mut FmtVisitor<'_>, &str, &str), { // Trim whitespace from the right hand side of each line. // Annoyingly, the library functions for splitting by lines etc. are not @@ -181,21 +171,28 @@ fn write_snippet_inner( let file_name = &char_pos.file.name.clone().into(); let mut status = SnippetStatus::new(char_pos.line); - let snippet = &*match self.config.emit_mode() { - EmitMode::Coverage => Cow::from(replace_chars(old_snippet)), - _ => Cow::from(old_snippet), - }; - + let snippet = &*transform_missing_snippet(self.config, old_snippet); + + let slice_within_file_lines_range = + |file_lines: FileLines, cur_line, s| -> (usize, usize, bool) { + let (lf_count, crlf_count) = count_lf_crlf(s); + let newline_count = lf_count + crlf_count; + let within_file_lines_range = file_lines.contains_range( + file_name, + cur_line, + // if a newline character is at the end of the slice, then the number of + // newlines needs to be decreased by 1 so that the range checked against + // the file_lines is the visual range one would expect. + cur_line + newline_count - if s.ends_with('\n') { 1 } else { 0 }, + ); + (lf_count, crlf_count, within_file_lines_range) + }; for (kind, offset, subslice) in CommentCodeSlices::new(snippet) { debug!("{:?}: {:?}", kind, subslice); - let newline_count = count_newlines(subslice); - let within_file_lines_range = self.config.file_lines().contains_range( - file_name, - status.cur_line, - status.cur_line + newline_count, - ); - + let (lf_count, crlf_count, within_file_lines_range) = + slice_within_file_lines_range(self.config.file_lines(), status.cur_line, subslice); + let newline_count = lf_count + crlf_count; if CodeCharKind::Comment == kind && within_file_lines_range { // 1: comment. self.process_comment( @@ -209,14 +206,22 @@ fn write_snippet_inner( // 2: blank lines. self.push_vertical_spaces(newline_count); status.cur_line += newline_count; - status.line_start = offset + newline_count; + status.line_start = offset + lf_count + crlf_count * 2; } else { // 3: code which we failed to format or which is not within file-lines range. self.process_missing_code(&mut status, snippet, subslice, offset, file_name); } } - process_last_snippet(self, &snippet[status.line_start..], snippet); + let last_snippet = &snippet[status.line_start..]; + let (_, _, within_file_lines_range) = + slice_within_file_lines_range(self.config.file_lines(), status.cur_line, last_snippet); + if within_file_lines_range { + process_last_snippet(self, last_snippet, snippet); + } else { + // just append what's left + self.push_str(last_snippet); + } } fn process_comment( @@ -234,6 +239,7 @@ fn process_comment( .next(); let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c)); + let mut on_same_line = false; let comment_indent = if fix_indent { if let Some('{') = last_char { @@ -242,6 +248,13 @@ fn process_comment( let indent_str = self.block_indent.to_string(self.config); self.push_str(&indent_str); self.block_indent + } else if self.config.version() == Version::Two && !snippet.starts_with('\n') { + // The comment appears on the same line as the previous formatted code. + // Assuming that comment is logically associated with that code, we want to keep it on + // the same level and avoid mixing it with possible other comment. + on_same_line = true; + self.push_str(" "); + self.block_indent } else { self.push_str(" "); Indent::from_width(self.config, last_line_width(&self.buffer)) @@ -252,22 +265,53 @@ fn process_comment( self.config.max_width() - self.block_indent.width(), ); let comment_shape = Shape::legacy(comment_width, comment_indent); - let comment_str = rewrite_comment(subslice, false, comment_shape, self.config) - .unwrap_or_else(|| String::from(subslice)); - self.push_str(&comment_str); + + if on_same_line { + match subslice.find("\n") { + None => { + self.push_str(subslice); + } + Some(offset) if offset + 1 == subslice.len() => { + self.push_str(&subslice[..offset]); + } + Some(offset) => { + // keep first line as is: if it were too long and wrapped, it may get mixed + // with the other lines. + let first_line = &subslice[..offset]; + self.push_str(first_line); + self.push_str(&comment_indent.to_string_with_newline(self.config)); + + let other_lines = &subslice[offset + 1..]; + let comment_str = + rewrite_comment(other_lines, false, comment_shape, self.config) + .unwrap_or_else(|| String::from(other_lines)); + self.push_str(&comment_str); + } + } + } else { + let comment_str = rewrite_comment(subslice, false, comment_shape, self.config) + .unwrap_or_else(|| String::from(subslice)); + self.push_str(&comment_str); + } status.last_wspace = None; status.line_start = offset + subslice.len(); - if let Some('/') = subslice.chars().nth(1) { - // Only add a newline if the last line is a line comment - if !subslice.trim_end().ends_with("*/") { - self.push_str("\n"); - } - } else if status.line_start <= snippet.len() { - // For other comments add a newline if there isn't one at the end already - match snippet[status.line_start..].chars().next() { - Some('\n') | Some('\r') => (), + // Add a newline: + // - if there isn't one already + // - otherwise, only if the last line is a line comment + if status.line_start <= snippet.len() { + match snippet[status.line_start..] + .chars() + // skip trailing whitespaces + .skip_while(|c| *c == ' ' || *c == '\t') + .next() + { + Some('\n') | Some('\r') => { + if !is_last_comment_block(subslice) { + self.push_str("\n"); + } + } _ => self.push_str("\n"), } } @@ -319,10 +363,3 @@ fn process_missing_code( } } } - -fn replace_chars(string: &str) -> String { - string - .chars() - .map(|ch| if ch.is_whitespace() { ch } else { 'X' }) - .collect() -}