From ba129682e7f8f8b0ae6924670f0cb3007cb37ff2 Mon Sep 17 00:00:00 2001 From: Michael Morgan Date: Tue, 12 Jan 2021 14:29:11 -0500 Subject: [PATCH 1/3] Add imports_granularity="Item". This option splits all imports into their own `use` statement. --- Configurations.md | 17 ++++++++++++++++- src/config/options.rs | 2 ++ src/formatting/imports.rs | 17 +++++++++++++++++ src/formatting/reorder.rs | 15 ++++++++------- tests/target/imports_granularity_item.rs | 23 +++++++++++++++++++++++ 5 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 tests/target/imports_granularity_item.rs 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..17429028168 100644 --- a/src/formatting/imports.rs +++ b/src/formatting/imports.rs @@ -542,6 +542,7 @@ impl UseTree { SharedPrefix::Module => { self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1] } + SharedPrefix::NoPrefix => false, } } } @@ -854,6 +855,7 @@ impl Rewrite for UseTree { pub(crate) enum SharedPrefix { Crate, Module, + NoPrefix, } #[cfg(test)] @@ -1068,6 +1070,21 @@ mod test { ); } + #[test] + fn test_use_tree_merge_no_prefix() { + test_merge!( + NoPrefix, + ["foo::{a::{b, c}, d::e}"], + ["foo::a::b", "foo::a::c", "foo::d::e"] + ); + + test_merge!( + NoPrefix, + ["foo::{self, a, b::{c, d}, e::*}"], + ["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..bd49089788b 100644 --- a/src/formatting/reorder.rs +++ b/src/formatting/reorder.rs @@ -228,15 +228,16 @@ 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 => { + merge_use_trees(normalized_items, SharedPrefix::NoPrefix) + } + ImportGranularity::Preserve => normalized_items, + }; let mut regrouped_items = match context.config.group_imports() { GroupImportsTactic::Preserve => vec![normalized_items], diff --git a/tests/target/imports_granularity_item.rs b/tests/target/imports_granularity_item.rs new file mode 100644 index 00000000000..d2526081be6 --- /dev/null +++ b/tests/target/imports_granularity_item.rs @@ -0,0 +1,23 @@ +// rustfmt-imports_granularity: Item + +use a::b::c; +use a::d::e; +use a::f; +use a::g::h; +use a::g::i; +use a::j; +use a::j::k; +use a::j::k::l; +use a::j::m; +use a::n::o::p; +use a::n::q; +pub use a::r::s; +pub use a::t; + +use foo::e; +#[cfg(test)] +use foo::{a::b, c::d}; + +use bar::a::b; +use bar::c::d; +use bar::e::f; From 47fc453194add72b6b94df5d98aaaa5e869534f6 Mon Sep 17 00:00:00 2001 From: Michael Morgan Date: Wed, 13 Jan 2021 12:04:33 -0500 Subject: [PATCH 2/3] Update tests for imports_granularity=Item. --- src/formatting/imports.rs | 5 ++++ src/formatting/reorder.rs | 5 ++++ tests/source/imports_granularity_item.rs | 6 +++++ tests/target/imports_granularity_item.rs | 32 ++++++++---------------- 4 files changed, 27 insertions(+), 21 deletions(-) create mode 100644 tests/source/imports_granularity_item.rs diff --git a/src/formatting/imports.rs b/src/formatting/imports.rs index 17429028168..f1cac2bcf05 100644 --- a/src/formatting/imports.rs +++ b/src/formatting/imports.rs @@ -561,6 +561,11 @@ impl UseTree { for flattened in &mut nested_use_tree.clone().flatten() { let mut new_path = prefix.to_vec(); new_path.append(&mut flattened.path); + if flattened.path.len() == 1 { + if let UseSegment::Slf(..) = flattened.path[0] { + new_path.pop(); + } + } result.push(UseTree { path: new_path, span: self.span, diff --git a/src/formatting/reorder.rs b/src/formatting/reorder.rs index bd49089788b..a65c94eecf8 100644 --- a/src/formatting/reorder.rs +++ b/src/formatting/reorder.rs @@ -238,6 +238,11 @@ fn rewrite_reorderable_or_regroupable_items( } ImportGranularity::Preserve => normalized_items, }; + for item in normalized_items.iter_mut() { + if let Some(UseSegment::Slf(None)) = item.path.last() { + item.path.pop().unwrap(); + } + } 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 index d2526081be6..a6602ef33d9 100644 --- a/tests/target/imports_granularity_item.rs +++ b/tests/target/imports_granularity_item.rs @@ -1,23 +1,13 @@ // rustfmt-imports_granularity: Item -use a::b::c; -use a::d::e; -use a::f; -use a::g::h; -use a::g::i; -use a::j; -use a::j::k; -use a::j::k::l; -use a::j::m; -use a::n::o::p; -use a::n::q; -pub use a::r::s; -pub use a::t; - -use foo::e; -#[cfg(test)] -use foo::{a::b, c::d}; - -use bar::a::b; -use bar::c::d; -use bar::e::f; +use a::b; +use a::c; +use a::d; +use a::f::g; +use a::h::i; +use a::h::j; +use a::l; +use a::l::m; +use a::l::n::o; +use a::l::p::*; +use a::q::{self}; From f57f5d0e06303384c492927b41b00c0e85871e88 Mon Sep 17 00:00:00 2001 From: Michael Morgan Date: Wed, 13 Jan 2021 23:20:53 -0500 Subject: [PATCH 3/3] Omit final ::self and ::{self} from `use` items. --- src/formatting/imports.rs | 7 +------ src/formatting/reorder.rs | 13 +++++++++++-- tests/target/imports_granularity_crate.rs | 8 ++++---- tests/target/imports_granularity_item.rs | 2 +- tests/target/issue-3645.rs | 2 +- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/formatting/imports.rs b/src/formatting/imports.rs index f1cac2bcf05..9de47825824 100644 --- a/src/formatting/imports.rs +++ b/src/formatting/imports.rs @@ -550,11 +550,6 @@ impl UseTree { fn flatten(self) -> Vec { match self.path.last() { Some(UseSegment::List(list)) => { - if list.len() == 1 && list[0].path.len() == 1 { - if let UseSegment::Slf(..) = list[0].path[0] { - return vec![self]; - }; - } let prefix = &self.path[..self.path.len() - 1]; let mut result = vec![]; for nested_use_tree in list { @@ -1056,7 +1051,7 @@ mod test { test_merge!( Crate, ["a::{self}", "b::{self as foo}"], - ["a::{self}", "b::{self as foo}"] + ["a::self", "b::self as foo"] ); } diff --git a/src/formatting/reorder.rs b/src/formatting/reorder.rs index a65c94eecf8..0ca6c2cd443 100644 --- a/src/formatting/reorder.rs +++ b/src/formatting/reorder.rs @@ -239,8 +239,17 @@ fn rewrite_reorderable_or_regroupable_items( ImportGranularity::Preserve => normalized_items, }; for item in normalized_items.iter_mut() { - if let Some(UseSegment::Slf(None)) = item.path.last() { - item.path.pop().unwrap(); + if let Some(UseSegment::Slf(..)) = item.path.last() { + let self_seg = item.path.pop().unwrap(); + match self_seg { + UseSegment::Slf(Some(self_rename)) => match item.path.last_mut() { + Some(UseSegment::Ident(_, rename @ None)) + | Some(UseSegment::Crate(rename @ None)) + | Some(UseSegment::Super(rename @ None)) => *rename = Some(self_rename), + _ => {} + }, + _ => {} + } } } diff --git a/tests/target/imports_granularity_crate.rs b/tests/target/imports_granularity_crate.rs index d75906d30f1..472da59e653 100644 --- a/tests/target/imports_granularity_crate.rs +++ b/tests/target/imports_granularity_crate.rs @@ -16,13 +16,13 @@ pub use foo::{bar, foobar}; use a::b::c::{d, xxx, yyy, zzz, *}; // https://github.com/rust-lang/rustfmt/issues/3808 -use d::{self}; -use e::{self as foo}; +use d; +use e as foo; use f::{self, b}; use g::{self, a, b}; use h::a; -use i::a::{self}; -use j::a::{self}; +use i::a; +use j::a; use k::{a, b, c, d}; use l::{a, b, c, d}; diff --git a/tests/target/imports_granularity_item.rs b/tests/target/imports_granularity_item.rs index a6602ef33d9..466fe5242a1 100644 --- a/tests/target/imports_granularity_item.rs +++ b/tests/target/imports_granularity_item.rs @@ -10,4 +10,4 @@ use a::l; use a::l::m; use a::l::n::o; use a::l::p::*; -use a::q::{self}; +use a::q; diff --git a/tests/target/issue-3645.rs b/tests/target/issue-3645.rs index 14bf96e6383..bb2a28bc9fc 100644 --- a/tests/target/issue-3645.rs +++ b/tests/target/issue-3645.rs @@ -1,3 +1,3 @@ mod x { - use super::self as x; + use super as x; }