Skip to main content

ryo_mutations/basic/stmt/
insert_statement.rs

1//! InsertStatementMutation: Insert statements at specific positions
2//!
3//! Insert a statement at the start, end, or relative to another statement:
4//! ```ignore
5//! fn example() {
6//!     // <- Insert at Start
7//!     do_work();
8//!     // <- Insert at End
9//! }
10//! ```
11//!
12//! # Matching strategy (BeforePattern / AfterPattern)
13//!
14//! `reference_stmt` (PureStmt) に対して PartialEq で厳密比較する。
15//! これは RemoveStatement の `stmt_matches_pattern`(文字列パターン照合)とは
16//! 意図的に異なる方式である。
17//!
18//! - **InsertStatement**: 「この特定の文の隣に挿入」→ 正確な位置特定が必要 → PartialEq
19//! - **RemoveStatement**: 「パターンに合う文を除去」→ 柔軟な照合が必要 → 文字列パターン
20//!
21//! `reference_stmt` は converter 側で `syn::parse_str` → `to_pure()` により生成される。
22//! 元ソースコードも同じ `syn::parse_file` → `to_pure()` パイプラインを経由するため、
23//! 同一の Rust コード文字列からは同一の PureStmt が生成される。
24
25use ryo_source::pure::PureStmt;
26use ryo_symbol::SymbolId;
27
28use crate::Mutation;
29
30/// Position for inserting statements
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
32pub enum InsertPosition {
33    /// At the start of the function body
34    Start,
35    /// At the end of the function body (before return statement if any)
36    #[default]
37    End,
38    /// Before a statement matching the reference pattern
39    BeforePattern,
40    /// After a statement matching the reference pattern
41    AfterPattern,
42}
43
44/// Insert a statement at a specific position
45#[derive(Debug, Clone)]
46pub struct InsertStatementMutation {
47    /// Statement to insert
48    pub stmt: PureStmt,
49    /// Target function SymbolId
50    pub target_fn: SymbolId,
51    /// Insert position
52    pub position: InsertPosition,
53    /// Reference statement for BeforePattern/AfterPattern.
54    /// Matched via PartialEq (exact structural match).
55    pub reference_stmt: Option<PureStmt>,
56}
57
58impl InsertStatementMutation {
59    pub fn new(stmt: PureStmt, target_fn: SymbolId) -> Self {
60        Self {
61            stmt,
62            target_fn,
63            position: InsertPosition::End,
64            reference_stmt: None,
65        }
66    }
67
68    /// Insert at the start of the function
69    pub fn at_start(mut self) -> Self {
70        self.position = InsertPosition::Start;
71        self
72    }
73
74    /// Insert at the end of the function
75    pub fn at_end(mut self) -> Self {
76        self.position = InsertPosition::End;
77        self
78    }
79
80    /// Insert before a statement matching the reference
81    pub fn before(mut self, reference_stmt: PureStmt) -> Self {
82        self.position = InsertPosition::BeforePattern;
83        self.reference_stmt = Some(reference_stmt);
84        self
85    }
86
87    /// Insert after a statement matching the reference
88    pub fn after(mut self, reference_stmt: PureStmt) -> Self {
89        self.position = InsertPosition::AfterPattern;
90        self.reference_stmt = Some(reference_stmt);
91        self
92    }
93}
94
95impl Mutation for InsertStatementMutation {
96    fn describe(&self) -> String {
97        format!(
98            "Insert statement in function '{}' at {:?}",
99            self.target_fn, self.position
100        )
101    }
102
103    fn mutation_type(&self) -> &'static str {
104        "InsertStatement"
105    }
106
107    fn box_clone(&self) -> Box<dyn Mutation> {
108        Box::new(self.clone())
109    }
110}