@@ -2,7 +2,7 @@ use crate::utils::{in_macro, snippet, span_lint_and_sugg};
2
2
use hir:: def:: { DefKind , Res } ;
3
3
use if_chain:: if_chain;
4
4
use rustc_ast:: ast;
5
- use rustc_data_structures:: fx:: FxHashMap ;
5
+ use rustc_data_structures:: fx:: FxHashSet ;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir as hir;
8
8
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
@@ -29,7 +29,7 @@ declare_clippy_lint! {
29
29
30
30
const BRACKETS : & [ char ] = & [ '<' , '>' ] ;
31
31
32
- /// MacroRefData includes the name of the macro
32
+ /// ` MacroRefData` includes the name of the macro
33
33
/// and the path from `SourceMap::span_to_filename`.
34
34
#[ derive( Debug , Clone ) ]
35
35
pub struct MacroRefData {
@@ -38,11 +38,11 @@ pub struct MacroRefData {
38
38
}
39
39
40
40
impl MacroRefData {
41
- pub fn new ( name : String , span : Span , ecx : & LateContext < ' _ , ' _ > ) -> Self {
41
+ pub fn new ( name : & str , span : Span , ecx : & LateContext < ' _ , ' _ > ) -> Self {
42
42
let mut path = ecx. sess ( ) . source_map ( ) . span_to_filename ( span) . to_string ( ) ;
43
43
44
44
// std lib paths are <::std::module::file type>
45
- // so remove brackets and space
45
+ // so remove brackets, space and type.
46
46
if path. contains ( '<' ) {
47
47
path = path. replace ( BRACKETS , "" ) ;
48
48
}
@@ -57,13 +57,12 @@ impl MacroRefData {
57
57
}
58
58
59
59
#[ derive( Default ) ]
60
+ #[ allow( clippy:: module_name_repetitions) ]
60
61
pub struct MacroUseImports {
61
62
/// the actual import path used and the span of the attribute above it.
62
63
imports : Vec < ( String , Span ) > ,
63
- /// the span of the macro reference and the `MacroRefData`
64
- /// for the use of the macro.
65
- /// TODO make this FxHashSet<Span> to guard against inserting already found macros
66
- collected : FxHashMap < Span , MacroRefData > ,
64
+ /// the span of the macro reference, kept to ensure only one reference is used per macro call.
65
+ collected : FxHashSet < Span > ,
67
66
mac_refs : Vec < ( Span , MacroRefData ) > ,
68
67
}
69
68
@@ -72,34 +71,28 @@ impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
72
71
impl < ' l , ' txc > LateLintPass < ' l , ' txc > for MacroUseImports {
73
72
fn check_item ( & mut self , lcx : & LateContext < ' _ , ' _ > , item : & hir:: Item < ' _ > ) {
74
73
if_chain ! {
75
- if lcx. sess( ) . opts. edition == Edition :: Edition2018 ;
76
- if let hir:: ItemKind :: Use ( path, _kind) = & item. kind;
77
- if let Some ( mac_attr) = item
78
- . attrs
79
- . iter( )
80
- . find( |attr| attr. ident( ) . map( |s| s. to_string( ) ) == Some ( "macro_use" . to_string( ) ) ) ;
81
- if let Res :: Def ( DefKind :: Mod , id) = path. res;
82
- then {
83
- // println!("{:#?}", lcx.tcx.def_path_str(id));
84
- for kid in lcx. tcx. item_children( id) . iter( ) {
85
- // println!("{:#?}", kid);
86
- if let Res :: Def ( DefKind :: Macro ( _mac_type) , mac_id) = kid. res {
87
- let span = mac_attr. span. clone( ) ;
88
-
89
- // println!("{:#?}", lcx.tcx.def_path_str(mac_id));
90
-
91
- self . imports. push( ( lcx. tcx. def_path_str( mac_id) , span) ) ;
74
+ if lcx. sess( ) . opts. edition == Edition :: Edition2018 ;
75
+ if let hir:: ItemKind :: Use ( path, _kind) = & item. kind;
76
+ if let Some ( mac_attr) = item
77
+ . attrs
78
+ . iter( )
79
+ . find( |attr| attr. ident( ) . map( |s| s. to_string( ) ) == Some ( "macro_use" . to_string( ) ) ) ;
80
+ if let Res :: Def ( DefKind :: Mod , id) = path. res;
81
+ then {
82
+ for kid in lcx. tcx. item_children( id) . iter( ) {
83
+ if let Res :: Def ( DefKind :: Macro ( _mac_type) , mac_id) = kid. res {
84
+ let span = mac_attr. span;
85
+ self . imports. push( ( lcx. tcx. def_path_str( mac_id) , span) ) ;
86
+ }
92
87
}
93
- }
94
- } else {
88
+ } else {
95
89
if in_macro( item. span) {
96
90
let call_site = item. span. source_callsite( ) ;
97
91
let name = snippet( lcx, lcx. sess( ) . source_map( ) . span_until_char( call_site, '!' ) , "_" ) ;
98
92
if let Some ( callee) = item. span. source_callee( ) {
99
- if !self . collected. contains_key( & call_site) {
100
- let mac = MacroRefData :: new( name. to_string( ) , callee. def_site, lcx) ;
101
- self . mac_refs. push( ( call_site, mac. clone( ) ) ) ;
102
- self . collected. insert( call_site, mac) ;
93
+ if !self . collected. contains( & call_site) {
94
+ self . mac_refs. push( ( call_site, MacroRefData :: new( & name, callee. def_site, lcx) ) ) ;
95
+ self . collected. insert( call_site) ;
103
96
}
104
97
}
105
98
}
@@ -111,18 +104,16 @@ impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
111
104
let call_site = attr. span . source_callsite ( ) ;
112
105
let name = snippet ( lcx, lcx. sess ( ) . source_map ( ) . span_until_char ( call_site, '!' ) , "_" ) ;
113
106
if let Some ( callee) = attr. span . source_callee ( ) {
114
- if !self . collected . contains_key ( & call_site) {
115
- println ! ( "{:?}\n {:#?}" , call_site, attr) ;
116
-
107
+ if !self . collected . contains ( & call_site) {
117
108
let name = if name. contains ( "::" ) {
118
109
name. split ( "::" ) . last ( ) . unwrap ( ) . to_string ( )
119
110
} else {
120
111
name. to_string ( )
121
112
} ;
122
113
123
- let mac = MacroRefData :: new ( name , callee . def_site , lcx ) ;
124
- self . mac_refs . push ( ( call_site, mac . clone ( ) ) ) ;
125
- self . collected . insert ( call_site, mac ) ;
114
+ self . mac_refs
115
+ . push ( ( call_site, MacroRefData :: new ( & name , callee . def_site , lcx ) ) ) ;
116
+ self . collected . insert ( call_site) ;
126
117
}
127
118
}
128
119
}
@@ -132,16 +123,16 @@ impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
132
123
let call_site = expr. span . source_callsite ( ) ;
133
124
let name = snippet ( lcx, lcx. sess ( ) . source_map ( ) . span_until_char ( call_site, '!' ) , "_" ) ;
134
125
if let Some ( callee) = expr. span . source_callee ( ) {
135
- if !self . collected . contains_key ( & call_site) {
126
+ if !self . collected . contains ( & call_site) {
136
127
let name = if name. contains ( "::" ) {
137
128
name. split ( "::" ) . last ( ) . unwrap ( ) . to_string ( )
138
129
} else {
139
130
name. to_string ( )
140
131
} ;
141
132
142
- let mac = MacroRefData :: new ( name , callee . def_site , lcx ) ;
143
- self . mac_refs . push ( ( call_site, mac . clone ( ) ) ) ;
144
- self . collected . insert ( call_site, mac ) ;
133
+ self . mac_refs
134
+ . push ( ( call_site, MacroRefData :: new ( & name , callee . def_site , lcx ) ) ) ;
135
+ self . collected . insert ( call_site) ;
145
136
}
146
137
}
147
138
}
@@ -151,16 +142,16 @@ impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
151
142
let call_site = stmt. span . source_callsite ( ) ;
152
143
let name = snippet ( lcx, lcx. sess ( ) . source_map ( ) . span_until_char ( call_site, '!' ) , "_" ) ;
153
144
if let Some ( callee) = stmt. span . source_callee ( ) {
154
- if !self . collected . contains_key ( & call_site) {
145
+ if !self . collected . contains ( & call_site) {
155
146
let name = if name. contains ( "::" ) {
156
147
name. split ( "::" ) . last ( ) . unwrap ( ) . to_string ( )
157
148
} else {
158
149
name. to_string ( )
159
150
} ;
160
151
161
- let mac = MacroRefData :: new ( name , callee . def_site , lcx ) ;
162
- self . mac_refs . push ( ( call_site, mac . clone ( ) ) ) ;
163
- self . collected . insert ( call_site, mac ) ;
152
+ self . mac_refs
153
+ . push ( ( call_site, MacroRefData :: new ( & name , callee . def_site , lcx ) ) ) ;
154
+ self . collected . insert ( call_site) ;
164
155
}
165
156
}
166
157
}
@@ -170,10 +161,10 @@ impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
170
161
let call_site = pat. span . source_callsite ( ) ;
171
162
let name = snippet ( lcx, lcx. sess ( ) . source_map ( ) . span_until_char ( call_site, '!' ) , "_" ) ;
172
163
if let Some ( callee) = pat. span . source_callee ( ) {
173
- if !self . collected . contains_key ( & call_site) {
174
- let mac = MacroRefData :: new ( name . to_string ( ) , callee . def_site , lcx ) ;
175
- self . mac_refs . push ( ( call_site, mac . clone ( ) ) ) ;
176
- self . collected . insert ( call_site, mac ) ;
164
+ if !self . collected . contains ( & call_site) {
165
+ self . mac_refs
166
+ . push ( ( call_site, MacroRefData :: new ( & name , callee . def_site , lcx ) ) ) ;
167
+ self . collected . insert ( call_site) ;
177
168
}
178
169
}
179
170
}
@@ -183,22 +174,18 @@ impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
183
174
let call_site = ty. span . source_callsite ( ) ;
184
175
let name = snippet ( lcx, lcx. sess ( ) . source_map ( ) . span_until_char ( call_site, '!' ) , "_" ) ;
185
176
if let Some ( callee) = ty. span . source_callee ( ) {
186
- if !self . collected . contains_key ( & call_site) {
187
- let mac = MacroRefData :: new ( name . to_string ( ) , callee . def_site , lcx ) ;
188
- self . mac_refs . push ( ( call_site, mac . clone ( ) ) ) ;
189
- self . collected . insert ( call_site, mac ) ;
177
+ if !self . collected . contains ( & call_site) {
178
+ self . mac_refs
179
+ . push ( ( call_site, MacroRefData :: new ( & name , callee . def_site , lcx ) ) ) ;
180
+ self . collected . insert ( call_site) ;
190
181
}
191
182
}
192
183
}
193
184
}
194
185
195
186
fn check_crate_post ( & mut self , lcx : & LateContext < ' _ , ' _ > , _krate : & hir:: Crate < ' _ > ) {
196
- for ( import, span) in self . imports . iter ( ) {
197
- let matched = self
198
- . mac_refs
199
- . iter ( )
200
- . find ( |( _span, mac) | import. ends_with ( & mac. name ) )
201
- . is_some ( ) ;
187
+ for ( import, span) in & self . imports {
188
+ let matched = self . mac_refs . iter ( ) . any ( |( _span, mac) | import. ends_with ( & mac. name ) ) ;
202
189
203
190
if matched {
204
191
self . mac_refs . retain ( |( _span, mac) | !import. ends_with ( & mac. name ) ) ;
@@ -218,30 +205,8 @@ impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
218
205
if !self . mac_refs . is_empty ( ) {
219
206
// TODO if not empty we found one we could not make a suggestion for
220
207
// such as std::prelude::v1 or something else I haven't thought of.
221
- // println!("{:#?}", self.mac_refs);
208
+ // If we defer the calling of span_lint_and_sugg we can make a decision about its
209
+ // applicability?
222
210
}
223
211
}
224
212
}
225
-
226
- const PRELUDE : & [ & str ] = & [
227
- "marker" , "ops" , "convert" , "iter" , "option" , "result" , "borrow" , "boxed" , "string" , "vec" , "macros" ,
228
- ] ;
229
-
230
- /// This is somewhat of a fallback for imports from `std::prelude` because they
231
- /// are not recognized by `LateLintPass::check_item` `lcx.tcx.item_children(id)`
232
- fn make_path ( mac : & MacroRefData , use_path : & str ) -> String {
233
- let segs = mac. path . split ( "::" ) . filter ( |s| * s != "" ) . collect :: < Vec < _ > > ( ) ;
234
-
235
- if segs. starts_with ( & [ "std" ] ) && PRELUDE . iter ( ) . any ( |m| segs. contains ( m) ) {
236
- return format ! (
237
- "std::prelude::{} is imported by default, remove `use` statement" ,
238
- mac. name
239
- ) ;
240
- }
241
-
242
- if use_path. split ( "::" ) . count ( ) == 1 {
243
- return format ! ( "{}::{}" , use_path, mac. name) ;
244
- }
245
-
246
- mac. path . clone ( )
247
- }
0 commit comments