Skip to content

Commit 76e2ba2

Browse files
la10736topecongiro
authored andcommitted
1 parent 66c27c9 commit 76e2ba2

17 files changed

+207
-54
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- Add new attribute `rustfmt::skip::attributes` to prevent rustfmt
8+
from formatting an attribute #3665
9+
510
## [1.3.3] 2019-07-15
611

712
### Added

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,16 @@ needs to be specified in `rustfmt.toml`, e.g., with `edition = "2018"`.
179179
## Tips
180180

181181
* For things you do not want rustfmt to mangle, use `#[rustfmt::skip]`
182-
* To prevent rustfmt from formatting a macro,
183-
use `#[rustfmt::skip::macros(target_macro_name)]`
182+
* To prevent rustfmt from formatting a macro or an attribute,
183+
use `#[rustfmt::skip::macros(target_macro_name)]` or
184+
`#[rustfmt::skip::attributes(target_attribute_name)]`
184185

185186
Example:
186187

187188
```rust
189+
#![rustfmt::skip::attributes(custom_attribute)]
190+
191+
#[custom_attribute(formatting , here , should , be , Skipped)]
188192
#[rustfmt::skip::macros(html)]
189193
fn main() {
190194
let macro_result1 = html! { <div>

src/attr.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,13 @@ impl Rewrite for ast::Attribute {
319319
if self.is_sugared_doc {
320320
rewrite_doc_comment(snippet, shape.comment(context.config), context.config)
321321
} else {
322+
let should_skip = self
323+
.ident()
324+
.map(|s| context.skip_context.skip_attribute(&s.name.as_str()))
325+
.unwrap_or(false);
322326
let prefix = attr_prefix(self);
323327

324-
if contains_comment(snippet) {
328+
if should_skip || contains_comment(snippet) {
325329
return Some(snippet.to_owned());
326330
}
327331

src/formatting.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::comment::{CharClasses, FullCodeCharKind};
1717
use crate::config::{Config, FileName, Verbosity};
1818
use crate::ignore_path::IgnorePathSet;
1919
use crate::issues::BadIssueSeeker;
20-
use crate::utils::{count_newlines, get_skip_macro_names};
20+
use crate::utils::count_newlines;
2121
use crate::visitor::{FmtVisitor, SnippetProvider};
2222
use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session};
2323

@@ -158,10 +158,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
158158
&snippet_provider,
159159
self.report.clone(),
160160
);
161-
visitor
162-
.skip_macro_names
163-
.borrow_mut()
164-
.append(&mut get_skip_macro_names(&self.krate.attrs));
161+
visitor.skip_context.update_with_attrs(&self.krate.attrs);
165162

166163
// Format inner attributes if available.
167164
if !self.krate.attrs.is_empty() && is_root {

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ mod reorder;
6969
mod rewrite;
7070
pub(crate) mod rustfmt_diff;
7171
mod shape;
72+
mod skip;
7273
pub(crate) mod source_file;
7374
pub(crate) mod source_map;
7475
mod spanned;

src/macros.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,8 @@ pub(crate) fn rewrite_macro(
211211
position: MacroPosition,
212212
) -> Option<String> {
213213
let should_skip = context
214-
.skip_macro_names
215-
.borrow()
216-
.contains(&context.snippet(mac.node.path.span).to_owned());
214+
.skip_context
215+
.skip_macro(&context.snippet(mac.node.path.span).to_owned());
217216
if should_skip {
218217
None
219218
} else {

src/rewrite.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use syntax::source_map::{SourceMap, Span};
88

99
use crate::config::{Config, IndentStyle};
1010
use crate::shape::Shape;
11+
use crate::skip::SkipContext;
1112
use crate::visitor::SnippetProvider;
1213
use crate::FormatReport;
1314

@@ -39,7 +40,7 @@ pub(crate) struct RewriteContext<'a> {
3940
// Used for `format_snippet`
4041
pub(crate) macro_rewrite_failure: RefCell<bool>,
4142
pub(crate) report: FormatReport,
42-
pub(crate) skip_macro_names: RefCell<Vec<String>>,
43+
pub(crate) skip_context: SkipContext,
4344
}
4445

4546
impl<'a> RewriteContext<'a> {

src/skip.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//! Module that contains skip related stuffs.
2+
3+
use syntax::ast;
4+
5+
/// Take care of skip name stack. You can update it by attributes slice or
6+
/// by other context. Query this context to know if you need skip a block.
7+
#[derive(Default, Clone)]
8+
pub(crate) struct SkipContext {
9+
macros: Vec<String>,
10+
attributes: Vec<String>,
11+
}
12+
13+
impl SkipContext {
14+
pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) {
15+
self.macros.append(&mut get_skip_names("macros", attrs));
16+
self.attributes
17+
.append(&mut get_skip_names("attributes", attrs));
18+
}
19+
20+
pub(crate) fn update(&mut self, mut other: SkipContext) {
21+
self.macros.append(&mut other.macros);
22+
self.attributes.append(&mut other.attributes);
23+
}
24+
25+
pub(crate) fn skip_macro(&self, name: &str) -> bool {
26+
self.macros.iter().any(|n| n == name)
27+
}
28+
29+
pub(crate) fn skip_attribute(&self, name: &str) -> bool {
30+
self.attributes.iter().any(|n| n == name)
31+
}
32+
}
33+
34+
static RUSTFMT: &'static str = "rustfmt";
35+
static SKIP: &'static str = "skip";
36+
37+
/// Say if you're playing with `rustfmt`'s skip attribute
38+
pub(crate) fn is_skip_attr(segments: &[ast::PathSegment]) -> bool {
39+
if segments.len() < 2 || segments[0].ident.to_string() != RUSTFMT {
40+
return false;
41+
}
42+
match segments.len() {
43+
2 => segments[1].ident.to_string() == SKIP,
44+
3 => {
45+
segments[1].ident.to_string() == SKIP
46+
&& ["macros", "attributes"]
47+
.iter()
48+
.any(|&n| n == &segments[2].ident.name.as_str())
49+
}
50+
_ => false,
51+
}
52+
}
53+
54+
fn get_skip_names(kind: &str, attrs: &[ast::Attribute]) -> Vec<String> {
55+
let mut skip_names = vec![];
56+
let path = format!("{}::{}::{}", RUSTFMT, SKIP, kind);
57+
for attr in attrs {
58+
// syntax::ast::Path is implemented partialEq
59+
// but it is designed for segments.len() == 1
60+
if format!("{}", attr.path) != path {
61+
continue;
62+
}
63+
64+
if let Some(list) = attr.meta_item_list() {
65+
for nested_meta_item in list {
66+
if let Some(name) = nested_meta_item.ident() {
67+
skip_names.push(name.to_string());
68+
}
69+
}
70+
}
71+
}
72+
skip_names
73+
}

src/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const SKIP_FILE_WHITE_LIST: &[&str] = &[
2626
// so we do not want to test this file directly.
2727
"configs/skip_children/foo/mod.rs",
2828
"issue-3434/no_entry.rs",
29+
"issue-3665/sub_mod.rs",
2930
// These files and directory are a part of modules defined inside `cfg_if!`.
3031
"cfg_if/mod.rs",
3132
"cfg_if/detect",

src/utils.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -638,26 +638,6 @@ pub(crate) fn unicode_str_width(s: &str) -> usize {
638638
s.width()
639639
}
640640

641-
pub(crate) fn get_skip_macro_names(attrs: &[ast::Attribute]) -> Vec<String> {
642-
let mut skip_macro_names = vec![];
643-
for attr in attrs {
644-
// syntax::ast::Path is implemented partialEq
645-
// but it is designed for segments.len() == 1
646-
if format!("{}", attr.path) != "rustfmt::skip::macros" {
647-
continue;
648-
}
649-
650-
if let Some(list) = attr.meta_item_list() {
651-
for nested_meta_item in list {
652-
if let Some(name) = nested_meta_item.ident() {
653-
skip_macro_names.push(name.to_string());
654-
}
655-
}
656-
}
657-
}
658-
skip_macro_names
659-
}
660-
661641
#[cfg(test)]
662642
mod test {
663643
use super::*;

src/visitor.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ use crate::items::{
1717
use crate::macros::{rewrite_macro, rewrite_macro_def, MacroPosition};
1818
use crate::rewrite::{Rewrite, RewriteContext};
1919
use crate::shape::{Indent, Shape};
20+
use crate::skip::{is_skip_attr, SkipContext};
2021
use crate::source_map::{LineRangeUtils, SpanUtils};
2122
use crate::spanned::Spanned;
2223
use crate::stmt::Stmt;
2324
use crate::utils::{
24-
self, contains_skip, count_newlines, depr_skip_annotation, get_skip_macro_names,
25-
inner_attributes, mk_sp, ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
25+
self, contains_skip, count_newlines, depr_skip_annotation, inner_attributes, mk_sp,
26+
ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
2627
};
2728
use crate::{ErrorKind, FormatReport, FormattingError};
2829

@@ -67,7 +68,7 @@ pub(crate) struct FmtVisitor<'a> {
6768
pub(crate) skipped_range: Vec<(usize, usize)>,
6869
pub(crate) macro_rewrite_failure: bool,
6970
pub(crate) report: FormatReport,
70-
pub(crate) skip_macro_names: RefCell<Vec<String>>,
71+
pub(crate) skip_context: SkipContext,
7172
}
7273

7374
impl<'a> Drop for FmtVisitor<'a> {
@@ -347,10 +348,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
347348
// the AST lumps them all together.
348349
let filtered_attrs;
349350
let mut attrs = &item.attrs;
350-
let temp_skip_macro_names = self.skip_macro_names.clone();
351-
self.skip_macro_names
352-
.borrow_mut()
353-
.append(&mut get_skip_macro_names(&attrs));
351+
let skip_context_saved = self.skip_context.clone();
352+
self.skip_context.update_with_attrs(&attrs);
354353

355354
let should_visit_node_again = match item.node {
356355
// For use/extern crate items, skip rewriting attributes but check for a skip attribute.
@@ -501,7 +500,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
501500
}
502501
};
503502
}
504-
self.skip_macro_names = temp_skip_macro_names;
503+
self.skip_context = skip_context_saved;
505504
}
506505

507506
pub(crate) fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
@@ -656,10 +655,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
656655
ctx.snippet_provider,
657656
ctx.report.clone(),
658657
);
659-
visitor
660-
.skip_macro_names
661-
.borrow_mut()
662-
.append(&mut ctx.skip_macro_names.borrow().clone());
658+
visitor.skip_context.update(ctx.skip_context.clone());
663659
visitor.set_parent_context(ctx);
664660
visitor
665661
}
@@ -684,7 +680,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
684680
skipped_range: vec![],
685681
macro_rewrite_failure: false,
686682
report,
687-
skip_macro_names: RefCell::new(vec![]),
683+
skip_context: Default::default(),
688684
}
689685
}
690686

@@ -741,14 +737,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
741737
if segments[0].ident.to_string() != "rustfmt" {
742738
return false;
743739
}
744-
745-
match segments.len() {
746-
2 => segments[1].ident.to_string() != "skip",
747-
3 => {
748-
segments[1].ident.to_string() != "skip" || segments[2].ident.to_string() != "macros"
749-
}
750-
_ => false,
751-
}
740+
!is_skip_attr(segments)
752741
}
753742

754743
fn walk_mod_items(&mut self, m: &ast::Mod) {
@@ -881,7 +870,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
881870
snippet_provider: self.snippet_provider,
882871
macro_rewrite_failure: RefCell::new(false),
883872
report: self.report.clone(),
884-
skip_macro_names: self.skip_macro_names.clone(),
873+
skip_context: self.skip_context.clone(),
885874
}
886875
}
887876
}

tests/source/issue-3665/lib.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#![rustfmt::skip::attributes(skip_mod_attr)]
2+
3+
mod sub_mod;
4+
5+
#[rustfmt::skip::attributes(other, skip_attr)]
6+
fn main() {
7+
#[other(should,
8+
skip,
9+
this, format)]
10+
struct S {}
11+
12+
#[skip_attr(should, skip,
13+
this, format,too)]
14+
fn doesnt_mater() {}
15+
16+
#[skip_mod_attr(should, skip,
17+
this, format,
18+
enerywhere)]
19+
fn more() {}
20+
21+
#[not_skip(not,
22+
skip, me)]
23+
struct B {}
24+
}
25+
26+
#[other(should, not, skip,
27+
this, format, here)]
28+
fn foo() {}
29+
30+
#[skip_mod_attr(should, skip,
31+
this, format,in, master,
32+
and, sub, module)]
33+
fn bar() {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![this::is::not::skip::attribute(ouch)]
2+
3+
#[ouch(not, skip, me)]
4+
fn main() {}

tests/source/issue-3665/sub_mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[rustfmt::skip::attributes(more_skip)]
2+
#[more_skip(should,
3+
skip,
4+
this, format)]
5+
fn foo() {}
6+
7+
#[skip_mod_attr(should, skip,
8+
this, format,in, master,
9+
and, sub, module)]
10+
fn bar() {}
11+
12+
#[skip_attr(should, not,
13+
skip, this, attribute, here)]
14+
fn baz() {}

tests/target/issue-3665/lib.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![rustfmt::skip::attributes(skip_mod_attr)]
2+
3+
mod sub_mod;
4+
5+
#[rustfmt::skip::attributes(other, skip_attr)]
6+
fn main() {
7+
#[other(should,
8+
skip,
9+
this, format)]
10+
struct S {}
11+
12+
#[skip_attr(should, skip,
13+
this, format,too)]
14+
fn doesnt_mater() {}
15+
16+
#[skip_mod_attr(should, skip,
17+
this, format,
18+
enerywhere)]
19+
fn more() {}
20+
21+
#[not_skip(not, skip, me)]
22+
struct B {}
23+
}
24+
25+
#[other(should, not, skip, this, format, here)]
26+
fn foo() {}
27+
28+
#[skip_mod_attr(should, skip,
29+
this, format,in, master,
30+
and, sub, module)]
31+
fn bar() {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![this::is::not::skip::attribute(ouch)]
2+
3+
#[ouch(not, skip, me)]
4+
fn main() {}

0 commit comments

Comments
 (0)