use std::collections::HashMap;
use syn::spanned::Spanned;
use syn::UseTree;
fn for_each_use_tree<F: FnMut(&UseTree)>(ast: &syn::File, mut f: F) {
ast.items
.iter()
.filter_map(|item| match item {
syn::Item::Use(u) => Some(u),
_ => None,
})
.for_each(|u| f(&u.tree));
}
pub fn gather_imports(ast: &syn::File) -> Vec<(Vec<String>, proc_macro2::Span)> {
let mut out = Vec::new();
for_each_use_tree(ast, |tree| collect_use_paths(&[], tree, &mut out));
out
}
pub fn collect_use_paths(
prefix: &[String],
tree: &UseTree,
out: &mut Vec<(Vec<String>, proc_macro2::Span)>,
) {
match tree {
UseTree::Path(p) => {
let mut next = prefix.to_vec();
next.push(p.ident.to_string());
collect_use_paths(&next, &p.tree, out);
}
UseTree::Name(n) => {
let mut full = prefix.to_vec();
full.push(n.ident.to_string());
out.push((full, n.ident.span()));
}
UseTree::Rename(r) => {
let mut full = prefix.to_vec();
full.push(r.ident.to_string());
out.push((full, r.ident.span()));
}
UseTree::Glob(g) => {
out.push((prefix.to_vec(), g.span()));
}
UseTree::Group(g) => {
for sub in &g.items {
collect_use_paths(prefix, sub, out);
}
}
}
}
pub fn gather_alias_map(ast: &syn::File) -> HashMap<String, Vec<String>> {
let mut out = HashMap::new();
for_each_use_tree(ast, |tree| collect_alias_entries(&[], tree, &mut out));
out
}
fn collect_alias_entries(
prefix: &[String],
tree: &UseTree,
out: &mut HashMap<String, Vec<String>>,
) {
match tree {
UseTree::Path(p) => {
let mut next = prefix.to_vec();
next.push(p.ident.to_string());
collect_alias_entries(&next, &p.tree, out);
}
UseTree::Name(n) => {
let ident = n.ident.to_string();
if ident == "self" {
if let Some(last) = prefix.last().cloned() {
out.insert(last, prefix.to_vec());
}
} else {
let mut full = prefix.to_vec();
full.push(ident.clone());
out.insert(ident, full);
}
}
UseTree::Rename(r) => {
if r.ident == "self" {
if prefix.is_empty() {
out.insert(r.rename.to_string(), vec!["self".to_string()]);
} else {
out.insert(r.rename.to_string(), prefix.to_vec());
}
} else {
let mut full = prefix.to_vec();
full.push(r.ident.to_string());
out.insert(r.rename.to_string(), full);
}
}
UseTree::Glob(_) => {
}
UseTree::Group(g) => {
for sub in &g.items {
collect_alias_entries(prefix, sub, out);
}
}
}
}