Skip to content

Place all objects and passthrough items in the same block, to pass th… #1282

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/src/generator/cpp/inherit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn generate(

for &method in inherited_methods {
// Skip if the cfg attributes are not resolved to true
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &method.cfgs)? {
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &method.common_attrs.cfgs)? {
continue;
}

Expand Down
6 changes: 4 additions & 2 deletions crates/cxx-qt-gen/src/generator/cpp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ impl GeneratedCppBlocks {
.iter()
.filter_map(|qobject| {
// Skip if the cfg attributes are not resolved to true
match try_eval_attributes(opt.cfg_evaluator.as_ref(), &qobject.declaration.cfgs)
{
match try_eval_attributes(
opt.cfg_evaluator.as_ref(),
&qobject.declaration.common_attrs.cfgs,
) {
Ok(true) => {
Some(GeneratedCppQObject::from(qobject, &parser.type_names, opt))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/src/generator/cpp/qenum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub fn generate_declaration(
opt: &GeneratedOpt,
) -> Result<String> {
// Skip if the cfg attributes are not resolved to true
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &qenum.cfgs)? {
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &qenum.common_attrs.cfgs)? {
return Ok(String::new());
}

Expand Down Expand Up @@ -75,7 +75,7 @@ pub fn generate_on_qobject<'a>(

for qenum in qenums {
// Skip if the cfg attributes are not resolved to true
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &qenum.cfgs)? {
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &qenum.common_attrs.cfgs)? {
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/src/generator/cpp/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub fn generate_cpp_signal(
let mut generated = CppSignalFragment::default();

// Skip if the cfg attributes are not resolved to true
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &signal.cfgs)? {
if !try_eval_attributes(opt.cfg_evaluator.as_ref(), &signal.common_attrs.cfgs)? {
return Ok(generated);
}

Expand Down
126 changes: 64 additions & 62 deletions crates/cxx-qt-gen/src/generator/rust/externcxxqt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ use crate::{
generator::rust::{fragment::GeneratedRustFragment, signals::generate_rust_signal},
naming::TypeNames,
parser::externcxxqt::ParsedExternCxxQt,
syntax::path::path_compare_str,
};
use quote::quote;
use syn::{parse_quote, Attribute, Result};
use syn::{parse_quote, Item, Result};

impl GeneratedRustFragment {
pub fn from_extern_cxx_qt(
Expand All @@ -22,76 +21,79 @@ impl GeneratedRustFragment {
} else {
quote! {}
};
let extern_block_docs = &extern_cxxqt_block.common_attrs.docs;

// Add the pass through blocks
let unsafety = &extern_cxxqt_block.unsafety;
let items = &extern_cxxqt_block.passthrough_items;
let mut generated = extern_cxxqt_block
.qobjects
.iter()
.map(|ty| -> Result<GeneratedRustFragment> {
let mut generated = vec![];
let qobject_names = QObjectNames::from_extern_qobject(ty, type_names)?;

generated.push(GeneratedRustFragment::generate_casting_impl(
&qobject_names,
type_names,
&ty.name,
&ty.base_class,
)?);
let mut qobject_items: Vec<Item> = vec![];
let mut cxx_qt_mod = vec![];
let mut cxx_mod = vec![];
for obj in &extern_cxxqt_block.qobjects {
let qobject_names = QObjectNames::from_extern_qobject(obj, type_names)?;

let namespace = if let Some(namespace) = &ty.name.namespace() {
quote! { #[namespace = #namespace ] }
} else {
quote! {}
};
let cpp_name = &ty.name.cxx_unqualified();
let rust_name = &ty.name.rust_unqualified();
let vis = &ty.declaration.vis;
let ident = &ty.name.rust_unqualified();
let cxx_name = if &rust_name.to_string() == cpp_name {
quote! {}
} else {
let cxx_name = cpp_name.to_string();
quote! {
#[cxx_name = #cxx_name]
}
};
let cfgs: Vec<&Attribute> = ty
.declaration
.attrs
.iter()
.filter(|attr| path_compare_str(attr.meta.path(), &["cfg"]))
.collect();
let docs: Vec<&Attribute> = ty
.declaration
.attrs
.iter()
.filter(|attr| path_compare_str(attr.meta.path(), &["doc"]))
.collect();
generated.push(GeneratedRustFragment::from_cxx_item(parse_quote! {
#extern_block_namespace
#unsafety extern "C++" {
#namespace
#cxx_name
#(#cfgs)*
#(#docs)*
#vis type #ident;
}
}));
Ok(GeneratedRustFragment::flatten(generated))
})
.collect::<Result<Vec<_>>>()?;
let casting = GeneratedRustFragment::generate_casting_impl(
&qobject_names,
type_names,
&obj.name,
&obj.base_class,
)?;
cxx_mod.extend(casting.cxx_mod_contents);
cxx_qt_mod.extend(casting.cxx_qt_mod_contents);

if !items.is_empty() {
generated.push(GeneratedRustFragment::from_cxx_item(parse_quote! {
#extern_block_namespace
#unsafety extern "C++" {
#(#items)*
let namespace = if let Some(namespace) = &obj.name.namespace() {
quote! { #[namespace = #namespace ] }
} else {
quote! {}
};
let cpp_name = &obj.name.cxx_unqualified();
let rust_name = &obj.name.rust_unqualified();
let vis = &obj.declaration.vis;
let ident = &obj.name.rust_unqualified();
let cxx_name = if &rust_name.to_string() == cpp_name {
quote! {}
} else {
let cxx_name = cpp_name.to_string();
quote! {
#[cxx_name = #cxx_name]
}
}));
};
// TODO: (cfg everywhere) Can we make extract_docs return references, and then use here?
let cfgs = obj.common_attrs.cfgs.iter().collect::<Vec<_>>();
let docs = obj.common_attrs.docs.iter().collect::<Vec<_>>();
qobject_items.push(parse_quote! {
#namespace
#cxx_name
#(#cfgs)*
#(#docs)*
#vis type #ident;
});
}

let passthrough_items = if !items.is_empty() {
quote! {
#(#items)*
}
} else {
quote! {}
};

cxx_mod.push(parse_quote! {
#extern_block_namespace
#(#extern_block_docs)*
#unsafety extern "C++" {
#(#qobject_items)*

#passthrough_items
}
});

let mut generated = vec![GeneratedRustFragment {
cxx_mod_contents: cxx_mod,
cxx_qt_mod_contents: cxx_qt_mod,
}];

// Build the signals
for signal in &extern_cxxqt_block.signals {
let qobject_name = type_names.lookup(&signal.qobject_ident)?;
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/src/generator/rust/inherit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ pub fn generate(
if method.safe {
std::mem::swap(&mut unsafe_call, &mut unsafe_block);
}
let doc_comments = &method.docs;
let cfgs = &method.cfgs;
let doc_comments = &method.common_attrs.docs;
let cfgs = &method.common_attrs.cfgs;
let namespace = qobject_names.namespace_tokens();

syn::parse2(quote_spanned! {
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/src/generator/rust/qenum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub fn generate_cxx_mod_contents(qenums: &[ParsedQEnum]) -> Vec<Item> {
let item = &qenum.item;
let vis = &item.vis;
let variants = &item.variants;
let docs = &qenum.docs;
let cfgs = &qenum.cfgs;
let docs = &qenum.common_attrs.docs;
let cfgs = &qenum.common_attrs.cfgs;

let cxx_namespace = if namespace.is_none() {
quote! {}
Expand Down
27 changes: 21 additions & 6 deletions crates/cxx-qt-gen/src/generator/rust/qobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::generator::structuring::StructuredQObject;
use crate::parser::CommonAttrs;
use crate::{
generator::{
naming::{namespace::NamespaceName, qobject::QObjectNames},
Expand All @@ -15,7 +16,7 @@ use crate::{
naming::TypeNames,
};
use quote::quote;
use syn::{parse_quote, Attribute, Result};
use syn::{parse_quote, Result};

impl GeneratedRustFragment {
pub fn from_qobject(
Expand All @@ -28,7 +29,7 @@ impl GeneratedRustFragment {
let namespace_idents = NamespaceName::from(qobject);

let mut generated = vec![
generate_qobject_definitions(&qobject_names, &qobject.cfgs)?,
generate_qobject_definitions(&qobject_names, &qobject.common_attrs)?,
generate_rust_properties(
&qobject.properties,
&qobject_names,
Expand Down Expand Up @@ -57,7 +58,7 @@ impl GeneratedRustFragment {
&qobject_names,
&namespace_idents,
type_names,
&qobject.cfgs,
&qobject.common_attrs.cfgs,
)?);
}

Expand All @@ -75,9 +76,9 @@ impl GeneratedRustFragment {
&qobject_names,
&namespace_idents,
type_names,
&qobject.cfgs,
&qobject.common_attrs.cfgs,
)?,
cxxqttype::generate(&qobject_names, type_names, &qobject.cfgs)?,
cxxqttype::generate(&qobject_names, type_names, &qobject.common_attrs.cfgs)?,
]);

Ok(GeneratedRustFragment::flatten(generated))
Expand All @@ -87,8 +88,11 @@ impl GeneratedRustFragment {
/// Generate the C++ and Rust CXX definitions for the QObject
fn generate_qobject_definitions(
qobject_idents: &QObjectNames,
cfgs: &[Attribute],
common_attrs: &CommonAttrs,
) -> Result<GeneratedRustFragment> {
let docs = &common_attrs.docs;
let cfgs = &common_attrs.cfgs;

let cpp_class_name_rust = &qobject_idents.name.rust_unqualified();
let cpp_class_name_cpp = &qobject_idents.name.cxx_unqualified();

Expand All @@ -106,6 +110,15 @@ fn generate_qobject_definitions(
}
};

let maybe_docs = if docs.is_empty() {
quote! {}
} else {
quote! {
#[doc = "\n"]
#(#docs)*
}
};

Ok(GeneratedRustFragment {
cxx_mod_contents: vec![
parse_quote! {
Expand All @@ -116,6 +129,7 @@ fn generate_qobject_definitions(
#[doc = "Use this type when referring to the QObject as a pointer"]
#[doc = "\n"]
#[doc = "See the book for more information: <https://kdab.github.io/cxx-qt/book/concepts/generated_qobject.html>"]
#maybe_docs
#namespace
#cxx_name
#(#cfgs)*
Expand All @@ -130,6 +144,7 @@ fn generate_qobject_definitions(
// but to apply it to only certain types, it is needed here too
#namespace
#(#cfgs)*
#(#docs)*
type #rust_struct_name_rust;
}
},
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/src/generator/rust/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ pub fn generate_rust_signal(
} else {
Some(quote! { unsafe })
};
let doc_comments = &signal.docs;
let cfgs = &signal.cfgs;
let doc_comments = &signal.common_attrs.docs;
let cfgs = &signal.common_attrs.cfgs;
let namespace = if let Some(namespace) = qobject_name.namespace() {
quote_spanned! { span=> #[namespace = #namespace ] }
} else {
Expand Down
12 changes: 8 additions & 4 deletions crates/cxx-qt-gen/src/parser/externcxxqt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use crate::parser::CommonAttrs;
use crate::{
parser::{
externqobject::ParsedExternQObject, require_attributes, signals::ParsedSignal,
Expand All @@ -19,6 +20,8 @@ use syn::{
pub struct ParsedExternCxxQt {
/// The namespace of the type in C++.
pub namespace: Option<String>,
/// All the universal top level attributes for the block
pub common_attrs: CommonAttrs,
/// Whether this block has an unsafe token
pub unsafety: Option<Token![unsafe]>,
/// Items which can be passed into the extern "C++Qt" block
Expand All @@ -35,10 +38,10 @@ impl ParsedExternCxxQt {
module_ident: &Ident,
parent_namespace: Option<&str>,
) -> Result<Self> {
// TODO: support cfg on foreign mod blocks
let attrs = require_attributes(
// TODO: (cfg everywhere) support cfg on foreign mod blocks
let (attrs, common_attrs) = require_attributes(
&foreign_mod.attrs,
&["namespace", "auto_cxx_name", "auto_rust_name"],
&["doc", "namespace", "auto_cxx_name", "auto_rust_name"],
)?;

let auto_case = CaseConversion::from_attrs(&attrs)?;
Expand All @@ -52,6 +55,7 @@ impl ParsedExternCxxQt {

let mut extern_cxx_block = ParsedExternCxxQt {
namespace,
common_attrs,
unsafety: foreign_mod.unsafety,
..Default::default()
};
Expand All @@ -67,7 +71,7 @@ impl ParsedExternCxxQt {
ForeignItem::Type(foreign_ty) => {
// Test that there is a #[qobject] attribute on any type
//
// TODO: what happens to any docs here?
// TODO: (cfg everywhere) what happens to any docs here?
if attribute_get_path(&foreign_ty.attrs, &["qobject"]).is_some() {
let extern_ty =
ParsedExternQObject::parse(foreign_ty, module_ident, parent_namespace)?;
Expand Down
Loading
Loading