Skip to content

Commit 7f256a6

Browse files
Place all objects and passthrough items in the same block, to pass through module docs and cfg (C++Qt only)
1 parent a87fcb1 commit 7f256a6

File tree

8 files changed

+111
-75
lines changed

8 files changed

+111
-75
lines changed

crates/cxx-qt-gen/src/generator/rust/externcxxqt.rs

Lines changed: 73 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
syntax::path::path_compare_str,
1111
};
1212
use quote::quote;
13-
use syn::{parse_quote, Attribute, Result};
13+
use syn::{parse_quote, Attribute, Item, Result};
1414

1515
impl GeneratedRustFragment {
1616
pub fn from_extern_cxx_qt(
@@ -22,76 +22,88 @@ impl GeneratedRustFragment {
2222
} else {
2323
quote! {}
2424
};
25+
let extern_block_docs = &extern_cxxqt_block.docs;
2526

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

36-
generated.push(GeneratedRustFragment::generate_casting_impl(
37-
&qobject_names,
38-
type_names,
39-
&ty.name,
40-
&ty.base_class,
41-
)?);
31+
let mut qobject_items: Vec<Item> = vec![];
32+
let mut cxx_qt_mod = vec![];
33+
let mut cxx_mod = vec![];
34+
for obj in &extern_cxxqt_block.qobjects {
35+
let qobject_names = QObjectNames::from_extern_qobject(obj, type_names)?;
4236

43-
let namespace = if let Some(namespace) = &ty.name.namespace() {
44-
quote! { #[namespace = #namespace ] }
45-
} else {
46-
quote! {}
47-
};
48-
let cpp_name = &ty.name.cxx_unqualified();
49-
let rust_name = &ty.name.rust_unqualified();
50-
let vis = &ty.declaration.vis;
51-
let ident = &ty.name.rust_unqualified();
52-
let cxx_name = if &rust_name.to_string() == cpp_name {
53-
quote! {}
54-
} else {
55-
let cxx_name = cpp_name.to_string();
56-
quote! {
57-
#[cxx_name = #cxx_name]
58-
}
59-
};
60-
let cfgs: Vec<&Attribute> = ty
61-
.declaration
62-
.attrs
63-
.iter()
64-
.filter(|attr| path_compare_str(attr.meta.path(), &["cfg"]))
65-
.collect();
66-
let docs: Vec<&Attribute> = ty
67-
.declaration
68-
.attrs
69-
.iter()
70-
.filter(|attr| path_compare_str(attr.meta.path(), &["doc"]))
71-
.collect();
72-
generated.push(GeneratedRustFragment::from_cxx_item(parse_quote! {
73-
#extern_block_namespace
74-
#unsafety extern "C++" {
75-
#namespace
76-
#cxx_name
77-
#(#cfgs)*
78-
#(#docs)*
79-
#vis type #ident;
80-
}
81-
}));
82-
Ok(GeneratedRustFragment::flatten(generated))
83-
})
84-
.collect::<Result<Vec<_>>>()?;
37+
let casting = GeneratedRustFragment::generate_casting_impl(
38+
&qobject_names,
39+
type_names,
40+
&obj.name,
41+
&obj.base_class,
42+
)?;
43+
cxx_mod.extend(casting.cxx_mod_contents);
44+
cxx_qt_mod.extend(casting.cxx_qt_mod_contents);
8545

86-
if !items.is_empty() {
87-
generated.push(GeneratedRustFragment::from_cxx_item(parse_quote! {
88-
#extern_block_namespace
89-
#unsafety extern "C++" {
90-
#(#items)*
46+
let namespace = if let Some(namespace) = &obj.name.namespace() {
47+
quote! { #[namespace = #namespace ] }
48+
} else {
49+
quote! {}
50+
};
51+
let cpp_name = &obj.name.cxx_unqualified();
52+
let rust_name = &obj.name.rust_unqualified();
53+
let vis = &obj.declaration.vis;
54+
let ident = &obj.name.rust_unqualified();
55+
let cxx_name = if &rust_name.to_string() == cpp_name {
56+
quote! {}
57+
} else {
58+
let cxx_name = cpp_name.to_string();
59+
quote! {
60+
#[cxx_name = #cxx_name]
9161
}
92-
}));
62+
};
63+
let cfgs: Vec<&Attribute> = obj
64+
.declaration
65+
.attrs
66+
.iter()
67+
.filter(|attr| path_compare_str(attr.meta.path(), &["cfg"]))
68+
.collect();
69+
let docs: Vec<&Attribute> = obj
70+
.declaration
71+
.attrs
72+
.iter()
73+
.filter(|attr| path_compare_str(attr.meta.path(), &["doc"]))
74+
.collect();
75+
qobject_items.push(parse_quote! {
76+
#namespace
77+
#cxx_name
78+
#(#cfgs)*
79+
#(#docs)*
80+
#vis type #ident;
81+
});
9382
}
9483

84+
let passthrough_items = if !items.is_empty() {
85+
quote! {
86+
#(#items)*
87+
}
88+
} else {
89+
quote! {}
90+
};
91+
92+
cxx_mod.push(parse_quote! {
93+
#extern_block_namespace
94+
#(#extern_block_docs)*
95+
#unsafety extern "C++" {
96+
#(#qobject_items)*
97+
98+
#passthrough_items
99+
}
100+
});
101+
102+
let mut generated = vec![GeneratedRustFragment {
103+
cxx_mod_contents: cxx_mod,
104+
cxx_qt_mod_contents: cxx_qt_mod,
105+
}];
106+
95107
// Build the signals
96108
for signal in &extern_cxxqt_block.signals {
97109
let qobject_name = type_names.lookup(&signal.qobject_ident)?;

crates/cxx-qt-gen/src/generator/rust/qobject.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl GeneratedRustFragment {
2828
let namespace_idents = NamespaceName::from(qobject);
2929

3030
let mut generated = vec![
31-
generate_qobject_definitions(&qobject_names, &qobject.cfgs)?,
31+
generate_qobject_definitions(&qobject_names, &qobject.cfgs, &qobject.docs)?,
3232
generate_rust_properties(
3333
&qobject.properties,
3434
&qobject_names,
@@ -88,6 +88,7 @@ impl GeneratedRustFragment {
8888
fn generate_qobject_definitions(
8989
qobject_idents: &QObjectNames,
9090
cfgs: &[Attribute],
91+
docs: &[Attribute],
9192
) -> Result<GeneratedRustFragment> {
9293
let cpp_class_name_rust = &qobject_idents.name.rust_unqualified();
9394
let cpp_class_name_cpp = &qobject_idents.name.cxx_unqualified();
@@ -106,6 +107,15 @@ fn generate_qobject_definitions(
106107
}
107108
};
108109

110+
let maybe_docs = if docs.is_empty() {
111+
quote! {}
112+
} else {
113+
quote! {
114+
#[doc = "\n"]
115+
#(#docs)*
116+
}
117+
};
118+
109119
Ok(GeneratedRustFragment {
110120
cxx_mod_contents: vec![
111121
parse_quote! {
@@ -116,6 +126,7 @@ fn generate_qobject_definitions(
116126
#[doc = "Use this type when referring to the QObject as a pointer"]
117127
#[doc = "\n"]
118128
#[doc = "See the book for more information: <https://kdab.github.io/cxx-qt/book/concepts/generated_qobject.html>"]
129+
#maybe_docs
119130
#namespace
120131
#cxx_name
121132
#(#cfgs)*
@@ -130,6 +141,7 @@ fn generate_qobject_definitions(
130141
// but to apply it to only certain types, it is needed here too
131142
#namespace
132143
#(#cfgs)*
144+
#(#docs)*
133145
type #rust_struct_name_rust;
134146
}
135147
},

crates/cxx-qt-gen/src/parser/externcxxqt.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

6+
use crate::parser::extract_docs;
67
use crate::{
78
parser::{
89
externqobject::ParsedExternQObject, require_attributes, signals::ParsedSignal,
@@ -11,14 +12,17 @@ use crate::{
1112
syntax::{attribute::attribute_get_path, expr::expr_to_string},
1213
};
1314
use syn::{
14-
spanned::Spanned, Error, ForeignItem, ForeignItemFn, Ident, ItemForeignMod, Result, Token,
15+
spanned::Spanned, Attribute, Error, ForeignItem, ForeignItemFn, Ident, ItemForeignMod, Result,
16+
Token,
1517
};
1618

1719
/// Representation of an extern "C++Qt" block
1820
#[derive(Default)]
1921
pub struct ParsedExternCxxQt {
2022
/// The namespace of the type in C++.
2123
pub namespace: Option<String>,
24+
/// The Top level docs on the module
25+
pub docs: Vec<Attribute>,
2226
/// Whether this block has an unsafe token
2327
pub unsafety: Option<Token![unsafe]>,
2428
/// Items which can be passed into the extern "C++Qt" block
@@ -38,9 +42,11 @@ impl ParsedExternCxxQt {
3842
// TODO: support cfg on foreign mod blocks
3943
let attrs = require_attributes(
4044
&foreign_mod.attrs,
41-
&["namespace", "auto_cxx_name", "auto_rust_name"],
45+
&["namespace", "doc", "auto_cxx_name", "auto_rust_name"],
4246
)?;
4347

48+
let docs = extract_docs(&foreign_mod.attrs);
49+
4450
let auto_case = CaseConversion::from_attrs(&attrs)?;
4551

4652
let namespace = attrs
@@ -52,6 +58,7 @@ impl ParsedExternCxxQt {
5258

5359
let mut extern_cxx_block = ParsedExternCxxQt {
5460
namespace,
61+
docs,
5562
unsafety: foreign_mod.unsafety,
5663
..Default::default()
5764
};

crates/cxx-qt-gen/src/parser/qobject.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
#[cfg(test)]
1212
use quote::format_ident;
1313

14-
use crate::parser::{parse_base_type, CaseConversion};
14+
use crate::parser::{extract_docs, parse_base_type, CaseConversion};
1515
use syn::{Attribute, Error, Ident, Meta, Result};
1616

1717
/// Metadata for registering QML element
@@ -44,6 +44,8 @@ pub struct ParsedQObject {
4444
pub declaration: ForeignTypeIdentAlias,
4545
/// Cfgs for the object
4646
pub cfgs: Vec<Attribute>,
47+
/// Docs for the object
48+
pub docs: Vec<Attribute>,
4749
}
4850

4951
impl ParsedQObject {
@@ -75,6 +77,7 @@ impl ParsedQObject {
7577
ident_right: format_ident!("MyObjectRust"),
7678
},
7779
cfgs: vec![],
80+
docs: vec![],
7881
}
7982
}
8083

@@ -86,8 +89,8 @@ impl ParsedQObject {
8689
auto_case: CaseConversion,
8790
) -> Result<Self> {
8891
let attributes = require_attributes(&declaration.attrs, &Self::ALLOWED_ATTRS)?;
89-
// TODO: handle docs through to generation
9092
let cfgs = extract_cfgs(&declaration.attrs);
93+
let docs = extract_docs(&declaration.attrs);
9194

9295
let has_qobject_macro = attributes.contains_key("qobject");
9396

@@ -126,6 +129,7 @@ impl ParsedQObject {
126129
qml_metadata,
127130
has_qobject_macro,
128131
cfgs,
132+
docs,
129133
})
130134
}
131135

crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub mod ffi {
9292
}
9393

9494
#[namespace = ""]
95+
/// Top level docs for a module
9596
unsafe extern "C++Qt" {
9697
#[qobject]
9798
type QPushButton;
@@ -102,6 +103,7 @@ pub mod ffi {
102103
#[namespace = "mynamespace"]
103104
#[cxx_name = "ExternObjectCpp"]
104105
#[qobject]
106+
/// An external object with some docs on it
105107
type ExternObject;
106108

107109
#[qsignal]
@@ -130,6 +132,7 @@ pub mod ffi {
130132
#[qobject]
131133
#[namespace = "second_object"]
132134
#[qproperty(i32, property_name, cxx_name = "propertyName")]
135+
/// The second QObject with some different docs on it
133136
type SecondObject = super::SecondObjectRust;
134137
}
135138

crates/cxx-qt-gen/test_outputs/inheritance.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ mod inheritance {
103103
}
104104
extern "C++" {
105105
type QPushButton;
106-
}
107-
extern "C++" {
108106
include ! (< QtWidgets / QPushButton >);
109107
}
110108
extern "C++" {

crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,14 @@ pub mod ffi {
201201
#[doc = "Use this type when referring to the QObject as a pointer"]
202202
#[doc = "\n"]
203203
#[doc = "See the book for more information: <https://kdab.github.io/cxx-qt/book/concepts/generated_qobject.html>"]
204+
#[doc = "\n"]
205+
#[doc = " The second QObject with some different docs on it"]
204206
#[namespace = "second_object"]
205207
type SecondObject;
206208
}
207209
extern "Rust" {
208210
#[namespace = "second_object"]
211+
#[doc = " The second QObject with some different docs on it"]
209212
type SecondObjectRust;
210213
}
211214
extern "Rust" {
@@ -381,11 +384,6 @@ pub mod ffi {
381384
#[namespace = "rust::cxxqt1"]
382385
unsafe fn cxx_qt_ffi_QPushButton_downcastPtr(base: *const QObject) -> *const QPushButton;
383386
}
384-
#[namespace = ""]
385-
unsafe extern "C++" {
386-
#[namespace = "cxx_qt::multi_object"]
387-
type QPushButton;
388-
}
389387
extern "C++" {
390388
#[doc(hidden)]
391389
#[cxx_name = "upcastPtr"]
@@ -400,9 +398,13 @@ pub mod ffi {
400398
) -> *const ExternObject;
401399
}
402400
#[namespace = ""]
401+
#[doc = " Top level docs for a module"]
403402
unsafe extern "C++" {
403+
#[namespace = "cxx_qt::multi_object"]
404+
type QPushButton;
404405
#[namespace = "mynamespace"]
405406
#[cxx_name = "ExternObjectCpp"]
407+
#[doc = " An external object with some docs on it"]
406408
type ExternObject;
407409
}
408410
unsafe extern "C++" {

crates/cxx-qt-gen/test_outputs/signals.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ mod ffi {
196196
#[namespace = "cxx_qt::my_object"]
197197
#[doc = " QTimer"]
198198
type QTimer;
199-
}
200-
unsafe extern "C++" {
201199
include ! (< QtCore / QTimer >);
202200
}
203201
unsafe extern "C++" {

0 commit comments

Comments
 (0)