1
- use clippy_utils:: diagnostics:: span_lint_and_sugg ;
1
+ use clippy_utils:: diagnostics:: span_lint_hir_and_then ;
2
2
use clippy_utils:: source:: snippet;
3
3
use hir:: def:: { DefKind , Res } ;
4
4
use if_chain:: if_chain;
@@ -51,8 +51,9 @@ impl MacroRefData {
51
51
#[ derive( Default ) ]
52
52
#[ expect( clippy:: module_name_repetitions) ]
53
53
pub struct MacroUseImports {
54
- /// the actual import path used and the span of the attribute above it.
55
- imports : Vec < ( String , Span ) > ,
54
+ /// the actual import path used and the span of the attribute above it. The value is
55
+ /// the location, where the lint should be emitted.
56
+ imports : Vec < ( String , Span , hir:: HirId ) > ,
56
57
/// the span of the macro reference, kept to ensure only one reference is used per macro call.
57
58
collected : FxHashSet < Span > ,
58
59
mac_refs : Vec < MacroRefData > ,
@@ -91,7 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
91
92
if_chain ! {
92
93
if cx. sess( ) . opts. edition >= Edition :: Edition2018 ;
93
94
if let hir:: ItemKind :: Use ( path, _kind) = & item. kind;
94
- let attrs = cx. tcx. hir( ) . attrs( item. hir_id( ) ) ;
95
+ let hir_id = item. hir_id( ) ;
96
+ let attrs = cx. tcx. hir( ) . attrs( hir_id) ;
95
97
if let Some ( mac_attr) = attrs. iter( ) . find( |attr| attr. has_name( sym:: macro_use) ) ;
96
98
if let Res :: Def ( DefKind :: Mod , id) = path. res;
97
99
if !id. is_local( ) ;
@@ -100,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
100
102
if let Res :: Def ( DefKind :: Macro ( _mac_type) , mac_id) = kid. res {
101
103
let span = mac_attr. span;
102
104
let def_path = cx. tcx. def_path_str( mac_id) ;
103
- self . imports. push( ( def_path, span) ) ;
105
+ self . imports. push( ( def_path, span, hir_id ) ) ;
104
106
}
105
107
}
106
108
} else {
@@ -138,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
138
140
fn check_crate_post ( & mut self , cx : & LateContext < ' _ > ) {
139
141
let mut used = FxHashMap :: default ( ) ;
140
142
let mut check_dup = vec ! [ ] ;
141
- for ( import, span) in & self . imports {
143
+ for ( import, span, hir_id ) in & self . imports {
142
144
let found_idx = self . mac_refs . iter ( ) . position ( |mac| import. ends_with ( & mac. name ) ) ;
143
145
144
146
if let Some ( idx) = found_idx {
@@ -151,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
151
153
[ ] | [ _] => return ,
152
154
[ root, item] => {
153
155
if !check_dup. contains ( & ( * item) . to_string ( ) ) {
154
- used. entry ( ( ( * root) . to_string ( ) , span) )
156
+ used. entry ( ( ( * root) . to_string ( ) , span, hir_id ) )
155
157
. or_insert_with ( Vec :: new)
156
158
. push ( ( * item) . to_string ( ) ) ;
157
159
check_dup. push ( ( * item) . to_string ( ) ) ;
@@ -169,13 +171,13 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
169
171
}
170
172
} )
171
173
. collect :: < Vec < _ > > ( ) ;
172
- used. entry ( ( ( * root) . to_string ( ) , span) )
174
+ used. entry ( ( ( * root) . to_string ( ) , span, hir_id ) )
173
175
. or_insert_with ( Vec :: new)
174
176
. push ( filtered. join ( "::" ) ) ;
175
177
check_dup. extend ( filtered) ;
176
178
} else {
177
179
let rest = rest. to_vec ( ) ;
178
- used. entry ( ( ( * root) . to_string ( ) , span) )
180
+ used. entry ( ( ( * root) . to_string ( ) , span, hir_id ) )
179
181
. or_insert_with ( Vec :: new)
180
182
. push ( rest. join ( "::" ) ) ;
181
183
check_dup. extend ( rest. iter ( ) . map ( ToString :: to_string) ) ;
@@ -186,27 +188,33 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
186
188
}
187
189
188
190
let mut suggestions = vec ! [ ] ;
189
- for ( ( root, span) , path) in used {
191
+ for ( ( root, span, hir_id ) , path) in used {
190
192
if path. len ( ) == 1 {
191
- suggestions. push ( ( span, format ! ( "{}::{}" , root, path[ 0 ] ) ) ) ;
193
+ suggestions. push ( ( span, format ! ( "{}::{}" , root, path[ 0 ] ) , hir_id ) ) ;
192
194
} else {
193
- suggestions. push ( ( span, format ! ( "{}::{{{}}}" , root, path. join( ", " ) ) ) ) ;
195
+ suggestions. push ( ( span, format ! ( "{}::{{{}}}" , root, path. join( ", " ) ) , hir_id ) ) ;
194
196
}
195
197
}
196
198
197
199
// If mac_refs is not empty we have encountered an import we could not handle
198
200
// such as `std::prelude::v1::foo` or some other macro that expands to an import.
199
201
if self . mac_refs . is_empty ( ) {
200
- for ( span, import) in suggestions {
202
+ for ( span, import, hir_id ) in suggestions {
201
203
let help = format ! ( "use {};" , import) ;
202
- span_lint_and_sugg (
204
+ span_lint_hir_and_then (
203
205
cx,
204
206
MACRO_USE_IMPORTS ,
207
+ * hir_id,
205
208
* span,
206
209
"`macro_use` attributes are no longer needed in the Rust 2018 edition" ,
207
- "remove the attribute and import the macro directly, try" ,
208
- help,
209
- Applicability :: MaybeIncorrect ,
210
+ |diag| {
211
+ diag. span_suggestion (
212
+ * span,
213
+ "remove the attribute and import the macro directly, try" ,
214
+ help,
215
+ Applicability :: MaybeIncorrect ,
216
+ ) ;
217
+ } ,
210
218
) ;
211
219
}
212
220
}
0 commit comments