]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 XL |
1 | use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; |
2 | use clippy_utils::in_macro; | |
3 | use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind}; | |
f20569fa XL |
4 | use rustc_errors::Applicability; |
5 | use rustc_lint::{EarlyContext, EarlyLintPass}; | |
6 | use rustc_session::{declare_lint_pass, declare_tool_lint}; | |
cdc7bbd5 | 7 | use rustc_span::{edition::Edition, symbol::kw, Span, Symbol}; |
f20569fa XL |
8 | |
9 | declare_clippy_lint! { | |
94222f64 XL |
10 | /// ### What it does |
11 | /// Checking for imports with single component use path. | |
f20569fa | 12 | /// |
94222f64 XL |
13 | /// ### Why is this bad? |
14 | /// Import with single component use path such as `use cratename;` | |
f20569fa XL |
15 | /// is not necessary, and thus should be removed. |
16 | /// | |
94222f64 | 17 | /// ### Example |
f20569fa XL |
18 | /// ```rust,ignore |
19 | /// use regex; | |
20 | /// | |
21 | /// fn main() { | |
22 | /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); | |
23 | /// } | |
24 | /// ``` | |
25 | /// Better as | |
26 | /// ```rust,ignore | |
27 | /// fn main() { | |
28 | /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); | |
29 | /// } | |
30 | /// ``` | |
31 | pub SINGLE_COMPONENT_PATH_IMPORTS, | |
32 | style, | |
33 | "imports with single component path are redundant" | |
34 | } | |
35 | ||
36 | declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]); | |
37 | ||
38 | impl EarlyLintPass for SingleComponentPathImports { | |
cdc7bbd5 XL |
39 | fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { |
40 | if cx.sess.opts.edition < Edition::Edition2018 { | |
41 | return; | |
42 | } | |
43 | check_mod(cx, &krate.items); | |
44 | } | |
45 | } | |
46 | ||
47 | fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) { | |
48 | // keep track of imports reused with `self` keyword, | |
49 | // such as `self::crypto_hash` in the example below | |
50 | // ```rust,ignore | |
51 | // use self::crypto_hash::{Algorithm, Hasher}; | |
52 | // ``` | |
53 | let mut imports_reused_with_self = Vec::new(); | |
54 | ||
55 | // keep track of single use statements | |
56 | // such as `crypto_hash` in the example below | |
57 | // ```rust,ignore | |
58 | // use crypto_hash; | |
59 | // ``` | |
60 | let mut single_use_usages = Vec::new(); | |
61 | ||
62 | // keep track of macros defined in the module as we don't want it to trigger on this (#7106) | |
63 | // ```rust,ignore | |
64 | // macro_rules! foo { () => {} }; | |
65 | // pub(crate) use foo; | |
66 | // ``` | |
67 | let mut macros = Vec::new(); | |
68 | ||
69 | for item in items { | |
70 | track_uses( | |
71 | cx, | |
17df50a5 | 72 | item, |
cdc7bbd5 XL |
73 | &mut imports_reused_with_self, |
74 | &mut single_use_usages, | |
75 | &mut macros, | |
76 | ); | |
77 | } | |
78 | ||
79 | for single_use in &single_use_usages { | |
80 | if !imports_reused_with_self.contains(&single_use.0) { | |
81 | let can_suggest = single_use.2; | |
82 | if can_suggest { | |
f20569fa XL |
83 | span_lint_and_sugg( |
84 | cx, | |
85 | SINGLE_COMPONENT_PATH_IMPORTS, | |
cdc7bbd5 | 86 | single_use.1, |
f20569fa XL |
87 | "this import is redundant", |
88 | "remove it entirely", | |
89 | String::new(), | |
cdc7bbd5 XL |
90 | Applicability::MachineApplicable, |
91 | ); | |
92 | } else { | |
93 | span_lint_and_help( | |
94 | cx, | |
95 | SINGLE_COMPONENT_PATH_IMPORTS, | |
96 | single_use.1, | |
97 | "this import is redundant", | |
98 | None, | |
99 | "remove this import", | |
f20569fa XL |
100 | ); |
101 | } | |
102 | } | |
103 | } | |
104 | } | |
cdc7bbd5 XL |
105 | |
106 | fn track_uses( | |
107 | cx: &EarlyContext<'_>, | |
108 | item: &Item, | |
109 | imports_reused_with_self: &mut Vec<Symbol>, | |
110 | single_use_usages: &mut Vec<(Symbol, Span, bool)>, | |
111 | macros: &mut Vec<Symbol>, | |
112 | ) { | |
113 | if in_macro(item.span) || item.vis.kind.is_pub() { | |
114 | return; | |
115 | } | |
116 | ||
117 | match &item.kind { | |
118 | ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { | |
17df50a5 | 119 | check_mod(cx, items); |
cdc7bbd5 XL |
120 | }, |
121 | ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => { | |
122 | macros.push(item.ident.name); | |
123 | }, | |
124 | ItemKind::Use(use_tree) => { | |
125 | let segments = &use_tree.prefix.segments; | |
126 | ||
127 | let should_report = | |
128 | |name: &Symbol| !macros.contains(name) || matches!(item.vis.kind, VisibilityKind::Inherited); | |
129 | ||
130 | // keep track of `use some_module;` usages | |
131 | if segments.len() == 1 { | |
132 | if let UseTreeKind::Simple(None, _, _) = use_tree.kind { | |
133 | let name = segments[0].ident.name; | |
134 | if should_report(&name) { | |
135 | single_use_usages.push((name, item.span, true)); | |
136 | } | |
137 | } | |
138 | return; | |
139 | } | |
140 | ||
141 | if segments.is_empty() { | |
142 | // keep track of `use {some_module, some_other_module};` usages | |
143 | if let UseTreeKind::Nested(trees) = &use_tree.kind { | |
144 | for tree in trees { | |
145 | let segments = &tree.0.prefix.segments; | |
146 | if segments.len() == 1 { | |
147 | if let UseTreeKind::Simple(None, _, _) = tree.0.kind { | |
148 | let name = segments[0].ident.name; | |
149 | if should_report(&name) { | |
150 | single_use_usages.push((name, tree.0.span, false)); | |
151 | } | |
152 | } | |
153 | } | |
154 | } | |
155 | } | |
156 | } else { | |
157 | // keep track of `use self::some_module` usages | |
158 | if segments[0].ident.name == kw::SelfLower { | |
159 | // simple case such as `use self::module::SomeStruct` | |
160 | if segments.len() > 1 { | |
161 | imports_reused_with_self.push(segments[1].ident.name); | |
162 | return; | |
163 | } | |
164 | ||
165 | // nested case such as `use self::{module1::Struct1, module2::Struct2}` | |
166 | if let UseTreeKind::Nested(trees) = &use_tree.kind { | |
167 | for tree in trees { | |
168 | let segments = &tree.0.prefix.segments; | |
169 | if !segments.is_empty() { | |
170 | imports_reused_with_self.push(segments[0].ident.name); | |
171 | } | |
172 | } | |
173 | } | |
174 | } | |
175 | } | |
176 | }, | |
177 | _ => {}, | |
178 | } | |
179 | } |