use syn::spanned::Spanned;
use syn::visit::Visit;
use super::{MetaMutation, MetaOperator};
#[must_use]
#[inline]
pub fn discover(component: &'static str, source: &str) -> Vec<MetaMutation> {
let syntax = match syn::parse_file(source) {
Ok(s) => s,
Err(_) => return Vec::new(),
};
let mut visitor = DiscoveryVisitor {
component,
mutations: Vec::new(),
};
visitor.visit_file(&syntax);
visitor.mutations
}
struct DiscoveryVisitor {
component: &'static str,
mutations: Vec<MetaMutation>,
}
impl<'ast> Visit<'ast> for DiscoveryVisitor {
fn visit_expr_binary(&mut self, i: &'ast syn::ExprBinary) {
let span = i.op.span().start();
match i.op {
syn::BinOp::Eq(_) | syn::BinOp::Ne(_) | syn::BinOp::Lt(_) | syn::BinOp::Gt(_) => {
self.mutations.push(MetaMutation::Syntactic {
component: self.component,
operator: MetaOperator::SwapComparison,
line: span.line,
column: span.column,
});
}
_ => {}
}
match i.op {
syn::BinOp::Lt(_) | syn::BinOp::Gt(_) => {
self.mutations.push(MetaMutation::Syntactic {
component: self.component,
operator: MetaOperator::WeakenBound,
line: span.line,
column: span.column,
});
}
_ => {}
}
syn::visit::visit_expr_binary(self, i);
}
fn visit_expr_macro(&mut self, i: &'ast syn::ExprMacro) {
if i.mac.path.is_ident("assert") || i.mac.path.is_ident("assert_eq") {
let span = i.mac.path.span().start();
self.mutations.push(MetaMutation::Syntactic {
component: self.component,
operator: MetaOperator::DropAssertion,
line: span.line,
column: span.column,
});
}
syn::visit::visit_expr_macro(self, i);
}
fn visit_lit_int(&mut self, i: &'ast syn::LitInt) {
if let Ok(val) = i.base10_parse::<u64>() {
if val == 0 || val == 1 {
let span = i.span().start();
self.mutations.push(MetaMutation::Syntactic {
component: self.component,
operator: MetaOperator::OffByOne,
line: span.line,
column: span.column,
});
}
}
}
fn visit_expr_try(&mut self, i: &'ast syn::ExprTry) {
let span = i.question_token.span.start();
self.mutations.push(MetaMutation::Syntactic {
component: self.component,
operator: MetaOperator::SwallowError,
line: span.line,
column: span.column,
});
syn::visit::visit_expr_try(self, i);
}
}