1
- use std:: hash:: { Hash , Hasher } ;
2
1
use clippy_utils:: diagnostics:: { span_lint_and_sugg, span_lint_hir_and_then} ;
3
2
use clippy_utils:: is_from_proc_macro;
4
3
use rustc_ast:: Attribute ;
5
4
use rustc_data_structures:: fx:: FxIndexSet ;
6
5
use rustc_errors:: Applicability ;
7
6
use rustc_hir:: def:: Res ;
8
7
use rustc_hir:: def_id:: DefId ;
9
- use rustc_hir:: { Arm , Block , Body , Expr , FieldDef , FnDecl , ForeignItem , GenericParam , Generics , HirId , ImplItem , Item , ItemKind , Local , Mod , Pat , Path , PathSegment , PolyTraitRef , Stmt , TraitItem , Ty , UseKind , Variant , VariantData } ;
10
8
use rustc_hir:: intravisit:: FnKind ;
9
+ use rustc_hir:: {
10
+ Arm , Block , Body , Expr , FieldDef , FnDecl , ForeignItem , GenericParam , Generics , HirId , ImplItem , Item , ItemKind ,
11
+ Local , Mod , Pat , Path , PathSegment , PolyTraitRef , Stmt , TraitItem , Ty , UseKind , Variant , VariantData ,
12
+ } ;
11
13
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
12
14
use rustc_middle:: lint:: in_external_macro;
13
15
use rustc_session:: impl_lint_pass;
16
+ use rustc_span:: def_id:: LocalDefId ;
14
17
use rustc_span:: symbol:: kw;
15
18
use rustc_span:: { sym, Span } ;
16
- use rustc_span :: def_id :: LocalDefId ;
19
+ use std :: hash :: { Hash , Hasher } ;
17
20
18
21
declare_clippy_lint ! {
19
22
/// ### What it does
@@ -98,15 +101,21 @@ pub struct StdReexports {
98
101
// twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
99
102
// when the path could be also be used to access the module.
100
103
prev_span : Span ,
101
- open_use : Option < OpenUseSpan >
104
+ // When inside of a UseKind::ListStem the previous check
105
+ // isn't enough to ensure correct parsing
106
+ open_use : Option < OpenUseSpan > ,
102
107
}
103
108
104
109
impl_lint_pass ! ( StdReexports => [ STD_INSTEAD_OF_CORE , STD_INSTEAD_OF_ALLOC , ALLOC_INSTEAD_OF_CORE ] ) ;
105
110
111
+ /// Save all members of a UseKind::ListStem `use std::fmt::{Debug, Result};`
112
+ /// Lint when the ListStem closes. However, since there's no look-ahead (that I know of).
113
+ /// Close whenever something is encountered that's outside of the container `Span`.
106
114
#[ derive( Debug ) ]
107
115
struct OpenUseSpan {
108
116
container : Span ,
109
- members : FxIndexSet < UseSpanMember >
117
+ // Preserve insert order on iteration, so that lints come out in 'source order'
118
+ members : FxIndexSet < UseSpanMember > ,
110
119
}
111
120
112
121
#[ derive( Debug , Copy , Clone ) ]
@@ -152,37 +161,51 @@ impl StdReexports {
152
161
self . open_use = Some ( collected_use) ;
153
162
return ;
154
163
}
164
+ // Short circuit
155
165
if collected_use. members . is_empty ( ) {
156
166
return ;
157
167
}
158
168
let mut place_holder_unique_check: Option < ( Span , ReplaceLintData ) > = None ;
159
- let mut can_chunk = true ;
169
+ // If true after checking all members, the lint is 'fixable'.
170
+ // Otherwise, just warn
171
+ let mut all_same_valid_lint = true ;
160
172
for member in collected_use. members . iter ( ) {
161
173
match & member. lint_data {
162
174
LintData :: CanReplace ( lint_data) => {
163
175
if let Some ( ( _span, prev_lint_data) ) = place_holder_unique_check. take ( ) {
164
- if prev_lint_data. lint . name == lint_data. lint . name && prev_lint_data. used_mod == lint_data. used_mod && prev_lint_data. replace_with == lint_data. replace_with {
176
+ if prev_lint_data. lint . name == lint_data. lint . name
177
+ && prev_lint_data. used_mod == lint_data. used_mod
178
+ && prev_lint_data. replace_with == lint_data. replace_with
179
+ {
165
180
place_holder_unique_check = Some ( ( member. first_seg_ident_span , * lint_data) ) ;
166
181
} else {
167
182
// Will have to warn for individual entries
168
- can_chunk = false ;
183
+ all_same_valid_lint = false ;
169
184
break ;
170
185
}
171
186
} else {
172
187
place_holder_unique_check = Some ( ( member. first_seg_ident_span , * lint_data) ) ;
173
188
}
174
- }
189
+ } ,
175
190
LintData :: NoReplace => {
176
191
// Will have to warn for individual entries
177
- can_chunk = false ;
192
+ all_same_valid_lint = false ;
178
193
break ;
179
- }
194
+ } ,
180
195
}
181
196
}
182
197
// If they can all be replaced with the same thing, just lint and suggest, then
183
198
// clippy-fix works as well
184
- if can_chunk {
185
- if let Some ( ( first_segment_ident_span, ReplaceLintData { lint, used_mod, replace_with } ) ) = place_holder_unique_check {
199
+ if all_same_valid_lint {
200
+ if let Some ( (
201
+ first_segment_ident_span,
202
+ ReplaceLintData {
203
+ lint,
204
+ used_mod,
205
+ replace_with,
206
+ } ,
207
+ ) ) = place_holder_unique_check
208
+ {
186
209
span_lint_and_sugg (
187
210
cx,
188
211
lint,
@@ -195,10 +218,23 @@ impl StdReexports {
195
218
}
196
219
} else {
197
220
for member in collected_use. members {
198
- if let LintData :: CanReplace ( ReplaceLintData { lint, used_mod, replace_with } ) = member. lint_data {
199
- span_lint_hir_and_then ( cx, lint, member. hir_id , member. inner , & format ! ( "used import from `{used_mod}` instead of `{replace_with}`" ) , |diag| {
200
- diag. help ( format ! ( "consider importing the item from `{replace_with}`" ) ) ;
201
- } )
221
+ if let LintData :: CanReplace ( ReplaceLintData {
222
+ lint,
223
+ used_mod,
224
+ replace_with,
225
+ } ) = member. lint_data
226
+ {
227
+ // Just lint, don't suggest a change
228
+ span_lint_hir_and_then (
229
+ cx,
230
+ lint,
231
+ member. hir_id ,
232
+ member. inner ,
233
+ & format ! ( "used import from `{used_mod}` instead of `{replace_with}`" ) ,
234
+ |diag| {
235
+ diag. help ( format ! ( "consider importing the item from `{replace_with}`" ) ) ;
236
+ } ,
237
+ )
202
238
}
203
239
}
204
240
}
@@ -217,12 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
217
253
{
218
254
let lint_data = match first_segment. ident . name {
219
255
sym:: std => match cx. tcx . crate_name ( def_id. krate ) {
220
- sym:: core => LintData :: CanReplace ( ReplaceLintData {
256
+ sym:: core => LintData :: CanReplace ( ReplaceLintData {
221
257
lint : STD_INSTEAD_OF_CORE ,
222
258
used_mod : "std" ,
223
259
replace_with : "core" ,
224
260
} ) ,
225
- sym:: alloc => LintData :: CanReplace ( ReplaceLintData {
261
+ sym:: alloc => LintData :: CanReplace ( ReplaceLintData {
226
262
lint : STD_INSTEAD_OF_ALLOC ,
227
263
used_mod : "std" ,
228
264
replace_with : "alloc" ,
@@ -234,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
234
270
} ,
235
271
sym:: alloc => {
236
272
if cx. tcx . crate_name ( def_id. krate ) == sym:: core {
237
- LintData :: CanReplace ( ReplaceLintData {
273
+ LintData :: CanReplace ( ReplaceLintData {
238
274
lint : ALLOC_INSTEAD_OF_CORE ,
239
275
used_mod : "alloc" ,
240
276
replace_with : "core" ,
@@ -255,7 +291,12 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
255
291
} ) ;
256
292
return ;
257
293
}
258
- if let LintData :: CanReplace ( ReplaceLintData { lint, used_mod, replace_with } ) = lint_data {
294
+ if let LintData :: CanReplace ( ReplaceLintData {
295
+ lint,
296
+ used_mod,
297
+ replace_with,
298
+ } ) = lint_data
299
+ {
259
300
if first_segment. ident . span != self . prev_span {
260
301
span_lint_and_sugg (
261
302
cx,
@@ -280,7 +321,6 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
280
321
members : FxIndexSet :: default ( ) ,
281
322
} )
282
323
}
283
-
284
324
}
285
325
286
326
// Essentially, check every other parsable thing's start (except for attributes),
@@ -358,7 +398,15 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
358
398
}
359
399
360
400
#[ inline]
361
- fn check_fn ( & mut self , cx : & LateContext < ' tcx > , _: FnKind < ' tcx > , _: & ' tcx FnDecl < ' tcx > , _: & ' tcx Body < ' tcx > , s : Span , _: LocalDefId ) {
401
+ fn check_fn (
402
+ & mut self ,
403
+ cx : & LateContext < ' tcx > ,
404
+ _: FnKind < ' tcx > ,
405
+ _: & ' tcx FnDecl < ' tcx > ,
406
+ _: & ' tcx Body < ' tcx > ,
407
+ s : Span ,
408
+ _: LocalDefId ,
409
+ ) {
362
410
self . suggest_for_open_use_item_if_after ( cx, s) ;
363
411
}
364
412
0 commit comments