Skip to content

Commit 840f04d

Browse files
committed
wip
1 parent 75c6fb1 commit 840f04d

File tree

1 file changed

+76
-50
lines changed

1 file changed

+76
-50
lines changed

clippy_lints/src/use_crate_prefix_for_self_imports.rs

Lines changed: 76 additions & 50 deletions
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
@@ -54,93 +54,119 @@ declare_clippy_lint! {
5454
#[derive(Clone, Default)]
5555
pub struct UseCratePrefixForSelfImports<'a, 'tcx> {
5656
/// code block of `use <foo>` or `mod <foo>`
57-
use_block: Vec<&'a Item<'tcx>>,
57+
use_block: Vec<&'a UsePath<'tcx>>,
58+
mod_names: FxHashSet<Symbol>,
59+
/// spans of `mod`, `use`, and attributes
60+
spans: Vec<Span>,
5861
}
5962

6063
impl_lint_pass!(UseCratePrefixForSelfImports<'_, '_> => [USE_CRATE_PREFIX_FOR_SELF_IMPORTS]);
6164

6265
impl<'a, 'tcx> LateLintPass<'tcx> for UseCratePrefixForSelfImports<'a, 'tcx> {
6366
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'a Item<'tcx>) {
6467
let FileName::Real(RealFileName::LocalPath(p)) = cx.sess().source_map().span_to_filename(item.span) else {
65-
self.use_block.clear();
68+
self.clear();
6669
return;
6770
};
6871
let Some(file_name) = p.file_name() else {
69-
self.use_block.clear();
72+
self.clear();
7073
return;
7174
};
7275
// only check `main.rs` and `lib.rs`
7376
if !(file_name == "main.rs" || file_name == "lib.rs") {
7477
return;
7578
}
7679

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

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

92113
impl<'tcx> UseCratePrefixForSelfImports<'_, 'tcx> {
93-
fn in_same_block(&self, item: &Item<'tcx>) -> bool {
94-
if self.use_block.is_empty() {
114+
fn in_same_block(&self, span: Span) -> bool {
115+
if self.spans.is_empty() {
95116
return true;
96117
}
97-
if self.use_block.iter().any(|x| x.span.contains(item.span)) {
118+
if self.spans.iter().any(|x| x.contains(span)) {
98119
return true;
99120
}
100-
if self
101-
.use_block
102-
.iter()
103-
.any(|x| item.span.lo() - x.span.hi() == BytePos(1))
104-
{
121+
if self.spans.iter().any(|x| span.lo() - x.hi() == BytePos(1)) {
105122
return true;
106123
}
107124
false
108125
}
109126

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();
127+
fn insert_item(&mut self, item: &Item<'tcx>) {
128+
match item.kind {
129+
ItemKind::Mod(_) => {
130+
self.spans.push(item.span);
131+
self.mod_names.insert(item.ident.name);
132+
},
133+
ItemKind::Use(use_tree, _) => {
134+
self.spans.push(item.span);
135+
self.use_block.push(use_tree);
136+
},
137+
_ => {},
138+
}
139+
}
119140

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
141+
fn deal(&self, cx: &LateContext<'tcx>) {
142+
for use_path in &self.use_block {
143+
if let Some(segment) = use_path.segments.first()
144+
&& let Res::Def(_, def_id) = segment.res
145+
&& def_id.krate == LOCAL_CRATE
146+
{
147+
let root = segment.ident.name;
148+
if root != rustc_span::symbol::kw::Crate
149+
&& root != rustc_span::symbol::kw::Super
150+
&& root != rustc_span::symbol::kw::SelfLower
151+
&& !self.mod_names.contains(&root)
125152
{
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-
}
153+
span_lint_and_sugg(
154+
cx,
155+
USE_CRATE_PREFIX_FOR_SELF_IMPORTS,
156+
segment.ident.span,
157+
"this import is not clear",
158+
"prefix with `crate::`",
159+
format!("crate::{}", snippet_opt(cx, segment.ident.span).unwrap()),
160+
Applicability::MachineApplicable,
161+
);
142162
}
143163
}
144164
}
145165
}
166+
167+
fn clear(&mut self) {
168+
self.use_block.clear();
169+
self.mod_names.clear();
170+
self.spans.clear();
171+
}
146172
}

0 commit comments

Comments
 (0)