80 lines
1.9 KiB
Rust
80 lines
1.9 KiB
Rust
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 mut input = Input::Match(input);
|
|
|
|
*out = match crate::check::sorted(&mut input) {
|
|
Ok(_) => parse_quote!(#input),
|
|
Err(err) => {
|
|
let err = err.to_compile_error();
|
|
parse_quote!({
|
|
#err
|
|
#input
|
|
})
|
|
}
|
|
};
|
|
}
|