1
1
use clippy_config:: Conf ;
2
- use clippy_utils:: diagnostics:: span_lint_and_then ;
2
+ use clippy_utils:: diagnostics:: span_lint_and_sugg ;
3
3
use clippy_utils:: is_from_proc_macro;
4
4
use clippy_utils:: msrvs:: Msrv ;
5
5
use rustc_attr_data_structures:: { StabilityLevel , StableSince } ;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir:: def:: Res ;
8
8
use rustc_hir:: def_id:: DefId ;
9
- use rustc_hir:: { HirId , Path , PathSegment } ;
10
- use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
9
+ use rustc_hir:: { Block , Body , HirId , Path , PathSegment } ;
10
+ use rustc_lint:: { LateContext , LateLintPass , Lint , LintContext } ;
11
11
use rustc_session:: impl_lint_pass;
12
12
use rustc_span:: symbol:: kw;
13
13
use rustc_span:: { Span , sym} ;
@@ -88,24 +88,35 @@ declare_clippy_lint! {
88
88
}
89
89
90
90
pub struct StdReexports {
91
- // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen
92
- // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
93
- // when the path could be also be used to access the module.
94
- prev_span : Span ,
91
+ lint_point : ( Span , Option < LintPoint > ) ,
95
92
msrv : Msrv ,
96
93
}
97
94
98
95
impl StdReexports {
99
96
pub fn new ( conf : & ' static Conf ) -> Self {
100
97
Self {
101
- prev_span : Span :: default ( ) ,
98
+ lint_point : Default :: default ( ) ,
102
99
msrv : conf. msrv ,
103
100
}
104
101
}
102
+
103
+ fn lint_if_finish ( & mut self , cx : & LateContext < ' _ > , ( span, item) : ( Span , Option < LintPoint > ) ) {
104
+ if span. source_equal ( self . lint_point . 0 ) {
105
+ return ;
106
+ }
107
+
108
+ if !self . lint_point . 0 . is_dummy ( ) {
109
+ emit_lints ( cx, & self . lint_point ) ;
110
+ }
111
+
112
+ self . lint_point = ( span, item) ;
113
+ }
105
114
}
106
115
107
116
impl_lint_pass ! ( StdReexports => [ STD_INSTEAD_OF_CORE , STD_INSTEAD_OF_ALLOC , ALLOC_INSTEAD_OF_CORE ] ) ;
108
117
118
+ type LintPoint = ( & ' static Lint , & ' static str , & ' static str ) ;
119
+
109
120
impl < ' tcx > LateLintPass < ' tcx > for StdReexports {
110
121
fn check_path ( & mut self , cx : & LateContext < ' tcx > , path : & Path < ' tcx > , _: HirId ) {
111
122
if let Res :: Def ( _, def_id) = path. res
@@ -119,40 +130,52 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
119
130
sym:: core => ( STD_INSTEAD_OF_CORE , "std" , "core" ) ,
120
131
sym:: alloc => ( STD_INSTEAD_OF_ALLOC , "std" , "alloc" ) ,
121
132
_ => {
122
- self . prev_span = first_segment. ident . span ;
133
+ self . lint_if_finish ( cx , ( first_segment. ident . span , None ) ) ;
123
134
return ;
124
135
} ,
125
136
} ,
126
137
sym:: alloc => {
127
138
if cx. tcx . crate_name ( def_id. krate ) == sym:: core {
128
139
( ALLOC_INSTEAD_OF_CORE , "alloc" , "core" )
129
140
} else {
130
- self . prev_span = first_segment. ident . span ;
141
+ self . lint_if_finish ( cx , ( first_segment. ident . span , None ) ) ;
131
142
return ;
132
143
}
133
144
} ,
134
145
_ => return ,
135
146
} ;
136
- if first_segment. ident . span != self . prev_span {
137
- #[ expect( clippy:: collapsible_span_lint_calls, reason = "rust-clippy#7797" ) ]
138
- span_lint_and_then (
139
- cx,
140
- lint,
141
- first_segment. ident . span ,
142
- format ! ( "used import from `{used_mod}` instead of `{replace_with}`" ) ,
143
- |diag| {
144
- diag. span_suggestion (
145
- first_segment. ident . span ,
146
- format ! ( "consider importing the item from `{replace_with}`" ) ,
147
- replace_with. to_string ( ) ,
148
- Applicability :: MachineApplicable ,
149
- ) ;
150
- } ,
151
- ) ;
152
- self . prev_span = first_segment. ident . span ;
153
- }
147
+
148
+ self . lint_if_finish ( cx, ( first_segment. ident . span , Some ( ( lint, used_mod, replace_with) ) ) ) ;
154
149
}
155
150
}
151
+
152
+ fn check_block_post ( & mut self , cx : & LateContext < ' tcx > , _: & Block < ' tcx > ) {
153
+ self . lint_if_finish ( cx, Default :: default ( ) ) ;
154
+ }
155
+
156
+ fn check_body_post ( & mut self , cx : & LateContext < ' tcx > , _: & Body < ' tcx > ) {
157
+ self . lint_if_finish ( cx, Default :: default ( ) ) ;
158
+ }
159
+
160
+ fn check_crate_post ( & mut self , cx : & LateContext < ' tcx > ) {
161
+ self . lint_if_finish ( cx, Default :: default ( ) ) ;
162
+ }
163
+ }
164
+
165
+ fn emit_lints ( cx : & LateContext < ' _ > , ( span, item) : & ( Span , Option < LintPoint > ) ) {
166
+ let Some ( ( lint, used_mod, replace_with) ) = item else {
167
+ return ;
168
+ } ;
169
+
170
+ span_lint_and_sugg (
171
+ cx,
172
+ lint,
173
+ * span,
174
+ format ! ( "used import from `{used_mod}` instead of `{replace_with}`" ) ,
175
+ format ! ( "consider importing the item from `{replace_with}`" ) ,
176
+ ( * replace_with) . to_string ( ) ,
177
+ Applicability :: MachineApplicable ,
178
+ ) ;
156
179
}
157
180
158
181
/// Returns the first named segment of a [`Path`].
0 commit comments