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