From 1768efa33344022c550f3cfcd30ede168bcf3143 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 14 Mar 2021 19:35:35 +0100 Subject: [PATCH 1/4] Fix FP in `single_component_path_imports` lint --- clippy_lints/src/lib.rs | 2 +- .../src/single_component_path_imports.rs | 90 +++++++++++++++---- ...ingle_component_path_imports_self_after.rs | 16 ++++ ...ngle_component_path_imports_self_before.rs | 17 ++++ 4 files changed, 109 insertions(+), 16 deletions(-) create mode 100644 tests/ui/single_component_path_imports_self_after.rs create mode 100644 tests/ui/single_component_path_imports_self_before.rs diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f013613119cf1..97557fefe3eca 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1232,7 +1232,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box as_conversions::AsConversions); store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_late_pass(|| box atomic_ordering::AtomicOrdering); - store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); + store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports::default()); let max_fn_params_bools = conf.max_fn_params_bools; let max_struct_bools = conf.max_struct_bools; store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index c9d72aabb6a3c..ee74ef97bcdf8 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_macro; use if_chain::if_chain; -use rustc_ast::{Item, ItemKind, UseTreeKind}; +use rustc_ast::{Crate, Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::edition::Edition; +use rustc_span::symbol::kw; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// **What it does:** Checking for imports with single component use path. @@ -35,29 +37,87 @@ declare_clippy_lint! { "imports with single component path are redundant" } -declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]); +#[derive(Default)] +pub struct SingleComponentPathImports { + /// keep track of imports reused with `self` keyword, + /// such as `self::crypto_hash` in the example below + /// + /// ```rust,ignore + /// use self::crypto_hash::{Algorithm, Hasher}; + /// ``` + imports_reused_with_self: Vec, + /// keep track of single use statements + /// such as `crypto_hash` in the example below + /// + /// ```rust,ignore + /// use crypto_hash; + /// ``` + single_use_usages: Vec<(Symbol, Span)>, +} + +impl_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]); impl EarlyLintPass for SingleComponentPathImports { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if_chain! { - if !in_macro(item.span); - if cx.sess.opts.edition >= Edition::Edition2018; - if !item.vis.kind.is_pub(); - if let ItemKind::Use(use_tree) = &item.kind; - if let segments = &use_tree.prefix.segments; - if segments.len() == 1; - if let UseTreeKind::Simple(None, _, _) = use_tree.kind; - then { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { + if cx.sess.opts.edition < Edition::Edition2018 { + return; + } + for item in &krate.items { + self.track_uses(&item); + } + for single_use in &self.single_use_usages { + if !self.imports_reused_with_self.contains(&single_use.0) { span_lint_and_sugg( cx, SINGLE_COMPONENT_PATH_IMPORTS, - item.span, + single_use.1, "this import is redundant", "remove it entirely", String::new(), - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } } } + +impl SingleComponentPathImports { + fn track_uses(&mut self, item: &Item) { + if_chain! { + if !in_macro(item.span); + if !item.vis.kind.is_pub(); + if let ItemKind::Use(use_tree) = &item.kind; + if let segments = &use_tree.prefix.segments; + + then { + // keep track of `use some_module;` usages + if segments.len() == 1 { + if let UseTreeKind::Simple(None, _, _) = use_tree.kind { + let ident = &segments[0].ident; + self.single_use_usages.push((ident.name, item.span)); + } + 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 { + self.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() { + self.imports_reused_with_self.push(segments[0].ident.name); + } + } + } + } + } + } + } +} diff --git a/tests/ui/single_component_path_imports_self_after.rs b/tests/ui/single_component_path_imports_self_after.rs new file mode 100644 index 0000000000000..94319ade0ac4b --- /dev/null +++ b/tests/ui/single_component_path_imports_self_after.rs @@ -0,0 +1,16 @@ +// edition:2018 +#![warn(clippy::single_component_path_imports)] +#![allow(unused_imports)] + +use self::regex::{Regex as xeger, RegexSet as tesxeger}; +pub use self::{ + regex::{Regex, RegexSet}, + some_mod::SomeType, +}; +use regex; + +mod some_mod { + pub struct SomeType; +} + +fn main() {} diff --git a/tests/ui/single_component_path_imports_self_before.rs b/tests/ui/single_component_path_imports_self_before.rs new file mode 100644 index 0000000000000..c7437b234566a --- /dev/null +++ b/tests/ui/single_component_path_imports_self_before.rs @@ -0,0 +1,17 @@ +// edition:2018 +#![warn(clippy::single_component_path_imports)] +#![allow(unused_imports)] + +use regex; + +use self::regex::{Regex as xeger, RegexSet as tesxeger}; +pub use self::{ + regex::{Regex, RegexSet}, + some_mod::SomeType, +}; + +mod some_mod { + pub struct SomeType; +} + +fn main() {} From 6985d13a9783bb7181b6c43e83465e7630e48ec2 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 28 Mar 2021 09:35:44 +0200 Subject: [PATCH 2/4] Take into account sub modules --- .../src/single_component_path_imports.rs | 24 ++++++++++++------- tests/ui/single_component_path_imports.fixed | 6 +++++ tests/ui/single_component_path_imports.rs | 6 +++++ tests/ui/single_component_path_imports.stderr | 8 ++++++- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index ee74ef97bcdf8..901f7642a1271 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_macro; -use if_chain::if_chain; -use rustc_ast::{Crate, Item, ItemKind, UseTreeKind}; +use rustc_ast::{Crate, Item, ItemKind, ModKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -83,13 +82,19 @@ impl EarlyLintPass for SingleComponentPathImports { impl SingleComponentPathImports { fn track_uses(&mut self, item: &Item) { - if_chain! { - if !in_macro(item.span); - if !item.vis.kind.is_pub(); - if let ItemKind::Use(use_tree) = &item.kind; - if let segments = &use_tree.prefix.segments; + if in_macro(item.span) || item.vis.kind.is_pub() { + return; + } + + match &item.kind { + ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { + for item in items.iter() { + self.track_uses(&item); + } + }, + ItemKind::Use(use_tree) => { + let segments = &use_tree.prefix.segments; - then { // keep track of `use some_module;` usages if segments.len() == 1 { if let UseTreeKind::Simple(None, _, _) = use_tree.kind { @@ -117,7 +122,8 @@ impl SingleComponentPathImports { } } } - } + }, + _ => {}, } } } diff --git a/tests/ui/single_component_path_imports.fixed b/tests/ui/single_component_path_imports.fixed index a7a8499b58f00..226d2b315d7a3 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -19,3 +19,9 @@ fn main() { // False positive #5154, shouldn't trigger lint. m!(); } + +mod hello_mod { + + #[allow(dead_code)] + fn hello_mod() {} +} diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 9a427e90ad3df..88bf7f1fc5ab0 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -19,3 +19,9 @@ fn main() { // False positive #5154, shouldn't trigger lint. m!(); } + +mod hello_mod { + use regex; + #[allow(dead_code)] + fn hello_mod() {} +} diff --git a/tests/ui/single_component_path_imports.stderr b/tests/ui/single_component_path_imports.stderr index 519ada0169a6d..646e6d3647acc 100644 --- a/tests/ui/single_component_path_imports.stderr +++ b/tests/ui/single_component_path_imports.stderr @@ -6,5 +6,11 @@ LL | use regex; | = note: `-D clippy::single-component-path-imports` implied by `-D warnings` -error: aborting due to previous error +error: this import is redundant + --> $DIR/single_component_path_imports.rs:24:5 + | +LL | use regex; + | ^^^^^^^^^^ help: remove it entirely + +error: aborting due to 2 previous errors From 81dfb9ecfb13f67a56176bd82c846530858b8ef5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 4 Apr 2021 14:21:02 +0200 Subject: [PATCH 3/4] Check path imports per module --- clippy_lints/src/lib.rs | 2 +- .../src/single_component_path_imports.rs | 150 +++++++++--------- tests/ui/single_component_path_imports.fixed | 7 + tests/ui/single_component_path_imports.rs | 7 + tests/ui/single_component_path_imports.stderr | 12 +- 5 files changed, 96 insertions(+), 82 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 97557fefe3eca..f013613119cf1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1232,7 +1232,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box as_conversions::AsConversions); store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_late_pass(|| box atomic_ordering::AtomicOrdering); - store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports::default()); + store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); let max_fn_params_bools = conf.max_fn_params_bools; let max_struct_bools = conf.max_struct_bools; store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 901f7642a1271..adf0d7998f808 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,12 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_macro; -use rustc_ast::{Crate, Item, ItemKind, ModKind, UseTreeKind}; +use rustc_ast::{ptr::P, Crate, Item, ItemKind, ModKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::edition::Edition; -use rustc_span::symbol::kw; -use rustc_span::{Span, Symbol}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{edition::Edition, symbol::kw, Span, Symbol}; declare_clippy_lint! { /// **What it does:** Checking for imports with single component use path. @@ -36,94 +34,96 @@ declare_clippy_lint! { "imports with single component path are redundant" } -#[derive(Default)] -pub struct SingleComponentPathImports { - /// keep track of imports reused with `self` keyword, - /// such as `self::crypto_hash` in the example below - /// - /// ```rust,ignore - /// use self::crypto_hash::{Algorithm, Hasher}; - /// ``` - imports_reused_with_self: Vec, - /// keep track of single use statements - /// such as `crypto_hash` in the example below - /// - /// ```rust,ignore - /// use crypto_hash; - /// ``` - single_use_usages: Vec<(Symbol, Span)>, -} - -impl_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]); +declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]); impl EarlyLintPass for SingleComponentPathImports { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { if cx.sess.opts.edition < Edition::Edition2018 { return; } - for item in &krate.items { - self.track_uses(&item); - } - for single_use in &self.single_use_usages { - if !self.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, - ); - } - } + check_mod(cx, &krate.items); } } -impl SingleComponentPathImports { - fn track_uses(&mut self, item: &Item) { - if in_macro(item.span) || item.vis.kind.is_pub() { - return; +fn check_mod(cx: &EarlyContext<'_>, items: &[P]) { + // keep track of imports reused with `self` keyword, + // such as `self::crypto_hash` in the example below + // ```rust,ignore + // use self::crypto_hash::{Algorithm, Hasher}; + // ``` + let mut imports_reused_with_self = Vec::new(); + + // keep track of single use statements + // such as `crypto_hash` in the example below + // ```rust,ignore + // use crypto_hash; + // ``` + let mut single_use_usages = Vec::new(); + + for item in items { + track_uses(cx, &item, &mut imports_reused_with_self, &mut single_use_usages); + } + + 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, + ); } + } +} + +fn track_uses( + cx: &EarlyContext<'_>, + item: &Item, + imports_reused_with_self: &mut Vec, + single_use_usages: &mut Vec<(Symbol, Span)>, +) { + if in_macro(item.span) || item.vis.kind.is_pub() { + return; + } + + match &item.kind { + ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { + check_mod(cx, &items); + }, + ItemKind::Use(use_tree) => { + let segments = &use_tree.prefix.segments; - match &item.kind { - ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { - for item in items.iter() { - self.track_uses(&item); + // keep track of `use some_module;` usages + 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)); } - }, - ItemKind::Use(use_tree) => { - let segments = &use_tree.prefix.segments; + return; + } - // keep track of `use some_module;` usages - if segments.len() == 1 { - if let UseTreeKind::Simple(None, _, _) = use_tree.kind { - let ident = &segments[0].ident; - self.single_use_usages.push((ident.name, item.span)); - } + // 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; } - // 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 { - self.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() { - self.imports_reused_with_self.push(segments[0].ident.name); - } + // 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.fixed b/tests/ui/single_component_path_imports.fixed index 226d2b315d7a3..f66b445b7b6a3 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -25,3 +25,10 @@ mod hello_mod { #[allow(dead_code)] fn hello_mod() {} } + +mod hi_mod { + use self::regex::{Regex, RegexSet}; + use regex; + #[allow(dead_code)] + fn hi_mod() {} +} diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 88bf7f1fc5ab0..09d4865859584 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -25,3 +25,10 @@ mod hello_mod { #[allow(dead_code)] fn hello_mod() {} } + +mod hi_mod { + use self::regex::{Regex, RegexSet}; + use regex; + #[allow(dead_code)] + fn hi_mod() {} +} diff --git a/tests/ui/single_component_path_imports.stderr b/tests/ui/single_component_path_imports.stderr index 646e6d3647acc..7005fa8f125d3 100644 --- a/tests/ui/single_component_path_imports.stderr +++ b/tests/ui/single_component_path_imports.stderr @@ -1,16 +1,16 @@ error: this import is redundant - --> $DIR/single_component_path_imports.rs:6:1 + --> $DIR/single_component_path_imports.rs:24:5 | -LL | use regex; - | ^^^^^^^^^^ help: remove it entirely +LL | use regex; + | ^^^^^^^^^^ help: remove it entirely | = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant - --> $DIR/single_component_path_imports.rs:24:5 + --> $DIR/single_component_path_imports.rs:6:1 | -LL | use regex; - | ^^^^^^^^^^ help: remove it entirely +LL | use regex; + | ^^^^^^^^^^ help: remove it entirely error: aborting due to 2 previous errors From 297e84f3f4b7ff3c2648e65b0f2c144982cfad63 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 10 Apr 2021 10:26:53 +0200 Subject: [PATCH 4/4] Handle imports which are nested directly --- .../src/single_component_path_imports.rs | 73 +++++++++++++------ ...gle_component_path_imports_nested_first.rs | 17 +++++ ...component_path_imports_nested_first.stderr | 25 +++++++ 3 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 tests/ui/single_component_path_imports_nested_first.rs create mode 100644 tests/ui/single_component_path_imports_nested_first.stderr diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index adf0d7998f808..6104103580e98 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]) { 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, - 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 0000000000000..94117061b270d --- /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 0000000000000..0c3256c1ce43a --- /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 +