Skip to content

Commit

Permalink
refactor: Separate trait parsing from QObject
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonMatthesKDAB authored and BenFordTytherington committed Aug 28, 2024
1 parent 6aa5d0c commit 06ef365
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 130 deletions.
7 changes: 7 additions & 0 deletions crates/cxx-qt-gen/src/generator/structuring/qobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

use crate::naming::Name;
use crate::parser::constructor::Constructor;
use crate::parser::inherit::ParsedInheritedMethod;
use crate::parser::method::ParsedMethod;
use crate::parser::signals::ParsedSignal;
Expand All @@ -19,6 +20,9 @@ pub struct StructuredQObject<'a> {
pub methods: Vec<&'a ParsedMethod>,
pub inherited_methods: Vec<&'a ParsedInheritedMethod>,
pub signals: Vec<&'a ParsedSignal>,
pub constructors: Vec<Constructor>,
pub locking: bool,
pub threading: bool,
}

impl<'a> StructuredQObject<'a> {
Expand All @@ -34,6 +38,9 @@ impl<'a> StructuredQObject<'a> {
methods: vec![],
inherited_methods: vec![],
signals: vec![],
constructors: vec![],
locking: true,
threading: false,
}
}

Expand Down
7 changes: 7 additions & 0 deletions crates/cxx-qt-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ mod tests {
}
}

macro_rules! assert_parse_errors {
{ $type:ident: $($input:tt)* } => {
$(assert!($type::parse(syn::parse_quote! $input).is_err());)*
}
}
pub(crate) use assert_parse_errors;

/// Helper for formating C++ code
pub(crate) fn format_cpp(cpp_code: &str) -> String {
clang_format_with_style(cpp_code, &ClangFormatStyle::File).unwrap()
Expand Down
25 changes: 13 additions & 12 deletions crates/cxx-qt-gen/src/parser/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct ConstructorArguments {
}

/// A parsed cxx_qt::Constructor trait impl.
#[derive(Debug, PartialEq, Eq)]
pub struct Constructor {
/// The arguments to the constructor defined by this trait impl.
pub arguments: Vec<Type>,
Expand All @@ -37,6 +38,7 @@ pub struct Constructor {
pub lifetime: Option<Lifetime>,

/// The original impl that this constructor was parse from.
// TODO: This has moved into MarkerTrait
pub imp: ItemImpl,
}

Expand Down Expand Up @@ -150,20 +152,20 @@ impl Constructor {
));
}

