Skip to content

Commit 9e1dbdc

Browse files
committed
wip
1 parent 75c6fb1 commit 9e1dbdc

File tree

1 file changed

+78
-51
lines changed

1 file changed

+78
-51
lines changed

clippy_lints/src/use_crate_prefix_for_self_imports.rs

+78-51
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use def_id::LOCAL_CRATE;
44
use rustc_data_structures::fx::FxHashSet;
55
use rustc_errors::Applicability;
66
use rustc_hir::def::Res;
7-
use rustc_hir::{Item, ItemKind, def_id};
7+
use rustc_hir::{Attribute, Item, ItemKind, UsePath, def_id};
88
use rustc_lint::{LateContext, LateLintPass, LintContext};
99
use rustc_session::impl_lint_pass;
10-
use rustc_span::{BytePos, FileName, RealFileName, Symbol};
10+
use rustc_span::{BytePos, FileName, RealFileName, Span, Symbol};
1111

1212
declare_clippy_lint! {
1313
/// ### What it does
@@ -53,94 +53,121 @@ declare_clippy_lint! {
5353

5454
#[derive(Clone, Default)]
5555
pub struct UseCratePrefixForSelfImports<'a, 'tcx> {
56-
/// code block of `use <foo>` or `mod <foo>`
57-
use_block: Vec<&'a Item<'tcx>>,
56+
/// collect `use` in current block
57+
use_block: Vec<&'a UsePath<'tcx>>,
58+
/// collect `mod` in current block
59+
mod_names: FxHashSet<Symbol>,
60+
/// spans of `mod`, `use`, and attributes
61+
spans: Vec<Span>,
5862
}
5963

6064
impl_lint_pass!(UseCratePrefixForSelfImports<'_, '_> => [USE_CRATE_PREFIX_FOR_SELF_IMPORTS]);
6165

6266
impl<'a, 'tcx> LateLintPass<'tcx> for UseCratePrefixForSelfImports<'a, 'tcx> {
6367
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'a Item<'tcx>) {
6468
let FileName::Real(RealFileName::LocalPath(p)) = cx.sess().source_map().span_to_filename(item.span) else {
65-
self.use_block.clear();
69+
self.clear();
6670
return;
6771
};
6872
let Some(file_name) = p.file_name() else {
69-
self.use_block.clear();
73+
self.clear();
7074
return;
7175
};
7276
// only check `main.rs` and `lib.rs`
7377
if !(file_name == "main.rs" || file_name == "lib.rs") {
7478
return;
7579
}
7680

77-
match item.kind {
78-
ItemKind::Mod(_) | ItemKind::Use(_, _) => {},
79-
_ => return,
81+
if self.in_same_block(item.span) {
82+
self.insert_item(item);
83+
} else {
84+
self.deal(cx);
85+
self.clear();
86+
self.insert_item(item);
8087
}
88+
}
8189

82-
if self.in_same_block(item) {
83-
self.use_block.push(item);
90+
fn check_attribute(&mut self, cx: &LateContext<'tcx>, attribute: &'a Attribute) {
91+
let FileName::Real(RealFileName::LocalPath(p)) = cx.sess().source_map().span_to_filename(attribute.span) else {
92+
self.clear();
93+
return;
94+
};
95+
let Some(file_name) = p.file_name() else {
96+
self.clear();
97+
return;
98+
};
99+
// only check `main.rs` and `lib.rs`
100+
if !(file_name == "main.rs" || file_name == "lib.rs") {
101+
return;
102+
}
103+
104+
if self.in_same_block(attribute.span) {
105+
self.spans.push(attribute.span);
84106
} else {
85107
self.deal(cx);
86-
self.use_block.clear();
87-
self.use_block.push(item);
108+
self.clear();
109+
self.spans.push(attribute.span);
88110
}
89111
}
90112
}
91113

92114
impl<'tcx> UseCratePrefixForSelfImports<'_, 'tcx> {
93-
fn in_same_block(&self, item: &Item<'tcx>) -> bool {
94-
if self.use_block.is_empty() {
115+
fn in_same_block(&self, span: Span) -> bool {
116+
if self.spans.is_empty() {
95117
return true;
96118
}
97-
if self.use_block.iter().any(|x| x.span.contains(item.span)) {
119+
if self.spans.iter().any(|x| x.contains(span)) {
98120
return true;
99121
}
100-
if self
101-
.use_block
102-
.iter()
103-
.any(|x| item.span.lo() - x.span.hi() == BytePos(1))
104-
{
122+
if self.spans.iter().any(|x| span.lo() - x.hi() == BytePos(1)) {
105123
return true;
106124
}
107125
false
108126
}
109127

110-
fn deal(&self, cx: &LateContext<'tcx>) {
111-
let mod_names: FxHashSet<Symbol> = self
112-
.use_block
113-
.iter()
114-
.filter_map(|item| match item.kind {
115-
ItemKind::Mod(_) => Some(item.ident.name),
116-
_ => None,
117-
})
118-
.collect();
128+
fn insert_item(&mut self, item: &Item<'tcx>) {
129+
match item.kind {
130+
ItemKind::Mod(_) => {
131+
self.spans.push(item.span);
132+
self.mod_names.insert(item.ident.name);
133+
},
134+
ItemKind::Use(use_tree, _) => {
135+
self.spans.push(item.span);
136+
self.use_block.push(use_tree);
137+
},
138+
_ => {},
139+
}
140+
}
119141

120-
for item in &self.use_block {
121-
if let ItemKind::Use(use_path, _) = &item.kind {
122-
if let Some(segment) = use_path.segments.first()
123-
&& let Res::Def(_, def_id) = segment.res
124-
&& def_id.krate == LOCAL_CRATE
142+
fn deal(&self, cx: &LateContext<'tcx>) {
143+
for use_path in &self.use_block {
144+
if let Some(segment) = use_path.segments.first()
145+
&& let Res::Def(_, def_id) = segment.res
146+
&& def_id.krate == LOCAL_CRATE
147+
{
148+
let root = segment.ident.name;
149+
if root != rustc_span::symbol::kw::Crate
150+
&& root != rustc_span::symbol::kw::Super
151+
&& root != rustc_span::symbol::kw::SelfLower
152+
&& !self.mod_names.contains(&root)
125153
{
126-
let root = segment.ident.name;
127-
if root != rustc_span::symbol::kw::Crate
128-
&& root != rustc_span::symbol::kw::Super
129-
&& root != rustc_span::symbol::kw::SelfLower
130-
&& !mod_names.contains(&root)
131-
{
132-
span_lint_and_sugg(
133-
cx,
134-
USE_CRATE_PREFIX_FOR_SELF_IMPORTS,
135-
segment.ident.span,
136-
"this import is not clear",
137-
"prefix with `crate::`",
138-
format!("crate::{}", snippet_opt(cx, segment.ident.span).unwrap()),
139-
Applicability::MachineApplicable,
140-
);
141-
}
154+
span_lint_and_sugg(
155+
cx,
156+
USE_CRATE_PREFIX_FOR_SELF_IMPORTS,
157+
segment.ident.span,
158+
"this import is not clear",
159+
"prefix with `crate::`",
160+
format!("crate::{}", snippet_opt(cx, segment.ident.span).unwrap()),
161+
Applicability::MachineApplicable,
162+
);
142163
}
143164
}
144165
}
145166
}
167+
168+
fn clear(&mut self) {
169+
self.use_block.clear();
170+
self.mod_names.clear();
171+
self.spans.clear();
172+
}
146173
}

0 commit comments

Comments
 (0)