Skip to content

Commit

Permalink
Merge pull request #2025 from fzyzcjy/feat/12138
Browse files Browse the repository at this point in the history
Improve pub use parsing and trait definition parsing in third party crates
  • Loading branch information
fzyzcjy authored Jun 4, 2024
2 parents 67ac654 + 6821c19 commit 2db59f2
Show file tree
Hide file tree
Showing 16 changed files with 204 additions and 64 deletions.
17 changes: 12 additions & 5 deletions frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
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};

#[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())
}
Expand All @@ -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<NamespacedName>,
},
Expand Down
8 changes: 8 additions & 0 deletions frb_codegen/src/library/codegen/ir/hir/hierarchical/misc.rs
Original file line number Diff line number Diff line change
@@ -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;
}
1 change: 1 addition & 0 deletions frb_codegen/src/library/codegen/ir/hir/hierarchical/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -27,13 +28,17 @@ pub struct HirStructOrEnum<Item: SynItemStructOrEnum> {
pub type HirStruct = HirStructOrEnum<ItemStruct>;
pub type HirEnum = HirStructOrEnum<ItemEnum>;

impl<Item: SynItemStructOrEnum> HirStructOrEnum<Item> {
pub(crate) fn with_namespace(&self, namespace: Namespace) -> Self {
impl<Item: SynItemStructOrEnum> HirCommon for HirStructOrEnum<Item> {
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<T: ToTokens, S: Serializer>(
Expand Down
33 changes: 30 additions & 3 deletions frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs
Original file line number Diff line number Diff line change
@@ -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<S: Serializer>(x: &ItemTrait, s: S) -> Result<S::Ok, S::Error> {
s.serialize_str(&format!("ident={}", x.ident))
}

fn serialize_item_impl<S: Serializer>(x: &ItemImpl, s: S) -> Result<S::Ok, S::Error> {
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()
}
10 changes: 10 additions & 0 deletions frb_codegen/src/library/codegen/parser/hir/flat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -60,6 +61,15 @@ fn collect_enums(hir_pack: &HirPack) -> HashMap<String, &HirEnum> {
)
}

// TODO move
pub(crate) fn collect_traits(hir_pack: &HirPack) -> HashMap<String, &HirTrait> {
collect_objects_map(
hir_pack,
|module| &module.content.traits,
|x| (x.item_trait.ident.to_string(), x),
)
}

fn collect_types(hir_pack: &HirPack) -> HashMap<String, Type> {
collect_objects_map(
hir_pack,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<HirModule> {
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<Namespace> {
fn parse_pub_use_from_items(items: &[syn::Item]) -> Vec<PubUseInfo> {
items
.iter()
.filter_map(parse_pub_use_from_item)
.collect_vec()
}

fn parse_pub_use_from_item(item: &syn::Item) -> Option<Namespace> {
fn parse_pub_use_from_item(item: &syn::Item) -> Option<PubUseInfo> {
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<Vec<String>>,
}

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<T: HirCommon>(
items: &[T],
self_namespace: &Namespace,
pub_use_info: &PubUseInfo,
) -> Vec<T> {
(items.iter())
.filter(|x| pub_use_info.is_interest_name(&x.ident().to_string()))
.map(|x| x.with_namespace(self_namespace.clone()))
.collect_vec()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -12,20 +13,15 @@ use std::collections::HashMap;
use syn::{ItemImpl, TraitItem};

pub(super) fn transform(mut pack: HirPack) -> anyhow::Result<HirPack> {
let trait_map = collect_traits(&pack);
let trait_map = (collect_traits(&pack).into_iter())
.map(|(k, v)| (k, v.to_owned()))
.collect::<HashMap<_, _>>();

pack.visit_mut(&mut |module| {
(module.content.functions).extend(compute_methods(module, &trait_map));
});
Ok(pack)
}

fn collect_traits(pack: &HirPack) -> HashMap<String, HirTrait> {
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<String, HirTrait>) -> Vec<HirFunction> {
Expand Down
10 changes: 5 additions & 5 deletions frb_codegen/src/library/utils/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ pub struct Namespace {
}

impl Namespace {
const SEP: &'static str = "::";
pub(crate) const SEP: &'static str = "::";

// pub fn new(path: Vec<String>) -> Self {
// assert!((path.iter()).all(|item| !item.contains(Self::SEP)));
// Self::new_raw(path.join(Self::SEP))
// }
pub fn new(path: Vec<String>) -> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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": [],
Expand Down
Loading

0 comments on commit 2db59f2

Please sign in to comment.