about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/single_component_path_imports.rs73
-rw-r--r--tests/ui/single_component_path_imports_nested_first.rs17
-rw-r--r--tests/ui/single_component_path_imports_nested_first.stderr25
3 files changed, 92 insertions, 23 deletions
diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs
index adf0d7998f8..6104103580e 100644
--- a/clippy_lints/src/single_component_path_imports.rs
+++ b/clippy_lints/src/single_component_path_imports.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::in_macro;
 use rustc_ast::{ptr::P, Crate, Item, ItemKind, ModKind, UseTreeKind};
 use rustc_errors::Applicability;
@@ -66,15 +66,27 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
 
     for single_use in &single_use_usages {
         if !imports_reused_with_self.contains(&single_use.0) {
-            span_lint_and_sugg(
-                cx,
-                SINGLE_COMPONENT_PATH_IMPORTS,
-                single_use.1,
-                "this import is redundant",
-                "remove it entirely",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
+            let can_suggest = single_use.2;
+            if can_suggest {
+                span_lint_and_sugg(
+                    cx,
+                    SINGLE_COMPONENT_PATH_IMPORTS,
+                    single_use.1,
+                    "this import is redundant",
+                    "remove it entirely",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                span_lint_and_help(
+                    cx,
+                    SINGLE_COMPONENT_PATH_IMPORTS,
+                    single_use.1,
+                    "this import is redundant",
+                    None,
+                    "remove this import",
+                );
+            }
         }
     }
 }
@@ -83,7 +95,7 @@ fn track_uses(
     cx: &EarlyContext<'_>,
     item: &Item,
     imports_reused_with_self: &mut Vec<Symbol>,
-    single_use_usages: &mut Vec<(Symbol, Span)>,
+    single_use_usages: &mut Vec<(Symbol, Span, bool)>,
 ) {
     if in_macro(item.span) || item.vis.kind.is_pub() {
         return;
@@ -100,25 +112,40 @@ fn track_uses(
             if segments.len() == 1 {
                 if let UseTreeKind::Simple(None, _, _) = use_tree.kind {
                     let ident = &segments[0].ident;
-                    single_use_usages.push((ident.name, item.span));
+                    single_use_usages.push((ident.name, item.span, true));
                 }
                 return;
             }
 
-            // keep track of `use self::some_module` usages
-            if segments[0].ident.name == kw::SelfLower {
-                // simple case such as `use self::module::SomeStruct`
-                if segments.len() > 1 {
-                    imports_reused_with_self.push(segments[1].ident.name);
-                    return;
-                }
-
-                // nested case such as `use self::{module1::Struct1, module2::Struct2}`
+            if segments.is_empty() {
+                // keep track of `use {some_module, some_other_module};` usages
                 if let UseTreeKind::Nested(trees) = &use_tree.kind {
                     for tree in trees {
                         let segments = &tree.0.prefix.segments;
-                        if !segments.is_empty() {
-                            imports_reused_with_self.push(segments[0].ident.name);
+                        if segments.len() == 1 {
+                            if let UseTreeKind::Simple(None, _, _) = tree.0.kind {
+                                let ident = &segments[0].ident;
+                                single_use_usages.push((ident.name, tree.0.span, false));
+                            }
+                        }
+                    }
+                }
+            } else {
+                // keep track of `use self::some_module` usages
+                if segments[0].ident.name == kw::SelfLower {
+                    // simple case such as `use self::module::SomeStruct`
+                    if segments.len() > 1 {
+                        imports_reused_with_self.push(segments[1].ident.name);
+                        return;
+                    }
+
+                    // nested case such as `use self::{module1::Struct1, module2::Struct2}`
+                    if let UseTreeKind::Nested(trees) = &use_tree.kind {
+                        for tree in trees {
+                            let segments = &tree.0.prefix.segments;
+                            if !segments.is_empty() {
+                                imports_reused_with_self.push(segments[0].ident.name);
+                            }
                         }
                     }
                 }
diff --git a/tests/ui/single_component_path_imports_nested_first.rs b/tests/ui/single_component_path_imports_nested_first.rs
new file mode 100644
index 00000000000..94117061b27
--- /dev/null
+++ b/tests/ui/single_component_path_imports_nested_first.rs
@@ -0,0 +1,17 @@
+// edition:2018
+#![warn(clippy::single_component_path_imports)]
+#![allow(unused_imports)]
+
+use regex;
+use serde as edres;
+pub use serde;
+
+fn main() {
+    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+}
+
+mod root_nested_use_mod {
+    use {regex, serde};
+    #[allow(dead_code)]
+    fn root_nested_use_mod() {}
+}
diff --git a/tests/ui/single_component_path_imports_nested_first.stderr b/tests/ui/single_component_path_imports_nested_first.stderr
new file mode 100644
index 00000000000..0c3256c1ce4
--- /dev/null
+++ b/tests/ui/single_component_path_imports_nested_first.stderr
@@ -0,0 +1,25 @@
+error: this import is redundant
+  --> $DIR/single_component_path_imports_nested_first.rs:14:10
+   |
+LL |     use {regex, serde};
+   |          ^^^^^
+   |
+   = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
+   = help: remove this import
+
+error: this import is redundant
+  --> $DIR/single_component_path_imports_nested_first.rs:14:17
+   |
+LL |     use {regex, serde};
+   |                 ^^^^^
+   |
+   = help: remove this import
+
+error: this import is redundant
+  --> $DIR/single_component_path_imports_nested_first.rs:5:1
+   |
+LL | use regex;
+   | ^^^^^^^^^^ help: remove it entirely
+
+error: aborting due to 3 previous errors
+