ryo-mutations 0.1.0

[experimental] Code transformation primitives for Rust source code
Documentation
//! Match arm mutations: AddMatchArmMutation, RemoveMatchArmMutation, ReplaceMatchArmMutation
//!
//! Adds, removes, or replaces match arms in existing match expressions.

use ryo_symbol::SymbolId;

use crate::Mutation;

/// Add a match arm to an existing match expression in a function
#[derive(Debug, Clone)]
pub struct AddMatchArmMutation {
    /// Target function SymbolId
    pub function_id: SymbolId,
    /// Enum name to identify the target match expression
    pub enum_name: String,
    /// Pattern string (e.g., "Status::Cancelled")
    pub pattern: String,
    /// Body string (e.g., "todo!()")
    pub body: String,
}

impl AddMatchArmMutation {
    pub fn new(
        function_id: SymbolId,
        enum_name: impl Into<String>,
        pattern: impl Into<String>,
        body: impl Into<String>,
    ) -> Self {
        Self {
            function_id,
            enum_name: enum_name.into(),
            pattern: pattern.into(),
            body: body.into(),
        }
    }
}

impl Mutation for AddMatchArmMutation {
    fn describe(&self) -> String {
        format!(
            "Add match arm '{}' => {} in function {}",
            self.pattern, self.body, self.function_id
        )
    }

    fn mutation_type(&self) -> &'static str {
        "AddMatchArm"
    }

    fn box_clone(&self) -> Box<dyn Mutation> {
        Box::new(self.clone())
    }
}

/// Remove a match arm from an existing match expression in a function
#[derive(Debug, Clone)]
pub struct RemoveMatchArmMutation {
    /// Target function SymbolId
    pub function_id: SymbolId,
    /// Enum name to identify the target match expression
    pub enum_name: String,
    /// Pattern string to remove (e.g., "Status::Completed")
    pub pattern: String,
}

impl RemoveMatchArmMutation {
    pub fn new(
        function_id: SymbolId,
        enum_name: impl Into<String>,
        pattern: impl Into<String>,
    ) -> Self {
        Self {
            function_id,
            enum_name: enum_name.into(),
            pattern: pattern.into(),
        }
    }
}

impl Mutation for RemoveMatchArmMutation {
    fn describe(&self) -> String {
        format!(
            "Remove match arm '{}' in function {}",
            self.pattern, self.function_id
        )
    }

    fn mutation_type(&self) -> &'static str {
        "RemoveMatchArm"
    }

    fn box_clone(&self) -> Box<dyn Mutation> {
        Box::new(self.clone())
    }
}

/// Replace a match arm (pattern + body) in an existing match expression
///
/// This mutation allows replacing both the pattern and body of a match arm
/// atomically, solving the issue where ReplaceExpr only modifies the body
/// but leaves the pattern unchanged.
#[derive(Debug, Clone)]
pub struct ReplaceMatchArmMutation {
    /// Target function SymbolId
    pub function_id: SymbolId,
    /// Enum name to identify the target match expression
    pub enum_name: String,
    /// Pattern to match for replacement (e.g., "PathSegment::Slice { start: _, end: _ }")
    pub old_pattern: String,
    /// New pattern string (e.g., "PathSegment::Slice { start, end }")
    pub new_pattern: String,
    /// New body string (e.g., "{ /* implementation */ }")
    pub new_body: String,
}

impl ReplaceMatchArmMutation {
    pub fn new(
        function_id: SymbolId,
        enum_name: impl Into<String>,
        old_pattern: impl Into<String>,
        new_pattern: impl Into<String>,
        new_body: impl Into<String>,
    ) -> Self {
        Self {
            function_id,
            enum_name: enum_name.into(),
            old_pattern: old_pattern.into(),
            new_pattern: new_pattern.into(),
            new_body: new_body.into(),
        }
    }
}

impl Mutation for ReplaceMatchArmMutation {
    fn describe(&self) -> String {
        format!(
            "Replace match arm '{}' with '{}' in function {}",
            self.old_pattern, self.new_pattern, self.function_id
        )
    }

    fn mutation_type(&self) -> &'static str {
        "ReplaceMatchArm"
    }

    fn box_clone(&self) -> Box<dyn Mutation> {
        Box::new(self.clone())
    }
}