Skip to content

Commit 81dfb9e

Browse files
committed
Check path imports per module
1 parent 6985d13 commit 81dfb9e

5 files changed

+96
-82
lines changed

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12321232
store.register_early_pass(|| box as_conversions::AsConversions);
12331233
store.register_late_pass(|| box let_underscore::LetUnderscore);
12341234
store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
1235-
store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports::default());
1235+
store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
12361236
let max_fn_params_bools = conf.max_fn_params_bools;
12371237
let max_struct_bools = conf.max_struct_bools;
12381238
store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
Lines changed: 75 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::in_macro;
3-
use rustc_ast::{Crate, Item, ItemKind, ModKind, UseTreeKind};
3+
use rustc_ast::{ptr::P, Crate, Item, ItemKind, ModKind, UseTreeKind};
44
use rustc_errors::Applicability;
55
use rustc_lint::{EarlyContext, EarlyLintPass};
6-
use rustc_session::{declare_tool_lint, impl_lint_pass};
7-
use rustc_span::edition::Edition;
8-
use rustc_span::symbol::kw;
9-
use rustc_span::{Span, Symbol};
6+
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
use rustc_span::{edition::Edition, symbol::kw, Span, Symbol};
108

119
declare_clippy_lint! {
1210
/// **What it does:** Checking for imports with single component use path.
@@ -36,94 +34,96 @@ declare_clippy_lint! {
3634
"imports with single component path are redundant"
3735
}
3836

39-
#[derive(Default)]
40-
pub struct SingleComponentPathImports {
41-
/// keep track of imports reused with `self` keyword,
42-
/// such as `self::crypto_hash` in the example below
43-
///
44-
/// ```rust,ignore
45-
/// use self::crypto_hash::{Algorithm, Hasher};
46-
/// ```
47-
imports_reused_with_self: Vec<Symbol>,
48-
/// keep track of single use statements
49-
/// such as `crypto_hash` in the example below
50-
///
51-
/// ```rust,ignore
52-
/// use crypto_hash;
53-
/// ```
54-
single_use_usages: Vec<(Symbol, Span)>,
55-
}
56-
57-
impl_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]);
37+
declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]);
5838

5939
impl EarlyLintPass for SingleComponentPathImports {
6040
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
6141
if cx.sess.opts.edition < Edition::Edition2018 {
6242
return;
6343
}
64-
for item in &krate.items {
65-
self.track_uses(&item);
66-
}
67-
for single_use in &self.single_use_usages {
68-
if !self.imports_reused_with_self.contains(&single_use.0) {
69-
span_lint_and_sugg(
70-
cx,
71-
SINGLE_COMPONENT_PATH_IMPORTS,
72-
single_use.1,
73-
"this import is redundant",
74-
"remove it entirely",
75-
String::new(),
76-
Applicability::MachineApplicable,
77-
);
78-
}
79-
}
44+
check_mod(cx, &krate.items);
8045
}
8146
}
8247

