1 use clippy_utils
::diagnostics
::{span_lint_and_help, span_lint_and_sugg}
;
2 use rustc_ast
::node_id
::{NodeId, NodeMap}
;
3 use rustc_ast
::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind}
;
4 use rustc_errors
::Applicability
;
5 use rustc_lint
::{EarlyContext, EarlyLintPass, LintContext}
;
6 use rustc_session
::{declare_tool_lint, impl_lint_pass}
;
7 use rustc_span
::{edition::Edition, symbol::kw, Span, Symbol}
;
11 /// Checking for imports with single component use path.
13 /// ### Why is this bad?
14 /// Import with single component use path such as `use cratename;`
15 /// is not necessary, and thus should be removed.
22 /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
28 /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
31 #[clippy::version = "1.43.0"]
32 pub SINGLE_COMPONENT_PATH_IMPORTS
,
34 "imports with single component path are redundant"
38 pub struct SingleComponentPathImports
{
39 /// Buffer found usages to emit when visiting that item so that `#[allow]` works as expected
40 found
: NodeMap
<Vec
<SingleUse
>>,
50 impl_lint_pass
!(SingleComponentPathImports
=> [SINGLE_COMPONENT_PATH_IMPORTS
]);
52 impl EarlyLintPass
for SingleComponentPathImports
{
53 fn check_crate(&mut self, cx
: &EarlyContext
<'_
>, krate
: &Crate
) {
54 if cx
.sess().opts
.edition
< Edition
::Edition2018
{
58 self.check_mod(cx
, &krate
.items
);
61 fn check_item(&mut self, cx
: &EarlyContext
<'_
>, item
: &Item
) {
62 for SingleUse { span, can_suggest, .. }
in self.found
.remove(&item
.id
).into_iter().flatten() {
66 SINGLE_COMPONENT_PATH_IMPORTS
,
68 "this import is redundant",
71 Applicability
::MachineApplicable
,
76 SINGLE_COMPONENT_PATH_IMPORTS
,
78 "this import is redundant",
87 impl SingleComponentPathImports
{
88 fn check_mod(&mut self, cx
: &EarlyContext
<'_
>, items
: &[P
<Item
>]) {
89 // keep track of imports reused with `self` keyword, such as `self::crypto_hash` in the example
90 // below. Removing the `use crypto_hash;` would make this a compile error
94 // use self::crypto_hash::{Algorithm, Hasher};
96 let mut imports_reused_with_self
= Vec
::new();
98 // keep track of single use statements such as `crypto_hash` in the example below
102 let mut single_use_usages
= Vec
::new();
104 // keep track of macros defined in the module as we don't want it to trigger on this (#7106)
106 // macro_rules! foo { () => {} };
107 // pub(crate) use foo;
109 let mut macros
= Vec
::new();
115 &mut imports_reused_with_self
,
116 &mut single_use_usages
,
121 for usage
in single_use_usages
{
122 if !imports_reused_with_self
.contains(&usage
.name
) {
123 self.found
.entry(usage
.item_id
).or_default().push(usage
);
130 cx
: &EarlyContext
<'_
>,
132 imports_reused_with_self
: &mut Vec
<Symbol
>,
133 single_use_usages
: &mut Vec
<SingleUse
>,
134 macros
: &mut Vec
<Symbol
>,
136 if item
.span
.from_expansion() || item
.vis
.kind
.is_pub() {
141 ItemKind
::Mod(_
, ModKind
::Loaded(ref items
, ..)) => {
142 self.check_mod(cx
, items
);
144 ItemKind
::MacroDef(MacroDef { macro_rules: true, .. }
) => {
145 macros
.push(item
.ident
.name
);
147 ItemKind
::Use(use_tree
) => {
148 let segments
= &use_tree
.prefix
.segments
;
150 // keep track of `use some_module;` usages
151 if segments
.len() == 1 {
152 if let UseTreeKind
::Simple(None
) = use_tree
.kind
{
153 let name
= segments
[0].ident
.name
;
154 if !macros
.contains(&name
) {
155 single_use_usages
.push(SingleUse
{
166 if segments
.is_empty() {
167 // keep track of `use {some_module, some_other_module};` usages
168 if let UseTreeKind
::Nested(trees
) = &use_tree
.kind
{
170 let segments
= &tree
.0.prefix
.segments
;
171 if segments
.len() == 1 {
172 if let UseTreeKind
::Simple(None
) = tree
.0.kind
{
173 let name
= segments
[0].ident
.name
;
174 if !macros
.contains(&name
) {
175 single_use_usages
.push(SingleUse
{
187 // keep track of `use self::some_module` usages
188 if segments
[0].ident
.name
== kw
::SelfLower
{
189 // simple case such as `use self::module::SomeStruct`
190 if segments
.len() > 1 {
191 imports_reused_with_self
.push(segments
[1].ident
.name
);
195 // nested case such as `use self::{module1::Struct1, module2::Struct2}`
196 if let UseTreeKind
::Nested(trees
) = &use_tree
.kind
{
198 let segments
= &tree
.0.prefix
.segments
;
199 if !segments
.is_empty() {
200 imports_reused_with_self
.push(segments
[0].ident
.name
);