Skip to content

Commit 5a4ff27

Browse files
committedMar 6, 2024·
Fix redundant import errors for preload extern crate
1 parent 62415e2 commit 5a4ff27

10 files changed

+230
-72
lines changed
 

‎compiler/rustc_lint/src/context/diagnostics.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
143143
BuiltinLintDiag::RedundantImport(spans, ident) => {
144144
for (span, is_imported) in spans {
145145
let introduced = if is_imported { "imported" } else { "defined" };
146-
diag.span_label(span, format!("the item `{ident}` is already {introduced} here"));
146+
let span_msg = if span.is_dummy() { "by prelude" } else { "here" };
147+
diag.span_label(
148+
span,
149+
format!("the item `{ident}` is already {introduced} {span_msg}"),
150+
);
147151
}
148152
}
149153
BuiltinLintDiag::DeprecatedMacro(suggestion, span) => {

‎compiler/rustc_resolve/src/check_unused.rs

+77-69
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,81 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
137137
self.check_import_as_underscore(item, *id);
138138
}
139139
}
140+
141+
fn report_unused_extern_crate_items(
142+
&mut self,
143+
maybe_unused_extern_crates: FxHashMap<ast::NodeId, Span>,
144+
) {
145+
let tcx = self.r.tcx();
146+
for extern_crate in &self.extern_crate_items {
147+
let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');
148+
149+
// If the crate is fully unused, we suggest removing it altogether.
150+
// We do this in any edition.
151+
if warn_if_unused {
152+
if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
153+
self.r.lint_buffer.buffer_lint_with_diagnostic(
154+
UNUSED_EXTERN_CRATES,
155+
extern_crate.id,
156+
span,
157+
"unused extern crate",
158+
BuiltinLintDiag::UnusedExternCrate {
159+
removal_span: extern_crate.span_with_attributes,
160+
},
161+
);
162+
continue;
163+
}
164+
}
165+
166+
// If we are not in Rust 2018 edition, then we don't make any further
167+
// suggestions.
168+
if !tcx.sess.at_least_rust_2018() {
169+
continue;
170+
}
171+
172+
// If the extern crate has any attributes, they may have funky
173+
// semantics we can't faithfully represent using `use` (most
174+
// notably `#[macro_use]`). Ignore it.
175+
if extern_crate.has_attrs {
176+
continue;
177+
}
178+
179+
// If the extern crate is renamed, then we cannot suggest replacing it with a use as this
180+
// would not insert the new name into the prelude, where other imports in the crate may be
181+
// expecting it.
182+
if extern_crate.renames {
183+
continue;
184+
}
185+
186+
// If the extern crate isn't in the extern prelude,
187+
// there is no way it can be written as a `use`.
188+
if !self
189+
.r
190+
.extern_prelude
191+
.get(&extern_crate.ident)
192+
.is_some_and(|entry| !entry.introduced_by_item)
193+
{
194+
continue;
195+
}
196+
197+
let vis_span = extern_crate
198+
.vis_span
199+
.find_ancestor_inside(extern_crate.span)
200+
.unwrap_or(extern_crate.vis_span);
201+
let ident_span = extern_crate
202+
.ident
203+
.span
204+
.find_ancestor_inside(extern_crate.span)
205+
.unwrap_or(extern_crate.ident.span);
206+
self.r.lint_buffer.buffer_lint_with_diagnostic(
207+
UNUSED_EXTERN_CRATES,
208+
extern_crate.id,
209+
extern_crate.span,
210+
"`extern crate` is not idiomatic in the new edition",
211+
BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span },
212+
);
213+
}
214+
}
140215
}
141216

142217
impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
@@ -335,6 +410,8 @@ impl Resolver<'_, '_> {
335410
};
336411
visit::walk_crate(&mut visitor, krate);
337412

413+
visitor.report_unused_extern_crate_items(maybe_unused_extern_crates);
414+
338415
for unused in visitor.unused_imports.values() {
339416
let mut fixes = Vec::new();
340417
let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
@@ -416,75 +493,6 @@ impl Resolver<'_, '_> {
416493
);
417494
}
418495

