generate_code/
types.rs

1use std::collections::HashMap;
2
3use syn::{
4    parse_quote,
5    visit_mut::{visit_file_mut, VisitMut},
6    File, Ident, ItemUse, Path, PathSegment, TypePath, UseTree,
7};
8
9pub fn qualify_types(mut file: File) -> File {
10    let use_items = collect_use_items(&file);
11
12    let mut map = HashMap::new();
13
14    for item in use_items {
15        // e.g. use swc_allocator::boxed::Box;
16        // becomes `Box: "swc_allocator::boxed::Box"` in the map.
17
18        for_each_use_item(&[], &item.tree, &mut |local_name, path| {
19            map.insert(local_name.to_string(), path);
20        });
21    }
22
23    map.entry("Option".into())
24        .or_insert_with(|| parse_quote!(::std::option::Option));
25
26    map.entry("Box".into())
27        .or_insert_with(|| parse_quote!(::std::boxed::Box));
28
29    map.entry("Vec".into())
30        .or_insert_with(|| parse_quote!(::std::vec::Vec));
31
32    visit_file_mut(&mut Folder { map }, &mut file);
33
34    file
35}
36
37fn for_each_use_item(path: &[Ident], tree: &UseTree, op: &mut impl FnMut(Ident, Path)) {
38    match tree {
39        UseTree::Path(p) => {
40            if p.ident == "self" || p.ident == "super" || p.ident == "crate" {
41                return;
42            }
43
44            let mut path = path.to_vec();
45            path.push(p.ident.clone());
46
47            for_each_use_item(&path, &p.tree, op);
48        }
49        UseTree::Name(name) => {
50            let mut path = path.to_vec();
51            path.push(name.ident.clone());
52            op(
53                name.ident.clone(),
54                Path {
55                    leading_colon: None,
56                    segments: path.into_iter().map(PathSegment::from).collect(),
57                },
58            );
59        }
60        UseTree::Rename(..) => {}
61        UseTree::Glob(_) => {}
62        UseTree::Group(g) => {
63            for item in &g.items {
64                for_each_use_item(path, item, op);
65            }
66        }
67    }
68}
69
70fn collect_use_items(file: &File) -> Vec<ItemUse> {
71    let mut use_items = Vec::new();
72    for item in &file.items {
73        if let syn::Item::Use(item_use) = item {
74            use_items.push(item_use.clone());
75        }
76    }
77    use_items
78}
79
80struct Folder {
81    /// e.g. `("Box", "std::boxed::Box")`
82    map: HashMap<String, Path>,
83}
84
85impl VisitMut for Folder {
86    fn visit_type_path_mut(&mut self, i: &mut TypePath) {
87        if let Some(id) = i.path.get_ident() {
88            if let Some(path) = self.map.get(&id.to_string()) {
89                i.path = path.clone();
90            }
91        }
92
93        syn::visit_mut::visit_type_path_mut(self, i);
94    }
95}