Fix handling of code that is annotated with rustfmt::skip.

A rustfmt::skip'ed block is indented although original lines are
returned. In order to resolve this, the leading whitespaces are trimmed
on each line while retaining the layout; this leaves the skipped code
to be indented as necessary by the caller.
This commit is contained in:
Stéphane Campinas 2018-10-18 22:58:45 +02:00
parent 4789f65041
commit 9c75a15f4c
No known key found for this signature in database
GPG Key ID: 6D5620D908210133
5 changed files with 116 additions and 51 deletions

View File

@ -19,7 +19,7 @@ use config::Config;
use rewrite::RewriteContext;
use shape::{Indent, Shape};
use string::{rewrite_string, StringFormat};
use utils::{count_newlines, first_line_width, last_line_width};
use utils::{count_newlines, first_line_width, last_line_width, trim_left_preserve_layout};
use {ErrorKind, FormattingError};
fn is_custom_comment(comment: &str) -> bool {
@ -332,12 +332,12 @@ fn identify_comment(
let (first_group, rest) = orig.split_at(first_group_ending);
let rewritten_first_group =
if !config.normalize_comments() && has_bare_lines && style.is_block_comment() {
light_rewrite_block_comment_with_bare_lines(first_group, shape, config)?
trim_left_preserve_layout(first_group, &shape.indent, config)
} else if !config.normalize_comments()
&& !config.wrap_comments()
&& !config.format_doc_comments()
{
light_rewrite_comment(first_group, shape.indent, config, is_doc_comment)?
light_rewrite_comment(first_group, shape.indent, config, is_doc_comment)
} else {
rewrite_comment_inner(
first_group,
@ -370,47 +370,6 @@ fn identify_comment(
}
}
/// Trims a minimum of leading whitespaces so that the content layout is kept and aligns to indent.
fn light_rewrite_block_comment_with_bare_lines(
orig: &str,
shape: Shape,
config: &Config,
) -> Option<String> {
let prefix_whitespace_min = orig
.lines()
// skip the line with the starting sigil since the leading whitespace is removed
// otherwise, the minimum would always be zero
.skip(1)
.filter(|line| !line.is_empty())
.map(|line| {
let mut width = 0;
for c in line.chars() {
match c {
' ' => width += 1,
'\t' => width += config.tab_spaces(),
_ => break,
}
}
width
})
.min()?;
let indent_str = shape.indent.to_string(config);
let mut lines = orig.lines();
let first_line = lines.next()?;
let rest = lines
.map(|line| {
if line.is_empty() {
line
} else {
&line[prefix_whitespace_min..]
}
})
.collect::<Vec<&str>>()
.join(&format!("\n{}", indent_str));
Some(format!("{}\n{}{}", first_line, indent_str, rest))
}
/// Attributes for code blocks in rustdoc.
/// See https://doc.rust-lang.org/rustdoc/print.html#attributes
enum CodeBlockAttribute {
@ -912,7 +871,7 @@ fn light_rewrite_comment(
offset: Indent,
config: &Config,
is_doc_comment: bool,
) -> Option<String> {
) -> String {
let lines: Vec<&str> = orig
.lines()
.map(|l| {
@ -933,7 +892,7 @@ fn light_rewrite_comment(
trim_right_unless_two_whitespaces(left_trimmed, is_doc_comment)
})
.collect();
Some(lines.join(&format!("\n{}", offset.to_string(config))))
lines.join(&format!("\n{}", offset.to_string(config)))
}
/// Trims comment characters and possibly a single space from the left of a string.

View File

@ -21,8 +21,9 @@ use syntax::ptr;
use syntax::source_map::{BytePos, Span, NO_EXPANSION};
use comment::{filter_normal_code, CharClasses, FullCodeCharKind};
use config::Config;
use rewrite::RewriteContext;
use shape::Shape;
use shape::{Indent, Shape};
pub const DEPR_SKIP_ANNOTATION: &str = "rustfmt_skip";
pub const SKIP_ANNOTATION: &str = "rustfmt::skip";
@ -482,6 +483,44 @@ pub fn remove_trailing_white_spaces(text: &str) -> String {
buffer
}
/// Trims a minimum of leading whitespaces so that the content layout is kept and aligns to indent.
pub fn trim_left_preserve_layout(orig: &str, indent: &Indent, config: &Config) -> String {
let prefix_whitespace_min = orig
.lines()
// skip the line with the starting sigil since the leading whitespace is removed
// otherwise, the minimum would always be zero
.skip(1)
.filter(|line| !line.is_empty())
.map(|line| {
let mut width = 0;
for c in line.chars() {
match c {
' ' => width += 1,
'\t' => width += config.tab_spaces(),
_ => break,
}
}
width
})
.min()
.unwrap_or(0);
let indent_str = indent.to_string(config);
let mut lines = orig.lines();
let first_line = lines.next().unwrap();
let rest = lines
.map(|line| {
if line.is_empty() {
String::from("\n")
} else {
format!("\n{}{}", indent_str, &line[prefix_whitespace_min..])
}
})
.collect::<Vec<String>>()
.concat();
format!("{}{}", first_line, rest)
}
#[test]
fn test_remove_trailing_white_spaces() {
let s = " r#\"\n test\n \"#";

View File

@ -29,7 +29,7 @@ use source_map::{LineRangeUtils, SpanUtils};
use spanned::Spanned;
use utils::{
self, contains_skip, count_newlines, inner_attributes, mk_sp, ptr_vec_to_ref_vec,
rewrite_ident, DEPR_SKIP_ANNOTATION,
rewrite_ident, trim_left_preserve_layout, DEPR_SKIP_ANNOTATION,
};
use {ErrorKind, FormatReport, FormattingError};
@ -574,9 +574,16 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
}
#[allow(clippy::needless_pass_by_value)]
fn push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>) {
fn push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>, is_skipped: bool) {
if let Some(ref s) = rewrite {
self.push_str(s);
} else if is_skipped {
// in case the code block (e.g., inside a macro or a doc) is skipped a minimum of
// leading whitespaces is trimmed so that the code layout is kept but allows it to
// be indented as necessary
let snippet =
trim_left_preserve_layout(self.snippet(span), &self.block_indent, self.config);
self.push_str(&snippet);
} else {
let snippet = self.snippet(span);
self.push_str(snippet);
@ -586,13 +593,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
pub fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) {
self.format_missing_with_indent(source!(self, span).lo());
self.push_rewrite_inner(span, rewrite);
self.push_rewrite_inner(span, rewrite, false);
}
pub fn push_skipped_with_span(&mut self, span: Span) {
self.format_missing_with_indent(source!(self, span).lo());
let lo = self.line_number + 1;
self.push_rewrite_inner(span, None);
self.push_rewrite_inner(span, None, true);
let hi = self.line_number + 1;
self.skipped_range.push((lo, hi));
}

View File

@ -0,0 +1,30 @@
// rustfmt-wrap_comments: true
/// ```
/// pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
/// let imm8 = (imm8 & 0xFF) as u8;
/// let a = a.as_i16x16();
/// macro_rules! shuffle_done {
/// ($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
/// #[cfg_attr(rustfmt, rustfmt_skip)]
/// simd_shuffle16(a, a, [
/// 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
/// 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
/// ]);
/// };
/// }
/// }
/// ```
pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
let imm8 = (imm8 & 0xFF) as u8;
let a = a.as_i16x16();
macro_rules! shuffle_done {
($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
#[cfg_attr(rustfmt, rustfmt_skip)]
simd_shuffle16(a, a, [
0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
]);
};
}
}

View File

@ -0,0 +1,30 @@
// rustfmt-wrap_comments: true
/// ```
/// pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
/// let imm8 = (imm8 & 0xFF) as u8;
/// let a = a.as_i16x16();
/// macro_rules! shuffle_done {
/// ($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
/// #[cfg_attr(rustfmt, rustfmt_skip)]
/// simd_shuffle16(a, a, [
/// 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
/// 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
/// ]);
/// };
/// }
/// }
/// ```
pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
let imm8 = (imm8 & 0xFF) as u8;
let a = a.as_i16x16();
macro_rules! shuffle_done {
($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
#[cfg_attr(rustfmt, rustfmt_skip)]
simd_shuffle16(a, a, [
0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
]);
};
}
}