cargo/core/compiler/
unused_deps.rs1use std::collections::BTreeSet;
2
3use indexmap::IndexMap;
4use indexmap::IndexSet;
5use tracing::{instrument, trace};
6
7use super::BuildContext;
8use super::unit::Unit;
9use crate::core::Dependency;
10use crate::core::PackageId;
11use crate::core::compiler::build_config::CompileMode;
12use crate::core::dependency::DepKind;
13use crate::core::manifest::TargetKind;
14use crate::util::interning::InternedString;
15
16pub struct UnusedDepState {
18 pub states: IndexMap<PackageId, IndexMap<DepKind, DependenciesState>>,
19}
20
21impl UnusedDepState {
22 #[instrument(name = "UnusedDepState::new", skip_all)]
23 pub fn new(bcx: &BuildContext<'_, '_>) -> Self {
24 let mut root_build_script_builds = IndexSet::new();
26 let roots = &bcx.roots;
27 for root in roots.iter() {
28 for build_script_run in bcx.unit_graph[root].iter() {
29 if !build_script_run.unit.target.is_custom_build()
30 && build_script_run.unit.pkg.package_id() != root.pkg.package_id()
31 {
32 continue;
33 }
34 for build_script_build in bcx.unit_graph[&build_script_run.unit].iter() {
35 if !build_script_build.unit.target.is_custom_build()
36 && build_script_build.unit.pkg.package_id() != root.pkg.package_id()
37 {
38 continue;
39 }
40 if build_script_build.unit.mode != CompileMode::Build {
41 continue;
42 }
43 root_build_script_builds.insert(build_script_build.unit.clone());
44 }
45 }
46 }
47
48 trace!("selected dep kinds: {:?}", bcx.selected_dep_kinds);
49 let mut states = IndexMap::<_, IndexMap<_, DependenciesState>>::new();
50 for root in roots.iter().chain(root_build_script_builds.iter()) {
51 let pkg_id = root.pkg.package_id();
52 let dep_kind = dep_kind_of(root);
53 if !bcx.selected_dep_kinds.contains(dep_kind) {
54 trace!(
55 "pkg {} v{} ({dep_kind:?}): ignoring unused deps due to non-exhaustive units",
56 pkg_id.name(),
57 pkg_id.version(),
58 );
59 continue;
60 }
61 trace!(
62 "tracking root {} {} ({:?})",
63 root.pkg.name(),
64 unit_desc(root),
65 dep_kind
66 );
67
68 let state = states
69 .entry(pkg_id)
70 .or_default()
71 .entry(dep_kind)
72 .or_default();
73 state.needed_units += 1;
74 for dep in bcx.unit_graph[root].iter() {
75 trace!(
76 " => {} (deps={})",
77 dep.unit.pkg.name(),
78 dep.manifest_deps.0.is_some()
79 );
80 let manifest_deps = if let Some(manifest_deps) = &dep.manifest_deps.0 {
81 Some(manifest_deps.clone())
82 } else if dep.unit.pkg.package_id() == root.pkg.package_id() {
83 None
84 } else {
85 continue;
86 };
87 state.externs.insert(
88 dep.extern_crate_name,
89 ExternState {
90 unit: dep.unit.clone(),
91 manifest_deps,
92 },
93 );
94 }
95 }
96
97 Self { states }
98 }
99
100 pub fn record_unused_externs_for_unit(
101 &mut self,
102 unit: &Unit,
103 unused_externs: BTreeSet<InternedString>,
104 ) {
105 let pkg_id = unit.pkg.package_id();
106 let dep_kind = dep_kind_of(unit);
107 trace!(
108 "pkg {} v{} ({dep_kind:?}): unused externs {unused_externs:?}",
109 pkg_id.name(),
110 pkg_id.version(),
111 );
112 let state = self
113 .states
114 .entry(pkg_id)
115 .or_default()
116 .entry(dep_kind)
117 .or_default();
118 state.seen_units.push(unit.clone());
119 if let Some(existing) = state.unused_externs.as_mut() {
120 existing.retain(|ext| unused_externs.contains(ext));
121 } else {
122 state.unused_externs = Some(unused_externs);
123 }
124 }
125}
126
127#[derive(Default)]
129pub struct DependenciesState {
130 pub externs: IndexMap<InternedString, ExternState>,
132 pub needed_units: usize,
137 pub seen_units: Vec<Unit>,
139 pub unused_externs: Option<BTreeSet<InternedString>>,
141}
142
143#[derive(Clone)]
144pub struct ExternState {
145 pub unit: Unit,
146 pub manifest_deps: Option<Vec<Dependency>>,
147}
148
149fn dep_kind_of(unit: &Unit) -> DepKind {
150 match unit.target.kind() {
151 TargetKind::Lib(_) => match unit.mode {
152 CompileMode::Test => DepKind::Development,
154 _ => DepKind::Normal,
155 },
156 TargetKind::Bin => DepKind::Normal,
157 TargetKind::Test => DepKind::Development,
158 TargetKind::Bench => DepKind::Development,
159 TargetKind::ExampleLib(_) => DepKind::Development,
160 TargetKind::ExampleBin => DepKind::Development,
161 TargetKind::CustomBuild => DepKind::Build,
162 }
163}
164
165fn unit_desc(unit: &Unit) -> String {
166 format!(
167 "{}/{}+{:?}",
168 unit.target.name(),
169 unit.target.kind().description(),
170 unit.mode,
171 )
172}