diff --git a/Configurations.md b/Configurations.md index aaefc46180b..bff75027376 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1710,7 +1710,7 @@ pub enum Foo {} Merge together related imports based on their paths. - **Default value**: `Preserve` -- **Possible values**: `Preserve`, `Crate`, `Module` +- **Possible values**: `Preserve`, `Crate`, `Module`, `Item` - **Stable**: No #### `Preserve` (default): @@ -1749,6 +1749,21 @@ use foo::{a, b, c}; use qux::{h, i}; ``` +#### `Item`: + +Flatten imports so that each has its own `use` statement. + +```rust +use foo::a; +use foo::b; +use foo::b::f; +use foo::b::g; +use foo::c; +use foo::d::e; +use qux::h; +use qux::i; +``` + ## `merge_imports` This option is deprecated. Use `imports_granularity = "Crate"` instead. diff --git a/src/config/options.rs b/src/config/options.rs index a272eadd72f..0009d0a52bb 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -128,6 +128,8 @@ pub enum ImportGranularity { Crate, /// Use one `use` statement per module. Module, + /// Use one `use` statement per imported item. + Item, } #[config_type] diff --git a/src/formatting/imports.rs b/src/formatting/imports.rs index bfb862ae6e6..7b688c2f11c 100644 --- a/src/formatting/imports.rs +++ b/src/formatting/imports.rs @@ -182,6 +182,24 @@ pub(crate) fn merge_use_trees(use_trees: Vec, merge_by: SharedPrefix) - result } +pub(crate) fn flatten_use_trees(use_trees: Vec) -> Vec { + use_trees + .into_iter() + .flat_map(UseTree::flatten) + .map(|mut tree| { + // If a path ends in `::self`, rewrite it to `::{self}`. + if let Some(UseSegment::Slf(..)) = tree.path.last() { + let self_segment = tree.path.pop().unwrap(); + tree.path.push(UseSegment::List(vec![UseTree::from_path( + vec![self_segment], + DUMMY_SP, + )])); + } + tree + }) + .collect() +} + impl fmt::Debug for UseTree { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) @@ -1068,6 +1086,25 @@ mod test { ); } + #[test] + fn test_flatten_use_trees() { + assert_eq!( + flatten_use_trees(parse_use_trees!["foo::{a::{b, c}, d::e}"]), + parse_use_trees!["foo::a::b", "foo::a::c", "foo::d::e"] + ); + + assert_eq!( + flatten_use_trees(parse_use_trees!["foo::{self, a, b::{c, d}, e::*}"]), + parse_use_trees![ + "foo::{self}", + "foo::a", + "foo::b::c", + "foo::b::d", + "foo::e::*" + ] + ); + } + #[test] fn test_use_tree_flatten() { assert_eq!( diff --git a/src/formatting/reorder.rs b/src/formatting/reorder.rs index 9d1777d82df..110f7efee7a 100644 --- a/src/formatting/reorder.rs +++ b/src/formatting/reorder.rs @@ -12,7 +12,7 @@ use rustc_ast::ast; use rustc_span::{symbol::sym, Span}; use crate::config::{Config, GroupImportsTactic, ImportGranularity}; -use crate::formatting::imports::UseSegment; +use crate::formatting::imports::{flatten_use_trees, UseSegment}; use crate::formatting::modules::{get_mod_inner_attrs, FileModMap}; use crate::formatting::{ imports::{merge_use_trees, UseTree}, @@ -228,15 +228,14 @@ fn rewrite_reorderable_or_regroupable_items( for (item, list_item) in normalized_items.iter_mut().zip(list_items) { item.list_item = Some(list_item.clone()); } - match context.config.imports_granularity() { - ImportGranularity::Crate => { - normalized_items = merge_use_trees(normalized_items, SharedPrefix::Crate) - } + normalized_items = match context.config.imports_granularity() { + ImportGranularity::Crate => merge_use_trees(normalized_items, SharedPrefix::Crate), ImportGranularity::Module => { - normalized_items = merge_use_trees(normalized_items, SharedPrefix::Module) + merge_use_trees(normalized_items, SharedPrefix::Module) } - ImportGranularity::Preserve => {} - } + ImportGranularity::Item => flatten_use_trees(normalized_items), + ImportGranularity::Preserve => normalized_items, + }; let mut regrouped_items = match context.config.group_imports() { GroupImportsTactic::Preserve => vec![normalized_items], diff --git a/tests/source/imports_granularity_item.rs b/tests/source/imports_granularity_item.rs new file mode 100644 index 00000000000..d0e94df66ae --- /dev/null +++ b/tests/source/imports_granularity_item.rs @@ -0,0 +1,6 @@ +// rustfmt-imports_granularity: Item + +use a::{b, c, d}; +use a::{f::g, h::{i, j}}; +use a::{l::{self, m, n::o, p::*}}; +use a::q::{self}; diff --git a/tests/target/imports_granularity_item.rs b/tests/target/imports_granularity_item.rs new file mode 100644 index 00000000000..eace785e670 --- /dev/null +++ b/tests/target/imports_granularity_item.rs @@ -0,0 +1,13 @@ +// rustfmt-imports_granularity: Item + +use a::b; +use a::c; +use a::d; +use a::f::g; +use a::h::i; +use a::h::j; +use a::l::m; +use a::l::n::o; +use a::l::p::*; +use a::l::{self}; +use a::q::{self};