Skip to content

Commit b37cc85

Browse files
committed
rework to report errors from crates in a consistent order
We first collect unused crates into a map and then walk all extern crates in crate order.
1 parent 8b39808 commit b37cc85

File tree

3 files changed

+74
-82
lines changed

3 files changed

+74
-82
lines changed

src/librustc_typeck/check_unused.rs

+41-49
Original file line numberDiff line numberDiff line change
@@ -120,62 +120,68 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
120120
.cloned()
121121
.collect();
122122

123-
// Issue lints for fully unused crates that suggest removing them.
124-
for (&def_id, &span) in &unused_extern_crates {
125-
assert_eq!(def_id.krate, LOCAL_CRATE);
126-
let hir_id = tcx.hir.definitions().def_index_to_hir_id(def_id.index);
127-
let id = tcx.hir.hir_to_node_id(hir_id);
128-
let msg = "unused extern crate";
129-
tcx.struct_span_lint_node(lint, id, span, msg)
130-
.span_suggestion_short(span, "remove it", "".to_string())
131-
.emit();
132-
}
133-
134-
// If we are not in Rust 2018 edition, we are done.
135-
if !tcx.sess.rust_2018() {
136-
return;
137-
}
138-
139-
// Otherwise, we can *also* suggest rewriting `extern crate`
140-
// into `use` etc.
141-
let mut crates_to_convert_to_use = vec![];
123+
// Collect all the extern crates (in a reliable order).
124+
let mut crates_to_lint = vec![];
142125
tcx.hir.krate().visit_all_item_likes(&mut CollectExternCrateVisitor {
143126
tcx,
144-
unused_extern_crates: &unused_extern_crates,
145-
crates_to_convert_to_use: &mut crates_to_convert_to_use,
127+
crates_to_lint: &mut crates_to_lint,
146128
});
147129

148-
for to_convert in &crates_to_convert_to_use {
149-
assert_eq!(to_convert.def_id.krate, LOCAL_CRATE);
150-
let hir_id = tcx.hir.definitions().def_index_to_hir_id(to_convert.def_id.index);
130+
for extern_crate in &crates_to_lint {
131+
assert!(extern_crate.def_id.is_local());
132+
133+
// If the crate is fully unused, we suggest removing it altogether.
134+
// We do this in any edition.
135+
if let Some(&span) = unused_extern_crates.get(&extern_crate.def_id) {
136+
assert_eq!(extern_crate.def_id.krate, LOCAL_CRATE);
137+
let hir_id = tcx.hir.definitions().def_index_to_hir_id(extern_crate.def_id.index);
138+
let id = tcx.hir.hir_to_node_id(hir_id);
139+
let msg = "unused extern crate";
140+
tcx.struct_span_lint_node(lint, id, span, msg)
141+
.span_suggestion_short(span, "remove it", "".to_string())
142+
.emit();
143+
continue;
144+
}
145+
146+
// If we are not in Rust 2018 edition, then we don't make any further
147+
// suggestions.
148+
if !tcx.sess.rust_2018() {
149+
continue;
150+
}
151+
152+
// If the extern crate has any attributes, they may have funky
153+
// semantics we can't faithfully represent using `use` (most
154+
// notably `#[macro_use]`). Ignore it.
155+
if !tcx.get_attrs(extern_crate.def_id).is_empty() {
156+
continue;
157+
}
158+
159+
// Otherwise, we can convert it into a `use` of some kind.
160+
let hir_id = tcx.hir.definitions().def_index_to_hir_id(extern_crate.def_id.index);
151161
let id = tcx.hir.hir_to_node_id(hir_id);
152162
let item = tcx.hir.expect_item(id);
153163
let msg = "`extern crate` is not idiomatic in the new edition";
154-
155164
let help = format!(
156165
"convert it to a `{}`",
157166
visibility_qualified(&item.vis, "use")
158167
);
159-
160-
let base_replacement = match to_convert.orig_name {
168+
let base_replacement = match extern_crate.orig_name {
161169
Some(orig_name) => format!("use {} as {};", orig_name, item.name),
162170
None => format!("use {};", item.name),
163171
};
164172
let replacement = visibility_qualified(&item.vis, &base_replacement);
165-
166-
tcx.struct_span_lint_node(lint, id, to_convert.span, msg)
167-
.span_suggestion_short(to_convert.span, &help, replacement)
173+
tcx.struct_span_lint_node(lint, id, extern_crate.span, msg)
174+
.span_suggestion_short(extern_crate.span, &help, replacement)
168175
.emit();
169176
}
170177
}
171178

172179
struct CollectExternCrateVisitor<'a, 'tcx: 'a> {
173180
tcx: TyCtxt<'a, 'tcx, 'tcx>,
174-
unused_extern_crates: &'a FxHashMap<DefId, Span>,
175-
crates_to_convert_to_use: &'a mut Vec<ExternCrateToConvertToUse>,
181+
crates_to_lint: &'a mut Vec<ExternCrateToLint>,
176182
}
177183

