From d2422def21bae8b6fb819332c03e09edc4026ca3 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sat, 21 May 2022 10:05:27 +0100 Subject: [PATCH 01/11] feat: add skip_macro_names option --- Configurations.md | 33 +++++++++++++ src/config/config_type.rs | 7 +++ src/config/macro_names.rs | 81 ++++++++++++++++++++++++++++++++ src/config/mod.rs | 6 +++ src/skip.rs | 7 +++ src/visitor.rs | 4 +- tests/source/skip_macro_names.rs | 16 +++++++ tests/target/skip_macro_names.rs | 16 +++++++ 8 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/config/macro_names.rs create mode 100644 tests/source/skip_macro_names.rs create mode 100644 tests/target/skip_macro_names.rs diff --git a/Configurations.md b/Configurations.md index 8b96b9d3689..fb2422b7d82 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1014,6 +1014,39 @@ macro_rules! foo { See also [`format_macro_matchers`](#format_macro_matchers). +## `skip_macro_names` + +Skip formatting the bodies of macros invoked with the following names. + +- **Default value**: `[]` +- **Possible values**: a list of macro name idents, `["name_0", "name_1", ...]` +- **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346)) + +#### `[]` (default): + +```rust +macro_rules! foo { + ($a: ident : $b: ty) => { + $a(42): $b; + }; + ($a: ident $b: ident $c: ident) => { + $a = $b + $c; + }; +} +``` + +#### `["foo"]`: + +```rust +#![rustfmt::skip] + +macro_rules! foo { + ($a: ident : $b: ty) => { $a(42): $b; }; + ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; +} +``` + +See also [`format_macro_bodies`](#format_macro_bodies). ## `format_strings` diff --git a/src/config/config_type.rs b/src/config/config_type.rs index 26d57a13791..abbd0003dd7 100644 --- a/src/config/config_type.rs +++ b/src/config/config_type.rs @@ -1,4 +1,5 @@ use crate::config::file_lines::FileLines; +use crate::config::macro_names::MacroNames; use crate::config::options::{IgnoreList, WidthHeuristics}; /// Trait for types that can be used in `Config`. @@ -46,6 +47,12 @@ impl ConfigType for FileLines { } } +impl ConfigType for MacroNames { + fn doc_hint() -> String { + String::from("[, ...]") + } +} + impl ConfigType for WidthHeuristics { fn doc_hint() -> String { String::new() diff --git a/src/config/macro_names.rs b/src/config/macro_names.rs new file mode 100644 index 00000000000..7130b9f9b75 --- /dev/null +++ b/src/config/macro_names.rs @@ -0,0 +1,81 @@ +//! This module contains types and functions to support formatting specific macros. + +use itertools::Itertools; +use std::{fmt, str}; + +use serde::{Deserialize, Serialize}; +use serde_json as json; +use thiserror::Error; + +/// Defines the name of an input - either a file or stdin. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +pub struct MacroName(String); + +impl fmt::Display for MacroName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl From for String { + fn from(other: MacroName) -> Self { + other.0 + } +} + +/// A set of macro names. +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub struct MacroNames(Vec); + +impl fmt::Display for MacroNames { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0.iter().format(", ")) + } +} + +impl MacroNames { + /// Return the underlying macro names, as an iterator of strings. + pub(crate) fn into_name_strings(self) -> impl Iterator { + self.0.into_iter().map(Into::into) + } +} + +#[derive(Error, Debug)] +pub enum MacroNamesError { + #[error("{0}")] + Json(json::Error), +} + +// This impl is needed for `Config::override_value` to work for use in tests. +impl str::FromStr for MacroNames { + type Err = MacroNamesError; + + fn from_str(s: &str) -> Result { + json::from_str(s).map_err(MacroNamesError::Json) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::str::FromStr; + + #[test] + fn macro_names_from_str() { + let macro_names = MacroNames::from_str(r#"["foo", "bar"]"#).unwrap(); + assert_eq!( + macro_names, + MacroNames( + [MacroName("foo".to_owned()), MacroName("bar".to_owned())] + .into_iter() + .collect() + ) + ); + } + + #[test] + fn macro_names_display() { + let macro_names = MacroNames::from_str(r#"["foo", "bar"]"#).unwrap(); + assert_eq!(format!("{}", macro_names), "foo, bar"); + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index eaada8db090..1ff57ded73d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -13,6 +13,8 @@ pub use crate::config::file_lines::{FileLines, FileName, Range}; #[allow(unreachable_pub)] pub use crate::config::lists::*; #[allow(unreachable_pub)] +pub use crate::config::macro_names::MacroNames; +#[allow(unreachable_pub)] pub use crate::config::options::*; #[macro_use] @@ -22,6 +24,7 @@ pub(crate) mod options; pub(crate) mod file_lines; pub(crate) mod lists; +pub(crate) mod macro_names; // This macro defines configuration options used in rustfmt. Each option // is defined as follows: @@ -67,6 +70,8 @@ create_config! { format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; format_macro_bodies: bool, true, false, "Format the bodies of macros"; + skip_macro_names: MacroNames, MacroNames::default(), false, + "Skip formatting the bodies of macros invoked with the following names."; hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, "Format hexadecimal integer literals"; @@ -611,6 +616,7 @@ normalize_doc_attributes = false format_strings = false format_macro_matchers = false format_macro_bodies = true +skip_macro_names = [] hex_literal_case = "Preserve" empty_item_single_line = true struct_lit_single_line = true diff --git a/src/skip.rs b/src/skip.rs index 0fdc097efc2..f234f341f68 100644 --- a/src/skip.rs +++ b/src/skip.rs @@ -23,6 +23,13 @@ impl SkipContext { self.attributes.append(&mut other.attributes); } + pub(crate) fn update_macros(&mut self, other: T) + where + T: IntoIterator, + { + self.macros.extend(other.into_iter()); + } + pub(crate) fn skip_macro(&self, name: &str) -> bool { self.macros.iter().any(|n| n == name) } diff --git a/src/visitor.rs b/src/visitor.rs index 9a0e0752c12..449f35edf2d 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -770,6 +770,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { snippet_provider: &'a SnippetProvider, report: FormatReport, ) -> FmtVisitor<'a> { + let mut skip_context = SkipContext::default(); + skip_context.update_macros(config.skip_macro_names().into_name_strings()); FmtVisitor { parent_context: None, parse_sess: parse_session, @@ -784,7 +786,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { is_macro_def: false, macro_rewrite_failure: false, report, - skip_context: Default::default(), + skip_context, } } diff --git a/tests/source/skip_macro_names.rs b/tests/source/skip_macro_names.rs new file mode 100644 index 00000000000..eb2070f2eea --- /dev/null +++ b/tests/source/skip_macro_names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_names: ["items"] + +macro_rules! items { + ($($arg:item)*) => { $($arg)* }; +} + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +use self::items as renamed_items; +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_names.rs b/tests/target/skip_macro_names.rs new file mode 100644 index 00000000000..97a02a32fd9 --- /dev/null +++ b/tests/target/skip_macro_names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_names: ["items"] + +macro_rules! items { + ($($arg:item)*) => { $($arg)* }; +} + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +use self::items as renamed_items; +renamed_items!( + const _: u8 = 0; +); From cc9fb29db4894d7a9986e9a4e75b645583af01d6 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 10 Jun 2022 17:00:28 +0100 Subject: [PATCH 02/11] [review] update configuration documentation --- Configurations.md | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Configurations.md b/Configurations.md index fb2422b7d82..8e83163f606 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1016,7 +1016,7 @@ See also [`format_macro_matchers`](#format_macro_matchers). ## `skip_macro_names` -Skip formatting the bodies of macros invoked with the following names. +Skip formatting the bodies of macro invocations with the following names. - **Default value**: `[]` - **Possible values**: a list of macro name idents, `["name_0", "name_1", ...]` @@ -1024,29 +1024,31 @@ Skip formatting the bodies of macros invoked with the following names. #### `[]` (default): +The input: + ```rust -macro_rules! foo { - ($a: ident : $b: ty) => { - $a(42): $b; - }; - ($a: ident $b: ident $c: ident) => { - $a = $b + $c; - }; -} +items!( + const _: u8 = 0; +); ``` -#### `["foo"]`: +Is reformatted to: ```rust -#![rustfmt::skip] - -macro_rules! foo { - ($a: ident : $b: ty) => { $a(42): $b; }; - ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; -} +items!( + const _: u8 = 0; +); ``` -See also [`format_macro_bodies`](#format_macro_bodies). +#### `["items"]`: + +The input is preserved: + +```rust +items!( + const _: u8 = 0; +); +``` ## `format_strings` From 342925a4e1366fe2f8fd78ab6ec7459210607889 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 10 Jun 2022 17:29:03 +0100 Subject: [PATCH 03/11] [review] fix docstring --- src/config/macro_names.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/macro_names.rs b/src/config/macro_names.rs index 7130b9f9b75..91a61cd4787 100644 --- a/src/config/macro_names.rs +++ b/src/config/macro_names.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use serde_json as json; use thiserror::Error; -/// Defines the name of an input - either a file or stdin. +/// Defines the name of a macro. #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] pub struct MacroName(String); From 3b60f3ec0b41b94e3ac3940b84a8092f19e82118 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sat, 11 Jun 2022 09:37:36 +0100 Subject: [PATCH 04/11] [feat] implement wildcard macro invocation skip --- Configurations.md | 32 +++++++++---- src/config/config_type.rs | 4 +- src/config/macro_names.rs | 79 +++++++++++++++++++++++-------- src/config/mod.rs | 4 +- src/skip.rs | 3 +- src/test/configuration_snippet.rs | 7 ++- src/visitor.rs | 11 ++++- 7 files changed, 102 insertions(+), 38 deletions(-) diff --git a/Configurations.md b/Configurations.md index 8e83163f606..de5ad8bfb37 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1019,33 +1019,47 @@ See also [`format_macro_matchers`](#format_macro_matchers). Skip formatting the bodies of macro invocations with the following names. - **Default value**: `[]` -- **Possible values**: a list of macro name idents, `["name_0", "name_1", ...]` +- **Possible values**: a list of macro name idents, `["name_0", "name_1", ..., "*"]` - **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346)) #### `[]` (default): -The input: +All macro invocations will be formatted. ```rust -items!( - const _: u8 = 0; +lorem!( + const _: u8 = 0; +); + +ipsum!( + const _: u8 = 0; ); ``` -Is reformatted to: +#### `["lorem"]`: + +The named macro invocations will be skipped. ```rust -items!( +lorem!( + const _: u8 = 0; +); + +ipsum!( const _: u8 = 0; ); ``` -#### `["items"]`: +#### `["*"]`: -The input is preserved: +The special selector `*` will skip all macro invocations. ```rust -items!( +lorem!( + const _: u8 = 0; +); + +ipsum!( const _: u8 = 0; ); ``` diff --git a/src/config/config_type.rs b/src/config/config_type.rs index abbd0003dd7..48f4d9ce80e 100644 --- a/src/config/config_type.rs +++ b/src/config/config_type.rs @@ -1,5 +1,5 @@ use crate::config::file_lines::FileLines; -use crate::config::macro_names::MacroNames; +use crate::config::macro_names::MacroSelectors; use crate::config::options::{IgnoreList, WidthHeuristics}; /// Trait for types that can be used in `Config`. @@ -47,7 +47,7 @@ impl ConfigType for FileLines { } } -impl ConfigType for MacroNames { +impl ConfigType for MacroSelectors { fn doc_hint() -> String { String::from("[, ...]") } diff --git a/src/config/macro_names.rs b/src/config/macro_names.rs index 91a61cd4787..9c88d8397eb 100644 --- a/src/config/macro_names.rs +++ b/src/config/macro_names.rs @@ -23,35 +23,68 @@ impl From for String { } } -/// A set of macro names. -#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] -pub struct MacroNames(Vec); +/// Defines a selector to match against a macro. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +pub enum MacroSelector { + Name(MacroName), + All, +} -impl fmt::Display for MacroNames { +impl fmt::Display for MacroSelector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0.iter().format(", ")) + match self { + Self::Name(name) => name.fmt(f), + Self::All => write!(f, "*"), + } + } +} + +impl str::FromStr for MacroSelector { + type Err = std::convert::Infallible; + + fn from_str(s: &str) -> Result { + Ok(match s { + "*" => MacroSelector::All, + name => MacroSelector::Name(MacroName(name.to_owned())), + }) } } -impl MacroNames { - /// Return the underlying macro names, as an iterator of strings. - pub(crate) fn into_name_strings(self) -> impl Iterator { - self.0.into_iter().map(Into::into) +/// A set of macro selectors. +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub struct MacroSelectors(Vec); + +impl MacroSelectors { + pub fn into_inner(self) -> Vec { + self.0 + } +} + +impl fmt::Display for MacroSelectors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0.iter().format(", ")) } } #[derive(Error, Debug)] -pub enum MacroNamesError { +pub enum MacroSelectorsError { #[error("{0}")] Json(json::Error), } // This impl is needed for `Config::override_value` to work for use in tests. -impl str::FromStr for MacroNames { - type Err = MacroNamesError; +impl str::FromStr for MacroSelectors { + type Err = MacroSelectorsError; - fn from_str(s: &str) -> Result { - json::from_str(s).map_err(MacroNamesError::Json) + fn from_str(s: &str) -> Result { + let raw: Vec<&str> = json::from_str(s).map_err(MacroSelectorsError::Json)?; + Ok(Self( + raw.into_iter() + .map(|raw| { + MacroSelector::from_str(raw).expect("MacroSelector from_str is infallible") + }) + .collect(), + )) } } @@ -62,20 +95,24 @@ mod test { #[test] fn macro_names_from_str() { - let macro_names = MacroNames::from_str(r#"["foo", "bar"]"#).unwrap(); + let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap(); assert_eq!( macro_names, - MacroNames( - [MacroName("foo".to_owned()), MacroName("bar".to_owned())] - .into_iter() - .collect() + MacroSelectors( + [ + MacroSelector::Name(MacroName("foo".to_owned())), + MacroSelector::All, + MacroSelector::Name(MacroName("bar".to_owned())) + ] + .into_iter() + .collect() ) ); } #[test] fn macro_names_display() { - let macro_names = MacroNames::from_str(r#"["foo", "bar"]"#).unwrap(); - assert_eq!(format!("{}", macro_names), "foo, bar"); + let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap(); + assert_eq!(format!("{}", macro_names), "foo, *, bar"); } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 1ff57ded73d..3301c7491f4 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -13,7 +13,7 @@ pub use crate::config::file_lines::{FileLines, FileName, Range}; #[allow(unreachable_pub)] pub use crate::config::lists::*; #[allow(unreachable_pub)] -pub use crate::config::macro_names::MacroNames; +pub use crate::config::macro_names::{MacroSelector, MacroSelectors}; #[allow(unreachable_pub)] pub use crate::config::options::*; @@ -70,7 +70,7 @@ create_config! { format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; format_macro_bodies: bool, true, false, "Format the bodies of macros"; - skip_macro_names: MacroNames, MacroNames::default(), false, + skip_macro_names: MacroSelectors, MacroSelectors::default(), false, "Skip formatting the bodies of macros invoked with the following names."; hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, "Format hexadecimal integer literals"; diff --git a/src/skip.rs b/src/skip.rs index f234f341f68..8b2fd7736ae 100644 --- a/src/skip.rs +++ b/src/skip.rs @@ -7,6 +7,7 @@ use rustc_ast_pretty::pprust; /// by other context. Query this context to know if you need skip a block. #[derive(Default, Clone)] pub(crate) struct SkipContext { + pub(crate) all_macros: bool, macros: Vec, attributes: Vec, } @@ -31,7 +32,7 @@ impl SkipContext { } pub(crate) fn skip_macro(&self, name: &str) -> bool { - self.macros.iter().any(|n| n == name) + self.all_macros || self.macros.iter().any(|n| n == name) } pub(crate) fn skip_attribute(&self, name: &str) -> bool { diff --git a/src/test/configuration_snippet.rs b/src/test/configuration_snippet.rs index c8fda7c8556..c70b3c5facd 100644 --- a/src/test/configuration_snippet.rs +++ b/src/test/configuration_snippet.rs @@ -27,8 +27,13 @@ impl ConfigurationSection { lazy_static! { static ref CONFIG_NAME_REGEX: regex::Regex = regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern"); + // Configuration values, which will be passed to `from_str`: + // + // - must be prefixed with `####` + // - must be wrapped in backticks + // - may by wrapped in double quotes (which will be stripped) static ref CONFIG_VALUE_REGEX: regex::Regex = - regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#) + regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#) .expect("failed creating configuration value pattern"); } diff --git a/src/visitor.rs b/src/visitor.rs index 449f35edf2d..88117e45350 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -8,7 +8,7 @@ use rustc_span::{symbol, BytePos, Pos, Span}; use crate::attr::*; use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices}; use crate::config::Version; -use crate::config::{BraceStyle, Config}; +use crate::config::{BraceStyle, Config, MacroSelector}; use crate::coverage::transform_missing_snippet; use crate::items::{ format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate, @@ -771,7 +771,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { report: FormatReport, ) -> FmtVisitor<'a> { let mut skip_context = SkipContext::default(); - skip_context.update_macros(config.skip_macro_names().into_name_strings()); + let mut macro_names = Vec::new(); + for macro_selector in config.skip_macro_names().into_inner() { + match macro_selector { + MacroSelector::Name(name) => macro_names.push(name.to_string()), + MacroSelector::All => skip_context.all_macros = true, + } + } + skip_context.update_macros(macro_names); FmtVisitor { parent_context: None, parse_sess: parse_session, From c4f84a8ebfa9f940473587dd019767e5709418e3 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sat, 18 Jun 2022 13:19:05 +0100 Subject: [PATCH 05/11] commit missed files --- tests/source/skip_macro_names_all.rs | 16 ++++++++++++++++ tests/target/skip_macro_names_all.rs | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/source/skip_macro_names_all.rs create mode 100644 tests/target/skip_macro_names_all.rs diff --git a/tests/source/skip_macro_names_all.rs b/tests/source/skip_macro_names_all.rs new file mode 100644 index 00000000000..3e50fa5afdc --- /dev/null +++ b/tests/source/skip_macro_names_all.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_names: ["*","items"] + +macro_rules! items { + ($($arg:item)*) => { $($arg)* }; +} + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should also skip this invocation, as the wildcard covers it +use self::items as renamed_items; +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_names_all.rs b/tests/target/skip_macro_names_all.rs new file mode 100644 index 00000000000..3e50fa5afdc --- /dev/null +++ b/tests/target/skip_macro_names_all.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_names: ["*","items"] + +macro_rules! items { + ($($arg:item)*) => { $($arg)* }; +} + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should also skip this invocation, as the wildcard covers it +use self::items as renamed_items; +renamed_items!( + const _: u8 = 0; +); From a88ec638e9e80fcfdc39fefe84c7b82b8c63f044 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sat, 18 Jun 2022 13:58:39 +0100 Subject: [PATCH 06/11] [review] test override skip macro names --- src/config/macro_names.rs | 14 +++++++------- src/config/mod.rs | 14 ++++++++++++++ src/visitor.rs | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/config/macro_names.rs b/src/config/macro_names.rs index 9c88d8397eb..26ad78d6dca 100644 --- a/src/config/macro_names.rs +++ b/src/config/macro_names.rs @@ -11,6 +11,12 @@ use thiserror::Error; #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] pub struct MacroName(String); +impl MacroName { + pub fn new(other: String) -> Self { + Self(other) + } +} + impl fmt::Display for MacroName { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) @@ -52,13 +58,7 @@ impl str::FromStr for MacroSelector { /// A set of macro selectors. #[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] -pub struct MacroSelectors(Vec); - -impl MacroSelectors { - pub fn into_inner(self) -> Vec { - self.0 - } -} +pub struct MacroSelectors(pub Vec); impl fmt::Display for MacroSelectors { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/config/mod.rs b/src/config/mod.rs index 3301c7491f4..9eb738fd0ff 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -408,6 +408,7 @@ mod test { use super::*; use std::str; + use crate::config::macro_names::MacroName; use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test}; #[allow(dead_code)] @@ -1025,4 +1026,17 @@ make_backup = false ); } } + + #[test] + fn test_override_skip_macro_names() { + let mut config = Config::default(); + config.override_value("skip_macro_names", r#"["*", "println"]"#); + assert_eq!( + config.skip_macro_names(), + MacroSelectors(vec![ + MacroSelector::All, + MacroSelector::Name(MacroName::new("println".to_owned())) + ]) + ); + } } diff --git a/src/visitor.rs b/src/visitor.rs index 88117e45350..8f932e45fb4 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -772,7 +772,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ) -> FmtVisitor<'a> { let mut skip_context = SkipContext::default(); let mut macro_names = Vec::new(); - for macro_selector in config.skip_macro_names().into_inner() { + for macro_selector in config.skip_macro_names().0 { match macro_selector { MacroSelector::Name(name) => macro_names.push(name.to_string()), MacroSelector::All => skip_context.all_macros = true, From 89ec6d165251133c4fca24717fb59c641293ddf4 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sat, 18 Jun 2022 15:20:46 +0100 Subject: [PATCH 07/11] [review] skip_macro_names -> skip_macro_invocations --- Configurations.md | 2 +- src/config/mod.rs | 10 +++++----- src/visitor.rs | 2 +- tests/source/skip_macro_names.rs | 2 +- tests/source/skip_macro_names_all.rs | 2 +- tests/target/skip_macro_names.rs | 2 +- tests/target/skip_macro_names_all.rs | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Configurations.md b/Configurations.md index de5ad8bfb37..cc8ac03fa16 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1014,7 +1014,7 @@ macro_rules! foo { See also [`format_macro_matchers`](#format_macro_matchers). -## `skip_macro_names` +## `skip_macro_invocations` Skip formatting the bodies of macro invocations with the following names. diff --git a/src/config/mod.rs b/src/config/mod.rs index 9eb738fd0ff..0c6a3cbc953 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -70,7 +70,7 @@ create_config! { format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; format_macro_bodies: bool, true, false, "Format the bodies of macros"; - skip_macro_names: MacroSelectors, MacroSelectors::default(), false, + skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false, "Skip formatting the bodies of macros invoked with the following names."; hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, "Format hexadecimal integer literals"; @@ -617,7 +617,7 @@ normalize_doc_attributes = false format_strings = false format_macro_matchers = false format_macro_bodies = true -skip_macro_names = [] +skip_macro_invocations = [] hex_literal_case = "Preserve" empty_item_single_line = true struct_lit_single_line = true @@ -1028,11 +1028,11 @@ make_backup = false } #[test] - fn test_override_skip_macro_names() { + fn test_override_skip_macro_invocations() { let mut config = Config::default(); - config.override_value("skip_macro_names", r#"["*", "println"]"#); + config.override_value("skip_macro_invocations", r#"["*", "println"]"#); assert_eq!( - config.skip_macro_names(), + config.skip_macro_invocations(), MacroSelectors(vec![ MacroSelector::All, MacroSelector::Name(MacroName::new("println".to_owned())) diff --git a/src/visitor.rs b/src/visitor.rs index 8f932e45fb4..b93153de154 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -772,7 +772,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ) -> FmtVisitor<'a> { let mut skip_context = SkipContext::default(); let mut macro_names = Vec::new(); - for macro_selector in config.skip_macro_names().0 { + for macro_selector in config.skip_macro_invocations().0 { match macro_selector { MacroSelector::Name(name) => macro_names.push(name.to_string()), MacroSelector::All => skip_context.all_macros = true, diff --git a/tests/source/skip_macro_names.rs b/tests/source/skip_macro_names.rs index eb2070f2eea..0d3ce06ed77 100644 --- a/tests/source/skip_macro_names.rs +++ b/tests/source/skip_macro_names.rs @@ -1,4 +1,4 @@ -// rustfmt-skip_macro_names: ["items"] +// rustfmt-skip_macro_invocations: ["items"] macro_rules! items { ($($arg:item)*) => { $($arg)* }; diff --git a/tests/source/skip_macro_names_all.rs b/tests/source/skip_macro_names_all.rs index 3e50fa5afdc..7c3811f9aea 100644 --- a/tests/source/skip_macro_names_all.rs +++ b/tests/source/skip_macro_names_all.rs @@ -1,4 +1,4 @@ -// rustfmt-skip_macro_names: ["*","items"] +// rustfmt-skip_macro_invocations: ["*","items"] macro_rules! items { ($($arg:item)*) => { $($arg)* }; diff --git a/tests/target/skip_macro_names.rs b/tests/target/skip_macro_names.rs index 97a02a32fd9..55b0eeec578 100644 --- a/tests/target/skip_macro_names.rs +++ b/tests/target/skip_macro_names.rs @@ -1,4 +1,4 @@ -// rustfmt-skip_macro_names: ["items"] +// rustfmt-skip_macro_invocations: ["items"] macro_rules! items { ($($arg:item)*) => { $($arg)* }; diff --git a/tests/target/skip_macro_names_all.rs b/tests/target/skip_macro_names_all.rs index 3e50fa5afdc..7c3811f9aea 100644 --- a/tests/target/skip_macro_names_all.rs +++ b/tests/target/skip_macro_names_all.rs @@ -1,4 +1,4 @@ -// rustfmt-skip_macro_names: ["*","items"] +// rustfmt-skip_macro_invocations: ["*","items"] macro_rules! items { ($($arg:item)*) => { $($arg)* }; From bbce6ee2cf71c8d6730647ea146a722e5cfd71f1 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sat, 18 Jun 2022 15:25:28 +0100 Subject: [PATCH 08/11] [review] expand doc configuration --- Configurations.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Configurations.md b/Configurations.md index cc8ac03fa16..d0167d55c01 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1018,6 +1018,11 @@ See also [`format_macro_matchers`](#format_macro_matchers). Skip formatting the bodies of macro invocations with the following names. +rustfmt will not format any macro invocation for macros with names set in this list. +Including the special value "*" will prevent any macro invocations from being formatted. + +Note: This option does not have any impact on how rustfmt formats macro definitions. + - **Default value**: `[]` - **Possible values**: a list of macro name idents, `["name_0", "name_1", ..., "*"]` - **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346)) From 4bca4208575863b94f139d130eb3398e2be3def2 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sat, 18 Jun 2022 15:51:36 +0100 Subject: [PATCH 09/11] [review] add lots more tests --- tests/source/skip_macro_invocations/all.rs | 11 +++++++++++ .../all_and_name.rs} | 5 ----- tests/source/skip_macro_invocations/empty.rs | 11 +++++++++++ .../name.rs} | 5 ----- .../skip_macro_invocations/name_unknown.rs | 6 ++++++ tests/source/skip_macro_invocations/names.rs | 16 ++++++++++++++++ .../path_qualified_invocation_mismatch.rs | 6 ++++++ .../path_qualified_match.rs | 6 ++++++ .../path_qualified_name_mismatch.rs | 6 ++++++ tests/target/skip_macro_invocations/all.rs | 11 +++++++++++ .../all_and_name.rs} | 5 ----- tests/target/skip_macro_invocations/empty.rs | 11 +++++++++++ .../name.rs} | 5 ----- .../skip_macro_invocations/name_unknown.rs | 6 ++++++ tests/target/skip_macro_invocations/names.rs | 16 ++++++++++++++++ .../path_qualified_invocation_mismatch.rs | 6 ++++++ .../path_qualified_match.rs | 6 ++++++ .../path_qualified_name_mismatch.rs | 6 ++++++ 18 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 tests/source/skip_macro_invocations/all.rs rename tests/source/{skip_macro_names_all.rs => skip_macro_invocations/all_and_name.rs} (70%) create mode 100644 tests/source/skip_macro_invocations/empty.rs rename tests/source/{skip_macro_names.rs => skip_macro_invocations/name.rs} (67%) create mode 100644 tests/source/skip_macro_invocations/name_unknown.rs create mode 100644 tests/source/skip_macro_invocations/names.rs create mode 100644 tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs create mode 100644 tests/source/skip_macro_invocations/path_qualified_match.rs create mode 100644 tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs create mode 100644 tests/target/skip_macro_invocations/all.rs rename tests/target/{skip_macro_names_all.rs => skip_macro_invocations/all_and_name.rs} (70%) create mode 100644 tests/target/skip_macro_invocations/empty.rs rename tests/target/{skip_macro_names.rs => skip_macro_invocations/name.rs} (66%) create mode 100644 tests/target/skip_macro_invocations/name_unknown.rs create mode 100644 tests/target/skip_macro_invocations/names.rs create mode 100644 tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs create mode 100644 tests/target/skip_macro_invocations/path_qualified_match.rs create mode 100644 tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs diff --git a/tests/source/skip_macro_invocations/all.rs b/tests/source/skip_macro_invocations/all.rs new file mode 100644 index 00000000000..d0437ee10fd --- /dev/null +++ b/tests/source/skip_macro_invocations/all.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_names_all.rs b/tests/source/skip_macro_invocations/all_and_name.rs similarity index 70% rename from tests/source/skip_macro_names_all.rs rename to tests/source/skip_macro_invocations/all_and_name.rs index 7c3811f9aea..1f6722344fe 100644 --- a/tests/source/skip_macro_names_all.rs +++ b/tests/source/skip_macro_invocations/all_and_name.rs @@ -1,16 +1,11 @@ // rustfmt-skip_macro_invocations: ["*","items"] -macro_rules! items { - ($($arg:item)*) => { $($arg)* }; -} - // Should skip this invocation items!( const _: u8 = 0; ); // Should also skip this invocation, as the wildcard covers it -use self::items as renamed_items; renamed_items!( const _: u8 = 0; ); diff --git a/tests/source/skip_macro_invocations/empty.rs b/tests/source/skip_macro_invocations/empty.rs new file mode 100644 index 00000000000..f3dd89dc4db --- /dev/null +++ b/tests/source/skip_macro_invocations/empty.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: [] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_names.rs b/tests/source/skip_macro_invocations/name.rs similarity index 67% rename from tests/source/skip_macro_names.rs rename to tests/source/skip_macro_invocations/name.rs index 0d3ce06ed77..7fa5d3a6f71 100644 --- a/tests/source/skip_macro_names.rs +++ b/tests/source/skip_macro_invocations/name.rs @@ -1,16 +1,11 @@ // rustfmt-skip_macro_invocations: ["items"] -macro_rules! items { - ($($arg:item)*) => { $($arg)* }; -} - // Should skip this invocation items!( const _: u8 = 0; ); // Should not skip this invocation -use self::items as renamed_items; renamed_items!( const _: u8 = 0; ); diff --git a/tests/source/skip_macro_invocations/name_unknown.rs b/tests/source/skip_macro_invocations/name_unknown.rs new file mode 100644 index 00000000000..d5669532524 --- /dev/null +++ b/tests/source/skip_macro_invocations/name_unknown.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["unknown"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/names.rs b/tests/source/skip_macro_invocations/names.rs new file mode 100644 index 00000000000..a920381a455 --- /dev/null +++ b/tests/source/skip_macro_invocations/names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_invocations: ["foo","bar"] + +// Should skip this invocation +foo!( + const _: u8 = 0; +); + +// Should skip this invocation +bar!( + const _: u8 = 0; +); + +// Should not skip this invocation +baz!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs new file mode 100644 index 00000000000..61296869a50 --- /dev/null +++ b/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should not skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/path_qualified_match.rs b/tests/source/skip_macro_invocations/path_qualified_match.rs new file mode 100644 index 00000000000..9398918a9e1 --- /dev/null +++ b/tests/source/skip_macro_invocations/path_qualified_match.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs b/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs new file mode 100644 index 00000000000..4e3eb542dbe --- /dev/null +++ b/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/all.rs b/tests/target/skip_macro_invocations/all.rs new file mode 100644 index 00000000000..d0437ee10fd --- /dev/null +++ b/tests/target/skip_macro_invocations/all.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_names_all.rs b/tests/target/skip_macro_invocations/all_and_name.rs similarity index 70% rename from tests/target/skip_macro_names_all.rs rename to tests/target/skip_macro_invocations/all_and_name.rs index 7c3811f9aea..1f6722344fe 100644 --- a/tests/target/skip_macro_names_all.rs +++ b/tests/target/skip_macro_invocations/all_and_name.rs @@ -1,16 +1,11 @@ // rustfmt-skip_macro_invocations: ["*","items"] -macro_rules! items { - ($($arg:item)*) => { $($arg)* }; -} - // Should skip this invocation items!( const _: u8 = 0; ); // Should also skip this invocation, as the wildcard covers it -use self::items as renamed_items; renamed_items!( const _: u8 = 0; ); diff --git a/tests/target/skip_macro_invocations/empty.rs b/tests/target/skip_macro_invocations/empty.rs new file mode 100644 index 00000000000..4a398cc59c6 --- /dev/null +++ b/tests/target/skip_macro_invocations/empty.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: [] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_names.rs b/tests/target/skip_macro_invocations/name.rs similarity index 66% rename from tests/target/skip_macro_names.rs rename to tests/target/skip_macro_invocations/name.rs index 55b0eeec578..c4d577269c6 100644 --- a/tests/target/skip_macro_names.rs +++ b/tests/target/skip_macro_invocations/name.rs @@ -1,16 +1,11 @@ // rustfmt-skip_macro_invocations: ["items"] -macro_rules! items { - ($($arg:item)*) => { $($arg)* }; -} - // Should skip this invocation items!( const _: u8 = 0; ); // Should not skip this invocation -use self::items as renamed_items; renamed_items!( const _: u8 = 0; ); diff --git a/tests/target/skip_macro_invocations/name_unknown.rs b/tests/target/skip_macro_invocations/name_unknown.rs new file mode 100644 index 00000000000..7ab1440395c --- /dev/null +++ b/tests/target/skip_macro_invocations/name_unknown.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["unknown"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/names.rs b/tests/target/skip_macro_invocations/names.rs new file mode 100644 index 00000000000..c6b41ff93d7 --- /dev/null +++ b/tests/target/skip_macro_invocations/names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_invocations: ["foo","bar"] + +// Should skip this invocation +foo!( + const _: u8 = 0; +); + +// Should skip this invocation +bar!( + const _: u8 = 0; +); + +// Should not skip this invocation +baz!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs new file mode 100644 index 00000000000..6e372c72695 --- /dev/null +++ b/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should not skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/path_qualified_match.rs b/tests/target/skip_macro_invocations/path_qualified_match.rs new file mode 100644 index 00000000000..9398918a9e1 --- /dev/null +++ b/tests/target/skip_macro_invocations/path_qualified_match.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs b/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs new file mode 100644 index 00000000000..aa57a2a655c --- /dev/null +++ b/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); From d4d538155ae585649e4c021833e80973a7821774 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Tue, 28 Jun 2022 09:02:51 +0100 Subject: [PATCH 10/11] [review] add use alias test examples --- .../use_alias_examples.rs | 32 +++++++++++++++++++ .../use_alias_examples.rs | 32 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/source/skip_macro_invocations/use_alias_examples.rs create mode 100644 tests/target/skip_macro_invocations/use_alias_examples.rs diff --git a/tests/source/skip_macro_invocations/use_alias_examples.rs b/tests/source/skip_macro_invocations/use_alias_examples.rs new file mode 100644 index 00000000000..43cb8015de5 --- /dev/null +++ b/tests/source/skip_macro_invocations/use_alias_examples.rs @@ -0,0 +1,32 @@ +// rustfmt-skip_macro_invocations: ["aaa","ccc"] + +// These tests demonstrate a realistic use case with use aliases. +// The use statements should not impact functionality in any way. + +use crate::{aaa, bbb, ddd}; + +// No use alias, invocation in list +// Should skip this invocation +aaa!( + const _: u8 = 0; +); + +// Use alias, invocation in list +// Should skip this invocation +use crate::bbb as ccc; +ccc!( + const _: u8 = 0; +); + +// Use alias, invocation not in list +// Should not skip this invocation +use crate::ddd as eee; +eee!( + const _: u8 = 0; +); + +// No use alias, invocation not in list +// Should not skip this invocation +fff!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/use_alias_examples.rs b/tests/target/skip_macro_invocations/use_alias_examples.rs new file mode 100644 index 00000000000..799dd8c08af --- /dev/null +++ b/tests/target/skip_macro_invocations/use_alias_examples.rs @@ -0,0 +1,32 @@ +// rustfmt-skip_macro_invocations: ["aaa","ccc"] + +// These tests demonstrate a realistic use case with use aliases. +// The use statements should not impact functionality in any way. + +use crate::{aaa, bbb, ddd}; + +// No use alias, invocation in list +// Should skip this invocation +aaa!( + const _: u8 = 0; +); + +// Use alias, invocation in list +// Should skip this invocation +use crate::bbb as ccc; +ccc!( + const _: u8 = 0; +); + +// Use alias, invocation not in list +// Should not skip this invocation +use crate::ddd as eee; +eee!( + const _: u8 = 0; +); + +// No use alias, invocation not in list +// Should not skip this invocation +fff!( + const _: u8 = 0; +); From 7fd8be26344b7b42db4b4fe3067554376bd4387c Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Mon, 11 Jul 2022 10:42:15 +0100 Subject: [PATCH 11/11] [review] add link to standard macro behaviour --- Configurations.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Configurations.md b/Configurations.md index d0167d55c01..5579b5095af 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1029,7 +1029,9 @@ Note: This option does not have any impact on how rustfmt formats macro definiti #### `[]` (default): -All macro invocations will be formatted. +rustfmt will follow its standard approach to formatting macro invocations. + +No macro invocations will be skipped based on their name. More information about rustfmt's standard macro invocation formatting behavior can be found in [#5437](https://github.com/rust-lang/rustfmt/discussions/5437). ```rust lorem!(