|
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