|
1 | | -use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate}; |
2 | | -use rustc_data_structures::fx::FxHashMap; |
3 | 1 | use rustc_data_structures::unord::UnordSet; |
4 | | -use rustc_hir as hir; |
5 | 2 | use rustc_hir::def::DefKind; |
6 | | -use rustc_hir::def_id::{DefId, LocalDefId}; |
| 3 | +use rustc_hir::def_id::LocalDefId; |
7 | 4 | use rustc_middle::ty::TyCtxt; |
8 | 5 | use rustc_session::lint; |
9 | | -use rustc_span::{Span, Symbol}; |
10 | 6 |
|
11 | 7 | pub fn check_crate(tcx: TyCtxt<'_>) { |
12 | 8 | let mut used_trait_imports: UnordSet<LocalDefId> = Default::default(); |
@@ -43,131 +39,4 @@ pub fn check_crate(tcx: TyCtxt<'_>) { |
43 | 39 | |lint| lint, |
44 | 40 | ); |
45 | 41 | } |
46 | | - |
47 | | - unused_crates_lint(tcx); |
48 | | -} |
49 | | - |
50 | | -fn unused_crates_lint(tcx: TyCtxt<'_>) { |
51 | | - let lint = lint::builtin::UNUSED_EXTERN_CRATES; |
52 | | - |
53 | | - // Collect first the crates that are completely unused. These we |
54 | | - // can always suggest removing (no matter which edition we are |
55 | | - // in). |
56 | | - let unused_extern_crates: FxHashMap<LocalDefId, Span> = tcx |
57 | | - .maybe_unused_extern_crates(()) |
58 | | - .iter() |
59 | | - .filter(|&&(def_id, _)| { |
60 | | - tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| { |
61 | | - !tcx.is_compiler_builtins(cnum) |
62 | | - && !tcx.is_panic_runtime(cnum) |
63 | | - && !tcx.has_global_allocator(cnum) |
64 | | - && !tcx.has_panic_handler(cnum) |
65 | | - }) |
66 | | - }) |
67 | | - .cloned() |
68 | | - .collect(); |
69 | | - |
70 | | - // Collect all the extern crates (in a reliable order). |
71 | | - let mut crates_to_lint = vec![]; |
72 | | - |
73 | | - for id in tcx.hir().items() { |
74 | | - if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) { |
75 | | - let item = tcx.hir().item(id); |
76 | | - if let hir::ItemKind::ExternCrate(orig_name) = item.kind { |
77 | | - crates_to_lint.push(ExternCrateToLint { |
78 | | - def_id: item.owner_id.to_def_id(), |
79 | | - span: item.span, |
80 | | - orig_name, |
81 | | - warn_if_unused: !item.ident.as_str().starts_with('_'), |
82 | | - }); |
83 | | - } |
84 | | - } |
85 | | - } |
86 | | - |
87 | | - let extern_prelude = &tcx.resolutions(()).extern_prelude; |
88 | | - |
89 | | - for extern_crate in &crates_to_lint { |
90 | | - let def_id = extern_crate.def_id.expect_local(); |
91 | | - let item = tcx.hir().expect_item(def_id); |
92 | | - |
93 | | - // If the crate is fully unused, we suggest removing it altogether. |
94 | | - // We do this in any edition. |
95 | | - if extern_crate.warn_if_unused { |
96 | | - if let Some(&span) = unused_extern_crates.get(&def_id) { |
97 | | - // Removal suggestion span needs to include attributes (Issue #54400) |
98 | | - let id = tcx.hir().local_def_id_to_hir_id(def_id); |
99 | | - let span_with_attrs = tcx |
100 | | - .hir() |
101 | | - .attrs(id) |
102 | | - .iter() |
103 | | - .map(|attr| attr.span) |
104 | | - .fold(span, |acc, attr_span| acc.to(attr_span)); |
105 | | - |
106 | | - tcx.emit_spanned_lint(lint, id, span, UnusedExternCrate { span: span_with_attrs }); |
107 | | - continue; |
108 | | - } |
109 | | - } |
110 | | - |
111 | | - // If we are not in Rust 2018 edition, then we don't make any further |
112 | | - // suggestions. |
113 | | - if !tcx.sess.rust_2018() { |
114 | | - continue; |
115 | | - } |
116 | | - |
117 | | - // If the extern crate isn't in the extern prelude, |
118 | | - // there is no way it can be written as a `use`. |
119 | | - let orig_name = extern_crate.orig_name.unwrap_or(item.ident.name); |
120 | | - if !extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) { |
121 | | - continue; |
122 | | - } |
123 | | - |
124 | | - // If the extern crate is renamed, then we cannot suggest replacing it with a use as this |
125 | | - // would not insert the new name into the prelude, where other imports in the crate may be |
126 | | - // expecting it. |
127 | | - if extern_crate.orig_name.is_some() { |
128 | | - continue; |
129 | | - } |
130 | | - |
131 | | - let id = tcx.hir().local_def_id_to_hir_id(def_id); |
132 | | - // If the extern crate has any attributes, they may have funky |
133 | | - // semantics we can't faithfully represent using `use` (most |
134 | | - // notably `#[macro_use]`). Ignore it. |
135 | | - if !tcx.hir().attrs(id).is_empty() { |
136 | | - continue; |
137 | | - } |
138 | | - |
139 | | - let base_replacement = match extern_crate.orig_name { |
140 | | - Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name), |
141 | | - None => format!("use {};", item.ident.name), |
142 | | - }; |
143 | | - let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default(); |
144 | | - let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) }; |
145 | | - tcx.emit_spanned_lint( |
146 | | - lint, |
147 | | - id, |
148 | | - extern_crate.span, |
149 | | - ExternCrateNotIdiomatic { |
150 | | - span: extern_crate.span, |
151 | | - msg_code: add_vis("use".to_string()), |
152 | | - suggestion_code: add_vis(base_replacement), |
153 | | - }, |
154 | | - ); |
155 | | - } |
156 | | -} |
157 | | - |
158 | | -struct ExternCrateToLint { |
159 | | - /// `DefId` of the extern crate |
160 | | - def_id: DefId, |
161 | | - |
162 | | - /// span from the item |
163 | | - span: Span, |
164 | | - |
165 | | - /// if `Some`, then this is renamed (`extern crate orig_name as |
166 | | - /// crate_name`), and -- perhaps surprisingly -- this stores the |
167 | | - /// *original* name (`item.name` will contain the new name) |
168 | | - orig_name: Option<Symbol>, |
169 | | - |
170 | | - /// if `false`, the original name started with `_`, so we shouldn't lint |
171 | | - /// about it going unused (but we should still emit idiom lints). |
172 | | - warn_if_unused: bool, |
173 | 42 | } |
0 commit comments