blob: f681aa9afb451412f701ca1f0633e524e0b6ab3e [file] [log] [blame]
use quote::quote;
use syn::visit_mut::{self, VisitMut};
use syn::{parse_quote, Attribute, Expr, ExprMatch, ItemFn, Local};
use crate::parse::Input;
pub fn check(input: &mut ItemFn) {
Checker.visit_item_fn_mut(input);
}
struct Checker;
impl VisitMut for Checker {
fn visit_expr_mut(&mut self, expr: &mut Expr) {
visit_mut::visit_expr_mut(self, expr);
let expr_match = match expr {
Expr::Match(expr) => expr,
_ => return,
};
if !take_sorted_attr(&mut expr_match.attrs) {
return;
}
let input = expr_match.clone();
check_and_insert_error(input, expr);
}
fn visit_local_mut(&mut self, local: &mut Local) {
visit_mut::visit_local_mut(self, local);
let init = match &local.init {
Some((_, init)) => init,
None => return,
};
let expr_match = match init.as_ref() {
Expr::Match(expr) => expr,
_ => return,
};
if !take_sorted_attr(&mut local.attrs) {
return;
}
let input = expr_match.clone();
let expr = local.init.as_mut().unwrap().1.as_mut();
check_and_insert_error(input, expr);
}
}
fn take_sorted_attr(attrs: &mut Vec<Attribute>) -> bool {
for i in 0..attrs.len() {
let path = &attrs[i].path;
let path = quote!(#path).to_string();
if path == "sorted" || path == "remain :: sorted" {
attrs.remove(i);
return true;
}
}
false
}
fn check_and_insert_error(input: ExprMatch, out: &mut Expr) {
let original = quote!(#input);
let input = Input::Match(input);
if let Err(err) = crate::check::sorted(input) {
let err = err.to_compile_error();
*out = parse_quote!({
#err
#original
});
}
}