Skip to content

Commit dbed218

Browse files
committed
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.
1 parent e633f2b commit dbed218

File tree

5 files changed

+116
-51
lines changed

5 files changed

+116
-51
lines changed

src/comment.rs

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use config::Config;
1919
use rewrite::RewriteContext;
2020
use shape::{Indent, Shape};
2121
use string::{rewrite_string, StringFormat};
22-
use utils::{count_newlines, first_line_width, last_line_width};
22+
use utils::{count_newlines, first_line_width, last_line_width, trim_left_preserve_layout};
2323
use {ErrorKind, FormattingError};
2424

2525
fn is_custom_comment(comment: &str) -> bool {
@@ -332,12 +332,12 @@ fn identify_comment(
332332
let (first_group, rest) = orig.split_at(first_group_ending);
333333
let rewritten_first_group =
334334
if !config.normalize_comments() && has_bare_lines && style.is_block_comment() {
335-
light_rewrite_block_comment_with_bare_lines(first_group, shape, config)?
335+
trim_left_preserve_layout(first_group, &shape.indent, config)
336336
} else if !config.normalize_comments()
337337
&& !config.wrap_comments()
338338
&& !config.format_doc_comments()
339339
{
340-
light_rewrite_comment(first_group, shape.indent, config, is_doc_comment)?
340+
light_rewrite_comment(first_group, shape.indent, config, is_doc_comment)
341341
} else {
342342
rewrite_comment_inner(
343343
first_group,
@@ -370,47 +370,6 @@ fn identify_comment(
370370
}
371371
}
372372

373-
/// Trims a minimum of leading whitespaces so that the content layout is kept and aligns to indent.
374-
fn light_rewrite_block_comment_with_bare_lines(
375-
orig: &str,
376-
shape: Shape,
377-
config: &Config,
378-
) -> Option<String> {
379-
let prefix_whitespace_min = orig
380-
.lines()
381-
// skip the line with the starting sigil since the leading whitespace is removed
382-
// otherwise, the minimum would always be zero
383-
.skip(1)
384-
.filter(|line| !line.is_empty())
385-
.map(|line| {
386-
let mut width = 0;
387-
for c in line.chars() {
388-
match c {
389-
' ' => width += 1,
390-
'\t' => width += config.tab_spaces(),
391-
_ => break,
392-
}
393-
}
394-
width
395-
})
396-
.min()?;
397-
398-
let indent_str = shape.indent.to_string(config);
399-
let mut lines = orig.lines();
400-
let first_line = lines.next()?;
401-
let rest = lines
402-
.map(|line| {
403-
if line.is_empty() {
404-
line
405-
} else {
406-
&line[prefix_whitespace_min..]
407-
}
408-
})
409-
.collect::<Vec<&str>>()
410-
.join(&format!("\n{}", indent_str));
411-
Some(format!("{}\n{}{}", first_line, indent_str, rest))
412-
}
413-
414373
/// Attributes for code blocks in rustdoc.
415374
/// See https://doc.rust-lang.org/rustdoc/print.html#attributes
416375
enum CodeBlockAttribute {
@@ -912,7 +871,7 @@ fn light_rewrite_comment(
912871
offset: Indent,
913872
config: &Config,
914873
is_doc_comment: bool,
915-
) -> Option<String> {
874+
) -> String {
916875
let lines: Vec<&str> = orig
917876
.lines()
918877
.map(|l| {
@@ -933,7 +892,7 @@ fn light_rewrite_comment(
933892
trim_right_unless_two_whitespaces(left_trimmed, is_doc_comment)
934893
})
935894
.collect();
936-
Some(lines.join(&format!("\n{}", offset.to_string(config))))
895+
lines.join(&format!("\n{}", offset.to_string(config)))
937896
}
938897

939898
/// Trims comment characters and possibly a single space from the left of a string.

src/utils.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ use syntax::ptr;
2121
use syntax::source_map::{BytePos, Span, NO_EXPANSION};
2222

2323
use comment::{filter_normal_code, CharClasses, FullCodeCharKind};
24+
use config::Config;
2425
use rewrite::RewriteContext;
25-
use shape::Shape;
26+
use shape::{Indent, Shape};
2627

2728
pub const DEPR_SKIP_ANNOTATION: &str = "rustfmt_skip";
2829
pub const SKIP_ANNOTATION: &str = "rustfmt::skip";
@@ -482,6 +483,44 @@ pub fn remove_trailing_white_spaces(text: &str) -> String {
482483
buffer
483484
}
484485

486+
/// Trims a minimum of leading whitespaces so that the content layout is kept and aligns to indent.
487+
pub fn trim_left_preserve_layout(orig: &str, indent: &Indent, config: &Config) -> String {
488+
let prefix_whitespace_min = orig
489+
.lines()
490+
// skip the line with the starting sigil since the leading whitespace is removed
491+
// otherwise, the minimum would always be zero
492+
.skip(1)
493+
.filter(|line| !line.is_empty())
494+
.map(|line| {
495+
let mut width = 0;
496+
for c in line.chars() {
497+
match c {
498+
' ' => width += 1,
499+
'\t' => width += config.tab_spaces(),
500+
_ => break,
501+
}
502+
}
503+
width
504+
})
505+
.min()
506+
.unwrap_or(0);
507+
508+
let indent_str = indent.to_string(config);
509+
let mut lines = orig.lines();
510+
let first_line = lines.next().unwrap();
511+
let rest = lines
512+
.map(|line| {
513+
if line.is_empty() {
514+
String::from("\n")
515+
} else {
516+
format!("\n{}{}", indent_str, &line[prefix_whitespace_min..])
517+
}
518+
})
519+
.collect::<Vec<String>>()
520+
.concat();
521+
format!("{}{}", first_line, rest)
522+
}
523+
485524
#[test]
486525
fn test_remove_trailing_white_spaces() {
487526
let s = " r#\"\n test\n \"#";

src/visitor.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use source_map::{LineRangeUtils, SpanUtils};
2929
use spanned::Spanned;
3030
use utils::{
3131
self, contains_skip, count_newlines, inner_attributes, mk_sp, ptr_vec_to_ref_vec,
32-
rewrite_ident, DEPR_SKIP_ANNOTATION,
32+
rewrite_ident, trim_left_preserve_layout, DEPR_SKIP_ANNOTATION,
3333
};
3434
use {ErrorKind, FormatReport, FormattingError};
3535

@@ -574,9 +574,16 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
574574
}
575575

576576
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
577-
fn push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>) {
577+
fn push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>, is_skipped: bool) {
578578
if let Some(ref s) = rewrite {
579579
self.push_str(s);
580+
} else if is_skipped {
581+
// in case the code block (e.g., inside a macro or a doc) is skipped a minimum of
582+
// leading whitespaces is trimmed so that the code layout is kept but allows it to
583+
// be indented as necessary
584+
let snippet =
585+
trim_left_preserve_layout(self.snippet(span), &self.block_indent, self.config);
586+
self.push_str(&snippet);
580587
} else {
581588
let snippet = self.snippet(span);
582589
self.push_str(snippet);
@@ -586,13 +593,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
586593

587594
pub fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) {
588595
self.format_missing_with_indent(source!(self, span).lo());
589-
self.push_rewrite_inner(span, rewrite);
596+
self.push_rewrite_inner(span, rewrite, false);
590597
}
591598

592599
pub fn push_skipped_with_span(&mut self, span: Span) {
593600
self.format_missing_with_indent(source!(self, span).lo());
594601
let lo = self.line_number + 1;
595-
self.push_rewrite_inner(span, None);
602+
self.push_rewrite_inner(span, None, true);
596603
let hi = self.line_number + 1;
597604
self.skipped_range.push((lo, hi));
598605
}

tests/source/issue-3105.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// rustfmt-wrap_comments: true
2+
3+
/// ```
4+
/// pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
5+
/// let imm8 = (imm8 & 0xFF) as u8;
6+
/// let a = a.as_i16x16();
7+
/// macro_rules! shuffle_done {
8+
/// ($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
9+
/// #[cfg_attr(rustfmt, rustfmt_skip)]
10+
/// simd_shuffle16(a, a, [
11+
/// 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
12+
/// 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
13+
/// ]);
14+
/// };
15+
/// }
16+
/// }
17+
/// ```
18+
pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
19+
let imm8 = (imm8 & 0xFF) as u8;
20+
let a = a.as_i16x16();
21+
macro_rules! shuffle_done {
22+
($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
23+
#[cfg_attr(rustfmt, rustfmt_skip)]
24+
simd_shuffle16(a, a, [
25+
0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
26+
8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
27+
]);
28+
};
29+
}
30+
}

tests/target/issue-3105.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// rustfmt-wrap_comments: true
2+
3+
/// ```
4+
/// pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
5+
/// let imm8 = (imm8 & 0xFF) as u8;
6+
/// let a = a.as_i16x16();
7+
/// macro_rules! shuffle_done {
8+
/// ($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
9+
/// #[cfg_attr(rustfmt, rustfmt_skip)]
10+
/// simd_shuffle16(a, a, [
11+
/// 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
12+
/// 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
13+
/// ]);
14+
/// };
15+
/// }
16+
/// }
17+
/// ```
18+
pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i {
19+
let imm8 = (imm8 & 0xFF) as u8;
20+
let a = a.as_i16x16();
21+
macro_rules! shuffle_done {
22+
($x01:expr, $x23:expr, $x45:expr, $x67:expr) => {
23+
#[cfg_attr(rustfmt, rustfmt_skip)]
24+
simd_shuffle16(a, a, [
25+
0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67,
26+
8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67
27+
]);
28+
};
29+
}
30+
}

0 commit comments

Comments
 (0)