Skip to content

Commit f7c81e2

Browse files
Move inlining to a separate phase which processes a Parser
- Add function call to cxx-qt-build and cxx-qt-macro - Inlining now happens after parsing and before structuring
1 parent 4c733a7 commit f7c81e2

File tree

5 files changed

+110
-62
lines changed

5 files changed

+110
-62
lines changed

crates/cxx-qt-build/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ use std::{
4343
};
4444

4545
use cxx_qt_gen::{
46-
parse_qt_file, write_cpp, write_rust, CppFragment, CxxQtItem, GeneratedCppBlocks, GeneratedOpt,
47-
GeneratedRustBlocks, Parser,
46+
parse_qt_file, qualify_self_types, write_cpp, write_rust, CppFragment, CxxQtItem,
47+
GeneratedCppBlocks, GeneratedOpt, GeneratedRustBlocks, Parser,
4848
};
4949

5050
// TODO: we need to eventually support having multiple modules defined in a single file. This
@@ -132,7 +132,10 @@ impl GeneratedCpp {
132132
}
133133
found_bridge = true;
134134

135-
let parser = Parser::from(m.clone())
135+
let mut parser = Parser::from(m.clone())
136+
.map_err(GeneratedError::from)
137+
.map_err(to_diagnostic)?;
138+
qualify_self_types(&mut parser)
136139
.map_err(GeneratedError::from)
137140
.map_err(to_diagnostic)?;
138141
let generated_cpp = GeneratedCppBlocks::from(&parser, &cxx_qt_opt)

crates/cxx-qt-gen/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub use generator::{
2121
GeneratedOpt,
2222
};
2323
pub use parser::Parser;
24+
pub use preprocessor::self_inlining::qualify_self_types;
2425
pub use syntax::{parse_qt_file, CxxQtFile, CxxQtItem};
2526
pub use writer::{cpp::write_cpp, rust::write_rust};
2627

