Some initial support for `pub(.*) use` aliasing in type resolution
authorMatt Corallo <git@bluematt.me>
Fri, 23 Dec 2022 20:18:34 +0000 (20:18 +0000)
committerMatt Corallo <git@bluematt.me>
Fri, 23 Dec 2022 20:31:16 +0000 (20:31 +0000)
c-bindings-gen/src/main.rs
c-bindings-gen/src/types.rs

index 8b57bd9d265c9cf3b91dbdb4bed19da21abef87d..02aa72fdc46c2c36241f270b3e9b547df47ee49b 100644 (file)
@@ -271,7 +271,7 @@ macro_rules! get_module_type_resolver {
                let mut module_iter = module.rsplitn(2, "::");
                module_iter.next().unwrap();
                let module = module_iter.next().unwrap();
-               let imports = ImportResolver::new(module.splitn(2, "::").next().unwrap(), &$crate_types.lib_ast.dependencies,
+               let imports = ImportResolver::new(module.splitn(2, "::").next().unwrap(), &$crate_types.lib_ast,
                                module, &$crate_types.lib_ast.modules.get(module).unwrap().items);
                TypeResolver::new(module, imports, $crate_types)
        } }
@@ -1430,7 +1430,7 @@ fn create_alias_for_impl<F: FnMut(syn::ItemImpl, &mut TypeResolver)>(resolved_pa
 
                        let alias_resolver_override;
                        let alias_resolver = if alias_module != types.module_path {
-                               alias_resolver_override = ImportResolver::new(types.types.crate_name, &types.crate_types.lib_ast.dependencies,
+                               alias_resolver_override = ImportResolver::new(types.types.crate_name, &types.crate_types.lib_ast,
                                        alias_module, &types.crate_types.lib_ast.modules.get(alias_module).unwrap().items);
                                &alias_resolver_override
                        } else { &types.types };
@@ -1924,7 +1924,7 @@ fn convert_priv_mod<'a, 'b: 'a, W: std::io::Write>(w: &mut W, w_uses: &mut HashS
                        use_items.push(item);
                }
        }
-       let import_resolver = ImportResolver::from_borrowed_items(mod_path.splitn(2, "::").next().unwrap(), &libast.dependencies, mod_path, &use_items);
+       let import_resolver = ImportResolver::from_borrowed_items(mod_path.splitn(2, "::").next().unwrap(), libast, mod_path, &use_items);
        let mut types = TypeResolver::new(mod_path, import_resolver, crate_types);
 
        writeln!(w, "mod {} {{\n{}", module.ident, DEFAULT_IMPORTS).unwrap();
@@ -2006,7 +2006,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
 
                eprintln!("Converting {} entries...", module);
 
