rustc_hir_analysis/
check_unused.rs

1use rustc_data_structures::unord::{ExtendUnord, UnordSet};
2use rustc_hir::def::DefKind;
3use rustc_hir::def_id::LocalDefId;
4use rustc_middle::query::Providers;
5use rustc_middle::ty::TyCtxt;
6use rustc_session::lint;
7use tracing::debug;
8
9pub(crate) fn provide(providers: &mut Providers) {
10    *providers = Providers { check_unused_traits, ..*providers };
11}
12
13fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) {
14    let mut used_trait_imports = UnordSet::<LocalDefId>::default();
15
16    // FIXME: Use `tcx.hir().par_body_owners()` when we implement creating `DefId`s
17    // for anon constants during their parents' typeck.
18    // Doing so at current will produce queries cycle errors because it may typeck
19    // on anon constants directly.
20    for item_def_id in tcx.hir().body_owners() {
21        let imports = tcx.used_trait_imports(item_def_id);
22        debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
23        used_trait_imports.extend_unord(imports.items().copied());
24    }
25
26    for &id in tcx.maybe_unused_trait_imports(()) {
27        debug_assert_eq!(tcx.def_kind(id), DefKind::Use);
28        if tcx.visibility(id).is_public() {
29            continue;
30        }
31        if used_trait_imports.contains(&id) {
32            continue;
33        }
34        let item = tcx.hir().expect_item(id);
35        if item.span.is_dummy() {
36            continue;
37        }
38        let (path, _) = item.expect_use();
39        tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
40            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
41                lint.primary_message(format!("unused import: `{snippet}`"));
42            } else {
43                lint.primary_message("unused import");
44            }
45        });
46    }
47}