From 566384e7cdffec8257eced9ef1319ced13e943e5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 14 Mar 2021 19:35:35 +0100 Subject: [PATCH] Fix FP in `single_component_path_imports` lint --- clippy_lints/src/lib.rs | 2 +- .../src/single_component_path_imports.rs | 47 ++++++++++++++++++- .../ui/single_component_path_imports_self.rs | 16 +++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 tests/ui/single_component_path_imports_self.rs diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 04e151df8e85..7021d0fdd6a5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1231,7 +1231,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 1fc4ff5c2e61..7facce258ef4 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -3,8 +3,9 @@ use if_chain::if_chain; use rustc_ast::{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; declare_clippy_lint! { /// **What it does:** Checking for imports with single component use path. @@ -34,10 +35,50 @@ declare_clippy_lint! { "imports with single component path are redundant" } -declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]); +#[derive(Default)] +pub struct SingleComponentPathImports { + /// detect imports reused with `self` keyword, + /// such as `self::crypto_hash` in the example below + /// + /// ```rust,ignore + /// use self::crypto_hash::{Algorithm, Hasher}; + /// use crypto_hash; + /// ``` + imports_as_use_self: Vec, +} + +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 let ItemKind::Use(use_tree) = &item.kind; + if let segments = &use_tree.prefix.segments; + if segments[0].ident.name == sym!(self); + + then { + // simple case such as `use self::module::SomeStruct` + if segments.len() > 1 { + self.imports_as_use_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_as_use_self.push(segments[0].ident.name); + } + } + } + } + } + } + + fn check_item_post(&mut self, cx: &EarlyContext<'_>, item: &Item) { if_chain! { if !in_macro(item.span); if cx.sess.opts.edition >= Edition::Edition2018; @@ -46,6 +87,8 @@ impl EarlyLintPass for SingleComponentPathImports { if let segments = &use_tree.prefix.segments; if segments.len() == 1; if let UseTreeKind::Simple(None, _, _) = use_tree.kind; + if !self.imports_as_use_self.contains(&segments[0].ident.name); + then { span_lint_and_sugg( cx, diff --git a/tests/ui/single_component_path_imports_self.rs b/tests/ui/single_component_path_imports_self.rs new file mode 100644 index 000000000000..94319ade0ac4 --- /dev/null +++ b/tests/ui/single_component_path_imports_self.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() {}