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:
parent
4789f65041
commit
9c75a15f4c
@ -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.
|
||||
|
41
src/utils.rs
41
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::<Vec<String>>()
|
||||
.concat();
|
||||
format!("{}{}", first_line, rest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_trailing_white_spaces() {
|
||||
let s = " r#\"\n test\n \"#";
|
||||
|
@ -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));
|
||||
}
|
||||
|
30
tests/source/issue-3105.rs
Normal file
30
tests/source/issue-3105.rs
Normal 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
|
||||
]);
|
||||
};
|
||||
}
|
||||
}
|
30
tests/target/issue-3105.rs
Normal file
30
tests/target/issue-3105.rs
Normal 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
|
||||
]);
|
||||
};
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user