about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs27
-rw-r--r--tests/ui/suggestions/unused-imports.fixed35
-rw-r--r--tests/ui/suggestions/unused-imports.rs42
-rw-r--r--tests/ui/suggestions/unused-imports.stderr32
4 files changed, 135 insertions, 1 deletions
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 950a0f9ff65..5fe68085d65 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -292,7 +292,7 @@ fn calc_unused_spans(
                 UnusedSpanResult::Used
             }
         }
-        ast::UseTreeKind::Nested { items: ref nested, .. } => {
+        ast::UseTreeKind::Nested { items: ref nested, span: tree_span } => {
             if nested.is_empty() {
                 return UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span };
             }
@@ -300,6 +300,7 @@ fn calc_unused_spans(
             let mut unused_spans = Vec::new();
             let mut to_remove = Vec::new();
             let mut used_childs = 0;
+            let mut contains_self = false;
             let mut previous_unused = false;
             for (pos, (use_tree, use_tree_id)) in nested.iter().enumerate() {
                 let remove = match calc_unused_spans(unused_import, use_tree, *use_tree_id) {
@@ -339,6 +340,8 @@ fn calc_unused_spans(
                         to_remove.push(remove_span);
                     }
                 }
+                contains_self |= use_tree.prefix == kw::SelfLower
+                    && matches!(use_tree.kind, ast::UseTreeKind::Simple(None));
                 previous_unused = remove.is_some();
             }
             if unused_spans.is_empty() {
@@ -346,6 +349,28 @@ fn calc_unused_spans(
             } else if used_childs == 0 {
                 UnusedSpanResult::Unused { spans: unused_spans, remove: full_span }
             } else {
+                // If there is only one remaining child that is used, the braces around the use
+                // tree are not needed anymore. In that case, we determine the span of the left
+                // brace and the right brace, and tell rustfix to remove them as well.
+                //
+                // This means that `use a::{B, C};` will be turned into `use a::B;` rather than
+                // `use a::{B};`, removing a rustfmt roundtrip.
+                //
+                // Note that we cannot remove the braces if the only item inside the use tree is
+                // `self`: `use foo::{self};` is valid Rust syntax, while `use foo::self;` errors
+                // out. We also cannot turn `use foo::{self}` into `use foo`, as the former doesn't
+                // import types with the same name as the module.
+                if used_childs == 1 && !contains_self {
+                    // Left brace, from the start of the nested group to the first item.
+                    to_remove.push(
+                        tree_span.shrink_to_lo().to(nested.first().unwrap().0.span.shrink_to_lo()),
+                    );
+                    // Right brace, from the end of the last item to the end of the nested group.
+                    to_remove.push(
+                        nested.last().unwrap().0.span.shrink_to_hi().to(tree_span.shrink_to_hi()),
+                    );
+                }
+
                 UnusedSpanResult::PartialUnused { spans: unused_spans, remove: to_remove }
             }
         }
diff --git a/tests/ui/suggestions/unused-imports.fixed b/tests/ui/suggestions/unused-imports.fixed
new file mode 100644
index 00000000000..57dd091c043
--- /dev/null
+++ b/tests/ui/suggestions/unused-imports.fixed
@@ -0,0 +1,35 @@
+//@ run-rustfix
+//@ check-pass
+
+#![warn(unused_imports)]
+
+pub mod nested {
+    pub struct A;
+    pub struct B;
+    pub struct C;
+    pub struct D;
+    pub mod even_more {
+        pub struct E;
+        pub struct F;
+        pub struct G;
+    }
+    pub mod another {
+        pub struct H;
+        pub struct I;
+    }
+}
+
+use nested::B;
+//~^ WARN unused import
+
+use nested::even_more::F;
+//~^^^^^^^ WARN unused import
+
+// Note that the following fix should result in `::{self}`, not `::self`. The latter is invalid
+// Rust syntax, so the braces should not be removed.
+use nested::another::{self};
+//~^ WARN unused import
+
+fn main() {
+    let _ = (B, F, another::I);
+}
diff --git a/tests/ui/suggestions/unused-imports.rs b/tests/ui/suggestions/unused-imports.rs
new file mode 100644
index 00000000000..5f9dd243bdd
--- /dev/null
+++ b/tests/ui/suggestions/unused-imports.rs
@@ -0,0 +1,42 @@
+//@ run-rustfix
+//@ check-pass
+
+#![warn(unused_imports)]
+
+pub mod nested {
+    pub struct A;
+    pub struct B;
+    pub struct C;
+    pub struct D;
+    pub mod even_more {
+        pub struct E;
+        pub struct F;
+        pub struct G;
+    }
+    pub mod another {
+        pub struct H;
+        pub struct I;
+    }
+}
+
+use nested::{A, B, C};
+//~^ WARN unused import
+
+use nested::{
+    D,
+    even_more::{
+        E,
+        F,
+        G,
+                         },
+            };
+//~^^^^^^^ WARN unused import
+
+// Note that the following fix should result in `::{self}`, not `::self`. The latter is invalid
+// Rust syntax, so the braces should not be removed.
+use nested::another::{self, I};
+//~^ WARN unused import
+
+fn main() {
+    let _ = (B, F, another::I);
+}
diff --git a/tests/ui/suggestions/unused-imports.stderr b/tests/ui/suggestions/unused-imports.stderr
new file mode 100644
index 00000000000..bf112608da7
--- /dev/null
+++ b/tests/ui/suggestions/unused-imports.stderr
@@ -0,0 +1,32 @@
+warning: unused imports: `A`, `C`
+  --> $DIR/unused-imports.rs:22:14
+   |
+LL | use nested::{A, B, C};
+   |              ^     ^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-imports.rs:4:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: unused imports: `D`, `E`, `G`
+  --> $DIR/unused-imports.rs:26:5
+   |
+LL |     D,
+   |     ^
+LL |     even_more::{
+LL |         E,
+   |         ^
+LL |         F,
+LL |         G,
+   |         ^
+
+warning: unused import: `I`
+  --> $DIR/unused-imports.rs:37:29
+   |
+LL | use nested::another::{self, I};
+   |                             ^
+
+warning: 3 warnings emitted
+