83-
impl SingleComponentPathImports {
84-
fn track_uses(&mut self, item: &Item) {
85-
if in_macro(item.span) || item.vis.kind.is_pub() {
86-
return;
48+
fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
49+
// keep track of imports reused with `self` keyword,
50+
// such as `self::crypto_hash` in the example below
51+
// ```rust,ignore
52+
// use self::crypto_hash::{Algorithm, Hasher};
53+
// ```
54+
let mut imports_reused_with_self = Vec::new();
55+
56+
// keep track of single use statements
57+
// such as `crypto_hash` in the example below
58+
// ```rust,ignore
59+
// use crypto_hash;
60+
// ```
61+
let mut single_use_usages = Vec::new();
62+
63+
for item in items {
64+
track_uses(cx, &item, &mut imports_reused_with_self, &mut single_use_usages);
65+
}
66+
67+
for single_use in &single_use_usages {
68+
if !imports_reused_with_self.contains(&single_use.0) {
69+
span_lint_and_sugg(
70+
cx,
71+
SINGLE_COMPONENT_PATH_IMPORTS,
72+
single_use.1,
73+
"this import is redundant",
74+
"remove it entirely",
75+
String::new(),
76+
Applicability::MachineApplicable,
77+
);
8778
}
79+
}
80+
}
81+
82+
fn track_uses(
83+
cx: &EarlyContext<'_>,
84+
item: &Item,
85+
imports_reused_with_self: &mut Vec<Symbol>,
86+
single_use_usages: &mut Vec<(Symbol, Span)>,
87+
) {
88+
if in_macro(item.span) || item.vis.kind.is_pub() {
89+
return;
90+
}
91+
92+
match &item.kind {
93+
ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
94+
check_mod(cx, &items);
95+
},
96+
ItemKind::Use(use_tree) => {
97+
let segments = &use_tree.prefix.segments;
8898

89-
match &item.kind {
90-
ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
91-
for item in items.iter() {
92-
self.track_uses(&item);
99+
// keep track of `use some_module;` usages
100+
if segments.len() == 1 {
101+
if let UseTreeKind::Simple(None, _, _) = use_tree.kind {
102+
let ident = &segments[0].ident;
103+
single_use_usages.push((ident.name, item.span));
93104
}
94-
},
95-
ItemKind::Use(use_tree) => {
96-
let segments = &use_tree.prefix.segments;
105+
return;
106+
}
97107

98-
// keep track of `use some_module;` usages
99-
if segments.len() == 1 {
100-
if let UseTreeKind::Simple(None, _, _) = use_tree.kind {
101-
let ident = &segments[0].ident;
102-
self.single_use_usages.push((ident.name, item.span));
103-
}
108+
// keep track of `use self::some_module` usages
109+
if segments[0].ident.name == kw::SelfLower {
110+
// simple case such as `use self::module::SomeStruct`
111+
if segments.len() > 1 {
112+
imports_reused_with_self.push(segments[1].ident.name);
104113
return;
105114
}
106115

107-
// keep track of `use self::some_module` usages
108-
if segments[0].ident.name == kw::SelfLower {
109-
// simple case such as `use self::module::SomeStruct`
110-
if segments.len() > 1 {
111-
self.imports_reused_with_self.push(segments[1].ident.name);
112-
return;
113-
}
114-
115-
// nested case such as `use self::{module1::Struct1, module2::Struct2}`
116-
if let UseTreeKind::Nested(trees) = &use_tree.kind {
117-
for tree in trees {
118-
let segments = &tree.0.prefix.segments;
119-
if !segments.is_empty() {
120-
self.imports_reused_with_self.push(segments[0].ident.name);
121-
}
116+
// nested case such as `use self::{module1::Struct1, module2::Struct2}`
117+
if let UseTreeKind::Nested(trees) = &use_tree.kind {
118+
for tree in trees {
119+
let segments = &tree.0.prefix.segments;
120+
if !segments.is_empty() {
121+
imports_reused_with_self.push(segments[0].ident.name);
122122
}
123123
}
124124
}
125-
},
126-
_ => {},
127-
}
125+
}
126+
},
127+
_ => {},
128128
}
129129
}

tests/ui/single_component_path_imports.fixed

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,10 @@ mod hello_mod {
2525
#[allow(dead_code)]
2626
fn hello_mod() {}
2727
}
28+
29+
mod hi_mod {
30+
use self::regex::{Regex, RegexSet};
31+
use regex;
32+
#[allow(dead_code)]
33+
fn hi_mod() {}
34+
}

tests/ui/single_component_path_imports.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,10 @@ mod hello_mod {
2525
#[allow(dead_code)]
2626
fn hello_mod() {}
2727
}
28+
29+
mod hi_mod {
30+
use self::regex::{Regex, RegexSet};
31+
use regex;
32+
#[allow(dead_code)]
33+
fn hi_mod() {}
34+
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
error: this import is redundant
2-
--> $DIR/single_component_path_imports.rs:6:1
2+
--> $DIR/single_component_path_imports.rs:24:5
33
|
4-
LL | use regex;
5-
| ^^^^^^^^^^ help: remove it entirely
4+
LL | use regex;
5+
| ^^^^^^^^^^ help: remove it entirely
66
|
77
= note: `-D clippy::single-component-path-imports` implied by `-D warnings`
88

99
error: this import is redundant
10-
--> $DIR/single_component_path_imports.rs:24:5
10+
--> $DIR/single_component_path_imports.rs:6:1
1111
|
12-
LL | use regex;
13-
| ^^^^^^^^^^ help: remove it entirely
12+
LL | use regex;
13+
| ^^^^^^^^^^ help: remove it entirely
1414

1515
error: aborting due to 2 previous errors
1616

0 commit comments

Comments
 (0)