pub struct ArithmeticOperatorReplacement;
impl MutationOperator for ArithmeticOperatorReplacement {
fn name(&self) -> &str {
"AOR"
}
fn operator_type(&self) -> MutationOperatorType {
MutationOperatorType::ArithmeticReplacement
}
fn can_mutate(&self, expr: &Expr) -> bool {
matches!(expr, Expr::Binary(bin) if is_arithmetic_op(&bin.op))
}
fn mutate(&self, expr: &Expr, _location: SourceLocation) -> Result<Vec<Expr>> {
if let Expr::Binary(bin) = expr {
let mutants = mutate_arithmetic_op(bin);
return Ok(mutants);
}
Ok(vec![])
}
fn kill_probability(&self) -> f64 {
0.85 }
}
fn mutate_arithmetic_op(bin: &syn::ExprBinary) -> Vec<Expr> {
let replacements: &[BinOp] = match bin.op {
BinOp::Add(_) => &[
BinOp::Sub(Default::default()),
BinOp::Mul(Default::default()),
BinOp::Div(Default::default()),
],
BinOp::Sub(_) => &[
BinOp::Add(Default::default()),
BinOp::Mul(Default::default()),
BinOp::Div(Default::default()),
],
BinOp::Mul(_) => &[
BinOp::Add(Default::default()),
BinOp::Sub(Default::default()),
BinOp::Div(Default::default()),
],
BinOp::Div(_) => &[
BinOp::Add(Default::default()),
BinOp::Sub(Default::default()),
BinOp::Mul(Default::default()),
],
BinOp::Rem(_) => &[
BinOp::Mul(Default::default()),
BinOp::Div(Default::default()),
],
_ => &[],
};
apply_binary_replacements(bin, replacements)
}
fn apply_binary_replacements(bin: &syn::ExprBinary, ops: &[BinOp]) -> Vec<Expr> {
ops.iter()
.map(|&new_op| {
let mut mutated = bin.clone();
mutated.op = new_op;
Expr::Binary(mutated)
})
.collect()
}
pub struct RelationalOperatorReplacement;
impl MutationOperator for RelationalOperatorReplacement {
fn name(&self) -> &str {
"ROR"
}
fn operator_type(&self) -> MutationOperatorType {
MutationOperatorType::RelationalReplacement
}
fn can_mutate(&self, expr: &Expr) -> bool {
matches!(expr, Expr::Binary(bin) if is_relational_op(&bin.op))
}
fn mutate(&self, expr: &Expr, _location: SourceLocation) -> Result<Vec<Expr>> {
if let Expr::Binary(bin) = expr {
let mutants = mutate_relational_op(bin);
return Ok(mutants);
}
Ok(vec![])
}
fn kill_probability(&self) -> f64 {
0.90 }
}
fn mutate_relational_op(bin: &syn::ExprBinary) -> Vec<Expr> {
let replacements: &[BinOp] = match bin.op {
BinOp::Lt(_) => &[
BinOp::Le(Default::default()),
BinOp::Gt(Default::default()),
BinOp::Ge(Default::default()),
BinOp::Eq(Default::default()),
BinOp::Ne(Default::default()),
],
BinOp::Le(_) => &[
BinOp::Lt(Default::default()),
BinOp::Gt(Default::default()),
BinOp::Ge(Default::default()),
BinOp::Eq(Default::default()),
BinOp::Ne(Default::default()),
],
BinOp::Gt(_) => &[
BinOp::Lt(Default::default()),
BinOp::Le(Default::default()),
BinOp::Ge(Default::default()),
BinOp::Eq(Default::default()),
BinOp::Ne(Default::default()),
],
BinOp::Ge(_) => &[
BinOp::Lt(Default::default()),
BinOp::Le(Default::default()),
BinOp::Gt(Default::default()),
BinOp::Eq(Default::default()),
BinOp::Ne(Default::default()),
],
BinOp::Eq(_) => &[
BinOp::Ne(Default::default()),
BinOp::Lt(Default::default()),
BinOp::Le(Default::default()),
BinOp::Gt(Default::default()),
BinOp::Ge(Default::default()),
],
BinOp::Ne(_) => &[
BinOp::Eq(Default::default()),
BinOp::Lt(Default::default()),
BinOp::Le(Default::default()),
BinOp::Gt(Default::default()),
BinOp::Ge(Default::default()),
],
_ => &[],
};
apply_binary_replacements(bin, replacements)
}
pub struct ConditionalOperatorReplacement;
impl MutationOperator for ConditionalOperatorReplacement {
fn name(&self) -> &str {
"COR"
}
fn operator_type(&self) -> MutationOperatorType {
MutationOperatorType::ConditionalReplacement
}
fn can_mutate(&self, expr: &Expr) -> bool {
matches!(expr, Expr::Binary(bin) if is_logical_op(&bin.op))
}
fn mutate(&self, expr: &Expr, _location: SourceLocation) -> Result<Vec<Expr>> {
if let Expr::Binary(bin) = expr {
let replacement = match bin.op {
BinOp::And(_) => Some(BinOp::Or(Default::default())),
BinOp::Or(_) => Some(BinOp::And(Default::default())),
_ => None,
};
if let Some(new_op) = replacement {
let mut mutated = bin.clone();
mutated.op = new_op;
return Ok(vec![Expr::Binary(mutated)]);
}
}
Ok(vec![])
}
fn kill_probability(&self) -> f64 {
0.80 }
}
pub struct UnaryOperatorReplacement;
impl MutationOperator for UnaryOperatorReplacement {
fn name(&self) -> &str {
"UOR"
}
fn operator_type(&self) -> MutationOperatorType {
MutationOperatorType::UnaryReplacement
}
fn can_mutate(&self, expr: &Expr) -> bool {
matches!(expr, Expr::Unary(_))
}
fn mutate(&self, expr: &Expr, _location: SourceLocation) -> Result<Vec<Expr>> {
if let Expr::Unary(unary) = expr {
match unary.op {
UnOp::Not(_) => {
Ok(vec![(*unary.expr).clone()])
}
UnOp::Neg(_) => {
Ok(vec![(*unary.expr).clone()])
}
_ => Ok(vec![]),
}
} else {
Ok(vec![])
}
}
fn kill_probability(&self) -> f64 {
0.75
}
}
pub(crate) fn is_arithmetic_op(op: &BinOp) -> bool {
matches!(
op,
BinOp::Add(_) | BinOp::Sub(_) | BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_)
)
}
pub(crate) fn is_relational_op(op: &BinOp) -> bool {
matches!(
op,
BinOp::Lt(_) | BinOp::Le(_) | BinOp::Gt(_) | BinOp::Ge(_) | BinOp::Eq(_) | BinOp::Ne(_)
)
}
pub(crate) fn is_logical_op(op: &BinOp) -> bool {
matches!(op, BinOp::And(_) | BinOp::Or(_))
}