use std::collections::HashMap;
use syn::{
Expr, File, ItemUse, Macro, Path, UseTree,
visit_mut::{self, VisitMut},
};
struct DependencyResolver {
pub mappings: HashMap<String, String>,
}
impl DependencyResolver {
fn new() -> Self {
Self {
mappings: HashMap::new(),
}
}
}
impl<'ast> VisitMut for DependencyResolver {
fn visit_item_use_mut(&mut self, i: &mut ItemUse) {
if let UseTree::Path(path) = &i.tree {
if let UseTree::Name(name) = &*path.tree {
let crate_name = path.ident.to_string();
let item_name = name.ident.to_string();
if crate_name != "crate" && crate_name != "std" && crate_name != "core" {
let full_path = format!("{}::{}", crate_name, item_name);
self.mappings.insert(item_name, full_path);
}
}
}
visit_mut::visit_item_use_mut(self, i);
}
}
struct PathRewriter {
pub mappings: HashMap<String, String>,
}
impl PathRewriter {
fn rewrite_macro(mac: &mut Macro, mappings: &HashMap<String, String>) {
if let Ok(mut expr) = syn::parse2::<Expr>(mac.tokens.clone()) {
let mut rewriter = PathRewriter {
mappings: mappings.clone(),
};
visit_mut::visit_expr_mut(&mut rewriter, &mut expr);
mac.tokens = quote::quote!(#expr);
}
}
}
impl VisitMut for PathRewriter {
fn visit_expr_mut(&mut self, expr: &mut Expr) {
match expr {
Expr::Macro(expr_mac) => {
let is_op = expr_mac
.mac
.path
.segments
.last()
.map_or(false, |s| s.ident == "op");
if is_op {
Self::rewrite_macro(&mut expr_mac.mac, &self.mappings);
} else {
visit_mut::visit_expr_mut(self, expr);
}
}
_ => {
visit_mut::visit_expr_mut(self, expr);
if let Expr::Path(path_expr) = expr {
if !path_expr.path.segments.is_empty() && path_expr.qself.is_none() {
let first_ident = &path_expr.path.segments[0].ident;
let name = first_ident.to_string();
if path_expr.path.segments.len() == 1 {
if let Some(full_path_str) = self.mappings.get(&name) {
if let Ok(new_path) = syn::parse_str::<Path>(full_path_str) {
path_expr.path = new_path;
}
}
}
}
}
}
}
}
}
pub fn process_file(mut file: File) -> File {
let mut resolver = DependencyResolver::new();
resolver.visit_file_mut(&mut file);
let mut rewriter = PathRewriter {
mappings: resolver.mappings,
};
rewriter.visit_file_mut(&mut file);
file
}