Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pub use parsing and trait definition parsing in third party crates #2025

Merged
merged 34 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {

Check warning on line 17 in frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs#L17

Added line #L17 was not covered by tests
Self {
namespace,
..self.clone()
}
}

fn ident(&self) -> Ident {
self.item_fn.sig().ident.clone()

Check warning on line 25 in frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/ir/hir/hierarchical/function.rs#L24-L25

Added lines #L24 - L25 were not covered by tests
}
}

impl HirFunction {
pub(crate) fn owner_and_name(&self) -> SimpleOwnerAndName {
(self.owner.simple_name(), self.item_fn.name())
}
Expand All @@ -40,10 +46,11 @@
}
}

#[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 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 {

Check warning on line 32 in frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs#L32

Added line #L32 was not covered by tests
Self {
namespaced_name: NamespacedName::new(namespace, self.namespaced_name.name.clone()),
..self.to_owned()
}
}

fn ident(&self) -> Ident {
self.ident.clone()

Check warning on line 40 in frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/ir/hir/hierarchical/struct_or_enum.rs#L39-L40

Added lines #L39 - L40 were not covered by tests
}
}

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()

Check warning on line 25 in frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs#L22-L25

Added lines #L22 - L25 were not covered by tests
}
}

fn ident(&self) -> Ident {
self.item_trait.ident.clone()

Check warning on line 30 in frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/ir/hir/hierarchical/traits.rs#L29-L30

Added lines #L29 - L30 were not covered by tests
}
}

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)?;

Check warning on line 14 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L11-L14

Added lines #L11 - L14 were not covered by tests
}
Ok(module)
}

fn parse_pub_use_from_items(items: &[syn::Item]) -> Vec<Namespace> {
fn parse_pub_use_from_items(items: &[syn::Item]) -> Vec<PubUseInfo> {

Check warning on line 19 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L19

Added line #L19 was not covered by tests
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> {

Check warning on line 26 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L26

Added line #L26 was not covered by tests
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()]),

Check warning on line 34 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L31-L34

Added lines #L31 - L34 were not covered by tests
};

return Some(PubUseInfo {
namespace: Namespace::new(
(tree_parts[..tree_parts.len() - 1].iter())
.map(ToString::to_string)
.collect_vec(),
),
name_filters,
});

Check warning on line 44 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L37-L44

Added lines #L37 - L44 were not covered by tests
}
}
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())

Check warning on line 59 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L57-L59

Added lines #L57 - L59 were not covered by tests
} else {
true

Check warning on line 61 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L61

Added line #L61 was not covered by tests
}
}
}

fn transform_module_by_pub_use_single(
module: &mut HirModule,
pub_use_name: &Namespace,
pub_use_info: &PubUseInfo,

Check warning on line 68 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L68

Added line #L68 was not covered by tests
) -> 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={:?}",

Check warning on line 72 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L70-L72

Added lines #L70 - L72 were not covered by tests
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(());

Check warning on line 78 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L76-L78

Added lines #L76 - L78 were not covered by tests
}

Check warning on line 80 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L80

Added line #L80 was not covered by tests
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);

Check warning on line 87 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L83-L87

Added lines #L83 - L87 were not covered by tests

module.content.functions.extend(src_functions);
module.content.structs.extend(src_structs);
module.content.enums.extend(src_enums);
module.content.traits.extend(src_traits);

Check warning on line 92 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L92

Added line #L92 was not covered by tests
} 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"

Check warning on line 95 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L95

Added line #L95 was not covered by tests
);
}

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()

Check warning on line 110 in frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/codegen/parser/hir/hierarchical/module/pub_use_transformer.rs#L102-L110

Added lines #L102 - L110 were not covered by tests
}
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 @@
}

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))

Check warning on line 21 in frb_codegen/src/library/utils/namespace.rs

View check run for this annotation

Codecov / codecov/patch

frb_codegen/src/library/utils/namespace.rs#L19-L21

Added lines #L19 - L21 were not covered by tests
}

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
Loading