@@ -4,10 +4,10 @@ use def_id::LOCAL_CRATE;
4
4
use rustc_data_structures:: fx:: FxHashSet ;
5
5
use rustc_errors:: Applicability ;
6
6
use rustc_hir:: def:: Res ;
7
- use rustc_hir:: { Item , ItemKind , def_id} ;
7
+ use rustc_hir:: { Attribute , Item , ItemKind , UsePath , def_id} ;
8
8
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
9
9
use rustc_session:: impl_lint_pass;
10
- use rustc_span:: { BytePos , FileName , RealFileName , Symbol } ;
10
+ use rustc_span:: { BytePos , FileName , RealFileName , Span , Symbol } ;
11
11
12
12
declare_clippy_lint ! {
13
13
/// ### What it does
@@ -53,94 +53,121 @@ declare_clippy_lint! {
53
53
54
54
#[ derive( Clone , Default ) ]
55
55
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 > ,
58
62
}
59
63
60
64
impl_lint_pass ! ( UseCratePrefixForSelfImports <' _, ' _> => [ USE_CRATE_PREFIX_FOR_SELF_IMPORTS ] ) ;
61
65
62
66
impl < ' a , ' tcx > LateLintPass < ' tcx > for UseCratePrefixForSelfImports < ' a , ' tcx > {
63
67
fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' a Item < ' tcx > ) {
64
68
let FileName :: Real ( RealFileName :: LocalPath ( p) ) = cx. sess ( ) . source_map ( ) . span_to_filename ( item. span ) else {
65
- self . use_block . clear ( ) ;
69
+ self . clear ( ) ;
66
70
return ;
67
71
} ;
68
72
let Some ( file_name) = p. file_name ( ) else {
69
- self . use_block . clear ( ) ;
73
+ self . clear ( ) ;
70
74
return ;
71
75
} ;
72
76
// only check `main.rs` and `lib.rs`
73
77
if !( file_name == "main.rs" || file_name == "lib.rs" ) {
74
78
return ;
75
79
}
76
80
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) ;
80
87
}
88
+ }
81
89
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 ) ;
84
106
} else {
85
107
self . deal ( cx) ;
86
- self . use_block . clear ( ) ;
87
- self . use_block . push ( item ) ;
108
+ self . clear ( ) ;
109
+ self . spans . push ( attribute . span ) ;
88
110
}
89
111
}
90
112
}
91
113
92
114
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 ( ) {
95
117
return true ;
96
118
}
97
- if self . use_block . iter ( ) . any ( |x| x. span . contains ( item . span ) ) {
119
+ if self . spans . iter ( ) . any ( |x| x. contains ( span) ) {
98
120
return true ;
99
121
}
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 ) ) {
105
123
return true ;
106
124
}
107
125
false
108
126
}
109
127
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
+ }
119
141
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)
125
153
{
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
+ ) ;
142
163
}
143
164
}
144
165
}
145
166
}
167
+
168
+ fn clear ( & mut self ) {
169
+ self . use_block . clear ( ) ;
170
+ self . mod_names . clear ( ) ;
171
+ self . spans . clear ( ) ;
172
+ }
146
173
}
0 commit comments