-               let import_resolver = ImportResolver::new(orig_crate, &libast.dependencies, module, items);
+               let import_resolver = ImportResolver::new(orig_crate, libast, module, items);
                let mut type_resolver = TypeResolver::new(module, import_resolver, crate_types);
 
                for item in items.iter() {
@@ -2118,7 +2118,7 @@ fn walk_ast_second_pass<'a>(ast_storage: &'a FullLibraryAST, crate_types: &Crate
                let ASTModule { ref attrs, ref items, .. } = astmod;
                assert_eq!(export_status(&attrs), ExportStatus::Export);
 
-               let import_resolver = ImportResolver::new(orig_crate, &ast_storage.dependencies, module, items);
+               let import_resolver = ImportResolver::new(orig_crate, ast_storage, module, items);
                let mut types = TypeResolver::new(module, import_resolver, crate_types);
 
                for item in items.iter() {
@@ -2154,7 +2154,7 @@ fn walk_ast_second_pass<'a>(ast_storage: &'a FullLibraryAST, crate_types: &Crate
 }
 
 fn walk_private_mod<'a>(ast_storage: &'a FullLibraryAST, orig_crate: &str, module: String, items: &'a syn::ItemMod, crate_types: &mut CrateTypes<'a>) {
-       let import_resolver = ImportResolver::new(orig_crate, &ast_storage.dependencies, &module, &items.content.as_ref().unwrap().1);
+       let import_resolver = ImportResolver::new(orig_crate, ast_storage, &module, &items.content.as_ref().unwrap().1);
        for item in items.content.as_ref().unwrap().1.iter() {
                match item {
                        syn::Item::Mod(m) => walk_private_mod(ast_storage, orig_crate, format!("{}::{}", module, m.ident), m, crate_types),
@@ -2183,7 +2183,7 @@ fn walk_ast_first_pass<'a>(ast_storage: &'a FullLibraryAST, crate_types: &mut Cr
                let ASTModule { ref attrs, ref items, submods: _ } = astmod;
                assert_eq!(export_status(&attrs), ExportStatus::Export);
                let orig_crate = module.splitn(2, "::").next().unwrap();
-               let import_resolver = ImportResolver::new(orig_crate, &ast_storage.dependencies, module, items);
+               let import_resolver = ImportResolver::new(orig_crate, ast_storage, module, items);
 
                for item in items.iter() {
                        match item {
index 6564ac4756a8ba8c659c93d8b47011bbcc224916..b022f3255fec41a27efd03701bf8d0ac933b2813 100644 (file)
@@ -440,16 +440,18 @@ pub enum DeclType<'a> {
 
 pub struct ImportResolver<'mod_lifetime, 'crate_lft: 'mod_lifetime> {
        pub crate_name: &'mod_lifetime str,
-       dependencies: &'mod_lifetime HashSet<syn::Ident>,
+       library: &'crate_lft FullLibraryAST,
        module_path: &'mod_lifetime str,
        imports: HashMap<syn::Ident, (String, syn::Path)>,
        declared: HashMap<syn::Ident, DeclType<'crate_lft>>,
        priv_modules: HashSet<syn::Ident>,
 }
 impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'crate_lft> {
-       fn process_use_intern(crate_name: &str, module_path: &str, dependencies: &HashSet<syn::Ident>, imports: &mut HashMap<syn::Ident, (String, syn::Path)>,
-                       u: &syn::UseTree, partial_path: &str, mut path: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2>) {
-
+       fn walk_use_intern<F: FnMut(syn::Ident, (String, syn::Path))>(
+               crate_name: &str, module_path: &str, dependencies: &HashSet<syn::Ident>, u: &syn::UseTree,
+               partial_path: &str,
+               mut path: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2>, handle_use: &mut F
+       ) {
                let new_path;
                macro_rules! push_path {
                        ($ident: expr, $path_suffix: expr) => {
@@ -489,21 +491,21 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                match u {
                        syn::UseTree::Path(p) => {
                                push_path!(p.ident, "::");
-                               Self::process_use_intern(crate_name, module_path, dependencies, imports, &p.tree, &new_path, path);
+                               Self::walk_use_intern(crate_name, module_path, dependencies, &p.tree, &new_path, path, handle_use);
                        },
                        syn::UseTree::Name(n) => {
                                push_path!(n.ident, "");
                                let imported_ident = syn::Ident::new(new_path.rsplitn(2, "::").next().unwrap(), Span::call_site());
-                               imports.insert(imported_ident, (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
+                               handle_use(imported_ident, (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
                        },
                        syn::UseTree::Group(g) => {
                                for i in g.items.iter() {
-                                       Self::process_use_intern(crate_name, module_path, dependencies, imports, i, partial_path, path.clone());
+                                       Self::walk_use_intern(crate_name, module_path, dependencies, i, partial_path, path.clone(), handle_use);
                                }
                        },
                        syn::UseTree::Rename(r) => {
                                push_path!(r.ident, "");
-                               imports.insert(r.rename.clone(), (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
+                               handle_use(r.rename.clone(), (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
                        },
                        syn::UseTree::Glob(_) => {
                                eprintln!("Ignoring * use for {} - this may result in resolution failures", partial_path);
@@ -511,12 +513,15 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                }
        }
 
+       fn process_use_intern(crate_name: &str, module_path: &str, dependencies: &HashSet<syn::Ident>,
+               imports: &mut HashMap<syn::Ident, (String, syn::Path)>, u: &syn::UseTree, partial_path: &str,
+               path: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2>
+       ) {
+               Self::walk_use_intern(crate_name, module_path, dependencies, u, partial_path, path,
+                       &mut |k, v| { imports.insert(k, v); });
+       }
+
        fn process_use(crate_name: &str, module_path: &str, dependencies: &HashSet<syn::Ident>, imports: &mut HashMap<syn::Ident, (String, syn::Path)>, u: &syn::ItemUse) {
-               if let syn::Visibility::Public(_) = u.vis {
-                       // We actually only use these for #[cfg(fuzztarget)]
-                       eprintln!("Ignoring pub(use) tree!");
-                       return;
-               }
                if u.leading_colon.is_some() { eprintln!("Ignoring leading-colon use!"); return; }
                Self::process_use_intern(crate_name, module_path, dependencies, imports, &u.tree, "", syn::punctuated::Punctuated::new());
        }
@@ -527,10 +532,10 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                imports.insert(ident, (id.to_owned(), path));
        }
 
-       pub fn new(crate_name: &'mod_lifetime str, dependencies: &'mod_lifetime HashSet<syn::Ident>, module_path: &'mod_lifetime str, contents: &'crate_lft [syn::Item]) -> Self {
-               Self::from_borrowed_items(crate_name, dependencies, module_path, &contents.iter().map(|a| a).collect::<Vec<_>>())
+       pub fn new(crate_name: &'mod_lifetime str, library: &'crate_lft FullLibraryAST, module_path: &'mod_lifetime str, contents: &'crate_lft [syn::Item]) -> Self {
+               Self::from_borrowed_items(crate_name, library, module_path, &contents.iter().map(|a| a).collect::<Vec<_>>())
        }
-       pub fn from_borrowed_items(crate_name: &'mod_lifetime str, dependencies: &'mod_lifetime HashSet<syn::Ident>, module_path: &'mod_lifetime str, contents: &[&'crate_lft syn::Item]) -> Self {
+       pub fn from_borrowed_items(crate_name: &'mod_lifetime str, library: &'crate_lft FullLibraryAST, module_path: &'mod_lifetime str, contents: &[&'crate_lft syn::Item]) -> Self {
                let mut imports = HashMap::new();
                // Add primitives to the "imports" list:
                Self::insert_primitive(&mut imports, "bool");
@@ -553,7 +558,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
 
                for item in contents.iter() {
                        match item {
-                               syn::Item::Use(u) => Self::process_use(crate_name, module_path, dependencies, &mut imports, &u),
+                               syn::Item::Use(u) => Self::process_use(crate_name, module_path, &library.dependencies, &mut imports, &u),
                                syn::Item::Struct(s) => {
                                        if let syn::Visibility::Public(_) = s.vis {
                                                match export_status(&s.attrs) {
@@ -596,7 +601,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                        }
                }
 
-               Self { crate_name, dependencies, module_path, imports, declared, priv_modules }
+               Self { crate_name, library, module_path, imports, declared, priv_modules }
        }
 
        pub fn maybe_resolve_declared(&self, id: &syn::Ident) -> Option<&DeclType<'crate_lft>> {
@@ -611,7 +616,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                } else { None }
        }
 
-       pub fn maybe_resolve_path(&self, p: &syn::Path, generics: Option<&GenericTypes>) -> Option<String> {
+       fn maybe_resolve_imported_path(&self, p: &syn::Path, generics: Option<&GenericTypes>) -> Option<String> {
                if let Some(gen_types) = generics {
                        if let Some(resp) = gen_types.maybe_resolve_path(p) {
                                return Some(resp.clone());
@@ -623,7 +628,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                                format!("{}{}", if idx == 0 { "" } else { "::" }, seg.ident)
                        }).collect();
                        let firstseg = p.segments.iter().next().unwrap();
-                       if !self.dependencies.contains(&firstseg.ident) {
+                       if !self.library.dependencies.contains(&firstseg.ident) {
                                res = self.crate_name.to_owned() + "::" + &res;
                        }
                        Some(res)
@@ -648,7 +653,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                                }
                        } else if let Some(_) = self.priv_modules.get(&first_seg.ident) {
                                Some(format!("{}::{}{}", self.module_path, first_seg.ident, remaining))
-                       } else if first_seg_is_stdlib(&first_seg_str) || self.dependencies.contains(&first_seg.ident) {
+                       } else if first_seg_is_stdlib(&first_seg_str) || self.library.dependencies.contains(&first_seg.ident) {
                                Some(first_seg_str + &remaining)
                        } else if first_seg_str == "crate" {
                                Some(self.crate_name.to_owned() + &remaining)
@@ -656,6 +661,43 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                }
        }
 
+       pub fn maybe_resolve_path(&self, p: &syn::Path, generics: Option<&GenericTypes>) -> Option<String> {
+               self.maybe_resolve_imported_path(p, generics).map(|mut path| {
+                       loop {
+                               // Now that we've resolved the path to the path as-imported, check whether the path
+                               // is actually a pub(.*) use statement and map it to the real path.
+                               let path_tmp = path.clone();
+                               let crate_name = path_tmp.splitn(1, "::").next().unwrap();
+                               let mut module_riter = path_tmp.rsplitn(2, "::");
+                               let obj = module_riter.next().unwrap();
+                               if let Some(module_path) = module_riter.next() {
+                                       if let Some(m) = self.library.modules.get(module_path) {
+                                               for item in m.items.iter() {
+                                                       if let syn::Item::Use(syn::ItemUse { vis, tree, .. }) = item {
+                                                               match vis {
+                                                                       syn::Visibility::Public(_)|
+                                                                       syn::Visibility::Crate(_)|
+                                                                       syn::Visibility::Restricted(_) => {
+                                                                               Self::walk_use_intern(crate_name, module_path,
+                                                                                       &self.library.dependencies, tree, "",
+                                                                                       syn::punctuated::Punctuated::new(), &mut |ident, (use_path, _)| {
+                                                                                               if format!("{}", ident) == obj {
+                                                                                                       path = use_path;
+                                                                                               }
+                                                                               });
+                                                                       },
+                                                                       syn::Visibility::Inherited => {},
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+                       }
+                       path
+               })
+       }
+
        /// Map all the Paths in a Type into absolute paths given a set of imports (generated via process_use_intern)
        pub fn resolve_imported_refs(&self, mut ty: syn::Type) -> syn::Type {
                match &mut ty {