Skip to content

Commit e34e2dc

Browse files
committed
fix:: [std_instead_of_core] should check extern crate prelude
If `alloc` or `core` aren't present in the prelude, then downgrade suggestions to helps to avoid suggesting broken fixes.
1 parent 5e134b4 commit e34e2dc

6 files changed

Lines changed: 163 additions & 1 deletion

clippy_lints/src/std_instead_of_core.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
33
use clippy_utils::is_from_proc_macro;
44
use clippy_utils::msrvs::Msrv;
55
use clippy_utils::paths::{PathNS, lookup_path};
6+
use rustc_data_structures::fx::FxHashSet;
67
use rustc_errors::{Applicability, MultiSpan};
8+
use rustc_hir::attrs::AttributeKind;
79
use rustc_hir::def::{DefKind, Namespace, Res};
810
use rustc_hir::def_id::DefId;
9-
use rustc_hir::{Block, Body, HirId, Path, PathSegment, StabilityLevel, StableSince};
11+
use rustc_hir::{Attribute, Block, Body, HirId, Item, ItemKind, Node, Path, PathSegment, StabilityLevel, StableSince};
1012
use rustc_lint::{LateContext, LateLintPass, LintContext};
1113
use rustc_session::impl_lint_pass;
1214
use rustc_span::symbol::kw;
@@ -255,7 +257,18 @@ fn emit_lints(cx: &LateContext<'_>, lint_points: Option<(Span, Vec<LintPoint>)>)
255257
}
256258
}
257259

260+
let extern_prelude = extern_prelude(cx);
261+
258262
for (lint, used_mod, replace_with) in suggestions {
263+
// If the target crate isn't in the extern crate prelude,
264+
// the suggestion is likely to fail.
265+
// It's possible it could still work (e.g., extern crate in a local scope),
266+
// but we'll be cautious and downgrade from a suggestion to a help.
267+
if !extern_prelude.contains(replace_with) {
268+
helps.push((lint, used_mod, replace_with, krate_span.into()));
269+
continue;
270+
}
271+
259272
span_lint_and_sugg(
260273
cx,
261274
lint,
@@ -324,3 +337,43 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool {
324337
}
325338
}
326339
}
340+
341+
fn extern_prelude(cx: &LateContext<'_>) -> FxHashSet<Symbol> {
342+
let mut extern_prelude = cx
343+
.tcx
344+
.hir_root_module()
345+
.item_ids
346+
.iter()
347+
.filter_map(|item| match cx.tcx.hir_node(item.hir_id()) {
348+
Node::Item(Item {
349+
kind: ItemKind::ExternCrate(original_name, ident),
350+
..
351+
}) => Some(original_name.unwrap_or(ident.name)),
352+
_ => None,
353+
})
354+
.collect::<FxHashSet<_>>();
355+
356+
let implicit_core = !cx.tcx.hir_krate_attrs().iter().any(|attr| {
357+
matches!(
358+
attr,
359+
Attribute::Parsed(AttributeKind::NoCore | AttributeKind::NoImplicitPrelude)
360+
)
361+
});
362+
363+
if implicit_core {
364+
extern_prelude.insert(sym::core);
365+
}
366+
367+
let implicit_std = !cx.tcx.hir_krate_attrs().iter().any(|attr| {
368+
matches!(
369+
attr,
370+
Attribute::Parsed(AttributeKind::NoStd | AttributeKind::NoImplicitPrelude)
371+
)
372+
});
373+
374+
if implicit_std {
375+
extern_prelude.insert(sym::std);
376+
}
377+
378+
extern_prelude
379+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![warn(clippy::std_instead_of_core)]
2+
#![warn(clippy::std_instead_of_alloc)]
3+
#![allow(unused_imports)]
4+
#![no_implicit_prelude]
5+
6+
extern crate alloc;
7+
extern crate core;
8+
extern crate std;
9+
10+
fn pr17252() {
11+
use core::result::Result;
12+
//~^ std_instead_of_core
13+
14+
use alloc::vec::Vec;
15+
//~^ std_instead_of_alloc
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![warn(clippy::std_instead_of_core)]
2+
#![warn(clippy::std_instead_of_alloc)]
3+
#![allow(unused_imports)]
4+
#![no_implicit_prelude]
5+
6+
extern crate alloc;
7+
extern crate core;
8+
extern crate std;
9+
10+
fn pr17252() {
11+
use std::result::Result;
12+
//~^ std_instead_of_core
13+
14+
use std::vec::Vec;
15+
//~^ std_instead_of_alloc
16+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: used import from `std` instead of `core`
2+
--> tests/ui/std_instead_of_core_no_implicit_prelude.rs:11:9
3+
|
4+
LL | use std::result::Result;
5+
| ^^^ help: consider importing the item from `core`: `core`
6+
|
7+
= note: `-D clippy::std-instead-of-core` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]`
9+
10+
error: used import from `std` instead of `alloc`
11+
--> tests/ui/std_instead_of_core_no_implicit_prelude.rs:14:9
12+
|
13+
LL | use std::vec::Vec;
14+
| ^^^ help: consider importing the item from `alloc`: `alloc`
15+
|
16+
= note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
17+
= help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]`
18+
19+
error: aborting due to 2 previous errors
20+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![warn(clippy::std_instead_of_core)]
2+
#![warn(clippy::std_instead_of_alloc)]
3+
#![allow(unused_imports)]
4+
#![no_implicit_prelude]
5+
6+
extern crate std;
7+
8+
fn pr17252_no_core() {
9+
// This wont have a suggestion since `core` isn't in scope
10+
use std::result::Result;
11+
//~^ std_instead_of_core
12+
}
13+
14+
fn pr17252_no_alloc() {
15+
// This wont have a suggestion since `alloc` isn't in scope
16+
use std::vec::Vec;
17+
//~^ std_instead_of_alloc
18+
}
19+
20+
fn pr17252_local_core() {
21+
extern crate core;
22+
23+
// FIXME: This *should* have a suggestion, but we're not currently
24+
// checking local scope, only the extern crate prelude.
25+
use std::result::Result;
26+
//~^ std_instead_of_core
27+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: used import from `std` instead of `core`
2+
--> tests/ui/std_instead_of_core_no_implicit_prelude_unfixable.rs:10:9
3+
|
4+
LL | use std::result::Result;
5+
| ^^^
6+
|
7+
= help: consider importing the item from `core`
8+
= note: `-D clippy::std-instead-of-core` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]`
10+
11+
error: used import from `std` instead of `alloc`
12+
--> tests/ui/std_instead_of_core_no_implicit_prelude_unfixable.rs:16:9
13+
|
14+
LL | use std::vec::Vec;
15+
| ^^^
16+
|
17+
= help: consider importing the item from `alloc`
18+
= note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
19+
= help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]`
20+
21+
error: used import from `std` instead of `core`
22+
--> tests/ui/std_instead_of_core_no_implicit_prelude_unfixable.rs:25:9
23+
|
24+
LL | use std::result::Result;
25+
| ^^^
26+
|
27+
= help: consider importing the item from `core`
28+
29+
error: aborting due to 3 previous errors
30+

0 commit comments

Comments
 (0)