1- use std:: hash:: { Hash , Hasher } ;
21use clippy_utils:: diagnostics:: { span_lint_and_sugg, span_lint_hir_and_then} ;
32use clippy_utils:: is_from_proc_macro;
43use rustc_ast:: Attribute ;
54use rustc_data_structures:: fx:: FxIndexSet ;
65use rustc_errors:: Applicability ;
76use rustc_hir:: def:: Res ;
87use 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 } ;
108use 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+ } ;
1113use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1214use rustc_middle:: lint:: in_external_macro;
1315use rustc_session:: impl_lint_pass;
16+ use rustc_span:: def_id:: LocalDefId ;
1417use rustc_span:: symbol:: kw;
1518use rustc_span:: { sym, Span } ;
16- use rustc_span :: def_id :: LocalDefId ;
19+ use std :: hash :: { Hash , Hasher } ;
1720
1821declare_clippy_lint ! {
1922 /// ### What it does
@@ -98,15 +101,21 @@ pub struct StdReexports {
98101 // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
99102 // when the path could be also be used to access the module.
100103 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 > ,
102107}
103108
104109impl_lint_pass ! ( StdReexports => [ STD_INSTEAD_OF_CORE , STD_INSTEAD_OF_ALLOC , ALLOC_INSTEAD_OF_CORE ] ) ;
105110
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`.
106114#[ derive( Debug ) ]
107115struct OpenUseSpan {
108116 container : Span ,
109- members : FxIndexSet < UseSpanMember >
117+ // Preserve insert order on iteration, so that lints come out in 'source order'
118+ members : FxIndexSet < UseSpanMember > ,
110119}
111120
112121#[ derive( Debug , Copy , Clone ) ]
@@ -152,37 +161,51 @@ impl StdReexports {
152161 self . open_use = Some ( collected_use) ;
153162 return ;
154163 }
164+ // Short circuit
155165 if collected_use. members . is_empty ( ) {
156166 return ;
157167 }
158168 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 ;
160172 for member in collected_use. members . iter ( ) {
161173 match & member. lint_data {
162174 LintData :: CanReplace ( lint_data) => {
163175 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+ {
165180 place_holder_unique_check = Some ( ( member. first_seg_ident_span , * lint_data) ) ;
166181 } else {
167182 // Will have to warn for individual entries
168- can_chunk = false ;
183+ all_same_valid_lint = false ;
169184 break ;
170185 }
171186 } else {
172187 place_holder_unique_check = Some ( ( member. first_seg_ident_span , * lint_data) ) ;
173188 }
174- }
189+ } ,
175190 LintData :: NoReplace => {
176191 // Will have to warn for individual entries
177- can_chunk = false ;
192+ all_same_valid_lint = false ;
178193 break ;
179- }
194+ } ,
180195 }
181196 }
182197 // If they can all be replaced with the same thing, just lint and suggest, then
183198 // 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+ {
186209 span_lint_and_sugg (
187210 cx,
188211 lint,
@@ -195,10 +218,23 @@ impl StdReexports {
195218 }
196219 } else {
197220 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+ )
202238 }
203239 }
204240 }
@@ -217,12 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
217253 {
218254 let lint_data = match first_segment. ident . name {
219255 sym:: std => match cx. tcx . crate_name ( def_id. krate ) {
220- sym:: core => LintData :: CanReplace ( ReplaceLintData {
256+ sym:: core => LintData :: CanReplace ( ReplaceLintData {
221257 lint : STD_INSTEAD_OF_CORE ,
222258 used_mod : "std" ,
223259 replace_with : "core" ,
224260 } ) ,
225- sym:: alloc => LintData :: CanReplace ( ReplaceLintData {
261+ sym:: alloc => LintData :: CanReplace ( ReplaceLintData {
226262 lint : STD_INSTEAD_OF_ALLOC ,
227263 used_mod : "std" ,
228264 replace_with : "alloc" ,
@@ -234,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
234270 } ,
235271 sym:: alloc => {
236272 if cx. tcx . crate_name ( def_id. krate ) == sym:: core {
237- LintData :: CanReplace ( ReplaceLintData {
273+ LintData :: CanReplace ( ReplaceLintData {
238274 lint : ALLOC_INSTEAD_OF_CORE ,
239275 used_mod : "alloc" ,
240276 replace_with : "core" ,
@@ -255,7 +291,12 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
255291 } ) ;
256292 return ;
257293 }
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+ {
259300 if first_segment. ident . span != self . prev_span {
260301 span_lint_and_sugg (
261302 cx,
@@ -280,7 +321,6 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
280321 members : FxIndexSet :: default ( ) ,
281322 } )
282323 }
283-
284324 }
285325
286326 // Essentially, check every other parsable thing's start (except for attributes),
@@ -358,7 +398,15 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
358398 }
359399
360400 #[ 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+ ) {
362410 self . suggest_for_open_use_item_if_after ( cx, s) ;
363411 }
364412
0 commit comments