Skip to main content

ryo_executor/engine/impls/
bool_simplify.rs

1//! V2 ASTRegApply implementation for BoolSimplifyMutation
2//!
3//! Simplifies boolean comparisons:
4//! - `x == true` → `x`
5//! - `x == false` → `!x`
6//! - `true == x` → `x`
7//! - `false == x` → `!x`
8
9use 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};
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            // Target function specified: direct lookup
22            if let Some(PureItem::Fn(f)) = ctx.ast_registry.get_mut(target_id) {
23                total_changes += self.transform_block(&mut f.body);
24            }
25        } else {
26            // No target: process all functions
27            let fn_ids: Vec<_> = ctx
28                .symbol_registry
29                .iter()
30                .filter(|(id, _)| {
31                    matches!(ctx.symbol_registry.kind(*id), Some(SymbolKind::Function))
32                })
33                .map(|(id, _)| id)
34                .collect();
35
36            for id in fn_ids {
37                if let Some(PureItem::Fn(f)) = ctx.ast_registry.get_mut(id) {
38                    total_changes += self.transform_block(&mut f.body);
39                }
40            }
41
42            // Process impl blocks (methods)
43            let impl_ids: Vec<_> = ctx
44                .symbol_registry
45                .iter()
46                .filter(|(id, _)| matches!(ctx.symbol_registry.kind(*id), Some(SymbolKind::Impl)))
47                .map(|(id, _)| id)
48                .collect();
49
50            for id in impl_ids {
51                if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get_mut(id) {
52                    for impl_item in &mut imp.items {
53                        if let PureImplItem::Fn(f) = impl_item {
54                            total_changes += self.transform_block(&mut f.body);
55                        }
56                    }
57                }
58            }
59        }
60
61        MutationResult {
62            mutation_type: self.mutation_type().to_string(),
63            changes: total_changes,
64            description: if total_changes > 0 {
65                format!("Simplified {} boolean comparison(s)", total_changes)
66            } else {
67                "No boolean comparisons simplified".to_string()
68            },
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::engine::ASTMutationEngine;
77    use ryo_analysis::testing::ContextBuilder;
78
79    #[test]
80    fn test_v2_bool_simplify_eq_true() {
81        let mut ctx = ContextBuilder::new()
82            .with_file(
83                "src/lib.rs",
84                r#"
85fn check(x: bool) -> bool {
86    x == true
87}
88"#,
89            )
90            .build();
91
92        let mutation = BoolSimplifyMutation::new();
93        let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
94
95        assert_eq!(result.result.changes, 1);
96    }
97
98    #[test]
99    fn test_v2_bool_simplify_eq_false() {
100        let mut ctx = ContextBuilder::new()
101            .with_file(
102                "src/lib.rs",
103                r#"
104fn check(x: bool) -> bool {
105    x == false
106}
107"#,
108            )
109            .build();
110
111        let mutation = BoolSimplifyMutation::new();
112        let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
113
114        assert_eq!(result.result.changes, 1);
115    }
116
117    #[test]
118    fn test_v2_bool_simplify_in_if() {
119        let mut ctx = ContextBuilder::new()
120            .with_file(
121                "src/lib.rs",
122                r#"
123fn process(flag: bool) {
124    if flag == true {
125        println!("yes");
126    }
127}
128"#,
129            )
130            .build();
131
132        let mutation = BoolSimplifyMutation::new();
133        let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
134
135        assert_eq!(result.result.changes, 1);
136    }
137
138    #[test]
139    fn test_v2_bool_simplify_no_changes() {
140        let mut ctx = ContextBuilder::new()
141            .with_file(
142                "src/lib.rs",
143                r#"
144fn check(x: bool) -> bool {
145    x
146}
147"#,
148            )
149            .build();
150
151        let mutation = BoolSimplifyMutation::new();
152        let result = ASTMutationEngine::execute_ast_reg(&mutation, &mut ctx);
153
154        assert_eq!(result.result.changes, 0);
155    }
156}