419-
for extern_crate in visitor.extern_crate_items {
420-
let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');
421-
422-
// If the crate is fully unused, we suggest removing it altogether.
423-
// We do this in any edition.
424-
if warn_if_unused {
425-
if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
426-
visitor.r.lint_buffer.buffer_lint_with_diagnostic(
427-
UNUSED_EXTERN_CRATES,
428-
extern_crate.id,
429-
span,
430-
"unused extern crate",
431-
BuiltinLintDiag::UnusedExternCrate {
432-
removal_span: extern_crate.span_with_attributes,
433-
},
434-
);
435-
continue;
436-
}
437-
}
438-
439-
// If we are not in Rust 2018 edition, then we don't make any further
440-
// suggestions.
441-
if !tcx.sess.at_least_rust_2018() {
442-
continue;
443-
}
444-
445-
// If the extern crate has any attributes, they may have funky
446-
// semantics we can't faithfully represent using `use` (most
447-
// notably `#[macro_use]`). Ignore it.
448-
if extern_crate.has_attrs {
449-
continue;
450-
}
451-
452-
// If the extern crate is renamed, then we cannot suggest replacing it with a use as this
453-
// would not insert the new name into the prelude, where other imports in the crate may be
454-
// expecting it.
455-
if extern_crate.renames {
456-
continue;
457-
}
458-
459-
// If the extern crate isn't in the extern prelude,
460-
// there is no way it can be written as a `use`.
461-
if !visitor
462-
.r
463-
.extern_prelude
464-
.get(&extern_crate.ident)
465-
.is_some_and(|entry| !entry.introduced_by_item)
466-
{
467-
continue;
468-
}
469-
470-
let vis_span = extern_crate
471-
.vis_span
472-
.find_ancestor_inside(extern_crate.span)
473-
.unwrap_or(extern_crate.vis_span);
474-
let ident_span = extern_crate
475-
.ident
476-
.span
477-
.find_ancestor_inside(extern_crate.span)
478-
.unwrap_or(extern_crate.ident.span);
479-
visitor.r.lint_buffer.buffer_lint_with_diagnostic(
480-
UNUSED_EXTERN_CRATES,
481-
extern_crate.id,
482-
extern_crate.span,
483-
"`extern crate` is not idiomatic in the new edition",
484-
BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span },
485-
);
486-
}
487-
488496
let unused_imports = visitor.unused_imports;
489497
let mut check_redundant_imports = FxIndexSet::default();
490498
for module in self.arenas.local_modules().iter() {

‎compiler/rustc_resolve/src/imports.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1336,9 +1336,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13361336
}
13371337