@@ -175,7 +176,8 @@ mod tests {
175176
expected_cpp_header: &str,
176177
expected_cpp_source: &str,
177178
) {
178-
let parser = Parser::from(syn::parse_str(input).unwrap()).unwrap();
179+
let mut parser = Parser::from(syn::parse_str(input).unwrap()).unwrap();
180+
qualify_self_types(&mut parser).unwrap();
179181

180182
let mut cfg_evaluator = CfgEvaluatorTest::default();
181183
cfg_evaluator.cfgs.insert("crate", Some("cxx-qt-gen"));

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use super::qnamespace::ParsedQNamespace;
77
use super::trait_impl::TraitImpl;
88
use crate::naming::cpp::err_unsupported_item;
99
use crate::parser::CaseConversion;
10-
use crate::preprocessor::self_inlining::try_inline_self_invokables;
1110
use crate::{
1211
parser::{
1312
externcxxqt::ParsedExternCxxQt, inherit::ParsedInheritedMethod, method::ParsedMethod,
@@ -18,7 +17,6 @@ use crate::{
1817
path::path_compare_str,
1918
},
2019
};
21-
use quote::format_ident;
2220
use syn::{
2321
spanned::Spanned, Error, ForeignItem, Ident, Item, ItemEnum, ItemForeignMod, ItemImpl,
2422
ItemMacro, Meta, Result,
@@ -236,16 +234,6 @@ impl ParsedCxxQtData {
236234
}
237235
}
238236

239-
// If there is exaclty one qobject in the block, it can be inlined as a self type.
240-
let inline_self = qobjects.len() == 1;
241-
let inline_ident = qobjects
242-
.last()
243-
.map(|obj| format_ident!("{}", obj.declaration.ident_left));
244-
245-
try_inline_self_invokables(inline_self, &inline_ident, &mut methods)?;
246-
try_inline_self_invokables(inline_self, &inline_ident, &mut signals)?;
247-
try_inline_self_invokables(inline_self, &inline_ident, &mut inherited)?;
248-
249237
self.qobjects.push(qobjects);
250238
self.methods.push(methods);
251239
self.signals.push(signals);

crates/cxx-qt-gen/src/preprocessor/self_inlining.rs

Lines changed: 96 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

6-
use crate::parser::method::MethodFields;
6+
use crate::parser::cxxqtdata::ParsedCxxQtData;
7+
use crate::parser::inherit::ParsedInheritedMethod;
8+
use crate::parser::method::{MethodFields, ParsedMethod};
9+
use crate::parser::qobject::ParsedQObject;
10+
use crate::parser::signals::ParsedSignal;
11+
use crate::Parser;
712
use proc_macro2::Ident;
13+
use quote::format_ident;
814
use std::ops::DerefMut;
915
use syn::spanned::Spanned;
10-
use syn::Error;
16+
use syn::{Error, Result};
1117

1218
/// Inline any `Self` types in the methods signatures with the Ident of a qobject passed in
1319
///
@@ -41,86 +47,131 @@ pub fn try_inline_self_invokables(
4147
Ok(())
4248
}
4349

50+
/// A collection of items found in an extern block when parsing
51+
type BlockComponents<'a> = (
52+
&'a mut Vec<ParsedQObject>,
53+
&'a mut Vec<ParsedMethod>,
54+
&'a mut Vec<ParsedInheritedMethod>,
55+
&'a mut Vec<ParsedSignal>,
56+
);
57+
58+
// Separates the parsed data by block and returns tuples of the components
59+
fn separate_blocks(data: &mut ParsedCxxQtData) -> Vec<BlockComponents> {
60+
data.qobjects
61+
.iter_mut()
62+
.zip(data.methods.iter_mut())
63+
.zip(data.inherited_methods.iter_mut())
64+
.zip(data.signals.iter_mut())
65+
.map(|(((qobject, method), inherited_method), signal)| {
66+
(qobject, method, inherited_method, signal)
67+
})
68+
.collect()
69+
}
70+
71+
/// For a given parser, attempt to inline the `Self` type used in any of the blocks with that blocks unique QObject
72+
pub fn qualify_self_types(parser: &mut Parser) -> Result<()> {
73+
for (qobjects, methods, inherited, signals) in separate_blocks(&mut parser.cxx_qt_data) {
74+
let inline_self = qobjects.len() == 1;
75+
let inline_ident = qobjects
76+
.last()
77+
.map(|obj| format_ident!("{}", obj.declaration.ident_left));
78+
79+
try_inline_self_invokables(inline_self, &inline_ident, methods)?;
80+
try_inline_self_invokables(inline_self, &inline_ident, signals)?;
81+
try_inline_self_invokables(inline_self, &inline_ident, inherited)?;
82+
}
83+
84+
Ok(())
85+
}
86+
4487
#[cfg(test)]
4588
mod tests {
4689
use super::*;
47-
use crate::parser::cxxqtdata::ParsedCxxQtData;
4890
use crate::parser::method::ParsedMethod;
4991
use crate::tests::assert_parse_errors;
50-
use quote::format_ident;
51-
use syn::{parse_quote, Item};
92+
use syn::parse_quote;
5293

5394
#[test]
5495
fn test_self_inlining_ref() {
55-
let mut parsed_cxxqtdata = ParsedCxxQtData::new(format_ident!("ffi"), None);
56-
let extern_rust_qt: Item = parse_quote! {
57-
unsafe extern "RustQt" {
58-
#[qobject]
59-
type MyObject = super::T;
96+
let module = parse_quote! {
97+
#[cxx_qt::bridge]
98+
mod ffi {
99+
unsafe extern "RustQt" {
100+
#[qobject]
101+
type MyObject = super::T;
60102

61-
fn my_method(&self);
103+
fn my_method(&self);
62104

63-
#[inherit]
64-
fn my_inherited_method(&self);
105+
#[inherit]
106+
fn my_inherited_method(&self);
107+
}
65108
}
66109
};
67-
68-
parsed_cxxqtdata.parse_cxx_qt_item(extern_rust_qt).unwrap();
110+
let mut parser = Parser::from(module).unwrap();
111+
assert!(qualify_self_types(&mut parser).is_ok());
69112
}
70113

71114
#[test]
72115
fn test_self_inlining_pin() {
73-
let mut parsed_cxxqtdata = ParsedCxxQtData::new(format_ident!("ffi"), None);
74-
let extern_rust_qt: Item = parse_quote! {
75-
unsafe extern "RustQt" {
76-
#[qobject]
77-
type MyObject = super::T;
78-
79-
#[qsignal]
80-
fn my_signal(self: Pin<&mut Self>);
81-
}
82-
};
116+
let module = parse_quote! {
117+
#[cxx_qt::bridge]
118+
mod ffi {
119+
unsafe extern "RustQt" {
120+
#[qobject]
121+
type MyObject = super::T;
83122

84-
let extern_cpp_qt: Item = parse_quote! {
85-
unsafe extern "C++Qt" {
86-
#[qobject]
87-
type MyObject;
123+
#[qsignal]
124+
fn my_signal(self: Pin<&mut Self>);
125+
}
88126

89-
#[qsignal]
90-
fn my_signal(self: Pin<&mut Self>);
127+
unsafe extern "C++Qt" {
128+
#[qobject]
129+
type MyOtherObject;
130+
131+
#[qsignal]
132+
fn my_signal(self: Pin<&mut Self>);
133+
}
91134
}
92135
};
93-
94-
parsed_cxxqtdata.parse_cxx_qt_item(extern_rust_qt).unwrap();
95-
parsed_cxxqtdata.parse_cxx_qt_item(extern_cpp_qt).unwrap();
136+
let mut parser = Parser::from(module).unwrap();
137+
assert!(qualify_self_types(&mut parser).is_ok());
96138
}
97139

98140
#[test]
99141
fn test_self_inlining_methods_invalid() {
100142
assert_parse_errors! {
101-
|item| ParsedCxxQtData::new(format_ident!("ffi"), None).parse_cxx_qt_item(item) =>
143+
|item| qualify_self_types(&mut Parser::from(item)?) =>
102144
// No QObject in block
103145
{
104-
extern "RustQt" {
105-
fn my_method(&self);
146+
#[cxx_qt::bridge]
147+
mod ffi {
148+
extern "RustQt" {
149+
fn my_method(&self);
150+
}
106151
}
107152
}
108153

109154
{
110-
extern "RustQt" {
111-
fn my_method(self: Pin<&mut Self>);
155+
#[cxx_qt::bridge]
156+
mod ffi {
157+
extern "RustQt" {
158+
fn my_method(self: Pin<&mut Self>);
159+
}
112160
}
113161
}
114162
// More than 1 QObjects in block
115163
{
116-
extern "RustQt" {
117-
#[qobject]
118-
type MyObject = super::T;
164+
#[cxx_qt::bridge]
165+
mod ffi {
166+
extern "RustQt" {
167+
#[qobject]
168+
type MyObject = super::T;
119169

120-
#[qobject]
121-
type MyOtherObject = super::S;
170+
#[qobject]
171+
type MyOtherObject = super::S;
122172

123-
fn my_method(&self);
173+
fn my_method(&self);
174+
}
124175
}
125176
}
126177
}

crates/cxx-qt-macro/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use proc_macro::TokenStream;
1616
use syn::{parse_macro_input, ItemMod};
1717

18-
use cxx_qt_gen::{write_rust, GeneratedRustBlocks, Parser};
18+
use cxx_qt_gen::{qualify_self_types, write_rust, GeneratedRustBlocks, Parser};
1919

2020
#[proc_macro_attribute]
2121
pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
@@ -75,6 +75,10 @@ pub fn init_qml_module(args: TokenStream) -> TokenStream {
7575
// Take the module and C++ namespace and generate the rust code
7676
fn extract_and_generate(module: ItemMod) -> TokenStream {
7777
Parser::from(module)
78+
.and_then(|mut parser| {
79+
qualify_self_types(&mut parser)?;
80+
Ok(parser)
81+
})
7882
.and_then(|parser| GeneratedRustBlocks::from(&parser))
7983
.map(|generated_rust| write_rust(&generated_rust, None))
8084
.unwrap_or_else(|err| err.to_compile_error())

0 commit comments

Comments
 (0)