Skip to content

Commit 85d8ee3

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 402f443 commit 85d8ee3

File tree

5 files changed

+112
-62
lines changed

5 files changed

+112
-62
lines changed

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

+6-3
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

+3-1
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

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

+98-45
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,133 @@ 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(
60+
data: &mut ParsedCxxQtData,
61+
) -> Vec<BlockComponents> {
62+
data.qobjects
63+
.iter_mut()
64+
.zip(data.methods.iter_mut())
65+
.zip(data.inherited_methods.iter_mut())
66+
.zip(data.signals.iter_mut())
67+
.map(|(((qobject, method), inherited_method), signal)| {
68+
(qobject, method, inherited_method, signal)
69+
})
70+
.collect()
71+
}
72+
73+
/// For a given parser, attempt to inline the `Self` type used in any of the blocks with that blocks unique QObject
74+
pub fn qualify_self_types(parser: &mut Parser) -> Result<()> {
75+
for (qobjects, methods, inherited, signals) in separate_blocks(&mut parser.cxx_qt_data) {
76+
let inline_self = qobjects.len() == 1;
77+
let inline_ident = qobjects
78+
.last()
79+
.map(|obj| format_ident!("{}", obj.declaration.ident_left));
80+
81+
try_inline_self_invokables(inline_self, &inline_ident, methods)?;
82+
try_inline_self_invokables(inline_self, &inline_ident, signals)?;
83+
try_inline_self_invokables(inline_self, &inline_ident, inherited)?;
84+
}
85+
86+
Ok(())
87+
}
88+
4489
#[cfg(test)]
4590
mod tests {
4691
use super::*;
47-
use crate::parser::cxxqtdata::ParsedCxxQtData;
4892
use crate::parser::method::ParsedMethod;
4993
use crate::tests::assert_parse_errors;
50-
use quote::format_ident;
51-
use syn::{parse_quote, Item};
94+
use syn::parse_quote;
5295

5396
#[test]
5497
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;
98+
let module = parse_quote! {
99+
#[cxx_qt::bridge]
100+
mod ffi {
101+
unsafe extern "RustQt" {
102+
#[qobject]
103+
type MyObject = super::T;
60104

61-
fn my_method(&self);
105+
fn my_method(&self);
62106

63-
#[inherit]
64-
fn my_inherited_method(&self);
107+
#[inherit]
108+
fn my_inherited_method(&self);
109+
}
65110
}
66111
};
67-
68-
parsed_cxxqtdata.parse_cxx_qt_item(extern_rust_qt).unwrap();
112+
let mut parser = Parser::from(module).unwrap();
113+
assert!(qualify_self_types(&mut parser).is_ok());
69114
}
70115

71116
#[test]
72117
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-
};
118+
let module = parse_quote! {
119+
#[cxx_qt::bridge]
120+
mod ffi {
121+
unsafe extern "RustQt" {
122+
#[qobject]
123+
type MyObject = super::T;
83124

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

89-
#[qsignal]
90-
fn my_signal(self: Pin<&mut Self>);
129+
unsafe extern "C++Qt" {
130+
#[qobject]
131+
type MyOtherObject;
132+
133+
#[qsignal]
134+
fn my_signal(self: Pin<&mut Self>);
135+
}
91136
}
92137
};
93-
94-
parsed_cxxqtdata.parse_cxx_qt_item(extern_rust_qt).unwrap();
95-
parsed_cxxqtdata.parse_cxx_qt_item(extern_cpp_qt).unwrap();
138+
let mut parser = Parser::from(module).unwrap();
139+
assert!(qualify_self_types(&mut parser).is_ok());
96140
}
97141

98142
#[test]
99143
fn test_self_inlining_methods_invalid() {
100144
assert_parse_errors! {
101-
|item| ParsedCxxQtData::new(format_ident!("ffi"), None).parse_cxx_qt_item(item) =>
145+
|item| qualify_self_types(&mut Parser::from(item)?) =>
102146
// No QObject in block
103147
{
104-
extern "RustQt" {
105-
fn my_method(&self);
148+
#[cxx_qt::bridge]
149+
mod ffi {
150+
extern "RustQt" {
151+
fn my_method(&self);
152+
}
106153
}
107154
}
108155

109156
{
110-
extern "RustQt" {
111-
fn my_method(self: Pin<&mut Self>);
157+
#[cxx_qt::bridge]
158+
mod ffi {
159+
extern "RustQt" {
160+
fn my_method(self: Pin<&mut Self>);
161+
}
112162
}
113163
}
114164
// More than 1 QObjects in block
115165
{
116-
extern "RustQt" {
117-
#[qobject]
118-
type MyObject = super::T;
166+
#[cxx_qt::bridge]
167+
mod ffi {
168+
extern "RustQt" {
169+
#[qobject]
170+
type MyObject = super::T;
119171

120-
#[qobject]
121-
type MyOtherObject = super::S;
172+
#[qobject]
173+
type MyOtherObject = super::S;
122174

123-
fn my_method(&self);
175+
fn my_method(&self);
176+
}
124177
}
125178
}
126179
}

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

+5-1
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)