1 //! Module that contains skip related stuffs.
4 use rustc_ast_pretty
::pprust
;
5 use std
::collections
::HashSet
;
7 /// Track which blocks of code are to be skipped when formatting.
9 /// You can update it by:
11 /// - attributes slice
12 /// - manually feeding values into the underlying contexts
14 /// Query this context to know if you need to skip a block.
15 #[derive(Default, Clone)]
16 pub(crate) struct SkipContext
{
17 pub(crate) macros
: SkipNameContext
,
18 pub(crate) attributes
: SkipNameContext
,
22 pub(crate) fn update_with_attrs(&mut self, attrs
: &[ast
::Attribute
]) {
23 self.macros
.extend(get_skip_names("macros", attrs
));
24 self.attributes
.extend(get_skip_names("attributes", attrs
));
27 pub(crate) fn update(&mut self, other
: SkipContext
) {
28 let SkipContext { macros, attributes }
= other
;
29 self.macros
.update(macros
);
30 self.attributes
.update(attributes
);
34 /// Track which names to skip.
36 /// Query this context with a string to know whether to skip it.
38 pub(crate) enum SkipNameContext
{
40 Values(HashSet
<String
>),
43 impl Default
for SkipNameContext
{
44 fn default() -> Self {
45 Self::Values(Default
::default())
49 impl Extend
<String
> for SkipNameContext
{
50 fn extend
<T
: IntoIterator
<Item
= String
>>(&mut self, iter
: T
) {
53 Self::Values(values
) => values
.extend(iter
),
58 impl SkipNameContext
{
59 pub(crate) fn update(&mut self, other
: Self) {
61 // If we're already skipping everything, nothing more can be added
63 // If we want to skip all, set it
64 (this
, Self::All
) => {
67 // If we have some new values to skip, add them
68 (Self::Values(existing_values
), Self::Values(new_values
)) => {
69 existing_values
.extend(new_values
)
74 pub(crate) fn skip(&self, name
: &str) -> bool
{
77 Self::Values(values
) => values
.contains(name
),
81 pub(crate) fn skip_all(&mut self) {
86 static RUSTFMT
: &str = "rustfmt";
87 static SKIP
: &str = "skip";
89 /// Say if you're playing with `rustfmt`'s skip attribute
90 pub(crate) fn is_skip_attr(segments
: &[ast
::PathSegment
]) -> bool
{
91 if segments
.len() < 2 || segments
[0].ident
.to_string() != RUSTFMT
{
94 match segments
.len() {
95 2 => segments
[1].ident
.to_string() == SKIP
,
97 segments
[1].ident
.to_string() == SKIP
98 && ["macros", "attributes"]
100 .any(|&n
| n
== pprust
::path_segment_to_string(&segments
[2]))
106 fn get_skip_names(kind
: &str, attrs
: &[ast
::Attribute
]) -> Vec
<String
> {
107 let mut skip_names
= vec
![];
108 let path
= format
!("{RUSTFMT}::{SKIP}::{kind}");
110 // rustc_ast::ast::Path is implemented partialEq
111 // but it is designed for segments.len() == 1
112 if let ast
::AttrKind
::Normal(normal
) = &attr
.kind
{
113 if pprust
::path_to_string(&normal
.item
.path
) != path
{
118 if let Some(list
) = attr
.meta_item_list() {
119 for nested_meta_item
in list
{
120 if let Some(name
) = nested_meta_item
.ident() {
121 skip_names
.push(name
.to_string());