@@ -4,10 +4,10 @@ use def_id::LOCAL_CRATE;
44use rustc_data_structures:: fx:: FxHashSet ;
55use rustc_errors:: Applicability ;
66use rustc_hir:: def:: Res ;
7- use rustc_hir:: { Item , ItemKind , def_id} ;
7+ use rustc_hir:: { Attribute , Item , ItemKind , UsePath , def_id} ;
88use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
99use rustc_session:: impl_lint_pass;
10- use rustc_span:: { BytePos , FileName , RealFileName , Symbol } ;
10+ use rustc_span:: { BytePos , FileName , RealFileName , Span , Symbol } ;
1111
1212declare_clippy_lint ! {
1313 /// ### What it does
@@ -54,93 +54,119 @@ declare_clippy_lint! {
5454#[ derive( Clone , Default ) ]
5555pub 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
6063impl_lint_pass ! ( UseCratePrefixForSelfImports <' _, ' _> => [ USE_CRATE_PREFIX_FOR_SELF_IMPORTS ] ) ;
6164
6265impl < ' 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
92113impl < ' 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