From 81dfb9ecfb13f67a56176bd82c846530858b8ef5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 4 Apr 2021 14:21:02 +0200 Subject: [PATCH] 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 | 16 +- 5 files changed, 98 insertions(+), 84 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 97557fefe3e..f013613119c 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 901f7642a12..adf0d7998f8 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); + } +} + +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, + ); } } } -impl SingleComponentPathImports { - fn track_uses(&mut self, item: &Item) { - if in_macro(item.span) || item.vis.kind.is_pub() { - return; - } +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, ..)) => { - for item in items.iter() { - self.track_uses(&item); + match &item.kind { + ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { + check_mod(cx, &items); + }, + ItemKind::Use(use_tree) => { + let segments = &use_tree.prefix.segments; + + // 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 226d2b315d7..f66b445b7b6 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 88bf7f1fc5a..09d48658595 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 646e6d3647a..7005fa8f125 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 - | -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 | 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:6:1 + | +LL | use regex; + | ^^^^^^^^^^ help: remove it entirely error: aborting due to 2 previous errors