fallow_engine/
cross_reference.rs1use rustc_hash::FxHashSet;
4use serde::Serialize;
5
6use crate::core_backend;
7use crate::duplicates::{CloneInstance, DuplicationReport};
8use crate::results::AnalysisResults;
9
10#[derive(Debug, Clone, Serialize)]
12pub struct CombinedFinding {
13 pub clone_instance: CloneInstance,
15 pub dead_code_kind: DeadCodeKind,
17 pub group_index: usize,
19}
20
21#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
23pub enum DeadCodeKind {
24 UnusedFile,
26 UnusedExport { export_name: String },
28 UnusedType { type_name: String },
30}
31
32#[derive(Debug, Clone, Serialize)]
34pub struct CrossReferenceResult {
35 pub combined_findings: Vec<CombinedFinding>,
37 pub clones_in_unused_files: usize,
39 pub clones_with_unused_exports: usize,
41}
42
43impl CrossReferenceResult {
44 #[must_use]
46 pub const fn total(&self) -> usize {
47 self.combined_findings.len()
48 }
49
50 #[must_use]
52 pub const fn has_findings(&self) -> bool {
53 !self.combined_findings.is_empty()
54 }
55
56 #[must_use]
58 pub fn affected_group_indices(&self) -> FxHashSet<usize> {
59 self.combined_findings
60 .iter()
61 .map(|finding| finding.group_index)
62 .collect()
63 }
64}
65
66#[must_use]
68pub fn cross_reference(
69 duplication: &DuplicationReport,
70 dead_code: &AnalysisResults,
71) -> CrossReferenceResult {
72 core_backend::cross_reference(duplication, dead_code)
73}
74
75#[cfg(test)]
76mod tests {
77 use std::path::PathBuf;
78
79 use super::*;
80
81 fn clone_instance(file: &str, start_line: usize, end_line: usize) -> CloneInstance {
82 CloneInstance {
83 file: PathBuf::from(file),
84 start_line,
85 end_line,
86 start_col: 0,
87 end_col: 0,
88 fragment: String::new(),
89 }
90 }
91
92 #[test]
93 fn cross_reference_result_methods_use_engine_owned_findings() {
94 let result = CrossReferenceResult {
95 combined_findings: vec![
96 CombinedFinding {
97 clone_instance: clone_instance("src/a.ts", 1, 3),
98 dead_code_kind: DeadCodeKind::UnusedFile,
99 group_index: 2,
100 },
101 CombinedFinding {
102 clone_instance: clone_instance("src/b.ts", 4, 8),
103 dead_code_kind: DeadCodeKind::UnusedExport {
104 export_name: "unused".to_string(),
105 },
106 group_index: 4,
107 },
108 ],
109 clones_in_unused_files: 1,
110 clones_with_unused_exports: 1,
111 };
112
113 assert_eq!(result.total(), 2);
114 assert!(result.has_findings());
115 assert!(result.affected_group_indices().contains(&2));
116 assert!(result.affected_group_indices().contains(&4));
117 }
118}