diff --git a/frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs b/frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs index bb21ef4c76..613da0b888 100644 --- a/frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs +++ b/frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs @@ -1,5 +1,6 @@ +use crate::codegen::ir::hir::hierarchical::misc::HirCommon; use crate::utils::namespace::{Namespace, NamespacedName}; -use proc_macro2::Span; +use proc_macro2::{Ident, Span}; use serde::Serialize; use syn::spanned::Spanned; use syn::{Attribute, ImplItemFn, ItemFn, ItemImpl, Signature, TraitItemFn, Visibility}; @@ -7,20 +8,25 @@ use syn::{Attribute, ImplItemFn, ItemFn, ItemImpl, Signature, TraitItemFn, Visib #[derive(Debug, Clone, Serialize)] pub(crate) struct HirFunction { pub(crate) namespace: Namespace, - #[serde(skip_serializing)] pub(crate) owner: HirFunctionOwner, #[serde(skip_serializing)] pub(crate) item_fn: GeneralizedItemFn, } -impl HirFunction { - pub(crate) fn with_namespace(&self, namespace: Namespace) -> Self { +impl HirCommon for HirFunction { + fn with_namespace(&self, namespace: Namespace) -> Self { Self { namespace, ..self.clone() } } + fn ident(&self) -> Ident { + self.item_fn.sig().ident.clone() + } +} + +impl HirFunction { pub(crate) fn owner_and_name(&self) -> SimpleOwnerAndName { (self.owner.simple_name(), self.item_fn.name()) } @@ -40,10 +46,11 @@ impl HirFunction { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize)] pub(crate) enum HirFunctionOwner { Function, Method { + #[serde(skip_serializing)] item_impl: ItemImpl, trait_def_name: Option, }, diff --git a/frb_codegen/src/library/codegen/ir/hir/hierarchical/misc.rs b/frb_codegen/src/library/codegen/ir/hir/hierarchical/misc.rs new file mode 100644 index 0000000000..cfb7b88da1 --- /dev/null +++ b/frb_codegen/src/library/codegen/ir/hir/hierarchical/misc.rs @@ -0,0 +1,8 @@ +use crate::utils::namespace::Namespace; +use proc_macro2::Ident; + +pub(crate) trait HirCommon { + fn with_namespace(&self, namespace: Namespace) -> Self; + + fn ident(&self) -> Ident; +} diff --git a/frb_codegen/src/library/codegen/ir/hir/hierarchical/mod.rs b/frb_codegen/src/library/codegen/ir/hir/hierarchical/mod.rs index a596df54ad..2156ecb543 100644 --- a/frb_codegen/src/library/codegen/ir/hir/hierarchical/mod.rs +++ b/frb_codegen/src/library/codegen/ir/hir/hierarchical/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod crates; pub(crate) mod function; +pub(crate) mod misc; pub(crate) mod module; pub(crate) mod pack; pub(crate) mod struct_or_enum; diff --git a/frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs b/frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs index f677f9d0a9..3c56d3a314 100644 --- a/frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs +++ b/frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs @@ -1,3 +1,4 @@ +use crate::codegen::ir::hir::hierarchical::misc::HirCommon; use crate::codegen::ir::hir::hierarchical::module::HirVisibility; use crate::codegen::ir::hir::hierarchical::syn_item_struct_or_enum::SynItemStructOrEnum; use crate::utils::namespace::{Namespace, NamespacedName}; @@ -27,13 +28,17 @@ pub struct HirStructOrEnum { pub type HirStruct = HirStructOrEnum; pub type HirEnum = HirStructOrEnum; -impl HirStructOrEnum { - pub(crate) fn with_namespace(&self, namespace: Namespace) -> Self { +impl HirCommon for HirStructOrEnum { + fn with_namespace(&self, namespace: Namespace) -> Self { Self { namespaced_name: NamespacedName::new(namespace, self.namespaced_name.name.clone()), ..self.to_owned() } } + + fn ident(&self) -> Ident { + self.ident.clone() + } } pub(super) fn serialize_syn( diff --git a/frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs b/frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs index 451ce6e98c..764031c3ee 100644 --- a/frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs +++ b/frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs @@ -1,17 +1,44 @@ +use crate::codegen::ir::hir::hierarchical::misc::HirCommon; use crate::utils::namespace::Namespace; -use serde::Serialize; +use proc_macro2::Ident; +use serde::{Serialize, Serializer}; use syn::{ItemImpl, ItemTrait}; #[derive(Debug, Clone, Serialize)] pub(crate) struct HirTrait { pub(crate) namespace: Namespace, - #[serde(skip_serializing)] + #[serde(serialize_with = "serialize_item_trait")] pub(crate) item_trait: ItemTrait, } #[derive(Debug, Clone, Serialize)] pub(crate) struct HirTraitImpl { pub(crate) namespace: Namespace, - #[serde(skip_serializing)] + #[serde(serialize_with = "serialize_item_impl")] pub(crate) item_impl: ItemImpl, } + +impl HirCommon for HirTrait { + fn with_namespace(&self, namespace: Namespace) -> Self { + Self { + namespace, + ..self.to_owned() + } + } + + fn ident(&self) -> Ident { + self.item_trait.ident.clone() + } +} + +fn serialize_item_trait(x: &ItemTrait, s: S) -> Result { + s.serialize_str(&format!("ident={}", x.ident)) +} + +fn serialize_item_impl(x: &ItemImpl, s: S) -> Result { + s.serialize_str(&format!("self_ty={}", ty_to_string(&x.self_ty))) +} + +fn ty_to_string(ty: &syn::Type) -> String { + quote::quote!(#ty).to_string() +} diff --git a/frb_codegen/src/library/codegen/parser/hir/flat/mod.rs b/frb_codegen/src/library/codegen/parser/hir/flat/mod.rs index 35f46d984b..9e1c0b473d 100644 --- a/frb_codegen/src/library/codegen/parser/hir/flat/mod.rs +++ b/frb_codegen/src/library/codegen/parser/hir/flat/mod.rs @@ -4,6 +4,7 @@ use crate::codegen::ir::hir::hierarchical::module::HirModule; use crate::codegen::ir::hir::hierarchical::pack::HirPack; use crate::codegen::ir::hir::hierarchical::struct_or_enum::HirEnum; use crate::codegen::ir::hir::hierarchical::struct_or_enum::HirStruct; +use crate::codegen::ir::hir::hierarchical::traits::HirTrait; use crate::codegen::parser::hir::flat::type_alias_resolver::resolve_type_aliases; use crate::codegen::parser::hir::internal_config::ParserHirInternalConfig; use crate::utils::crate_name::CrateName; @@ -60,6 +61,15 @@ fn collect_enums(hir_pack: &HirPack) -> HashMap { ) } +// TODO move +pub(crate) fn collect_traits(hir_pack: &HirPack) -> HashMap { + collect_objects_map( + hir_pack, + |module| &module.content.traits, + |x| (x.item_trait.ident.to_string(), x), + ) +} + fn collect_types(hir_pack: &HirPack) -> HashMap { collect_objects_map( hir_pack, diff --git a/frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs b/frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs index 8e70b1ea69..11a7c30e87 100644 --- a/frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs +++ b/frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs @@ -1,60 +1,111 @@ +use crate::codegen::ir::hir::hierarchical::misc::HirCommon; use crate::codegen::ir::hir::hierarchical::module::HirModule; use crate::utils::namespace::Namespace; use itertools::Itertools; pub(crate) fn transform(mut module: HirModule, items: &[syn::Item]) -> anyhow::Result { - let pub_use_names = parse_pub_use_from_items(items); - for pub_use_name in pub_use_names { - transform_module_by_pub_use_single(&mut module, &pub_use_name)?; + // Only apply to third party crate currently, since in self crate usually no need to care about this + if module.meta.namespace.crate_name().is_self_crate() { + return Ok(module); + } + + let pub_use_infos = parse_pub_use_from_items(items); + for pub_use_info in pub_use_infos { + transform_module_by_pub_use_single(&mut module, &pub_use_info)?; } Ok(module) } -fn parse_pub_use_from_items(items: &[syn::Item]) -> Vec { +fn parse_pub_use_from_items(items: &[syn::Item]) -> Vec { items .iter() .filter_map(parse_pub_use_from_item) .collect_vec() } -fn parse_pub_use_from_item(item: &syn::Item) -> Option { +fn parse_pub_use_from_item(item: &syn::Item) -> Option { if let syn::Item::Use(item_use) = item { if matches!(item_use.vis, syn::Visibility::Public(_)) { let tree = &item_use.tree; let tree_string = quote::quote!(#tree).to_string().replace(' ', ""); - if let Some(interest_use_part) = tree_string.strip_suffix("::*") { - return Some(Namespace::new_raw(interest_use_part.to_owned())); - } + let tree_parts = tree_string.split(Namespace::SEP).collect_vec(); + let name_filters = match *tree_parts.last().unwrap() { + "*" => None, + x => Some(vec![x.to_string()]), + }; + + return Some(PubUseInfo { + namespace: Namespace::new( + (tree_parts[..tree_parts.len() - 1].iter()) + .map(ToString::to_string) + .collect_vec(), + ), + name_filters, + }); } } None } +#[derive(Debug, Clone)] +struct PubUseInfo { + namespace: Namespace, + name_filters: Option>, +} + +impl PubUseInfo { + fn is_interest_name(&self, name: &str) -> bool { + if let Some(name_filters) = &self.name_filters { + name_filters.contains(&name.to_owned()) + } else { + true + } + } +} + fn transform_module_by_pub_use_single( module: &mut HirModule, - pub_use_name: &Namespace, + pub_use_info: &PubUseInfo, ) -> anyhow::Result<()> { - if let Some(src_mod) = module.content.get_module_nested(&pub_use_name.path()) { + if let Some(src_mod) = (module.content).get_module_nested(&pub_use_info.namespace.path()) { + log::debug!( + "transform_module_by_pub_use_single pub_use_info={:?}", + pub_use_info + ); + + if src_mod.meta.is_public() { + log::debug!("transform_module_by_pub_use_single skip `{pub_use_info:?}` since src mod already public"); + return Ok(()); + } + let self_namespace = &module.meta.namespace; - let src_functions = (src_mod.content.functions.iter()) - .map(|x| x.with_namespace(self_namespace.clone())) - .collect_vec(); - let src_structs = (src_mod.content.structs.iter()) - .map(|x| x.with_namespace(self_namespace.clone())) - .collect_vec(); - let src_enums = (src_mod.content.enums.iter()) - .map(|x| x.with_namespace(self_namespace.clone())) - .collect_vec(); + let src_functions = + transform_items(&src_mod.content.functions, self_namespace, pub_use_info); + let src_structs = transform_items(&src_mod.content.structs, self_namespace, pub_use_info); + let src_enums = transform_items(&src_mod.content.enums, self_namespace, pub_use_info); + let src_traits = transform_items(&src_mod.content.traits, self_namespace, pub_use_info); module.content.functions.extend(src_functions); module.content.structs.extend(src_structs); module.content.enums.extend(src_enums); + module.content.traits.extend(src_traits); } else { log::debug!( - "transform_module_by_pub_use_single skip `{pub_use_name}` since cannot find mod" + "transform_module_by_pub_use_single skip `{pub_use_info:?}` since cannot find mod" ); } Ok(()) } + +fn transform_items( + items: &[T], + self_namespace: &Namespace, + pub_use_info: &PubUseInfo, +) -> Vec { + (items.iter()) + .filter(|x| pub_use_info.is_interest_name(&x.ident().to_string())) + .map(|x| x.with_namespace(self_namespace.clone())) + .collect_vec() +} diff --git a/frb_codegen/src/library/codegen/parser/hir/hierarchical/pack/trait_impl_transformer.rs b/frb_codegen/src/library/codegen/parser/hir/hierarchical/pack/trait_impl_transformer.rs index 7675af26be..8dadceb1ce 100644 --- a/frb_codegen/src/library/codegen/parser/hir/hierarchical/pack/trait_impl_transformer.rs +++ b/frb_codegen/src/library/codegen/parser/hir/hierarchical/pack/trait_impl_transformer.rs @@ -4,6 +4,7 @@ use crate::codegen::ir::hir::hierarchical::function::{ use crate::codegen::ir::hir::hierarchical::module::HirModule; use crate::codegen::ir::hir::hierarchical::pack::HirPack; use crate::codegen::ir::hir::hierarchical::traits::HirTrait; +use crate::codegen::parser::hir::flat::collect_traits; use crate::codegen::parser::hir::hierarchical::function::parse_syn_item_impl; use crate::if_then_some; use crate::utils::namespace::{Namespace, NamespacedName}; @@ -12,20 +13,15 @@ use std::collections::HashMap; use syn::{ItemImpl, TraitItem}; pub(super) fn transform(mut pack: HirPack) -> anyhow::Result { - let trait_map = collect_traits(&pack); + let trait_map = (collect_traits(&pack).into_iter()) + .map(|(k, v)| (k, v.to_owned())) + .collect::>(); + pack.visit_mut(&mut |module| { (module.content.functions).extend(compute_methods(module, &trait_map)); }); - Ok(pack) -} -fn collect_traits(pack: &HirPack) -> HashMap { - let mut traits = vec![]; - pack.visit(&mut |module| traits.extend(module.content.traits.clone())); - traits - .into_iter() - .map(|t| (t.item_trait.ident.to_string(), t)) - .collect() + Ok(pack) } fn compute_methods(module: &HirModule, trait_map: &HashMap) -> Vec { diff --git a/frb_codegen/src/library/utils/namespace.rs b/frb_codegen/src/library/utils/namespace.rs index 10ef0ba24b..1982c29a9a 100644 --- a/frb_codegen/src/library/utils/namespace.rs +++ b/frb_codegen/src/library/utils/namespace.rs @@ -14,12 +14,12 @@ pub struct Namespace { } impl Namespace { - const SEP: &'static str = "::"; + pub(crate) const SEP: &'static str = "::"; - // pub fn new(path: Vec) -> Self { - // assert!((path.iter()).all(|item| !item.contains(Self::SEP))); - // Self::new_raw(path.join(Self::SEP)) - // } + pub fn new(path: Vec) -> Self { + assert!((path.iter()).all(|item| !item.contains(Self::SEP))); + Self::new_raw(path.join(Self::SEP)) + } pub fn new_raw(joined_path: String) -> Self { // This will stop the whole generator and tell the users, so we do not care about testing it diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/generics/expect_hir_hierarchical.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/generics/expect_hir_hierarchical.json index cc8e0f9850..85c94ddb7c 100644 --- a/frb_codegen/test_fixtures/library/codegen/parser/mod/generics/expect_hir_hierarchical.json +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/generics/expect_hir_hierarchical.json @@ -19,19 +19,24 @@ ], "functions": [ { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" } ], "modules": [], diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/methods/expect_hir_hierarchical.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/methods/expect_hir_hierarchical.json index fa2ec3d260..2ed0a802e7 100644 --- a/frb_codegen/test_fixtures/library/codegen/parser/mod/methods/expect_hir_hierarchical.json +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/methods/expect_hir_hierarchical.json @@ -19,16 +19,36 @@ ], "functions": [ { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": { + "Method": { + "trait_def_name": null + } + } }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": { + "Method": { + "trait_def_name": null + } + } }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": { + "Method": { + "trait_def_name": null + } + } }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": { + "Method": { + "trait_def_name": null + } + } } ], "modules": [], diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/multi_input_file/expect_hir_hierarchical.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/multi_input_file/expect_hir_hierarchical.json index 29735bfbb2..5f6769526c 100644 --- a/frb_codegen/test_fixtures/library/codegen/parser/mod/multi_input_file/expect_hir_hierarchical.json +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/multi_input_file/expect_hir_hierarchical.json @@ -12,7 +12,8 @@ "enums": [], "functions": [ { - "namespace": "crate::api_one" + "namespace": "crate::api_one", + "owner": "Function" } ], "modules": [], @@ -32,7 +33,8 @@ "enums": [], "functions": [ { - "namespace": "crate::api_two" + "namespace": "crate::api_two", + "owner": "Function" } ], "modules": [], diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/non_qualified_names/expect_hir_hierarchical.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/non_qualified_names/expect_hir_hierarchical.json index 7c72530672..f2e2ca833d 100644 --- a/frb_codegen/test_fixtures/library/codegen/parser/mod/non_qualified_names/expect_hir_hierarchical.json +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/non_qualified_names/expect_hir_hierarchical.json @@ -12,10 +12,12 @@ "enums": [], "functions": [ { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" } ], "modules": [], diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/qualified_names/expect_hir_hierarchical.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/qualified_names/expect_hir_hierarchical.json index 0833090f70..a4a6469acc 100644 --- a/frb_codegen/test_fixtures/library/codegen/parser/mod/qualified_names/expect_hir_hierarchical.json +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/qualified_names/expect_hir_hierarchical.json @@ -12,16 +12,20 @@ "enums": [], "functions": [ { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" }, { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" } ], "modules": [], diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/simple/expect_hir_hierarchical.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/simple/expect_hir_hierarchical.json index 776f2e485e..1aee36ea99 100644 --- a/frb_codegen/test_fixtures/library/codegen/parser/mod/simple/expect_hir_hierarchical.json +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/simple/expect_hir_hierarchical.json @@ -12,7 +12,8 @@ "enums": [], "functions": [ { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" } ], "modules": [], diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/use_type_in_another_file/expect_hir_hierarchical.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/use_type_in_another_file/expect_hir_hierarchical.json index cc7bd2a0ee..a5cebe1bac 100644 --- a/frb_codegen/test_fixtures/library/codegen/parser/mod/use_type_in_another_file/expect_hir_hierarchical.json +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/use_type_in_another_file/expect_hir_hierarchical.json @@ -42,7 +42,8 @@ "enums": [], "functions": [ { - "namespace": "crate::api" + "namespace": "crate::api", + "owner": "Function" } ], "modules": [],