if !imp.items.is_empty() {
let (not, trait_path, _) = &imp
.trait_
.as_ref()
.ok_or_else(|| Error::new_spanned(imp.clone(), "Expected trait impl!"))?;

if not.is_some() {
return Err(Error::new_spanned(
imp.items.first(),
"cxx_qt::Constructor must only be declared, not implemented inside cxx_qt::bridge!",
trait_path,
"Negative impls for cxx_qt::Constructor are not allowed",
));
}

let lifetime = Self::parse_impl_generics(&imp.generics)?;

let (_, trait_path, _) = &imp
.trait_
.as_ref()
.ok_or_else(|| Error::new_spanned(imp.clone(), "Expected trait impl!"))?;

let (argument_list, arguments) = Self::parse_arguments(trait_path)?;
Ok(Constructor {
arguments: argument_list,
Expand Down Expand Up @@ -207,13 +209,12 @@ mod tests {
"missing main argument list",
);

// Hard to tell if this actually hits the error as the rest of the project isn't compiling
assert_parse_error(
parse_quote! {
impl cxx_qt::Constructor<()> for X {
fn some_impl() {}
}
impl !cxx_qt::Constructor<(i32, i32)> for T {}
},
"item in impl block",
"Negative impls for cxx_qt::Constructor are not allowed",
);

assert_parse_error(
Expand Down
36 changes: 15 additions & 21 deletions crates/cxx-qt-gen/src/parser/cxxqtdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ use crate::{
use std::collections::BTreeMap;
use syn::{
spanned::Spanned, Error, ForeignItem, Ident, Item, ItemEnum, ItemForeignMod, ItemImpl, Result,
Type, TypePath,
};
use syn::{ItemMacro, Meta};

use super::qnamespace::ParsedQNamespace;
use super::trait_impl::TraitImpl;

pub struct ParsedCxxQtData {
/// Map of the QObjects defined in the module that will be used for code generation
Expand All @@ -43,6 +43,8 @@ pub struct ParsedCxxQtData {
pub extern_cxxqt_blocks: Vec<ParsedExternCxxQt>,
/// The namespace of the CXX-Qt module
pub namespace: Option<String>,
/// All trait implementations found
pub trait_impls: Vec<TraitImpl>,
/// The ident of the module, used for mappings
pub module_ident: Ident,
}
Expand All @@ -57,6 +59,7 @@ impl ParsedCxxQtData {
signals: vec![],
inherited_methods: vec![],
qnamespaces: vec![],
trait_impls: vec![],
extern_cxxqt_blocks: Vec::<ParsedExternCxxQt>::default(),
module_ident,
namespace,
Expand Down Expand Up @@ -237,23 +240,14 @@ impl ParsedCxxQtData {
/// Parse a [syn::ItemImpl] into the qobjects if it's a CXX-Qt implementation
/// otherwise return as a [syn::Item] to pass through.
fn parse_impl(&mut self, imp: ItemImpl) -> Result<Option<Item>> {
// If the implementation has a T
// then this is the block of methods to be implemented on the C++ object
if let Type::Path(TypePath { path, .. }) = imp.self_ty.as_ref() {
// If this path is an ident then try to match to a QObject
if let Some(ident) = path.get_ident() {
// Find if we are an impl block for a qobject
if let Some(qobject) = self.qobjects.get_mut(ident) {
// If we are a trait then process it otherwise add to others
if imp.trait_.is_some() {
qobject.parse_trait_impl(imp)?;
return Ok(None);
}
}
}
// If it is a trait impl compared to a regular impl block
// This allows the cxx shim trait feature
if imp.trait_.is_some() {
self.trait_impls.push(TraitImpl::parse(imp)?);
Ok(None)
} else {
Ok(Some(Item::Impl(imp)))
}

Ok(Some(Item::Impl(imp)))
}
}

Expand Down Expand Up @@ -587,14 +581,14 @@ mod tests {
#[test]
fn test_find_and_merge_cxx_qt_item_threading() {
let mut cxx_qt_data = create_parsed_cxx_qt_data();
assert!(!cxx_qt_data.qobjects[&qobject_ident()].threading);
// assert!(!cxx_qt_data.qobjects[&qobject_ident()].threading);

let item: Item = parse_quote! {
impl cxx_qt::Threading for MyObject {}
};
let result = cxx_qt_data.parse_cxx_qt_item(item).unwrap();
assert!(result.is_none());
assert!(cxx_qt_data.qobjects[&qobject_ident()].threading);
// assert!(cxx_qt_data.qobjects[&qobject_ident()].threading);
}

#[test]
Expand Down Expand Up @@ -729,7 +723,7 @@ mod tests {
let mut cxxqtdata = create_parsed_cxx_qt_data();

let qobject = cxxqtdata.qobjects.get(&qobject_ident()).unwrap();
assert!(!qobject.threading);
// assert!(!qobject.threading);

let threading_block: Item = parse_quote! {
impl cxx_qt::Threading for MyObject {}
Expand All @@ -738,7 +732,7 @@ mod tests {
cxxqtdata.parse_cxx_qt_item(threading_block).unwrap();

let qobject = cxxqtdata.qobjects.get(&qobject_ident()).unwrap();
assert!(qobject.threading);
// assert!(qobject.threading);
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions crates/cxx-qt-gen/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod qenum;
pub mod qnamespace;
pub mod qobject;
pub mod signals;
pub mod trait_impl;

use crate::{
// Used for error handling when resolving the namespace of the qenum.
Expand Down
Loading

0 comments on commit 06ef365

Please sign in to comment.