ryo_executor/executor/
cascade_convert.rs1use ryo_analysis::cascade::{CascadeSpec, Visibility as CascadeVisibility};
20
21use super::spec::{InsertPosition, MutationSpec, MutationTargetSymbol, Visibility};
22
23impl From<CascadeSpec> for MutationSpec {
24 fn from(cascade: CascadeSpec) -> Self {
25 match cascade {
26 CascadeSpec::AddDerive { symbol_id, derives } => MutationSpec::AddDerive {
27 target: MutationTargetSymbol::ById(symbol_id),
28 derives,
29 },
30
31 CascadeSpec::GenerateImpl {
32 target,
33 trait_name,
34 call_new,
35 } => {
36 let body = if call_new {
37 format!("Self {{ inner: {}::new() }}", target.name())
38 } else {
39 "todo!()".to_string()
40 };
41
42 let parent = target.parent().unwrap_or_else(|| {
43 ryo_analysis::SymbolPath::parse("test_crate")
44 .expect("literal 'test_crate' is a valid SymbolPath")
45 });
46
47 MutationSpec::AddItem {
48 target: MutationTargetSymbol::ByPath(Box::new(parent)),
49 content: format!(
50 "impl {} for {} {{\n fn default() -> Self {{\n {}\n }}\n}}",
51 trait_name,
52 target.name(),
53 body
54 ),
55 position: InsertPosition::Bottom,
56 }
57 }
58
59 CascadeSpec::ChangeVisibility {
60 symbol_id,
61 visibility,
62 } => MutationSpec::ChangeVisibility {
63 target: MutationTargetSymbol::ById(symbol_id),
64 visibility: convert_visibility(visibility),
65 },
66
67 CascadeSpec::AddUse {
68 target_module,
69 path,
70 } => MutationSpec::AddItem {
71 target: MutationTargetSymbol::ByPath(Box::new(target_module)),
72 content: format!("use {};", path),
73 position: InsertPosition::Top,
74 },
75
76 CascadeSpec::AddMatchArm {
77 target,
78 function_name,
79 enum_name,
80 pattern,
81 body,
82 } => {
83 let fn_path = target
85 .child(&function_name)
86 .unwrap_or_else(|_| target.clone());
87 MutationSpec::AddMatchArm {
88 target: MutationTargetSymbol::ByPath(Box::new(fn_path)),
89 enum_name,
90 pattern,
91 body,
92 }
93 }
94
95 CascadeSpec::RemoveMatchArm {
96 target,
97 function_name,
98 enum_name,
99 pattern,
100 } => {
101 let fn_path = target
102 .child(&function_name)
103 .unwrap_or_else(|_| target.clone());
104 MutationSpec::RemoveMatchArm {
105 target: MutationTargetSymbol::ByPath(Box::new(fn_path)),
106 enum_name,
107 pattern,
108 }
109 }
110 }
111 }
112}
113
114fn convert_visibility(vis: CascadeVisibility) -> Visibility {
116 match vis {
117 CascadeVisibility::Private => Visibility::Private,
118 CascadeVisibility::Crate => Visibility::PubCrate,
119 CascadeVisibility::Super => Visibility::PubSuper,
120 CascadeVisibility::Public => Visibility::Pub,
121 }
122}
123
124pub fn convert_cascade_specs(specs: Vec<CascadeSpec>) -> Vec<MutationSpec> {
126 specs.into_iter().map(Into::into).collect()
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use ryo_analysis::SymbolPath;
133 use ryo_symbol::SymbolId;
134
135 fn dummy_id(index: u32) -> SymbolId {
137 SymbolId::parse(&format!("{}v1", index)).expect("valid dummy id")
138 }
139
140 #[test]
141 fn test_add_derive_conversion() {
142 let _path = SymbolPath::parse("test_crate::Config").unwrap();
143 let symbol_id = dummy_id(1);
144 let cascade = CascadeSpec::AddDerive {
145 symbol_id,
146 derives: vec!["Default".to_string(), "Debug".to_string()],
147 };
148
149 let mutation: MutationSpec = cascade.into();
150
151 match mutation {
152 MutationSpec::AddDerive {
153 target, derives, ..
154 } => {
155 assert_eq!(target, MutationTargetSymbol::ById(symbol_id));
156 assert_eq!(derives, vec!["Default", "Debug"]);
157 }
158 _ => panic!("Expected AddDerive"),
159 }
160 }
161
162 #[test]
163 fn test_change_visibility_conversion() {
164 let _path = SymbolPath::parse("test_crate::internal::Helper").unwrap();
165 let symbol_id = dummy_id(2);
166 let cascade = CascadeSpec::ChangeVisibility {
167 symbol_id,
168 visibility: CascadeVisibility::Public,
169 };
170
171 let mutation: MutationSpec = cascade.into();
172
173 match mutation {
174 MutationSpec::ChangeVisibility {
175 target, visibility, ..
176 } => {
177 assert_eq!(target, MutationTargetSymbol::ById(symbol_id));
178 assert!(matches!(visibility, Visibility::Pub));
179 }
180 _ => panic!("Expected ChangeVisibility"),
181 }
182 }
183
184 #[test]
185 fn test_add_use_conversion() {
186 let path = SymbolPath::parse("test_crate::module").unwrap();
187 let cascade = CascadeSpec::AddUse {
188 target_module: path.clone(),
189 path: "std::collections::HashMap".to_string(),
190 };
191
192 let mutation: MutationSpec = cascade.into();
193
194 match mutation {
195 MutationSpec::AddItem {
196 target,
197 content,
198 position,
199 } => {
200 if let MutationTargetSymbol::ByPath(target_path) = target {
201 assert_eq!(*target_path, path);
202 } else {
203 panic!("Expected ByPath target");
204 }
205 assert_eq!(content, "use std::collections::HashMap;");
206 assert_eq!(position, InsertPosition::Top);
207 }
208 _ => panic!("Expected AddItem"),
209 }
210 }
211}