|
1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg;
|
2 | 2 | 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}; |
4 | 4 | use rustc_errors::Applicability;
|
5 | 5 | 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}; |
10 | 8 |
|
11 | 9 | declare_clippy_lint! {
|
12 | 10 | /// **What it does:** Checking for imports with single component use path.
|
@@ -36,94 +34,96 @@ declare_clippy_lint! {
|
36 | 34 | "imports with single component path are redundant"
|
37 | 35 | }
|
38 | 36 |
|
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]); |
58 | 38 |
|
59 | 39 | impl EarlyLintPass for SingleComponentPathImports {
|
60 | 40 | fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
|
61 | 41 | if cx.sess.opts.edition < Edition::Edition2018 {
|
62 | 42 | return;
|
63 | 43 | }
|
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); |
80 | 45 | }
|
81 | 46 | }
|
82 | 47 |
|
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 | + ); |
87 | 78 | }
|
| 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; |
88 | 98 |
|
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)); |
93 | 104 | }
|
94 |
| - }, |
95 |
| - ItemKind::Use(use_tree) => { |
96 |
| - let segments = &use_tree.prefix.segments; |
| 105 | + return; |
| 106 | + } |
97 | 107 |
|
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); |
104 | 113 | return;
|
105 | 114 | }
|
106 | 115 |
|
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); |
122 | 122 | }
|
123 | 123 | }
|
124 | 124 | }
|
125 |
| - }, |
126 |
| - _ => {}, |
127 |
| - } |
| 125 | + } |
| 126 | + }, |
| 127 | + _ => {}, |
128 | 128 | }
|
129 | 129 | }
|
0 commit comments