13381338
let mut is_redundant = true;
1339-
13401339
let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None };
1341-
13421340
self.per_ns(|this, ns| {
13431341
if is_redundant && let Ok(binding) = source_bindings[ns].get() {
13441342
if binding.res() == Res::Err {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn item() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ compile-flags: --extern aux_issue_121915 --edition 2015
2+
//@ aux-build: aux-issue-121915.rs
3+
4+
extern crate aux_issue_121915;
5+
6+
#[deny(unused_imports)]
7+
fn main() {
8+
use aux_issue_121915;
9+
//~^ ERROR the item `aux_issue_121915` is imported redundantly
10+
aux_issue_121915::item();
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: the item `aux_issue_121915` is imported redundantly
2+
--> $DIR/redundant-import-issue-121915-2015.rs:8:9
3+
|
4+
LL | extern crate aux_issue_121915;
5+
| ------------------------------ the item `aux_issue_121915` is already imported here
6+
...
7+
LL | use aux_issue_121915;
8+
| ^^^^^^^^^^^^^^^^
9+
|
10+
note: the lint level is defined here
11+
--> $DIR/redundant-import-issue-121915-2015.rs:6:8
12+
|
13+
LL | #[deny(unused_imports)]
14+
| ^^^^^^^^^^^^^^
15+
16+
error: aborting due to 1 previous error
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ compile-flags: --extern aux_issue_121915 --edition 2018
2+
//@ aux-build: aux-issue-121915.rs
3+
4+
#[deny(unused_imports)]
5+
fn main() {
6+
use aux_issue_121915;
7+
//~^ ERROR the item `aux_issue_121915` is imported redundantly
8+
aux_issue_121915::item();
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: the item `aux_issue_121915` is imported redundantly
2+
--> $DIR/redundant-import-issue-121915.rs:6:9
3+
|
4+
LL | use aux_issue_121915;
5+
| ^^^^^^^^^^^^^^^^ the item `aux_issue_121915` is already defined by prelude
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/redundant-import-issue-121915.rs:4:8
9+
|
10+
LL | #[deny(unused_imports)]
11+
| ^^^^^^^^^^^^^^
12+
13+
error: aborting due to 1 previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//@ compile-flags: --edition 2021
2+
#![deny(unused_imports)]
3+
#![allow(dead_code)]
4+
5+
fn test0() {
6+
// Test remove FlatUnused
7+
use std::convert::TryFrom;
8+
//~^ ERROR the item `TryFrom` is imported redundantly
9+
let _ = u32::try_from(5i32);
10+
}
11+
12+
fn test1() {
13+
// FIXME(yukang) Test remove NestedFullUnused
14+
use std::convert::{TryFrom, TryInto};
15+
//~^ ERROR the item `TryFrom` is imported redundantly
16+
//~| ERROR the item `TryInto` is imported redundantly
17+
18+
let _ = u32::try_from(5i32);
19+
let _a: i32 = u32::try_into(5u32).unwrap();
20+
}
21+
22+
fn test2() {
23+
// FIXME(yukang): Test remove both redundant and unused
24+
use std::convert::{AsMut, Into};
25+
//~^ ERROR unused import: `AsMut`
26+
//~| ERROR the item `Into` is imported redundantly
27+
28+
let _a: u32 = (5u8).into();
29+
}
30+
31+
fn test3() {
32+
// Test remove NestedPartialUnused
33+
use std::convert::{From, Infallible};
34+
//~^ ERROR unused import: `From`
35+
36+
trait MyTrait {}
37+
impl MyTrait for fn() -> Infallible {}
38+
}
39+
40+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
error: the item `TryFrom` is imported redundantly
2+
--> $DIR/suggest-remove-issue-121315.rs:7:9
3+
|
4+
LL | use std::convert::TryFrom;
5+
| ^^^^^^^^^^^^^^^^^^^^^
6+
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
7+
|
8+
= note: the item `TryFrom` is already defined here
9+
|
10+
note: the lint level is defined here
11+
--> $DIR/suggest-remove-issue-121315.rs:2:9
12+
|
13+
LL | #![deny(unused_imports)]
14+
| ^^^^^^^^^^^^^^
15+
16+
error: the item `TryFrom` is imported redundantly
17+
--> $DIR/suggest-remove-issue-121315.rs:14:24
18+
|
19+
LL | use std::convert::{TryFrom, TryInto};
20+
| ^^^^^^^
21+
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
22+
|
23+
= note: the item `TryFrom` is already defined here
24+
25+
error: the item `TryInto` is imported redundantly
26+
--> $DIR/suggest-remove-issue-121315.rs:14:33
27+
|
28+
LL | use std::convert::{TryFrom, TryInto};
29+
| ^^^^^^^
30+
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
31+
|
32+
= note: the item `TryInto` is already defined here
33+
34+
error: unused import: `AsMut`
35+
--> $DIR/suggest-remove-issue-121315.rs:24:24
36+
|
37+
LL | use std::convert::{AsMut, Into};
38+
| ^^^^^
39+
40+
error: the item `Into` is imported redundantly
41+
--> $DIR/suggest-remove-issue-121315.rs:24:31
42+
|
43+
LL | use std::convert::{AsMut, Into};
44+
| ^^^^
45+
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
46+
|
47+
= note: the item `Into` is already defined here
48+
49+
error: unused import: `From`
50+
--> $DIR/suggest-remove-issue-121315.rs:33:24
51+
|
52+
LL | use std::convert::{From, Infallible};
53+
| ^^^^
54+
55+
error: aborting due to 6 previous errors
56+

0 commit comments

Comments
 (0)
Please sign in to comment.