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

Test for part of issue 642. #656

Merged
merged 2 commits into from
Oct 11, 2021
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
154 changes: 88 additions & 66 deletions engine/src/conversion/codegen_rs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl<'a> RsCodeGenerator<'a> {
// ... and now let's start to generate the output code.
// First off, when we generate structs we may need to add some methods
// if they're superclasses.
let mut methods_by_superclass = self.accumulate_superclass_methods(&all_apis);
let methods_by_superclass = self.accumulate_superclass_methods(&all_apis);
let subclasses_with_a_single_trivial_constructor =
find_trivially_constructed_subclasses(&all_apis);
// Now let's generate the Rust code.
Expand All @@ -172,7 +172,7 @@ impl<'a> RsCodeGenerator<'a> {
let name = api.name().clone();
let gen = self.generate_rs_for_api(
api,
&mut methods_by_superclass,
&methods_by_superclass,
&subclasses_with_a_single_trivial_constructor,
);
((name, gen), more_cpp_needed)
Expand Down Expand Up @@ -463,7 +463,7 @@ impl<'a> RsCodeGenerator<'a> {
fn generate_rs_for_api(
&self,
api: Api<FnPhase>,
associated_methods: &mut HashMap<QualifiedName, Vec<SuperclassMethod>>,
associated_methods: &HashMap<QualifiedName, Vec<SuperclassMethod>>,
subclasses_with_a_single_trivial_constructor: &HashSet<QualifiedName>,
) -> RsCodegenResult {
let name = api.name().clone();
Expand All @@ -486,28 +486,6 @@ impl<'a> RsCodeGenerator<'a> {
extern_rust_mod_items: Vec::new(),
}
}
Api::ConcreteType { .. } => RsCodegenResult {
global_items: self.generate_extern_type_impl(TypeKind::NonPod, &name),
bridge_items: create_impl_items(&id, self.config),
extern_c_mod_items: vec![ForeignItem::Verbatim(
self.generate_cxxbridge_type(&name),
)],
bindgen_mod_items: vec![Item::Struct(new_non_pod_struct(id.clone()))],
impl_entry: None,
materializations: Vec::new(),
extern_rust_mod_items: Vec::new(),
},
Api::ForwardDeclaration { .. } => RsCodegenResult {
extern_c_mod_items: vec![ForeignItem::Verbatim(
self.generate_cxxbridge_type(&name),
)],
bridge_items: Vec::new(),
global_items: self.generate_extern_type_impl(TypeKind::NonPod, &name),
bindgen_mod_items: vec![Item::Struct(new_non_pod_struct(id))],
impl_entry: None,
materializations: vec![Use::UsedFromCxxBridge],
extern_rust_mod_items: Vec::new(),
},
Api::Function { fun, analysis, .. } => {
gen_function(name.get_namespace(), *fun, analysis, cpp_call_name)
}
Expand All @@ -532,12 +510,22 @@ impl<'a> RsCodeGenerator<'a> {
materializations: vec![Use::UsedFromBindgen],
extern_rust_mod_items: Vec::new(),
},
Api::Struct { item, analysis, .. } => {
let methods = associated_methods.get(&name);
self.generate_type(&name, id, item, analysis.kind, Item::Struct, methods)
}
Api::Enum { item, .. } => {
self.generate_type(&name, id, item, TypeKind::Pod, Item::Enum, None)
Api::Struct { item, analysis, .. } => self.generate_type(
&name,
id,
analysis.kind,
|| Some(Item::Struct(item)),
associated_methods,
),
Api::Enum { item, .. } => self.generate_type(
&name,
id,
TypeKind::Pod,
|| Some(Item::Enum(item)),
associated_methods,
),
Api::ForwardDeclaration { .. } | Api::ConcreteType { .. } => {
self.generate_type(&name, id, TypeKind::Abstract, || None, associated_methods)
}
Api::CType { .. } => RsCodegenResult {
global_items: Vec::new(),
Expand Down Expand Up @@ -634,7 +622,7 @@ impl<'a> RsCodeGenerator<'a> {
},
];
let mut extern_c_mod_items = vec![
ForeignItem::Verbatim(self.generate_cxxbridge_type(&full_cpp)),
self.generate_cxxbridge_type(&full_cpp, true),
parse_quote! {
fn #relinquish_ownership_call(self: &#cpp_id);
},
Expand Down Expand Up @@ -804,21 +792,58 @@ impl<'a> RsCodeGenerator<'a> {
.flatten()
}

fn generate_type<T, F>(
fn generate_type<F>(
&self,
name: &QualifiedName,
id: Ident,
item: T,
analysis: TypeKind,
item_type: F,
methods: Option<&Vec<SuperclassMethod>>,
type_kind: TypeKind,
item_creator: F,
associated_methods: &HashMap<QualifiedName, Vec<SuperclassMethod>>,
) -> RsCodegenResult
where
F: FnOnce(T) -> Item,
F: FnOnce() -> Option<Item>,
{
let mut bindgen_mod_items = vec![item_type(item)];
let global_items = self.generate_extern_type_impl(analysis, name);
let mut bindgen_mod_items = Vec::new();
let mut materializations = vec![Use::UsedFromCxxBridge];
Self::add_superclass_stuff_to_type(
name,
&mut bindgen_mod_items,
&mut materializations,
associated_methods.get(name),
);
if type_kind.can_be_instantiated() {
bindgen_mod_items
.push(item_creator().expect("Instantiable types must provide instance"));
let global_items = self.generate_extern_type_impl(type_kind, name);
RsCodegenResult {
global_items,
impl_entry: None,
bridge_items: create_impl_items(&id, self.config),
extern_c_mod_items: vec![self.generate_cxxbridge_type(name, true)],
bindgen_mod_items,
materializations,
extern_rust_mod_items: Vec::new(),
}
} else {
bindgen_mod_items.push(Item::Use(parse_quote! { pub use cxxbridge::#id; }));
RsCodegenResult {
extern_c_mod_items: vec![self.generate_cxxbridge_type(name, false)],
extern_rust_mod_items: Vec::new(),
bridge_items: Vec::new(),
global_items: Vec::new(),
bindgen_mod_items,
impl_entry: None,
materializations,
}
}
}

fn add_superclass_stuff_to_type(
name: &QualifiedName,
bindgen_mod_items: &mut Vec<Item>,
materializations: &mut Vec<Use>,
methods: Option<&Vec<SuperclassMethod>>,
) {
if let Some(methods) = methods {
let (supers, mains): (Vec<_>, Vec<_>) = methods
.iter()
Expand Down Expand Up @@ -860,19 +885,6 @@ impl<'a> RsCodeGenerator<'a> {
});
materializations.push(Use::SpecificNameFromBindgen(methods_name));
}
RsCodegenResult {
global_items,
impl_entry: None,
bridge_items: if analysis.can_be_instantiated() {
create_impl_items(&id, self.config)
} else {
Vec::new()
},
extern_c_mod_items: vec![ForeignItem::Verbatim(self.generate_cxxbridge_type(name))],
bindgen_mod_items,
materializations,
extern_rust_mod_items: Vec::new(),
}
}

/// Generates something in the output mod that will carry a docstring
Expand Down Expand Up @@ -986,7 +998,11 @@ impl<'a> RsCodeGenerator<'a> {
})]
}

fn generate_cxxbridge_type(&self, name: &QualifiedName) -> TokenStream {
fn generate_cxxbridge_type(
&self,
name: &QualifiedName,
references_bindgen: bool,
) -> ForeignItem {
let ns = name.get_namespace();
let id = name.get_final_ident();
let mut ns_components: Vec<_> = ns.iter().cloned().collect();
Expand All @@ -1012,18 +1028,24 @@ impl<'a> RsCodeGenerator<'a> {
});
}

for_extern_c_ts.extend(quote! {
type #id = super::bindgen::root::
});
for_extern_c_ts.extend(ns.iter().map(make_ident).map(|id| {
quote! {
#id::
}
}));
for_extern_c_ts.extend(quote! {
#id;
});
for_extern_c_ts
if references_bindgen {
for_extern_c_ts.extend(quote! {
type #id = super::bindgen::root::
});
for_extern_c_ts.extend(ns.iter().map(make_ident).map(|id| {
quote! {
#id::
}
}));
for_extern_c_ts.extend(quote! {
#id;
});
} else {
for_extern_c_ts.extend(quote! {
type #id;
});
}
ForeignItem::Verbatim(for_extern_c_ts)
}

fn find_output_mod_root(ns: &Namespace) -> impl Iterator<Item = Ident> {
Expand Down
19 changes: 19 additions & 0 deletions integration-tests/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6876,6 +6876,25 @@ fn test_no_rvo_move() {
);
}

#[test]
fn test_abstract_up() {
let hdr = indoc! {"
#include <memory>
class A {
public:
virtual void foo() = 0;
virtual ~A() {}
};
class B : public A {
public:
void foo() {}
};
inline std::unique_ptr<A> get_a() { return std::make_unique<B>(); }
"};
let rs = quote! {};
run_test("", hdr, rs, &["A", "get_a"], &[]);
}

// Yet to test:
// - Ifdef
// - Out param pointers
Expand Down