1use std::path::Path;
2use std::time::Instant;
3
4use fallow_config::ProductionAnalysis;
5use fallow_engine::{
6 dead_code::DeadCodeAnalysisArtifacts,
7 project_config::{ProjectConfig, ProjectConfigOptions},
8 session::AnalysisSession,
9};
10use fallow_output::{
11 CHECK_SCHEMA_VERSION, CheckOutputInput, DeadCodeNextStepsInput, DiffIndex, build_check_output,
12 build_dead_code_next_steps, check_meta, relative_to_diff_path,
13};
14use fallow_types::output_format::OutputFormat;
15use fallow_types::path_util::is_absolute_path_any_platform;
16use fallow_types::results::{AnalysisResults, TraceHopRole};
17use rustc_hash::FxHashSet;
18
19use crate::{
20 AnalysisOptions, BoundaryViolationsProgrammaticOutput, CircularDependenciesProgrammaticOutput,
21 DeadCodeFilters, DeadCodeOptions, DeadCodeProgrammaticOutput, ProgrammaticError,
22 analysis_context::{
23 ProgrammaticAnalysisContext, changed_files_for_run,
24 resolve_programmatic_analysis_context_deferred_workspace, workspace_roots_for_session,
25 },
26 next_steps::{
27 default_workspace_ref_for_workspaces, setup_pointer_applicable, suggestions_enabled,
28 },
29};
30
31use super::{ProgrammaticResult, root_envelope_mode};
32
33pub(super) struct DeadCodeProgrammaticRunWithArtifacts {
34 pub output: DeadCodeProgrammaticOutput,
35 pub artifacts: DeadCodeAnalysisArtifacts,
36}
37
38pub fn run_dead_code(options: &DeadCodeOptions) -> ProgrammaticResult<DeadCodeProgrammaticOutput> {
46 let resolved = resolve_programmatic_analysis_context_deferred_workspace(&options.analysis)?;
47 resolved.install(|| run_dead_code_inner(options, &resolved, |_| {}))
48}
49
50pub fn run_circular_dependencies(
56 options: &DeadCodeOptions,
57) -> ProgrammaticResult<CircularDependenciesProgrammaticOutput> {
58 let resolved = resolve_programmatic_analysis_context_deferred_workspace(&options.analysis)?;
59 resolved.install(|| {
60 run_dead_code_inner(options, &resolved, keep_circular_dependencies).map(Into::into)
61 })
62}
63
64pub fn run_boundary_violations(
70 options: &DeadCodeOptions,
71) -> ProgrammaticResult<BoundaryViolationsProgrammaticOutput> {
72 let resolved = resolve_programmatic_analysis_context_deferred_workspace(&options.analysis)?;
73 resolved.install(|| {
74 run_dead_code_inner(options, &resolved, keep_boundary_violations).map(Into::into)
75 })
76}
77
78fn run_dead_code_inner(
79 options: &DeadCodeOptions,
80 resolved: &ProgrammaticAnalysisContext,
81 post_filter: impl FnOnce(&mut AnalysisResults),
82) -> ProgrammaticResult<DeadCodeProgrammaticOutput> {
83 let start = Instant::now();
84 let session = load_dead_code_session(options, resolved)?;
85 run_dead_code_with_session(options, resolved, &session, None, post_filter, start)
86}
87
88pub(super) fn run_dead_code_with_session(
89 options: &DeadCodeOptions,
90 resolved: &ProgrammaticAnalysisContext,
91 session: &AnalysisSession,
92 changed_files: Option<&FxHashSet<std::path::PathBuf>>,
93 post_filter: impl FnOnce(&mut AnalysisResults),
94 start: Instant,
95) -> ProgrammaticResult<DeadCodeProgrammaticOutput> {
96 let analysis = session.analyze_dead_code().map_err(|err| {
97 ProgrammaticError::new(format!("dead-code analysis failed: {err}"), 2)
98 .with_code("FALLOW_DEAD_CODE_FAILED")
99 .with_context("dead-code")
100 })?;
101 let mut results = analysis.results;
102
103 apply_dead_code_scope(options, resolved, session, changed_files, &mut results)?;
104 apply_dead_code_filters(&options.filters, &mut results);
105 post_filter(&mut results);
106
107 Ok(build_dead_code_programmatic_output(
108 options, resolved, session, results, start,
109 ))
110}
111
112pub(super) fn run_dead_code_with_session_artifacts(
113 options: &DeadCodeOptions,
114 resolved: &ProgrammaticAnalysisContext,
115 session: &AnalysisSession,
116 changed_files: Option<&FxHashSet<std::path::PathBuf>>,
117 post_filter: impl FnOnce(&mut AnalysisResults),
118 start: Instant,
119) -> ProgrammaticResult<DeadCodeProgrammaticRunWithArtifacts> {
120 let mut artifacts = session
121 .analyze_dead_code_with_artifacts(true, true)
122 .map_err(|err| {
123 ProgrammaticError::new(format!("dead-code analysis failed: {err}"), 2)
124 .with_code("FALLOW_DEAD_CODE_FAILED")
125 .with_context("dead-code")
126 })?;
127
128 apply_dead_code_scope(
129 options,
130 resolved,
131 session,
132 changed_files,
133 &mut artifacts.results,
134 )?;
135 apply_dead_code_filters(&options.filters, &mut artifacts.results);
136 post_filter(&mut artifacts.results);
137
138 Ok(build_dead_code_run_with_artifacts(
139 options, resolved, session, artifacts, start,
140 ))
141}
142
143pub(super) fn run_dead_code_from_artifacts(
144 options: &DeadCodeOptions,
145 resolved: &ProgrammaticAnalysisContext,
146 session: &AnalysisSession,
147 changed_files: Option<&FxHashSet<std::path::PathBuf>>,
148 mut artifacts: DeadCodeAnalysisArtifacts,
149 start: Instant,
150) -> ProgrammaticResult<DeadCodeProgrammaticRunWithArtifacts> {
151 apply_dead_code_scope(
152 options,
153 resolved,
154 session,
155 changed_files,
156 &mut artifacts.results,
157 )?;
158 apply_dead_code_filters(&options.filters, &mut artifacts.results);
159
160 Ok(build_dead_code_run_with_artifacts(
161 options, resolved, session, artifacts, start,
162 ))
163}
164
165fn build_dead_code_run_with_artifacts(
166 options: &DeadCodeOptions,
167 resolved: &ProgrammaticAnalysisContext,
168 session: &AnalysisSession,
169 artifacts: DeadCodeAnalysisArtifacts,
170 start: Instant,
171) -> DeadCodeProgrammaticRunWithArtifacts {
172 let output = build_dead_code_programmatic_output(
173 options,
174 resolved,
175 session,
176 artifacts.results.clone(),
177 start,
178 );
179 DeadCodeProgrammaticRunWithArtifacts { output, artifacts }
180}
181
182fn build_dead_code_programmatic_output(
183 options: &DeadCodeOptions,
184 resolved: &ProgrammaticAnalysisContext,
185 session: &AnalysisSession,
186 results: AnalysisResults,
187 start: Instant,
188) -> DeadCodeProgrammaticOutput {
189 let root = session.root();
190 let next_steps = build_dead_code_next_steps(DeadCodeNextStepsInput {
191 suggestions_enabled: suggestions_enabled(),
192 results: &results,
193 root,
194 offer_setup: setup_pointer_applicable(root),
195 impact_digest: None,
196 workspace_ref: default_workspace_ref_for_workspaces(root, session.workspaces()).as_deref(),
197 audit_changed: fallow_engine::churn::is_git_repo(root),
198 has_external_plugins: !fallow_config::discover_external_plugins(root, &[]).is_empty(),
199 });
200 let config_fixable =
201 fallow_config::is_config_fixable(&resolved.root, resolved.config_path.as_ref());
202 let output = build_check_output(CheckOutputInput {
203 schema_version: CHECK_SCHEMA_VERSION,
204 version: env!("CARGO_PKG_VERSION").to_string(),
205 elapsed: start.elapsed(),
206 results,
207 config_fixable,
208 meta: options.analysis.explain.then(check_meta),
209 workspace_diagnostics: session.workspace_diagnostics().to_vec(),
210 next_steps,
211 });
212 DeadCodeProgrammaticOutput {
213 output,
214 root: session.root().to_path_buf(),
215 config_fixable,
216 envelope_mode: root_envelope_mode(),
217 telemetry_analysis_run_id: None,
218 }
219}
220
221fn keep_circular_dependencies(results: &mut AnalysisResults) {
222 let entry_point_summary = results.entry_point_summary.take();
223 let circular_dependencies = std::mem::take(&mut results.circular_dependencies);
224 *results = AnalysisResults::default();
225 results.entry_point_summary = entry_point_summary;
226 results.circular_dependencies = circular_dependencies;
227}
228
229fn keep_boundary_violations(results: &mut AnalysisResults) {
230 let entry_point_summary = results.entry_point_summary.take();
231 let boundary_violations = std::mem::take(&mut results.boundary_violations);
232 let boundary_coverage_violations = std::mem::take(&mut results.boundary_coverage_violations);
233 let boundary_call_violations = std::mem::take(&mut results.boundary_call_violations);
234 *results = AnalysisResults::default();
235 results.entry_point_summary = entry_point_summary;
236 results.boundary_violations = boundary_violations;
237 results.boundary_coverage_violations = boundary_coverage_violations;
238 results.boundary_call_violations = boundary_call_violations;
239}
240
241pub(super) fn load_dead_code_session(
242 options: &DeadCodeOptions,
243 resolved: &ProgrammaticAnalysisContext,
244) -> ProgrammaticResult<AnalysisSession> {
245 let project_config = fallow_engine::project_config::config_for_project_analysis(
246 &resolved.root,
247 resolved.config_path.as_deref(),
248 ProjectConfigOptions {
249 output: OutputFormat::Json,
250 no_cache: resolved.no_cache,
251 threads: resolved.threads,
252 production_override: resolved.production_override,
253 quiet: true,
254 analysis: ProductionAnalysis::DeadCode,
255 },
256 )
257 .map_err(|err| {
258 ProgrammaticError::new(format!("failed to load config: {err}"), 2)
259 .with_code("FALLOW_CONFIG_LOAD_FAILED")
260 .with_context("analysis.configPath")
261 })?;
262 let project_config = configure_project_for_dead_code(project_config, options);
263 Ok(AnalysisSession::from_config(project_config))
264}
265
266pub(super) fn default_dead_code_options_for_context(
267 resolved: &ProgrammaticAnalysisContext,
268) -> DeadCodeOptions {
269 DeadCodeOptions {
270 analysis: AnalysisOptions {
271 root: Some(resolved.root().to_path_buf()),
272 config_path: resolved.config_path().clone(),
273 no_cache: resolved.no_cache(),
274 threads: Some(resolved.threads()),
275 production_override: resolved.production_override(),
276 changed_since: resolved.changed_since().map(str::to_owned),
277 workspace: resolved.workspace().map(<[String]>::to_vec),
278 changed_workspaces: resolved.changed_workspaces().map(str::to_owned),
279 explain: resolved.explain_enabled(),
280 ..AnalysisOptions::default()
281 },
282 filters: DeadCodeFilters::default(),
283 files: Vec::new(),
284 include_entry_exports: false,
285 }
286}
287
288fn configure_project_for_dead_code(
289 mut project_config: ProjectConfig,
290 options: &DeadCodeOptions,
291) -> ProjectConfig {
292 if options.include_entry_exports {
293 project_config.config.include_entry_exports = true;
294 }
295 activate_explicit_dead_code_opt_ins(&options.filters, &mut project_config.config.rules);
296 project_config
297}
298
299fn activate_explicit_dead_code_opt_ins(
300 filters: &DeadCodeFilters,
301 rules: &mut fallow_config::RulesConfig,
302) {
303 if filters.private_type_leaks && rules.private_type_leaks == fallow_config::Severity::Off {
304 rules.private_type_leaks = fallow_config::Severity::Warn;
305 }
306}
307
308fn apply_dead_code_scope(
309 options: &DeadCodeOptions,
310 resolved: &ProgrammaticAnalysisContext,
311 session: &AnalysisSession,
312 changed_files: Option<&FxHashSet<std::path::PathBuf>>,
313 results: &mut AnalysisResults,
314) -> ProgrammaticResult<()> {
315 let workspace_roots = workspace_roots_for_session(resolved, session.workspaces())?;
316 if let Some(workspace_roots) = workspace_roots.as_ref() {
317 fallow_engine::dead_code::filter_to_workspaces(results, workspace_roots);
318 }
319 let resolved_changed_files = if changed_files.is_some() {
320 None
321 } else {
322 changed_files_for_run(resolved)?
323 };
324 if let Some(changed_files) = changed_files.or(resolved_changed_files.as_ref()) {
325 fallow_engine::dead_code::filter_by_changed_files(results, changed_files);
326 }
327 if let Some(diff) = resolved.diff.as_ref() {
328 filter_dead_code_by_diff(results, diff, session.root());
329 }
330 apply_dead_code_file_filter(options, session.root(), results);
331 Ok(())
332}
333
334fn filter_dead_code_by_diff(results: &mut AnalysisResults, diff: &DiffIndex, root: &Path) {
335 let touches_file = |path: &Path| -> bool {
336 relative_to_diff_path(path, root).is_none_or(|rel| diff.touches_file(&rel))
337 };
338 let line_in_diff = |path: &Path, line: u32| -> bool {
339 relative_to_diff_path(path, root)
340 .is_none_or(|rel| diff.line_is_added(&rel, u64::from(line)))
341 };
342
343 filter_dead_code_source_findings(results, &touches_file, &line_in_diff);
344 filter_dead_code_security_findings(results, &touches_file, &line_in_diff);
345 filter_dead_code_dependency_findings(results, &line_in_diff);
346 filter_dead_code_graph_findings(results, &touches_file, &line_in_diff);
347 filter_dead_code_framework_findings(results, &line_in_diff);
348}
349
350fn filter_dead_code_source_findings(
351 results: &mut AnalysisResults,
352 touches_file: &dyn Fn(&Path) -> bool,
353 line_in_diff: &dyn Fn(&Path, u32) -> bool,
354) {
355 results
356 .unused_files
357 .retain(|finding| touches_file(&finding.file.path));
358 results
359 .unused_exports
360 .retain(|finding| line_in_diff(&finding.export.path, finding.export.line));
361 results
362 .unused_types
363 .retain(|finding| line_in_diff(&finding.export.path, finding.export.line));
364 results
365 .private_type_leaks
366 .retain(|finding| line_in_diff(&finding.leak.path, finding.leak.line));
367 results
368 .unused_enum_members
369 .retain(|finding| line_in_diff(&finding.member.path, finding.member.line));
370 results
371 .unused_class_members
372 .retain(|finding| line_in_diff(&finding.member.path, finding.member.line));
373 results
374 .unused_store_members
375 .retain(|finding| line_in_diff(&finding.member.path, finding.member.line));
376 results
377 .unprovided_injects
378 .retain(|finding| line_in_diff(&finding.inject.path, finding.inject.line));
379 results
380 .unrendered_components
381 .retain(|finding| line_in_diff(&finding.component.path, finding.component.line));
382 results
383 .unused_component_props
384 .retain(|finding| line_in_diff(&finding.prop.path, finding.prop.line));
385 results
386 .unused_component_emits
387 .retain(|finding| line_in_diff(&finding.emit.path, finding.emit.line));
388 results
389 .unused_component_inputs
390 .retain(|finding| line_in_diff(&finding.input.path, finding.input.line));
391 results
392 .unused_component_outputs
393 .retain(|finding| line_in_diff(&finding.output.path, finding.output.line));
394 results
395 .unused_svelte_events
396 .retain(|finding| line_in_diff(&finding.event.path, finding.event.line));
397 results
398 .unused_server_actions
399 .retain(|finding| line_in_diff(&finding.action.path, finding.action.line));
400 results
401 .unused_load_data_keys
402 .retain(|finding| line_in_diff(&finding.key.path, finding.key.line));
403 results
404 .unresolved_imports
405 .retain(|finding| line_in_diff(&finding.import.path, finding.import.line));
406}
407
408fn filter_dead_code_security_findings(
409 results: &mut AnalysisResults,
410 touches_file: &dyn Fn(&Path) -> bool,
411 line_in_diff: &dyn Fn(&Path, u32) -> bool,
412) {
413 results.security_findings.retain(|finding| {
414 line_in_diff(&finding.path, finding.line)
415 || finding.trace.iter().any(|hop| {
416 line_in_diff(&hop.path, hop.line)
417 || (matches!(hop.role, TraceHopRole::SecretSource) && touches_file(&hop.path))
418 })
419 || finding.reachability.as_ref().is_some_and(|reachability| {
420 reachability
421 .untrusted_source_trace
422 .iter()
423 .any(|hop| line_in_diff(&hop.path, hop.line))
424 })
425 });
426 results
427 .security_unresolved_callee_diagnostics
428 .retain(|finding| line_in_diff(&finding.path, finding.line));
429}
430
431fn filter_dead_code_dependency_findings(
432 results: &mut AnalysisResults,
433 line_in_diff: &dyn Fn(&Path, u32) -> bool,
434) {
435 for finding in &mut results.unlisted_dependencies {
436 finding
437 .dep
438 .imported_from
439 .retain(|source| line_in_diff(&source.path, source.line));
440 }
441 results
442 .unlisted_dependencies
443 .retain(|finding| !finding.dep.imported_from.is_empty());
444}
445
446fn filter_dead_code_graph_findings(
447 results: &mut AnalysisResults,
448 touches_file: &dyn Fn(&Path) -> bool,
449 line_in_diff: &dyn Fn(&Path, u32) -> bool,
450) {
451 results.duplicate_exports.retain(|finding| {
452 finding
453 .export
454 .locations
455 .iter()
456 .any(|location| line_in_diff(&location.path, location.line))
457 });
458 results
459 .circular_dependencies
460 .retain(|cycle| cycle.cycle.files.iter().any(|path| touches_file(path)));
461 results
462 .re_export_cycles
463 .retain(|cycle| cycle.cycle.files.iter().any(|path| touches_file(path)));
464 results
465 .boundary_violations
466 .retain(|finding| line_in_diff(&finding.violation.from_path, finding.violation.line));
467 results
468 .stale_suppressions
469 .retain(|finding| line_in_diff(&finding.path, finding.line));
470}
471
472fn filter_dead_code_framework_findings(
473 results: &mut AnalysisResults,
474 line_in_diff: &dyn Fn(&Path, u32) -> bool,
475) {
476 results
477 .invalid_client_exports
478 .retain(|finding| line_in_diff(&finding.export.path, finding.export.line));
479 results
480 .mixed_client_server_barrels
481 .retain(|finding| line_in_diff(&finding.barrel.path, finding.barrel.line));
482 results
483 .misplaced_directives
484 .retain(|finding| line_in_diff(&finding.directive_site.path, finding.directive_site.line));
485 results
486 .route_collisions
487 .retain(|finding| line_in_diff(&finding.collision.path, finding.collision.line));
488 results
489 .dynamic_segment_name_conflicts
490 .retain(|finding| line_in_diff(&finding.conflict.path, finding.conflict.line));
491}
492
493fn apply_dead_code_file_filter(
494 options: &DeadCodeOptions,
495 root: &Path,
496 results: &mut AnalysisResults,
497) {
498 if options.files.is_empty() {
499 return;
500 }
501 let file_set = options
502 .files
503 .iter()
504 .map(|path| {
505 if is_absolute_path_any_platform(path) {
506 path.clone()
507 } else {
508 root.join(path)
509 }
510 })
511 .collect::<FxHashSet<_>>();
512 fallow_engine::dead_code::filter_by_changed_files(results, &file_set);
513 clear_dead_code_dependency_findings(results);
514}
515
516fn apply_dead_code_filters(filters: &DeadCodeFilters, results: &mut AnalysisResults) {
517 if !dead_code_filters_active(filters) {
518 return;
519 }
520 apply_dead_code_core_filters(filters, results);
521 apply_dead_code_component_filters(filters, results);
522 apply_dead_code_graph_filters(filters, results);
523 apply_dead_code_policy_filters(filters, results);
524 apply_dead_code_catalog_filters(filters, results);
525}
526
527fn dead_code_filters_active(filters: &DeadCodeFilters) -> bool {
528 filters.unused_files
529 || filters.unused_exports
530 || filters.unused_deps
531 || filters.unused_types
532 || filters.private_type_leaks
533 || filters.unused_enum_members
534 || filters.unused_class_members
535 || filters.unused_store_members
536 || filters.unprovided_injects
537 || filters.unrendered_components
538 || filters.unused_component_props
539 || filters.unused_component_emits
540 || filters.unused_component_inputs
541 || filters.unused_component_outputs
542 || filters.unused_svelte_events
543 || filters.unused_server_actions
544 || filters.unused_load_data_keys
545 || filters.unresolved_imports
546 || filters.unlisted_deps
547 || filters.duplicate_exports
548 || filters.circular_deps
549 || filters.re_export_cycles
550 || filters.boundary_violations
551 || filters.policy_violations
552 || filters.stale_suppressions
553 || filters.unused_catalog_entries
554 || filters.empty_catalog_groups
555 || filters.unresolved_catalog_references
556 || filters.unused_dependency_overrides
557 || filters.misconfigured_dependency_overrides
558}
559
560fn apply_dead_code_core_filters(filters: &DeadCodeFilters, results: &mut AnalysisResults) {
561 if !filters.unused_files {
562 results.unused_files.clear();
563 }
564 if !filters.unused_exports {
565 results.unused_exports.clear();
566 }
567 if !filters.unused_types {
568 results.unused_types.clear();
569 }
570 if !filters.private_type_leaks {
571 results.private_type_leaks.clear();
572 }
573 if !filters.unused_deps {
574 clear_dead_code_dependency_findings(results);
575 }
576 if !filters.unused_enum_members {
577 results.unused_enum_members.clear();
578 }
579 if !filters.unused_class_members {
580 results.unused_class_members.clear();
581 }
582 if !filters.unused_store_members {
583 results.unused_store_members.clear();
584 }
585 if !filters.unlisted_deps {
586 results.unlisted_dependencies.clear();
587 }
588}
589
590fn clear_dead_code_dependency_findings(results: &mut AnalysisResults) {
591 results.unused_dependencies.clear();
592 results.unused_dev_dependencies.clear();
593 results.unused_optional_dependencies.clear();
594 results.type_only_dependencies.clear();
595 results.test_only_dependencies.clear();
596 results.dev_dependencies_in_production.clear();
597}
598
599fn apply_dead_code_component_filters(filters: &DeadCodeFilters, results: &mut AnalysisResults) {
600 if !filters.unprovided_injects {
601 results.unprovided_injects.clear();
602 }
603 if !filters.unrendered_components {
604 results.unrendered_components.clear();
605 }
606 if !filters.unused_component_props {
607 results.unused_component_props.clear();
608 }
609 if !filters.unused_component_emits {
610 results.unused_component_emits.clear();
611 }
612 if !filters.unused_component_inputs {
613 results.unused_component_inputs.clear();
614 }
615 if !filters.unused_component_outputs {
616 results.unused_component_outputs.clear();
617 }
618 if !filters.unused_svelte_events {
619 results.unused_svelte_events.clear();
620 }
621 if !filters.unused_server_actions {
622 results.unused_server_actions.clear();
623 }
624 if !filters.unused_load_data_keys {
625 results.unused_load_data_keys.clear();
626 }
627 if !filters.unresolved_imports {
628 results.unresolved_imports.clear();
629 }
630}
631
632fn apply_dead_code_graph_filters(filters: &DeadCodeFilters, results: &mut AnalysisResults) {
633 if !filters.duplicate_exports {
634 results.duplicate_exports.clear();
635 }
636 if !filters.circular_deps {
637 results.circular_dependencies.clear();
638 }
639 if !filters.re_export_cycles {
640 results.re_export_cycles.clear();
641 }
642 if !filters.boundary_violations {
643 results.boundary_violations.clear();
644 results.boundary_coverage_violations.clear();
645 results.boundary_call_violations.clear();
646 }
647}
648
649fn apply_dead_code_policy_filters(filters: &DeadCodeFilters, results: &mut AnalysisResults) {
650 if !filters.policy_violations {
651 results.policy_violations.clear();
652 }
653 if !filters.stale_suppressions {
654 results.stale_suppressions.clear();
655 }
656}
657
658fn apply_dead_code_catalog_filters(filters: &DeadCodeFilters, results: &mut AnalysisResults) {
659 if !filters.unused_catalog_entries {
660 results.unused_catalog_entries.clear();
661 }
662 if !filters.empty_catalog_groups {
663 results.empty_catalog_groups.clear();
664 }
665 if !filters.unresolved_catalog_references {
666 results.unresolved_catalog_references.clear();
667 }
668 if !filters.unused_dependency_overrides {
669 results.unused_dependency_overrides.clear();
670 }
671 if !filters.misconfigured_dependency_overrides {
672 results.misconfigured_dependency_overrides.clear();
673 }
674}