forge/mutation/mutators/
mod.rs1use std::path::PathBuf;
2
3use eyre::Result;
4use solar::ast::{Expr, ItemFunction, Span, VariableDefinition, yul};
5
6use crate::mutation::Mutant;
7
8pub mod assembly_mutator;
9pub mod assignment_mutator;
10pub mod binary_op_mutator;
11pub mod delete_expression_mutator;
12pub mod elim_delegate_mutator;
13pub mod function_body_mutator;
14pub mod mutator_registry;
15pub mod require_mutator;
16pub mod unary_op_mutator;
17
18pub trait Mutator: Send + Sync {
19 fn generate_mutants(&self, ctxt: &MutationContext<'_>) -> Result<Vec<Mutant>>;
21 fn is_applicable(&self, ctxt: &MutationContext<'_>) -> bool;
23}
24
25#[derive(Debug)]
26pub struct MutationContext<'a> {
27 pub path: PathBuf,
28 pub span: Span,
29 pub expr: Option<&'a Expr<'a>>,
31 pub var_definition: Option<&'a VariableDefinition<'a>>,
32 pub function: Option<&'a ItemFunction<'a>>,
33 pub yul_expr: Option<&'a yul::Expr<'a>>,
35 pub source: Option<&'a str>,
37}
38
39impl MutationContext<'_> {
40 pub fn original_text(&self) -> String {
42 self.source
43 .and_then(|src| {
44 let lo = self.span.lo().0 as usize;
45 let hi = self.span.hi().0 as usize;
46 src.get(lo..hi).map(|s| s.to_string())
47 })
48 .unwrap_or_default()
49 }
50
51 pub fn line_number(&self) -> usize {
53 self.source
54 .map(|src| {
55 let pos = self.span.lo().0 as usize;
56 src.get(..pos).map(|s| s.lines().count()).unwrap_or(0).max(1)
57 })
58 .unwrap_or(1)
59 }
60
61 pub fn column_number(&self) -> usize {
63 self.source
64 .map(|src| {
65 let pos = self.span.lo().0 as usize;
66 let line_start =
67 src.get(..pos).and_then(|s| s.rfind('\n')).map(|i| i + 1).unwrap_or(0);
68 pos - line_start + 1
69 })
70 .unwrap_or(1)
71 }
72
73 pub fn source_line(&self) -> String {
75 self.source
76 .and_then(|src| {
77 let pos = self.span.lo().0 as usize;
78 let line_start = src[..pos].rfind('\n').map(|i| i + 1).unwrap_or(0);
80 let line_end = src[pos..].find('\n').map(|i| pos + i).unwrap_or(src.len());
82 src.get(line_start..line_end).map(|s| s.trim().to_string())
83 })
84 .unwrap_or_default()
85 }
86}
87
88impl<'a> MutationContext<'a> {
89 #[must_use]
90 pub const fn builder() -> MutationContextBuilder<'a> {
91 MutationContextBuilder::new()
92 }
93}
94
95pub struct MutationContextBuilder<'a> {
96 path: Option<PathBuf>,
97 span: Option<Span>,
98 expr: Option<&'a Expr<'a>>,
99 var_definition: Option<&'a VariableDefinition<'a>>,
100 function: Option<&'a ItemFunction<'a>>,
101 yul_expr: Option<&'a yul::Expr<'a>>,
102 source: Option<&'a str>,
103}
104
105impl<'a> MutationContextBuilder<'a> {
106 pub const fn new() -> Self {
108 MutationContextBuilder {
109 path: None,
110 span: None,
111 expr: None,
112 var_definition: None,
113 function: None,
114 yul_expr: None,
115 source: None,
116 }
117 }
118
119 pub fn with_path(mut self, path: PathBuf) -> Self {
121 self.path = Some(path);
122 self
123 }
124
125 pub const fn with_span(mut self, span: Span) -> Self {
127 self.span = Some(span);
128 self
129 }
130
131 pub const fn with_expr(mut self, expr: &'a Expr<'a>) -> Self {
133 self.expr = Some(expr);
134 self
135 }
136
137 pub const fn with_var_definition(mut self, var_definition: &'a VariableDefinition<'a>) -> Self {
139 self.var_definition = Some(var_definition);
140 self
141 }
142
143 pub const fn with_function(mut self, function: &'a ItemFunction<'a>) -> Self {
144 self.function = Some(function);
145 self
146 }
147
148 pub const fn with_yul_expr(mut self, yul_expr: &'a yul::Expr<'a>) -> Self {
150 self.yul_expr = Some(yul_expr);
151 self
152 }
153
154 pub const fn with_source(mut self, source: &'a str) -> Self {
156 self.source = Some(source);
157 self
158 }
159
160 pub fn build(self) -> Result<MutationContext<'a>, &'static str> {
161 let span = self.span.ok_or("Span is required for MutationContext")?;
162 let path = self.path.ok_or("Path is required for MutationContext")?;
163
164 Ok(MutationContext {
165 path,
166 span,
167 expr: self.expr,
168 var_definition: self.var_definition,
169 function: self.function,
170 yul_expr: self.yul_expr,
171 source: self.source,
172 })
173 }
174}
175
176#[cfg(test)]
177mod tests;