ryo-mutations 0.1.0

[experimental] Code transformation primitives for Rust source code
Documentation
//! InsertStatementMutation: Insert statements at specific positions
//!
//! Insert a statement at the start, end, or relative to another statement:
//! ```ignore
//! fn example() {
//!     // <- Insert at Start
//!     do_work();
//!     // <- Insert at End
//! }
//! ```
//!
//! # Matching strategy (BeforePattern / AfterPattern)
//!
//! `reference_stmt` (PureStmt) に対して PartialEq で厳密比較する。
//! これは RemoveStatement の `stmt_matches_pattern`(文字列パターン照合)とは
//! 意図的に異なる方式である。
//!
//! - **InsertStatement**: 「この特定の文の隣に挿入」→ 正確な位置特定が必要 → PartialEq
//! - **RemoveStatement**: 「パターンに合う文を除去」→ 柔軟な照合が必要 → 文字列パターン
//!
//! `reference_stmt` は converter 側で `syn::parse_str` → `to_pure()` により生成される。
//! 元ソースコードも同じ `syn::parse_file` → `to_pure()` パイプラインを経由するため、
//! 同一の Rust コード文字列からは同一の PureStmt が生成される。

use ryo_source::pure::PureStmt;
use ryo_symbol::SymbolId;

use crate::Mutation;

/// Position for inserting statements
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum InsertPosition {
    /// At the start of the function body
    Start,
    /// At the end of the function body (before return statement if any)
    #[default]
    End,
    /// Before a statement matching the reference pattern
    BeforePattern,
    /// After a statement matching the reference pattern
    AfterPattern,
}

/// Insert a statement at a specific position
#[derive(Debug, Clone)]
pub struct InsertStatementMutation {
    /// Statement to insert
    pub stmt: PureStmt,
    /// Target function SymbolId
    pub target_fn: SymbolId,
    /// Insert position
    pub position: InsertPosition,
    /// Reference statement for BeforePattern/AfterPattern.
    /// Matched via PartialEq (exact structural match).
    pub reference_stmt: Option<PureStmt>,
}

impl InsertStatementMutation {
    pub fn new(stmt: PureStmt, target_fn: SymbolId) -> Self {
        Self {
            stmt,
            target_fn,
            position: InsertPosition::End,
            reference_stmt: None,
        }
    }

    /// Insert at the start of the function
    pub fn at_start(mut self) -> Self {
        self.position = InsertPosition::Start;
        self
    }

    /// Insert at the end of the function
    pub fn at_end(mut self) -> Self {
        self.position = InsertPosition::End;
        self
    }

    /// Insert before a statement matching the reference
    pub fn before(mut self, reference_stmt: PureStmt) -> Self {
        self.position = InsertPosition::BeforePattern;
        self.reference_stmt = Some(reference_stmt);
        self
    }

    /// Insert after a statement matching the reference
    pub fn after(mut self, reference_stmt: PureStmt) -> Self {
        self.position = InsertPosition::AfterPattern;
        self.reference_stmt = Some(reference_stmt);
        self
    }
}

impl Mutation for InsertStatementMutation {
    fn describe(&self) -> String {
        format!(
            "Insert statement in function '{}' at {:?}",
            self.target_fn, self.position
        )
    }

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

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