From 9c75a15f4c81a6e412844f85d6d24541a88b49e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Campinas?= Date: Thu, 18 Oct 2018 22:58:45 +0200 Subject: [PATCH] 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. --- src/comment.rs | 51 ++++---------------------------------- src/utils.rs | 41 +++++++++++++++++++++++++++++- src/visitor.rs | 15 ++++++++--- tests/source/issue-3105.rs | 30 ++++++++++++++++++++++ tests/target/issue-3105.rs | 30 ++++++++++++++++++++++ 5 files changed, 116 insertions(+), 51 deletions(-) create mode 100644 tests/source/issue-3105.rs create mode 100644 tests/target/issue-3105.rs diff --git a/src/comment.rs b/src/comment.rs index 358c18e1b95..7e06d9a8d60 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -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 { - 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::>() - .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 { 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. diff --git a/src/utils.rs b/src/utils.rs index d90bcc5931d..a2d15b820eb 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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::>() + .concat(); + format!("{}{}", first_line, rest) +} + #[test] fn test_remove_trailing_white_spaces() { let s = " r#\"\n test\n \"#"; diff --git a/src/visitor.rs b/src/visitor.rs index 9ad6d3ccaa8..036c4990a58 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -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) { + fn push_rewrite_inner(&mut self, span: Span, rewrite: Option, 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) { 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)); } diff --git a/tests/source/issue-3105.rs b/tests/source/issue-3105.rs new file mode 100644 index 00000000000..f6331cd6a02 --- /dev/null +++ b/tests/source/issue-3105.rs @@ -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 + ]); + }; + } +} diff --git a/tests/target/issue-3105.rs b/tests/target/issue-3105.rs new file mode 100644 index 00000000000..2b9f5ce91df --- /dev/null +++ b/tests/target/issue-3105.rs @@ -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 + ]); + }; + } +}