ryo_executor/engine/impls/
bool_simplify.rs1use ryo_analysis::SymbolKind;
10use ryo_mutations::idiom::BoolSimplifyMutation;
11use ryo_mutations::{Mutation, MutationResult};
12use ryo_source::pure::{PureImplItem, PureItem};
13
14use crate::engine::{ASTMutationContext, ASTRegApply, ModificationType};
15
16impl ASTRegApply for BoolSimplifyMutation {
17 fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
18 let mut total_changes = 0;
19
20 if let Some(target_id) = self.target_fn {
21 if let Some(PureItem::Fn(f)) = ctx.ast_registry.get_mut(target_id) {
23 let changes = self.transform_block(&mut f.body);
24 if changes > 0 {
25 ctx.emit_modified(target_id, ModificationType::BodyModified);
26 total_changes += changes;
27 }
28 }
29 } else {
30 let fn_ids: Vec<_> = ctx
32 .symbol_registry
33 .iter()
34 .filter(|(id, _)| {
35 matches!(ctx.symbol_registry.kind(*id), Some(SymbolKind::Function))
36 })
37 .map(|(id, _)| id)
38 .collect();
39
40 for id in fn_ids {
41 if let Some(PureItem::Fn(f)) = ctx.ast_registry.get_mut(id) {
42 let changes = self.transform_block(&mut f.body);
43 if changes > 0 {
44 ctx.emit_modified(id, ModificationType::BodyModified);
45 total_changes += changes;
46 }
47 }
48 }
49
50 let impl_ids: Vec<_> = ctx
52 .symbol_registry
53 .iter()
54 .filter(|(id, _)| matches!(ctx.symbol_registry.kind(*id), Some(SymbolKind::Impl)))
55 .map(|(id, _)| id)
56 .collect();
57
58 for id in impl_ids {
59 let mut impl_changes = 0;
60 if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get_mut(id) {
61 for impl_item in &mut imp.items {
62 if let PureImplItem::Fn(f) = impl_item {
63 impl_changes += self.transform_block(&mut f.body);
64 }
65 }
66 }
67 if impl_changes > 0 {
68 ctx.emit_modified(id, ModificationType::BodyModified);
69 total_changes += impl_changes;
70 }
71 }
72 }
73
74 MutationResult {
75 mutation_type: self.mutation_type().to_string(),
76 changes: total_changes,
77 description: if total_changes > 0 {
78 format!("Simplified {} boolean comparison(s)", total_changes)
79 } else {
80 "No boolean comparisons simplified".to_string()
81 },
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::engine::ASTMutationEngine;
90 use ryo_analysis::testing::ContextBuilder;
91
92 #[test]
93 fn test_v2_bool_simplify_eq_true() {
94 let mut ctx = ContextBuilder::new()
95 .with_file(
96 "src/lib.rs",
97 r#"
98fn check(x: bool) -> bool {
99 x == true
100}
101"#,
102 )
103 .build();
104
105 let mutation = BoolSimplifyMutation::new();
106 let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
107
108 assert_eq!(result.result.changes, 1);
109 }
110
111 #[test]
112 fn test_v2_bool_simplify_eq_false() {
113 let mut ctx = ContextBuilder::new()
114 .with_file(
115 "src/lib.rs",
116 r#"
117fn check(x: bool) -> bool {
118 x == false
119}
120"#,
121 )
122 .build();
123
124 let mutation = BoolSimplifyMutation::new();
125 let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
126
127 assert_eq!(result.result.changes, 1);
128 }
129
130 #[test]
131 fn test_v2_bool_simplify_in_if() {
132 let mut ctx = ContextBuilder::new()
133 .with_file(
134 "src/lib.rs",
135 r#"
136fn process(flag: bool) {
137 if flag == true {
138 println!("yes");
139 }
140}
141"#,
142 )
143 .build();
144
145 let mutation = BoolSimplifyMutation::new();
146 let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
147
148 assert_eq!(result.result.changes, 1);
149 }
150
151 #[test]
152 fn test_v2_bool_simplify_no_changes() {
153 let mut ctx = ContextBuilder::new()
154 .with_file(
155 "src/lib.rs",
156 r#"
157fn check(x: bool) -> bool {
158 x
159}
160"#,
161 )
162 .build();
163
164 let mutation = BoolSimplifyMutation::new();
165 let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
166
167 assert_eq!(result.result.changes, 0);
168 }
169}