Skip to main content

code_moniker_workspace/changes/semantic/
rollup.rs

1use 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}