From 433a932b3e1df8e7d36c6346a58d3a3e68ceebac Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 7 Jun 2023 18:37:52 +0100 Subject: [PATCH] cxx-qt-gen: syn 2 supports unsafety in ItemForeignMod We do not need to consider verbatim code paths for parsing unsafe extern "ABI" anymore, this is supportted in syn 2. eg compare ItemForeignMod and notice Option syn 1 https://docs.rs/syn/1.0.109/syn/struct.ItemForeignMod.html syn 2 https://docs.rs/syn/2.0.0/syn/struct.ItemForeignMod.html --- crates/cxx-qt-gen/src/parser/cxxqtdata.rs | 41 +++---------------- crates/cxx-qt-gen/src/parser/inherit.rs | 42 ++------------------ crates/cxx-qt-gen/src/parser/signals.rs | 27 +------------ crates/cxx-qt-gen/src/syntax/foreignmod.rs | 46 ---------------------- 4 files changed, 10 insertions(+), 146 deletions(-) diff --git a/crates/cxx-qt-gen/src/parser/cxxqtdata.rs b/crates/cxx-qt-gen/src/parser/cxxqtdata.rs index d8feea979..92f30ff3b 100644 --- a/crates/cxx-qt-gen/src/parser/cxxqtdata.rs +++ b/crates/cxx-qt-gen/src/parser/cxxqtdata.rs @@ -3,13 +3,13 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::syntax::foreignmod::{foreign_mod_to_foreign_item_types, verbatim_to_foreign_mod}; +use crate::syntax::foreignmod::foreign_mod_to_foreign_item_types; use crate::syntax::{attribute::attribute_find_path, path::path_to_single_ident}; use crate::{ parser::{ - inherit::{InheritMethods, MaybeInheritMethods, ParsedInheritedMethod}, + inherit::{InheritMethods, ParsedInheritedMethod}, qobject::ParsedQObject, - signals::{MaybeSignalMethods, ParsedSignal, SignalMethods}, + signals::{ParsedSignal, SignalMethods}, }, syntax::expr::expr_to_string, }; @@ -111,16 +111,8 @@ impl ParsedCxxQtData { _others => {} } - // Extract the foreign mod (extern "ABI" { ... }) - let foreign_mod = match item { - Item::ForeignMod(foreign_mod) => Some(foreign_mod.clone()), - // Could be Verbatim TokenStream when it's an unsafe block, the remainder of the blocks are a normal ForeignMod though - Item::Verbatim(tokens) => verbatim_to_foreign_mod(tokens)?, - _others => None, - }; - // If there is a foreign mod then process it - if let Some(foreign_mod) = &foreign_mod { + if let Item::ForeignMod(foreign_mod) = &item { // Retrieve a namespace from the mod or the bridge let block_namespace = if let Some(index) = attribute_find_path(&foreign_mod.attrs, &["namespace"]) { @@ -187,34 +179,11 @@ impl ParsedCxxQtData { self.uses.push(item); Ok(None) } - Item::Verbatim(tokens) => self.try_parse_verbatim(tokens), Item::ForeignMod(foreign_mod) => self.parse_foreign_mod(foreign_mod), _ => Ok(Some(item)), } } - fn try_parse_verbatim(&mut self, tokens: TokenStream) -> Result> { - let try_parse: MaybeInheritMethods = syn::parse2(tokens.clone())?; - - match try_parse { - MaybeInheritMethods::Found(inherited) => { - self.add_inherited_methods(inherited)?; - Ok(None) - } - MaybeInheritMethods::PassThrough(_item) => { - let try_parse: MaybeSignalMethods = syn::parse2(tokens)?; - - match try_parse { - MaybeSignalMethods::Found(signals) => { - self.add_signal_methods(signals)?; - Ok(None) - } - MaybeSignalMethods::PassThrough(item) => Ok(Some(item)), - } - } - } - } - fn parse_inherit_mod(&mut self, tokens: TokenStream) -> Result<()> { let inherited: InheritMethods = syn::parse2(tokens)?; @@ -594,7 +563,7 @@ mod tests { } #[test] - fn test_cxx_mappings_cxx_name_verbatim() { + fn test_cxx_mappings_cxx_name_unsafe() { let mut cxx_qt_data = create_parsed_cxx_qt_data(); let item: Item = parse_quote! { diff --git a/crates/cxx-qt-gen/src/parser/inherit.rs b/crates/cxx-qt-gen/src/parser/inherit.rs index b681cc78f..6e0ae85ec 100644 --- a/crates/cxx-qt-gen/src/parser/inherit.rs +++ b/crates/cxx-qt-gen/src/parser/inherit.rs @@ -14,35 +14,9 @@ use quote::format_ident; use syn::{ parse::{Parse, ParseStream}, spanned::Spanned, - Attribute, Error, ForeignItem, ForeignItemFn, Ident, Item, ItemForeignMod, LitStr, Result, - Token, + Attribute, Error, ForeignItem, ForeignItemFn, Ident, ItemForeignMod, LitStr, Result, Token, }; -/// Used when parsing a syn::Item::Verbatim, that we suspect may be a `#[cxx_qt::inherit]` block, -/// but we don't yet know whether this is actually the case. -/// This is the case if `#[cxx_qt::inherit]` is used with `unsafe extern "C++"`. -pub enum MaybeInheritMethods { - /// We found a `#[cxx_qt::inherit]` block - Found(InheritMethods), - /// `#[cxx_qt::inherit]` block not found, pass this Item through to outside code! - PassThrough(Item), -} - -impl Parse for MaybeInheritMethods { - fn parse(input: ParseStream) -> Result { - let lookahead = input.fork(); - if let Ok(attribute) = lookahead.call(Attribute::parse_outer) { - if attribute_find_path(attribute.as_slice(), &["cxx_qt", "inherit"]).is_some() { - input.call(Attribute::parse_outer)?; - let methods = input.parse::()?; - return Ok(Self::Found(methods)); - } - } - - Ok(Self::PassThrough(input.parse()?)) - } -} - /// This type is used when parsing the `#[cxx_qt::inherit]` macro contents into raw ForeignItemFn items pub struct InheritMethods { pub safety: Safety, @@ -185,22 +159,14 @@ mod tests { #[test] fn test_parse_safe_mod() { let module = quote! { - #[cxx_qt::inherit] unsafe extern "C++" { fn test(self: &qobject::T); unsafe fn test2(self: &qobject::T); } }; - let parsed: MaybeInheritMethods = syn::parse2(module).unwrap(); - match parsed { - MaybeInheritMethods::Found(inherit) => { - assert_eq!(inherit.base_functions.len(), 2); - assert_eq!(inherit.safety, Safety::Safe); - } - MaybeInheritMethods::PassThrough(item) => { - panic!("Expected InheritMethods, got {item:?}"); - } - } + let parsed: InheritMethods = syn::parse2(module).unwrap(); + assert_eq!(parsed.base_functions.len(), 2); + assert_eq!(parsed.safety, Safety::Safe); } #[test] diff --git a/crates/cxx-qt-gen/src/parser/signals.rs b/crates/cxx-qt-gen/src/parser/signals.rs index 159d0fcf5..ae7830cb7 100644 --- a/crates/cxx-qt-gen/src/parser/signals.rs +++ b/crates/cxx-qt-gen/src/parser/signals.rs @@ -14,34 +14,9 @@ use syn::Attribute; use syn::{ parse::{Parse, ParseStream}, spanned::Spanned, - Error, ForeignItem, ForeignItemFn, Ident, Item, ItemForeignMod, LitStr, Result, Token, + Error, ForeignItem, ForeignItemFn, Ident, ItemForeignMod, LitStr, Result, Token, }; -/// Used when parsing a syn::Item::Verbatim, that we suspect may be a `#[cxx_qt::qsignals]` block, -/// but we don't yet know whether this is actually the case. -/// This is the case if `#[cxx_qt::qsignals]` is used with `unsafe extern "C++"`. -pub enum MaybeSignalMethods { - /// We found a `#[cxx_qt::qsignals]` block - Found(SignalMethods), - /// `#[cxx_qt::qsignals]` block not found, pass this Item through to outside code! - PassThrough(Item), -} - -impl Parse for MaybeSignalMethods { - fn parse(input: ParseStream) -> Result { - let lookahead = input.fork(); - if let Ok(attribute) = lookahead.call(Attribute::parse_outer) { - if attribute_find_path(attribute.as_slice(), &["cxx_qt", "qsignals"]).is_some() { - input.call(Attribute::parse_outer)?; - let methods = input.parse::()?; - return Ok(Self::Found(methods)); - } - } - - Ok(Self::PassThrough(input.parse()?)) - } -} - /// This type is used when parsing the `#[cxx_qt::qsignals]` macro contents into raw ForeignItemFn items pub struct SignalMethods { pub safety: Safety, diff --git a/crates/cxx-qt-gen/src/syntax/foreignmod.rs b/crates/cxx-qt-gen/src/syntax/foreignmod.rs index 65733f552..c4b7f6b26 100644 --- a/crates/cxx-qt-gen/src/syntax/foreignmod.rs +++ b/crates/cxx-qt-gen/src/syntax/foreignmod.rs @@ -42,38 +42,6 @@ pub(crate) fn foreign_mod_to_foreign_item_types( .collect::>>() } -/// For a given verbatim [proc_macro2::TokenStream] return a [syn::ItemForegnMod] if there is one -/// -/// And ignore any unsafe token before the extern block -pub(crate) fn verbatim_to_foreign_mod(tokens: &TokenStream) -> Result> { - |input: ParseStream| -> Result> { - // Parse any namespace attributes on the outside of the unsafe extern block - let mut attrs = input.call(Attribute::parse_outer)?; - - // If we are an unsafe then extern block try to parse it - if input.peek(Token![unsafe]) && input.peek2(Token![extern]) { - input.parse::()?; - let mut foreign_mod = input.parse::()?; - // Inject the attributes from the outside of the unsafe block into the foreign mod - attrs.append(&mut foreign_mod.attrs); - foreign_mod.attrs = attrs; - Ok(Some(foreign_mod)) - } else { - // Move the cursor past all remaining tokens, otherwise parse2 fails - input.step(|cursor| { - let mut rest = *cursor; - while let Some((_, next)) = rest.token_tree() { - rest = next; - } - Ok(((), rest)) - })?; - - Ok(None) - } - } - .parse2(tokens.clone()) -} - /// For a given verbatim [proc_macro2::TokenStream] return the [syn::ForeignItemType] if there is one /// /// And ignore any extra syntax after the = in type A = ... @@ -178,20 +146,6 @@ mod tests { assert_eq!(result[1].ident, "B"); } - #[test] - fn test_verbatim_to_foreign_mod() { - let tokens = quote! { - #[namespace = "a"] - unsafe extern "C++" { - type A; - } - }; - let result = verbatim_to_foreign_mod(&tokens).unwrap(); - let result = result.unwrap(); - assert_eq!(result.attrs.len(), 1); - assert_eq!(result.items.len(), 1); - } - #[test] fn test_foreign_fn_self() { let foreign_fn: ForeignItemFn = parse_quote! {