Code change:
used_trait_imports.extend(imports.iter()); } <del> for id in tcx.hir().items() { if matches!(tcx.def_kind(id.def_id), DefKind::Use) { if tcx.visibility(id.def_id).is_public() { continue; } let item = tcx.hir().item(id); if item.span.is_dummy() { continue; } if let hir::ItemKind::Use(path, _) = item.kind { check_import(tcx, &mut used_trait_imports, item.item_id(), path.span); } </del> <ins> for &id in tcx.maybe_unused_trait_imports(()) { debug_assert_eq!(tcx.def_kind(id), DefKind::Use); if tcx.visibility(id).is_public() { continue; } if used_trait_imports.contains(&id) { continue; </ins> } <ins> let item = tcx.hir().expect_item(id); if item.span.is_dummy() { continue; } let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| { let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet) } else { "unused import".to_owned() }; lint.build(&msg).emit(); }); </ins> } unused_crates_lint(tcx); } <del> fn check_import<'tcx>( tcx: TyCtxt<'tcx>, used_trait_imports: &mut FxHashSet<LocalDefId>, item_id: hir::ItemId, span: Span, ) { if !tcx.maybe_unused_trait_import(item_id.def_id) { return; } if used_trait_imports.contains(&item_id.def_id) { return; } tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item_id.hir_id(), span, |lint| { let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { format!("unused import: `{}`", snippet) } else { "unused import".to_owned() }; lint.build(&msg).emit(); }); } </del> fn unused_crates_lint(tcx: TyCtxt<'_>) { let lint = lint::builtin::UNUSED_EXTERN_CRATES;

Related discussion:
text: The resolver gathers a list of possibly unused trait imports in . This list is passed to resolver outputs, into the query. This query takes a and returns whether the import is possibly unused. This is used by the post-typeck unused import check in . This query iterates over all the statements in the crate, checks whether they may be unused trait imports, and warns if they are indeed unused. As there are typically very few unused trait imports compared to the number of items in a crate, it would make sense to directly iterate on . Steps: make an both in and , this will ensure a deterministic iteration order; rename query and give it the signature , and adapt the call site; we do not want to access directly, as this would prevent the query system from detecting that the set has not changed; in , inline and replace the loop over by a loop over ; the filter over there can be removed too (or replaced by a debug-assertion): the set may only point to use statements. Extra: investigate why we check for , and the consequences of removing that check; investigate the impact on perf of converting the to a simple when producing from . I am available on Zulip for any question. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
claim
are you still working on this?
Hello yes sorry for the super slow pace. I am still working on it (mostly reading the rustc dev guide so far). Is that alright or is it important to get this done quickly?
no worries, I am a beginner looking for tasks, hence the qn.