code_moniker_workspace/changes/semantic/
rollup.rs1use std::path::PathBuf;
2
3use super::model::{ChangeFacets, SemanticKind, SymbolChange};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub enum FileDisposition {
7 Added,
8 Removed,
9 Moved { pure: bool },
10 Modified,
11}
12
13impl FileDisposition {
14 pub fn label(self) -> &'static str {
15 match self {
16 Self::Added => "added",
17 Self::Removed => "removed",
18 Self::Moved { pure: true } => "moved",
19 Self::Moved { pure: false } => "moved-and-modified",
20 Self::Modified => "modified",
21 }
22 }
23}
24
25#[derive(Clone, Debug, Eq, PartialEq)]
26pub struct FileRollup {
27 pub old_path: Option<PathBuf>,
28 pub new_path: Option<PathBuf>,
29 pub disposition: FileDisposition,
30 pub symbol_changes: usize,
31 pub moved_symbols: usize,
32}
33
34impl FileRollup {
35 pub fn pure_move(old_path: PathBuf, new_path: PathBuf, moved_symbols: usize) -> Self {
36 Self {
37 old_path: Some(old_path),
38 new_path: Some(new_path),
39 disposition: FileDisposition::Moved { pure: true },
40 symbol_changes: 0,
41 moved_symbols,
42 }
43 }
44}
45
46pub fn moved_file_rollup(
47 old_path: PathBuf,
48 new_path: PathBuf,
49 changes: &[SymbolChange],
50) -> FileRollup {
51 let moved_symbols = changes
52 .iter()
53 .filter(|change| change.kind == SemanticKind::Moved)
54 .count();
55 let symbol_changes = changes
56 .iter()
57 .filter(|change| !is_pure_move(change))
58 .count();
59 FileRollup {
60 old_path: Some(old_path),
61 new_path: Some(new_path),
62 disposition: FileDisposition::Moved {
63 pure: symbol_changes == 0,
64 },
65 symbol_changes,
66 moved_symbols,
67 }
68}
69
70fn is_pure_move(change: &SymbolChange) -> bool {
71 change.kind == SemanticKind::Moved
72 && change.facets
73 == ChangeFacets {
74 file_moved: change.facets.file_moved,
75 ..ChangeFacets::default()
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::super::model::Confidence;
82 use super::*;
83
84 fn moved_change(facets: ChangeFacets) -> SymbolChange {
85 SymbolChange {
86 kind: SemanticKind::Moved,
87 confidence: Confidence::Certain,
88 facets,
89 old: None,
90 new: None,
91 }
92 }
93
94 #[test]
95 fn all_pure_moves_roll_up_as_a_pure_file_move() {
96 let facets = ChangeFacets {
97 file_moved: true,
98 ..ChangeFacets::default()
99 };
100 let rollup = moved_file_rollup(
101 PathBuf::from("src/old.rs"),
102 PathBuf::from("src/new.rs"),
103 &[moved_change(facets), moved_change(facets)],
104 );
105
106 assert_eq!(rollup.disposition, FileDisposition::Moved { pure: true });
107 assert_eq!(rollup.moved_symbols, 2);
108 assert_eq!(rollup.symbol_changes, 0);
109 }
110
111 #[test]
112 fn an_edited_symbol_makes_the_move_impure() {
113 let pure = ChangeFacets {
114 file_moved: true,
115 ..ChangeFacets::default()
116 };
117 let edited = ChangeFacets {
118 file_moved: true,
119 body_changed: true,
120 ..ChangeFacets::default()
121 };
122 let rollup = moved_file_rollup(
123 PathBuf::from("src/old.rs"),
124 PathBuf::from("src/new.rs"),
125 &[moved_change(pure), moved_change(edited)],
126 );
127
128 assert_eq!(rollup.disposition, FileDisposition::Moved { pure: false });
129 assert_eq!(rollup.symbol_changes, 1);
130 }
131}