178-
struct ExternCrateToConvertToUse {
184+
struct ExternCrateToLint {
179185
/// def-id of the extern crate
180186
def_id: DefId,
181187

@@ -192,22 +198,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> {
192198
fn visit_item(&mut self, item: &hir::Item) {
193199
if let hir::ItemExternCrate(orig_name) = item.node {
194200
let extern_crate_def_id = self.tcx.hir.local_def_id(item.id);
195-
196-
// If the crate is fully unused, we are going to suggest
197-
// removing it anyway, so ignore it.
198-
if self.unused_extern_crates.contains_key(&extern_crate_def_id) {
199-
return;
200-
}
201-
202-
// If the extern crate has any attributes, they may have funky
203-
// semantics we can't entirely understand. Ignore it.
204-
if !self.tcx.get_attrs(extern_crate_def_id).is_empty() {
205-
return;
206-
}
207-
208-
// Otherwise, we can convert it into a `use` of some kind.
209-
self.crates_to_convert_to_use.push(
210-
ExternCrateToConvertToUse {
201+
self.crates_to_lint.push(
202+
ExternCrateToLint {
211203
def_id: extern_crate_def_id,
212204
span: item.span,
213205
orig_name,

src/test/ui-fulldeps/unnecessary-extern-crate.stderr

+27-27
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: unused extern crate
2-
--> $DIR/unnecessary-extern-crate.rs:51:5
2+
--> $DIR/unnecessary-extern-crate.rs:16:1
33
|
4-
LL | extern crate alloc;
5-
| ^^^^^^^^^^^^^^^^^^^ help: remove it
4+
LL | extern crate alloc;
5+
| ^^^^^^^^^^^^^^^^^^^ help: remove it
66
|
77
note: lint level defined here
88
--> $DIR/unnecessary-extern-crate.rs:13:9
@@ -16,30 +16,6 @@ error: unused extern crate
1616
LL | extern crate alloc as x;
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
1818

19-
error: unused extern crate
20-
--> $DIR/unnecessary-extern-crate.rs:55:5
21-
|
22-
LL | extern crate alloc as x;
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
24-
25-
error: unused extern crate
26-
--> $DIR/unnecessary-extern-crate.rs:68:9
27-
|
28-
LL | extern crate alloc;
29-
| ^^^^^^^^^^^^^^^^^^^ help: remove it
30-
31-
error: unused extern crate
32-
--> $DIR/unnecessary-extern-crate.rs:16:1
33-
|
34-
LL | extern crate alloc;
35-
| ^^^^^^^^^^^^^^^^^^^ help: remove it
36-
37-
error: unused extern crate
38-
--> $DIR/unnecessary-extern-crate.rs:72:9
39-
|
40-
LL | extern crate alloc as x;
41-
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
42-
4319
error: `extern crate` is not idiomatic in the new edition
4420
--> $DIR/unnecessary-extern-crate.rs:26:1
4521
|
@@ -76,6 +52,18 @@ error: `extern crate` is not idiomatic in the new edition
7652
LL | pub(super) extern crate libc as d;
7753
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub(super) use`
7854

55+
error: unused extern crate
56+
--> $DIR/unnecessary-extern-crate.rs:51:5
57+
|
58+
LL | extern crate alloc;
59+
| ^^^^^^^^^^^^^^^^^^^ help: remove it
60+
61+
error: unused extern crate
62+
--> $DIR/unnecessary-extern-crate.rs:55:5
63+
|
64+
LL | extern crate alloc as x;
65+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
66+
7967
error: `extern crate` is not idiomatic in the new edition
8068
--> $DIR/unnecessary-extern-crate.rs:59:5
8169
|
@@ -88,6 +76,18 @@ error: `extern crate` is not idiomatic in the new edition
8876
LL | pub extern crate test as y;
8977
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub use`
9078

79+
error: unused extern crate
80+
--> $DIR/unnecessary-extern-crate.rs:68:9
81+
|
82+
LL | extern crate alloc;
83+
| ^^^^^^^^^^^^^^^^^^^ help: remove it
84+
85+
error: unused extern crate
86+
--> $DIR/unnecessary-extern-crate.rs:72:9
87+
|
88+
LL | extern crate alloc as x;
89+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
90+
9191
error: `extern crate` is not idiomatic in the new edition
9292
--> $DIR/unnecessary-extern-crate.rs:76:9
9393
|

src/test/ui/suggestions/removing-extern-crate.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
warning: unused extern crate
2-
--> $DIR/removing-extern-crate.rs:24:5
2+
--> $DIR/removing-extern-crate.rs:19:1
33
|
4-
LL | extern crate std;
5-
| ^^^^^^^^^^^^^^^^^ help: remove it
4+
LL | extern crate std as foo;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
66
|
77
note: lint level defined here
88
--> $DIR/removing-extern-crate.rs:16:9
@@ -24,8 +24,8 @@ LL | extern crate std as foo;
2424
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
2525

2626
warning: unused extern crate
27-
--> $DIR/removing-extern-crate.rs:19:1
27+
--> $DIR/removing-extern-crate.rs:24:5
2828
|
29-
LL | extern crate std as foo;
30-
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
29+
LL | extern crate std;
30+
| ^^^^^^^^^^^^^^^^^ help: remove it
3131

0 commit comments

Comments
 (0)