ryo_executor/engine/impls/
default.rs1use ryo_mutations::idiom::{DefaultMutation, DeriveDefaultMutation};
7use ryo_mutations::MutationResult;
8use ryo_source::pure::PureItem;
9use ryo_symbol::SymbolKind;
10
11use crate::engine::{ASTMutationContext, ASTRegApply};
12
13impl ASTRegApply for DefaultMutation {
14 fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
15 let mut total_changes = 0;
16
17 let struct_ids: Vec<_> = ctx
19 .symbol_registry
20 .iter()
21 .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Struct))
22 .map(|(id, path)| (id, path.name().to_string()))
23 .collect();
24
25 for (struct_id, struct_name) in struct_ids {
26 if let Some(ref target) = self.target_struct {
28 if &struct_name != target {
29 continue;
30 }
31 }
32
33 if let Some(PureItem::Struct(s)) = ctx.ast_registry.get(struct_id) {
34 let has_default = s.attrs.iter().any(|attr| {
36 attr.path == "derive"
37 && matches!(&attr.meta, ryo_source::pure::PureAttrMeta::List(args) if args.contains("Default"))
38 });
39
40 if has_default {
41 continue;
42 }
43
44 let has_named_fields = matches!(&s.fields, ryo_source::pure::PureFields::Named(_));
46 if !has_named_fields {
47 continue;
48 }
49
50 let mut new_struct = s.clone();
51
52 if self.use_derive {
53 let derive_attr_idx = new_struct
55 .attrs
56 .iter()
57 .position(|attr| attr.path == "derive");
58
59 if let Some(idx) = derive_attr_idx {
60 if let ryo_source::pure::PureAttrMeta::List(ref args) =
61 new_struct.attrs[idx].meta
62 {
63 if !args.contains("Default") {
64 new_struct.attrs[idx].meta = ryo_source::pure::PureAttrMeta::List(
65 format!("{}, Default", args),
66 );
67 }
68 }
69 } else {
70 new_struct.attrs.push(ryo_source::pure::PureAttribute {
71 path: "derive".to_string(),
72 meta: ryo_source::pure::PureAttrMeta::List("Default".to_string()),
73 is_inner: false,
74 });
75 }
76
77 ctx.set_ast(struct_id, PureItem::Struct(new_struct));
78 total_changes += 1;
79 }
80 }
83 }
84
85 MutationResult {
86 mutation_type: "Default".to_string(),
87 changes: total_changes,
88 description: if total_changes > 0 {
89 format!("Added #[derive(Default)] to {} struct(s)", total_changes)
90 } else {
91 "No Default implementations added".to_string()
92 },
93 }
94 }
95}
96
97impl ASTRegApply for DeriveDefaultMutation {
98 fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
99 let mut types_to_derive: Vec<(ryo_symbol::SymbolId, String)> = Vec::new();
101
102 let impl_ids: Vec<_> = ctx
103 .symbol_registry
104 .iter()
105 .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Impl))
106 .map(|(id, _)| id)
107 .collect();
108
109 for impl_id in impl_ids {
110 if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get(impl_id) {
111 if imp.trait_.as_deref() != Some("Default") {
113 continue;
114 }
115
116 if let Some(ref target) = self.target_type {
117 if &imp.self_ty != target {
118 continue;
119 }
120 }
121
122 types_to_derive.push((impl_id, imp.self_ty.clone()));
125 }
126 }
127
128 if types_to_derive.is_empty() {
129 return MutationResult {
130 mutation_type: "DeriveDefault".to_string(),
131 changes: 0,
132 description: "No derivable Default implementations found".to_string(),
133 };
134 }
135
136 let mut changes = 0;
137
138 for (impl_id, type_name) in &types_to_derive {
140 let struct_id = ctx
142 .symbol_registry
143 .iter()
144 .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Struct))
145 .find(|(_, path)| path.name() == type_name)
146 .map(|(id, _)| id);
147
148 if let Some(struct_id) = struct_id {
149 if let Some(PureItem::Struct(s)) = ctx.ast_registry.get(struct_id) {
150 let mut new_struct = s.clone();
151
152 let has_default = new_struct.attrs.iter().any(|attr| {
154 attr.path == "derive"
155 && matches!(&attr.meta, ryo_source::pure::PureAttrMeta::List(args) if args.contains("Default"))
156 });
157
158 if !has_default {
159 let derive_attr_idx = new_struct
161 .attrs
162 .iter()
163 .position(|attr| attr.path == "derive");
164
165 if let Some(idx) = derive_attr_idx {
166 if let ryo_source::pure::PureAttrMeta::List(ref args) =
167 new_struct.attrs[idx].meta
168 {
169 new_struct.attrs[idx].meta = ryo_source::pure::PureAttrMeta::List(
170 format!("{}, Default", args),
171 );
172 }
173 } else {
174 new_struct.attrs.push(ryo_source::pure::PureAttribute {
175 path: "derive".to_string(),
176 meta: ryo_source::pure::PureAttrMeta::List("Default".to_string()),
177 is_inner: false,
178 });
179 }
180
181 ctx.set_ast(struct_id, PureItem::Struct(new_struct));
182 changes += 1;
183 }
184 }
185 }
186
187 ctx.ast_registry.remove(*impl_id);
189 changes += 1;
190 }
191
192 MutationResult {
193 mutation_type: "DeriveDefault".to_string(),
194 changes,
195 description: format!(
196 "Converted {} manual Default impl(s) to #[derive(Default)]",
197 types_to_derive.len()
198 ),
199 }
200 }
201}