Honor #[rustfmt::skip::attributes(derive)] attribute

Fixes 5270

Previously, rustfmt only checked the `merge_derives` configuration value
to determine if it should merge_derives. This lead to derives being
merged even when annotated with the `rustfmt::skip` attribute.

Now, rustfmt also checks if derives are explicitly being skipped in the
current context via the `rustfmt::skip` attribute.
This commit is contained in:
Yacin Tmimi 2022-03-18 09:48:45 -04:00 committed by Caleb Cartwright
parent 0dba01aee1
commit 8984438a6f
4 changed files with 189 additions and 1 deletions

View File

@ -389,6 +389,10 @@ impl Rewrite for [ast::Attribute] {
let mut attrs = self;
let mut result = String::new();
// Determine if the source text is annotated with `#[rustfmt::skip::attributes(derive)]`
// or `#![rustfmt::skip::attributes(derive)]`
let skip_derives = context.skip_context.skip_attribute("derive");
// This is not just a simple map because we need to handle doc comments
// (where we take as many doc comment attributes as possible) and possibly
// merging derives into a single attribute.
@ -431,7 +435,7 @@ impl Rewrite for [ast::Attribute] {
}
// Handle derives if we will merge them.
if context.config.merge_derives() && is_derive(&attrs[0]) {
if !skip_derives && context.config.merge_derives() && is_derive(&attrs[0]) {
let derives = take_while_with_pred(context, attrs, is_derive);
let derive_str = format_derive(derives, shape, context)?;
result.push_str(&derive_str);

View File

@ -0,0 +1,62 @@
// rustfmt-merge_derives:true
#[rustfmt::skip::attributes(derive)]
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[rustfmt::skip::attributes(derive)]
#[derive(Clone)]
struct DoNotMergeDerivesSkipInMiddle {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
#[rustfmt::skip::attributes(derive)]
struct DoNotMergeDerivesSkipAtEnd {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct MergeDerives {
field: String,
}
mod inner_attribute_derive_skip {
#![rustfmt::skip::attributes(derive)]
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
}
#[rustfmt::skip::attributes(derive)]
mod outer_attribute_derive_skip {
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
}
mod no_derive_skip {
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct MergeDerives {
field: String,
}
}

View File

@ -0,0 +1,62 @@
// rustfmt-merge_derives:false
#[rustfmt::skip::attributes(derive)]
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[rustfmt::skip::attributes(derive)]
#[derive(Clone)]
struct DoNotMergeDerivesSkipInMiddle {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
#[rustfmt::skip::attributes(derive)]
struct DoNotMergeDerivesSkipAtEnd {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct MergeDerives {
field: String,
}
mod inner_attribute_derive_skip {
#![rustfmt::skip::attributes(derive)]
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
}
#[rustfmt::skip::attributes(derive)]
mod outer_attribute_derive_skip {
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
}
mod no_derive_skip {
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct MergeDerives {
field: String,
}
}

View File

@ -0,0 +1,60 @@
// rustfmt-merge_derives:true
#[rustfmt::skip::attributes(derive)]
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[rustfmt::skip::attributes(derive)]
#[derive(Clone)]
struct DoNotMergeDerivesSkipInMiddle {
field: String,
}
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
#[rustfmt::skip::attributes(derive)]
struct DoNotMergeDerivesSkipAtEnd {
field: String,
}
#[allow(dead_code)]
#[derive(StructField, Clone)]
struct MergeDerives {
field: String,
}
mod inner_attribute_derive_skip {
#![rustfmt::skip::attributes(derive)]
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
}
#[rustfmt::skip::attributes(derive)]
mod outer_attribute_derive_skip {
#[allow(dead_code)]
#[derive(StructField)]
#[derive(Clone)]
struct DoNotMergeDerives {
field: String,
}
}
mod no_derive_skip {
#[allow(dead_code)]
#[derive(StructField, Clone)]
struct MergeDerives {
field: String,
}
}