Skip to content

Commit be2dde4

Browse files
committed
Backwards compat
1 parent 2ece8ea commit be2dde4

File tree

1 file changed

+192
-17
lines changed

1 file changed

+192
-17
lines changed

clippy_lints/src/std_instead_of_core.rs

Lines changed: 192 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
use std::hash::{Hash, Hasher};
2-
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
33
use clippy_utils::is_from_proc_macro;
4+
use rustc_ast::Attribute;
45
use rustc_data_structures::fx::FxIndexSet;
56
use rustc_errors::Applicability;
67
use rustc_hir::def::Res;
78
use rustc_hir::def_id::DefId;
8-
use rustc_hir::{HirId, Item, ItemKind, Path, PathSegment, UseKind};
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+
use rustc_hir::intravisit::FnKind;
911
use rustc_lint::{LateContext, LateLintPass, LintContext};
1012
use rustc_middle::lint::in_external_macro;
1113
use rustc_session::impl_lint_pass;
1214
use rustc_span::symbol::kw;
1315
use rustc_span::{sym, Span};
16+
use rustc_span::def_id::LocalDefId;
1417

1518
declare_clippy_lint! {
1619
/// ### What it does
@@ -109,6 +112,8 @@ struct OpenUseSpan {
109112
#[derive(Debug, Copy, Clone)]
110113
struct UseSpanMember {
111114
inner: Span,
115+
hir_id: HirId,
116+
first_seg_ident_span: Span,
112117
lint_data: LintData,
113118
}
114119

@@ -128,16 +133,79 @@ impl Hash for UseSpanMember {
128133

129134
#[derive(Debug, Copy, Clone)]
130135
enum LintData {
131-
CanReplace {
132-
lint: &'static crate::Lint,
133-
used_mod: &'static str,
134-
replace_with: &'static str,
135-
},
136+
CanReplace(ReplaceLintData),
136137
NoReplace,
137138
}
138139

140+
#[derive(Debug, Copy, Clone)]
141+
struct ReplaceLintData {
142+
lint: &'static crate::Lint,
143+
used_mod: &'static str,
144+
replace_with: &'static str,
145+
}
146+
147+
impl StdReexports {
148+
fn suggest_for_open_use_item_if_after<'tcx>(&mut self, cx: &LateContext<'tcx>, span: Span) {
149+
if let Some(collected_use) = self.open_use.take() {
150+
// Still contains other span, throw it back
151+
if collected_use.container.contains(span) {
152+
self.open_use = Some(collected_use);
153+
return;
154+
}
155+
let mut place_holder_unique_check: Option<(Span, ReplaceLintData)> = None;
156+
let mut can_chunk = true;
157+
for member in collected_use.members.iter() {
158+
match &member.lint_data {
159+
LintData::CanReplace(lint_data) => {
160+
if let Some((_span, prev_lint_data)) = place_holder_unique_check.take() {
161+
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 {
162+
place_holder_unique_check = Some((member.first_seg_ident_span, *lint_data));
163+
} else {
164+
// Will have to warn for individual entries
165+
can_chunk = false;
166+
break;
167+
}
168+
} else {
169+
place_holder_unique_check = Some((member.first_seg_ident_span, *lint_data));
170+
}
171+
}
172+
LintData::NoReplace => {
173+
// Will have to warn for individual entries
174+
can_chunk = false;
175+
break;
176+
}
177+
}
178+
}
179+
// If they can all be replaced with the same thing, just lint and suggest, then
180+
// clippy-fix works as well
181+
if can_chunk {
182+
if let Some((first_segment_ident_span, ReplaceLintData { lint, used_mod, replace_with })) = place_holder_unique_check {
183+
span_lint_and_sugg(
184+
cx,
185+
lint,
186+
first_segment_ident_span,
187+
&format!("used import from `{used_mod}` instead of `{replace_with}`"),
188+
&format!("consider importing the item from `{replace_with}`"),
189+
replace_with.to_string(),
190+
Applicability::MachineApplicable,
191+
);
192+
}
193+
} else {
194+
for member in collected_use.members {
195+
if let LintData::CanReplace(ReplaceLintData { lint, used_mod, replace_with }) = member.lint_data {
196+
span_lint_hir_and_then(cx, lint, member.hir_id, member.inner, &format!("used import from `{used_mod}` instead of `{replace_with}`"), |diag| {
197+
diag.help(format!("consider importing the item from `{replace_with}`"));
198+
})
199+
}
200+
}
201+
}
202+
}
203+
}
204+
}
205+
139206
impl<'tcx> LateLintPass<'tcx> for StdReexports {
140-
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
207+
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, hir_id: HirId) {
208+
self.suggest_for_open_use_item_if_after(cx, path.span);
141209
if let Res::Def(_, def_id) = path.res
142210
&& let Some(first_segment) = get_first_segment(path)
143211
&& is_stable(cx, def_id)
@@ -146,28 +214,28 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
146214
{
147215
let lint_data = match first_segment.ident.name {
148216
sym::std => match cx.tcx.crate_name(def_id.krate) {
149-
sym::core => LintData::CanReplace {
217+
sym::core => LintData::CanReplace(ReplaceLintData{
150218
lint: STD_INSTEAD_OF_CORE,
151219
used_mod: "std",
152220
replace_with: "core",
153-
},
154-
sym::alloc => LintData::CanReplace {
221+
}),
222+
sym::alloc => LintData::CanReplace(ReplaceLintData{
155223
lint: STD_INSTEAD_OF_ALLOC,
156224
used_mod: "std",
157225
replace_with: "alloc",
158-
},
226+
}),
159227
_ => {
160228
self.prev_span = first_segment.ident.span;
161229
LintData::NoReplace
162230
},
163231
},
164232
sym::alloc => {
165233
if cx.tcx.crate_name(def_id.krate) == sym::core {
166-
LintData::CanReplace {
234+
LintData::CanReplace(ReplaceLintData{
167235
lint: ALLOC_INSTEAD_OF_CORE,
168236
used_mod: "alloc",
169237
replace_with: "core",
170-
}
238+
})
171239
} else {
172240
self.prev_span = first_segment.ident.span;
173241
LintData::NoReplace
@@ -178,11 +246,13 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
178246
if let Some(in_use) = self.open_use.as_mut() {
179247
in_use.members.insert(UseSpanMember {
180248
inner: path.span,
249+
hir_id,
250+
first_seg_ident_span: first_segment.ident.span,
181251
lint_data,
182252
});
183253
return;
184254
}
185-
if let LintData::CanReplace { lint, used_mod, replace_with } = lint_data {
255+
if let LintData::CanReplace(ReplaceLintData { lint, used_mod, replace_with }) = lint_data {
186256
if first_segment.ident.span != self.prev_span {
187257
span_lint_and_sugg(
188258
cx,
@@ -200,6 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
200270
}
201271

202272
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
273+
self.suggest_for_open_use_item_if_after(cx, item.span);
203274
if matches!(item.kind, ItemKind::Use(_, UseKind::ListStem)) {
204275
self.open_use = Some(OpenUseSpan {
205276
container: item.span,
@@ -209,10 +280,114 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
209280

210281
}
211282

283+
#[inline]
212284
fn check_item_post(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
213-
if let Some(collected_use) = self.open_use.take() {
285+
self.suggest_for_open_use_item_if_after(cx, item.span);
286+
}
214287

215-
}
288+
#[inline]
289+
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
290+
self.suggest_for_open_use_item_if_after(cx, body.value.span);
291+
}
292+
293+
#[inline]
294+
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
295+
self.suggest_for_open_use_item_if_after(cx, Span::default());
296+
}
297+
298+
#[inline]
299+
fn check_mod(&mut self, cx: &LateContext<'tcx>, _: &'tcx Mod<'tcx>, _: HirId) {
300+
self.suggest_for_open_use_item_if_after(cx, Span::default());
301+
}
302+
303+
#[inline]
304+
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, f_item: &'tcx ForeignItem<'tcx>) {
305+
self.suggest_for_open_use_item_if_after(cx, f_item.span);
306+
}
307+
308+
#[inline]
309+
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
310+
self.suggest_for_open_use_item_if_after(cx, local.span);
311+
}
312+
313+
#[inline]
314+
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
315+
self.suggest_for_open_use_item_if_after(cx, block.span);
316+
}
317+
318+
#[inline]
319+
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
320+
self.suggest_for_open_use_item_if_after(cx, stmt.span);
321+
}
322+
323+
#[inline]
324+
fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx Arm<'tcx>) {
325+
self.suggest_for_open_use_item_if_after(cx, arm.span);
326+
}
327+
328+
#[inline]
329+
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'tcx>) {
330+
self.suggest_for_open_use_item_if_after(cx, pat.span);
331+
}
332+
333+
#[inline]
334+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
335+
self.suggest_for_open_use_item_if_after(cx, expr.span);
336+
}
337+
338+
#[inline]
339+
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
340+
self.suggest_for_open_use_item_if_after(cx, ty.span);
341+
}
342+
343+
#[inline]
344+
fn check_generic_param(&mut self, cx: &LateContext<'tcx>, gp: &'tcx GenericParam<'tcx>) {
345+
self.suggest_for_open_use_item_if_after(cx, gp.span);
346+
}
347+
348+
#[inline]
349+
fn check_generics(&mut self, cx: &LateContext<'tcx>, g: &'tcx Generics<'tcx>) {
350+
self.suggest_for_open_use_item_if_after(cx, g.span);
351+
}
352+
353+
#[inline]
354+
fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, ptr: &'tcx PolyTraitRef<'tcx>) {
355+
self.suggest_for_open_use_item_if_after(cx, ptr.span);
356+
}
357+
358+
#[inline]
359+
fn check_fn(&mut self, cx: &LateContext<'tcx>, _: FnKind<'tcx>, _: &'tcx FnDecl<'tcx>, _: &'tcx Body<'tcx>, s: Span, _: LocalDefId) {
360+
self.suggest_for_open_use_item_if_after(cx, s);
361+
}
362+
363+
#[inline]
364+
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, ti: &'tcx TraitItem<'tcx>) {
365+
self.suggest_for_open_use_item_if_after(cx, ti.span);
366+
}
367+
368+
#[inline]
369+
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, imp: &'tcx ImplItem<'tcx>) {
370+
self.suggest_for_open_use_item_if_after(cx, imp.span);
371+
}
372+
373+
#[inline]
374+
fn check_struct_def(&mut self, cx: &LateContext<'tcx>, _: &'tcx VariantData<'tcx>) {
375+
self.suggest_for_open_use_item_if_after(cx, Span::default());
376+
}
377+
378+
#[inline]
379+
fn check_field_def(&mut self, cx: &LateContext<'tcx>, fd: &'tcx FieldDef<'tcx>) {
380+
self.suggest_for_open_use_item_if_after(cx, fd.span);
381+
}
382+
383+
#[inline]
384+
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx Variant<'tcx>) {
385+
self.suggest_for_open_use_item_if_after(cx, v.span);
386+
}
387+
388+
#[inline]
389+
fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
390+
self.suggest_for_open_use_item_if_after(cx, attr.span);
216391
}
217392
}
218393

0 commit comments

Comments
 (0)