diff --git a/Cargo.lock b/Cargo.lock index 7e587ea1f..760e57bd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,7 +227,6 @@ dependencies = [ "regex", "rustversion", "serde_json", - "strum_macros", "syn 2.0.18", "tempfile", "thiserror", @@ -806,12 +805,6 @@ dependencies = [ "ahash", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hermit-abi" version = "0.1.19" @@ -1482,19 +1475,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - [[package]] name = "supports-color" version = "2.0.0" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index f2c9e46c2..9736db9fe 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -43,7 +43,6 @@ version_check = "0.9" aquamarine = "0.1" # docs tempfile = "3.4" once_cell = "1.7" -strum_macros = "0.24" serde_json = { version = "1.0", optional = true } miette = "5" thiserror = "1" diff --git a/engine/src/conversion/analysis/allocators.rs b/engine/src/conversion/analysis/allocators.rs index 075e97240..da25a776c 100644 --- a/engine/src/conversion/analysis/allocators.rs +++ b/engine/src/conversion/analysis/allocators.rs @@ -18,6 +18,7 @@ use crate::{ }, apivec::ApiVec, }, + minisyn::minisynize_punctuated, types::{make_ident, QualifiedName}, }; @@ -76,8 +77,8 @@ fn create_alloc_and_free(ty_name: QualifiedName) -> impl Iterator &QualifiedName; fn deps(&self) -> Box + '_>; - - fn format_deps(&self) -> String { - self.deps().join(",") - } } impl HasDependencies for Api { diff --git a/engine/src/conversion/analysis/fun/function_wrapper.rs b/engine/src/conversion/analysis/fun/function_wrapper.rs index 606b97a93..04955331c 100644 --- a/engine/src/conversion/analysis/fun/function_wrapper.rs +++ b/engine/src/conversion/analysis/fun/function_wrapper.rs @@ -6,12 +6,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::minisyn::Ident; use crate::{ conversion::{api::SubclassName, type_helpers::extract_pinned_mutable_reference_type}, types::{Namespace, QualifiedName}, }; use quote::ToTokens; -use syn::{parse_quote, Ident, Type, TypeReference}; +use syn::{parse_quote, Type, TypeReference}; #[derive(Clone, Debug)] pub(crate) enum CppConversionType { @@ -85,9 +86,9 @@ impl RustConversionType { /// variant params. That would remove the possibility of various runtime /// panics by enforcing (for example) that conversion from a pointer always /// has a Type::Ptr. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct TypeConversionPolicy { - unwrapped_type: Type, + unwrapped_type: crate::minisyn::Type, pub(crate) cpp_conversion: CppConversionType, pub(crate) rust_conversion: RustConversionType, } @@ -103,7 +104,7 @@ impl TypeConversionPolicy { rust_conversion: RustConversionType, ) -> Self { Self { - unwrapped_type: ty, + unwrapped_type: ty.into(), cpp_conversion, rust_conversion, } @@ -140,7 +141,7 @@ impl TypeConversionPolicy { pub(crate) fn new_to_unique_ptr(ty: Type) -> Self { TypeConversionPolicy { - unwrapped_type: ty, + unwrapped_type: ty.into(), cpp_conversion: CppConversionType::FromValueToUniquePtr, rust_conversion: RustConversionType::None, } @@ -148,7 +149,7 @@ impl TypeConversionPolicy { pub(crate) fn new_for_placement_return(ty: Type) -> Self { TypeConversionPolicy { - unwrapped_type: ty, + unwrapped_type: ty.into(), cpp_conversion: CppConversionType::FromReturnValueToPlacementPtr, // Rust conversion is marked as none here, since this policy // will be applied to the return value, and the Rust-side @@ -164,7 +165,7 @@ impl TypeConversionPolicy { pub(crate) fn unconverted_rust_type(&self) -> Type { match self.cpp_conversion { CppConversionType::FromValueToUniquePtr => self.make_unique_ptr_type(), - _ => self.unwrapped_type.clone(), + _ => self.unwrapped_type.clone().into(), } } @@ -177,7 +178,7 @@ impl TypeConversionPolicy { *mut #innerty } } - _ => self.unwrapped_type.clone(), + _ => self.unwrapped_type.clone().into(), } } @@ -229,7 +230,7 @@ impl TypeConversionPolicy { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum CppFunctionBody { FunctionCall(Namespace, Ident), StaticMethodCall(Namespace, Ident, Ident), @@ -241,7 +242,7 @@ pub(crate) enum CppFunctionBody { FreeUninitialized(QualifiedName), } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum CppFunctionKind { Function, Method, @@ -250,10 +251,10 @@ pub(crate) enum CppFunctionKind { SynthesizedConstructor, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct CppFunction { pub(crate) payload: CppFunctionBody, - pub(crate) wrapper_function_name: Ident, + pub(crate) wrapper_function_name: crate::minisyn::Ident, pub(crate) original_cpp_name: String, pub(crate) return_conversion: Option, pub(crate) argument_conversion: Vec, diff --git a/engine/src/conversion/analysis/fun/mod.rs b/engine/src/conversion/analysis/fun/mod.rs index 947b582e2..415e40a4d 100644 --- a/engine/src/conversion/analysis/fun/mod.rs +++ b/engine/src/conversion/analysis/fun/mod.rs @@ -29,6 +29,7 @@ use crate::{ error_reporter::{convert_apis, report_any_error}, }, known_types::known_types, + minisyn::minisynize_punctuated, types::validate_ident_ok_for_rust, }; use indexmap::map::IndexMap as HashMap; @@ -86,7 +87,7 @@ pub(crate) enum MethodKind { PureVirtual(ReceiverMutability), } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum TraitMethodKind { CopyConstructor, MoveConstructor, @@ -96,11 +97,11 @@ pub(crate) enum TraitMethodKind { Dealloc, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct TraitMethodDetails { pub(crate) trt: TraitImplSignature, pub(crate) avoid_self: bool, - pub(crate) method_name: Ident, + pub(crate) method_name: crate::minisyn::Ident, /// For traits, where we're trying to implement a specific existing /// interface, we may need to reorder the parameters to fit that /// interface. @@ -110,7 +111,7 @@ pub(crate) struct TraitMethodDetails { pub(crate) trait_call_is_unsafe: bool, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum FnKind { Function, Method { @@ -130,31 +131,31 @@ pub(crate) enum FnKind { /// Strategy for ensuring that the final, callable, Rust name /// is what the user originally expected. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum RustRenameStrategy { /// cxx::bridge name matches user expectations None, /// Even the #[rust_name] attribute would cause conflicts, and we need /// to use a 'use XYZ as ABC' - RenameInOutputMod(Ident), + RenameInOutputMod(crate::minisyn::Ident), /// This function requires us to generate a Rust function to do /// parameter conversion. RenameUsingWrapperFunction, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct FnAnalysis { /// Each entry in the cxx::bridge needs to have a unique name, even if /// (from the perspective of Rust and C++) things are in different /// namespaces/mods. - pub(crate) cxxbridge_name: Ident, + pub(crate) cxxbridge_name: crate::minisyn::Ident, /// ... so record also the name under which we wish to expose it in Rust. pub(crate) rust_name: String, pub(crate) rust_rename_strategy: RustRenameStrategy, pub(crate) params: Punctuated, pub(crate) kind: FnKind, - pub(crate) ret_type: ReturnType, + pub(crate) ret_type: crate::minisyn::ReturnType, pub(crate) param_details: Vec, pub(crate) ret_conversion: Option, pub(crate) requires_unsafe: UnsafetyNeeded, @@ -173,10 +174,10 @@ pub(crate) struct FnAnalysis { pub(crate) rust_wrapper_needed: bool, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct ArgumentAnalysis { pub(crate) conversion: TypeConversionPolicy, - pub(crate) name: Pat, + pub(crate) name: crate::minisyn::Pat, pub(crate) self_type: Option<(QualifiedName, ReceiverMutability)>, pub(crate) has_lifetime: bool, pub(crate) is_mutable_reference: bool, @@ -207,6 +208,7 @@ impl Default for ReturnTypeAnalysis { } } +#[derive(std::fmt::Debug)] pub(crate) struct PodAndConstructorAnalysis { pub(crate) pod: PodAnalysis, pub(crate) constructors: PublicConstructors, @@ -214,6 +216,7 @@ pub(crate) struct PodAndConstructorAnalysis { /// An analysis phase where we've analyzed each function, but /// haven't yet determined which constructors/etc. belong to each type. +#[derive(std::fmt::Debug)] pub(crate) struct FnPrePhase1; impl AnalysisPhase for FnPrePhase1 { @@ -224,6 +227,7 @@ impl AnalysisPhase for FnPrePhase1 { /// An analysis phase where we've analyzed each function, and identified /// what implicit constructors/destructors are present in each type. +#[derive(std::fmt::Debug)] pub(crate) struct FnPrePhase2; impl AnalysisPhase for FnPrePhase2 { @@ -232,6 +236,7 @@ impl AnalysisPhase for FnPrePhase2 { type FunAnalysis = FnAnalysis; } +#[derive(Debug)] pub(crate) struct PodAndDepAnalysis { pub(crate) pod: PodAnalysis, pub(crate) constructor_and_allocator_deps: Vec, @@ -240,6 +245,7 @@ pub(crate) struct PodAndDepAnalysis { /// Analysis phase after we've finished analyzing functions and determined /// which constructors etc. belong to them. +#[derive(std::fmt::Debug)] pub(crate) struct FnPhase; /// Indicates which kinds of public constructors are known to exist for a type. @@ -879,7 +885,7 @@ impl<'a> FnAnalyzer<'a> { impl_for: self_ty, details: Box::new(TraitMethodDetails { trt: TraitImplSignature { - ty, + ty: ty.into(), trait_signature: parse_quote! { autocxx::moveit::new:: #trait_id }, @@ -915,7 +921,7 @@ impl<'a> FnAnalyzer<'a> { impl_for: self_ty, details: Box::new(TraitMethodDetails { trt: TraitImplSignature { - ty, + ty: ty.into(), trait_signature: parse_quote! { Drop }, @@ -1370,10 +1376,10 @@ impl<'a> FnAnalyzer<'a> { params.clear(); for pd in ¶m_details { let type_name = pd.conversion.converted_rust_type(); - let arg_name = if pd.self_type.is_some() { + let arg_name: syn::Pat = if pd.self_type.is_some() { parse_quote!(autocxx_gen_this) } else { - pd.name.clone() + pd.name.clone().into() }; params.push(parse_quote!( #arg_name: #type_name @@ -1432,10 +1438,10 @@ impl<'a> FnAnalyzer<'a> { params, ret_conversion: ret_type_conversion, kind, - ret_type, + ret_type: ret_type.into(), param_details, requires_unsafe, - vis, + vis: vis.into(), cpp_wrapper, deps, ignore_reason, @@ -1557,7 +1563,7 @@ impl<'a> FnAnalyzer<'a> { impl_for: from_type.clone(), details: Box::new(TraitMethodDetails { trt: TraitImplSignature { - ty, + ty: ty.into(), trait_signature, unsafety: None, }, @@ -1601,7 +1607,7 @@ impl<'a> FnAnalyzer<'a> { impl_for: ty.clone(), details: Box::new(TraitMethodDetails { trt: TraitImplSignature { - ty: Type::Path(typ), + ty: Type::Path(typ).into(), trait_signature: parse_quote! { autocxx::moveit::MakeCppStorage }, unsafety: Some(parse_quote! { unsafe }), }, @@ -1699,7 +1705,7 @@ impl<'a> FnAnalyzer<'a> { syn::Pat::Ident(pp) => { validate_ident_ok_for_cxx(&pp.ident.to_string()) .map_err(ConvertErrorFromCpp::InvalidIdent)?; - pointer_treatment = references.param_treatment(&pp.ident); + pointer_treatment = references.param_treatment(&pp.ident.clone().into()); syn::Pat::Ident(pp) } _ => old_pat, @@ -1736,7 +1742,7 @@ impl<'a> FnAnalyzer<'a> { FnArg::Typed(pt), ArgumentAnalysis { self_type, - name: new_pat, + name: new_pat.into(), conversion, has_lifetime: matches!( annotated_type.kind, @@ -2152,9 +2158,12 @@ impl<'a> FnAnalyzer<'a> { Box::new(FuncToConvert { self_ty: Some(self_ty.clone()), ident, - doc_attrs: make_doc_attrs(format!("Synthesized {special_member}.")), - inputs, - output: ReturnType::Default, + doc_attrs: make_doc_attrs(format!("Synthesized {special_member}.")) + .into_iter() + .map(Into::into) + .collect(), + inputs: minisynize_punctuated(inputs), + output: ReturnType::Default.into(), vis: parse_quote! { pub }, virtualness: Virtualness::None, cpp_vis: CppVisibility::Public, @@ -2253,7 +2262,7 @@ impl Api { ) } - pub(crate) fn cxxbridge_name(&self) -> Option { + pub(crate) fn cxxbridge_name(&self) -> Option { match self { Api::Function { ref analysis, .. } => Some(analysis.cxxbridge_name.clone()), Api::StringConstructor { .. } diff --git a/engine/src/conversion/analysis/fun/subclass.rs b/engine/src/conversion/analysis/fun/subclass.rs index 4692c65ad..8698539c6 100644 --- a/engine/src/conversion/analysis/fun/subclass.rs +++ b/engine/src/conversion/analysis/fun/subclass.rs @@ -6,6 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::ops::DerefMut; + use indexmap::map::IndexMap as HashMap; use syn::{parse_quote, FnArg, PatType, Type, TypePtr}; @@ -17,6 +19,7 @@ use crate::conversion::api::{ SubclassName, SuperclassMethod, UnsafetyNeeded, Virtualness, }; use crate::conversion::apivec::ApiVec; +use crate::minisyn::minisynize_punctuated; use crate::{ conversion::{ analysis::fun::function_wrapper::{ @@ -85,6 +88,7 @@ pub(super) fn create_subclass_trait_item( .param_details .iter() .map(|pd| pd.name.clone()) + .map(Into::into) .collect(); let requires_unsafe = if matches!(unsafe_policy, UnsafePolicy::AllFunctionsUnsafe) { UnsafetyNeeded::Always @@ -95,7 +99,7 @@ pub(super) fn create_subclass_trait_item( name, details: SuperclassMethod { name: make_ident(&analysis.rust_name), - params: analysis.params.clone(), + params: minisynize_punctuated(analysis.params.clone()), ret_type: analysis.ret_type.clone(), param_names, receiver_mutability: *receiver_mutability, @@ -122,10 +126,10 @@ pub(super) fn create_subclass_function( sub.0.name.get_final_item(), name.name.get_final_item() )); - let params = std::iter::once(parse_quote! { + let params = std::iter::once(crate::minisyn::FnArg(parse_quote! { me: & #holder_name - }) - .chain(analysis.params.iter().skip(1).cloned()) + })) + .chain(analysis.params.iter().skip(1).cloned().map(Into::into)) .collect(); let kind = if matches!(receiver_mutability, ReceiverMutability::Mutable) { CppFunctionKind::Method @@ -213,7 +217,9 @@ pub(super) fn create_subclass_constructor( let subclass_constructor_name = make_ident(format!("{}_{}", cpp.get_final_item(), cpp.get_final_item())); let mut existing_params = fun.inputs.clone(); - if let Some(FnArg::Typed(PatType { ty, .. })) = existing_params.first_mut() { + if let Some(FnArg::Typed(PatType { ty, .. })) = + existing_params.first_mut().map(DerefMut::deref_mut) + { if let Type::Ptr(TypePtr { elem, .. }) = &mut **ty { *elem = Box::new(Type::Path(sub.cpp().to_type_path())); } else { @@ -229,7 +235,7 @@ pub(super) fn create_subclass_constructor( }; let inputs = self_param .into_iter() - .chain(std::iter::once(boxed_holder_param)) + .chain(std::iter::once(boxed_holder_param.into())) .chain(existing_params) .collect(); let maybe_wrap = Box::new(FuncToConvert { diff --git a/engine/src/conversion/analysis/name_check.rs b/engine/src/conversion/analysis/name_check.rs index 0ebdc9520..38b8db481 100644 --- a/engine/src/conversion/analysis/name_check.rs +++ b/engine/src/conversion/analysis/name_check.rs @@ -8,7 +8,7 @@ use indexmap::map::IndexMap as HashMap; -use syn::Ident; +use crate::minisyn::Ident; use crate::{ conversion::{ diff --git a/engine/src/conversion/analysis/pod/byvalue_checker.rs b/engine/src/conversion/analysis/pod/byvalue_checker.rs index f75094b1a..6e2e9b9ff 100644 --- a/engine/src/conversion/analysis/pod/byvalue_checker.rs +++ b/engine/src/conversion/analysis/pod/byvalue_checker.rs @@ -102,7 +102,7 @@ impl ByValueChecker { _ => None, }, TypedefKind::Use(_, ref ty) => match **ty { - Type::Path(ref typ) => { + crate::minisyn::Type(Type::Path(ref typ)) => { let target_tn = QualifiedName::from_type_path(typ); known_types().consider_substitution(&target_tn) } @@ -147,7 +147,7 @@ impl ByValueChecker { fn ingest_struct(&mut self, def: &ItemStruct, ns: &Namespace) { // For this struct, work out whether it _could_ be safe as a POD. - let tyname = QualifiedName::new(ns, def.ident.clone()); + let tyname = QualifiedName::new(ns, def.ident.clone().into()); let mut field_safety_problem = PodState::SafeToBePod; let fieldlist = Self::get_field_types(def); for ty_id in &fieldlist { @@ -272,10 +272,11 @@ impl ByValueChecker { #[cfg(test)] mod tests { use super::ByValueChecker; + use crate::minisyn::ItemStruct; use crate::types::{Namespace, QualifiedName}; - use syn::{parse_quote, Ident, ItemStruct}; + use syn::parse_quote; - fn ty_from_ident(id: &Ident) -> QualifiedName { + fn ty_from_ident(id: &syn::Ident) -> QualifiedName { QualifiedName::new_from_cpp_name(&id.to_string()) } diff --git a/engine/src/conversion/analysis/pod/mod.rs b/engine/src/conversion/analysis/pod/mod.rs index 983a6398d..2fafc9564 100644 --- a/engine/src/conversion/analysis/pod/mod.rs +++ b/engine/src/conversion/analysis/pod/mod.rs @@ -13,7 +13,7 @@ use indexmap::set::IndexSet as HashSet; use autocxx_parser::IncludeCppConfig; use byvalue_checker::ByValueChecker; -use syn::{ItemEnum, ItemStruct, Type, Visibility}; +use syn::{ItemStruct, Type, Visibility}; use crate::{ conversion::{ @@ -30,11 +30,14 @@ use crate::{ use super::tdef::{TypedefAnalysis, TypedefPhase}; +#[derive(std::fmt::Debug)] + pub(crate) struct FieldInfo { pub(crate) ty: Type, pub(crate) type_kind: type_converter::TypeKind, } +#[derive(std::fmt::Debug)] pub(crate) struct PodAnalysis { pub(crate) kind: TypeKind, pub(crate) bases: HashSet, @@ -54,6 +57,7 @@ pub(crate) struct PodAnalysis { pub(crate) in_anonymous_namespace: bool, } +#[derive(std::fmt::Debug)] pub(crate) struct PodPhase; impl AnalysisPhase for PodPhase { @@ -123,7 +127,7 @@ pub(crate) fn analyze_pod_apis( fn analyze_enum( name: ApiName, - mut item: ItemEnum, + mut item: crate::minisyn::ItemEnum, ) -> Result>>, ConvertErrorWithContext> { let metadata = BindgenSemanticAttributes::new_retaining_others(&mut item.attrs); metadata.check_for_fatal_attrs(&name.name.get_final_ident())?; diff --git a/engine/src/conversion/analysis/tdef.rs b/engine/src/conversion/analysis/tdef.rs index 8a82483d3..1c414e8c4 100644 --- a/engine/src/conversion/analysis/tdef.rs +++ b/engine/src/conversion/analysis/tdef.rs @@ -24,6 +24,7 @@ use crate::{ types::QualifiedName, }; +#[derive(std::fmt::Debug)] pub(crate) struct TypedefAnalysis { pub(crate) kind: TypedefKind, pub(crate) deps: HashSet, @@ -31,6 +32,7 @@ pub(crate) struct TypedefAnalysis { /// Analysis phase where typedef analysis has been performed but no other /// analyses just yet. +#[derive(std::fmt::Debug)] pub(crate) struct TypedefPhase; impl AnalysisPhase for TypedefPhase { @@ -57,7 +59,7 @@ pub(crate) fn convert_typedef_targets( Ok(Box::new(std::iter::once(match item { TypedefKind::Type(ity) => get_replacement_typedef( name, - ity, + ity.into(), old_tyname, &mut type_converter, &mut extra_apis, @@ -116,10 +118,10 @@ fn get_replacement_typedef( extra_apis.append(&mut final_type.extra_apis); Ok(Api::Typedef { name, - item: TypedefKind::Type(ity), + item: TypedefKind::Type(ity.into()), old_tyname, analysis: TypedefAnalysis { - kind: TypedefKind::Type(converted_type), + kind: TypedefKind::Type(converted_type.into()), deps: final_type.types_encountered, }, }) diff --git a/engine/src/conversion/analysis/type_converter.rs b/engine/src/conversion/analysis/type_converter.rs index d96f2be03..63f7ae99f 100644 --- a/engine/src/conversion/analysis/type_converter.rs +++ b/engine/src/conversion/analysis/type_converter.rs @@ -34,7 +34,7 @@ use super::tdef::TypedefAnalysis; pub(crate) enum TypeKind { Regular, Pointer, - SubclassHolder(Ident), + SubclassHolder(crate::minisyn::Ident), Reference, RValueReference, MutableReference, @@ -556,7 +556,7 @@ impl<'a> TypeConverter<'a> { let api = UnanalyzedApi::ConcreteType { name: ApiName::new_in_root_namespace(make_ident(synthetic_ident)), cpp_definition: cpp_definition.clone(), - rs_definition: Some(Box::new(rs_definition.clone())), + rs_definition: Some(Box::new(rs_definition.clone().into())), }; self.concrete_templates .insert(cpp_definition, api.name().clone()); diff --git a/engine/src/conversion/api.rs b/engine/src/conversion/api.rs index bb482b71f..d5da41c52 100644 --- a/engine/src/conversion/api.rs +++ b/engine/src/conversion/api.rs @@ -9,17 +9,20 @@ use indexmap::set::IndexSet as HashSet; use std::fmt::Display; -use crate::types::{make_ident, Namespace, QualifiedName}; -use autocxx_parser::{ExternCppType, RustFun, RustPath}; -use itertools::Itertools; -use quote::ToTokens; use syn::{ parse::Parse, punctuated::Punctuated, token::{Comma, Unsafe}, +}; + +use crate::minisyn::{ Attribute, FnArg, Ident, ItemConst, ItemEnum, ItemStruct, ItemType, ItemUse, LitBool, LitInt, Pat, ReturnType, Type, Visibility, }; +use crate::types::{make_ident, Namespace, QualifiedName}; +use autocxx_parser::{ExternCppType, RustFun, RustPath}; +use itertools::Itertools; +use quote::ToTokens; use super::{ analysis::{ @@ -33,7 +36,7 @@ use super::{ ConvertErrorFromCpp, }; -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] pub(crate) enum TypeKind { Pod, // trivial. Can be moved and copied in Rust. NonPod, // has destructor or non-trivial move constructors. Can only hold by UniquePtr @@ -53,6 +56,7 @@ pub(crate) enum CppVisibility { } /// Details about a C++ struct. +#[derive(Debug)] pub(crate) struct StructDetails { pub(crate) item: ItemStruct, pub(crate) layout: Option, @@ -60,7 +64,7 @@ pub(crate) struct StructDetails { } /// Layout of a type, equivalent to the same type in ir/layout.rs in bindgen -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct Layout { /// The size (in bytes) of this layout. pub(crate) size: usize, @@ -85,14 +89,14 @@ impl Parse for Layout { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum Virtualness { None, Virtual, PureVirtual, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub(crate) enum CastMutability { ConstToConst, MutToConst, @@ -101,7 +105,7 @@ pub(crate) enum CastMutability { /// Indicates that this function (which is synthetic) should /// be a trait implementation rather than a method or free function. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum TraitSynthesis { Cast { to_type: QualifiedName, @@ -113,7 +117,7 @@ pub(crate) enum TraitSynthesis { /// Details of a subclass constructor. /// TODO: zap this; replace with an extra API. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct SubclassConstructorDetails { pub(crate) subclass: SubclassName, pub(crate) is_trivial: bool, @@ -124,7 +128,7 @@ pub(crate) struct SubclassConstructorDetails { /// Contributions to traits representing C++ superclasses that /// we may implement as Rust subclasses. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct SuperclassMethod { pub(crate) name: Ident, pub(crate) receiver: QualifiedName, @@ -139,7 +143,7 @@ pub(crate) struct SuperclassMethod { /// Information about references (as opposed to pointers) to be found /// within the function signature. This is derived from bindgen annotations /// which is why it's not within `FuncToConvert::inputs` -#[derive(Default, Clone)] +#[derive(Default, Clone, Debug)] pub(crate) struct References { pub(crate) rvalue_ref_params: HashSet, pub(crate) ref_params: HashSet, @@ -175,7 +179,7 @@ impl References { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct TraitImplSignature { pub(crate) ty: Type, pub(crate) trait_signature: Type, @@ -239,7 +243,7 @@ impl Display for SpecialMemberKind { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum Provenance { Bindgen, SynthesizedOther, @@ -247,7 +251,7 @@ pub(crate) enum Provenance { } /// Whether a function has =delete or =default -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub(crate) enum DeletedOrDefaulted { Neither, Deleted, @@ -264,7 +268,7 @@ pub(crate) enum DeletedOrDefaulted { /// during normal bindgen parsing. If that happens, they'll create one /// of these structures, and typically fill in some of the /// `synthesized_*` members which are not filled in from bindgen. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct FuncToConvert { pub(crate) provenance: Provenance, pub(crate) ident: Ident, @@ -297,13 +301,14 @@ pub(crate) struct FuncToConvert { /// Layers of analysis which may be applied to decorate each API. /// See description of the purpose of this trait within `Api`. -pub(crate) trait AnalysisPhase { - type TypedefAnalysis; - type StructAnalysis; - type FunAnalysis; +pub(crate) trait AnalysisPhase: std::fmt::Debug { + type TypedefAnalysis: std::fmt::Debug; + type StructAnalysis: std::fmt::Debug; + type FunAnalysis: std::fmt::Debug; } /// No analysis has been applied to this API. +#[derive(std::fmt::Debug)] pub(crate) struct NullPhase; impl AnalysisPhase for NullPhase { @@ -312,7 +317,7 @@ impl AnalysisPhase for NullPhase { type FunAnalysis = (); } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum TypedefKind { Use(ItemUse, Box), Type(ItemType), @@ -443,7 +448,7 @@ impl SubclassName { } } -#[derive(strum_macros::Display)] +#[derive(std::fmt::Debug)] /// Different types of API we might encounter. /// /// This type is parameterized over an `ApiAnalysis`. This is any additional @@ -454,11 +459,9 @@ impl SubclassName { /// because sometimes we pass on the `bindgen` output directly in the /// Rust codegen output. /// -/// This derives from [strum_macros::Display] because we want to be -/// able to debug-print the enum discriminant without worrying about -/// the fact that their payloads may not be `Debug` or `Display`. -/// (Specifically, allowing `syn` Types to be `Debug` requires -/// enabling syn's `extra-traits` feature which increases compile time.) +/// Any `syn` types represented in this `Api` type, or any of the types from +/// which it is composed, should be wrapped in `crate::minisyn` equivalents +/// to avoid excessively verbose `Debug` logging. pub(crate) enum Api { /// A forward declaration, which we mustn't store in a UniquePtr. ForwardDeclaration { @@ -568,6 +571,7 @@ pub(crate) enum Api { }, } +#[derive(Debug)] pub(crate) struct RustSubclassFnDetails { pub(crate) params: Punctuated, pub(crate) ret: ReturnType, @@ -655,18 +659,6 @@ impl Api { } } -impl std::fmt::Debug for Api { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{:?} (kind={}, details={})", - self.name_info(), - self, - self.details_display() - ) - } -} - pub(crate) type UnanalyzedApi = Api; impl Api { @@ -726,25 +718,6 @@ impl Api { { Ok(Box::new(std::iter::once(Api::Enum { name, item }))) } - - /// Display some details of each API. It's a bit unfortunate that we can't - /// just use `Debug` here, but some of the `syn` types make that awkward. - pub(crate) fn details_display(&self) -> String { - match self { - Api::ForwardDeclaration { err, .. } => format!("{err:?}"), - Api::OpaqueTypedef { - forward_declaration, - .. - } => format!("forward_declaration={forward_declaration:?}"), - Api::ConcreteType { - rs_definition, - cpp_definition, - .. - } => format!("rs_definition={rs_definition:?}, cpp_definition={cpp_definition}"), - Api::ExternCppType { pod, .. } => format!("pod={pod}"), - _ => String::new(), - } - } } /// Whether a type is a pointer of some kind. diff --git a/engine/src/conversion/codegen_rs/fun_codegen.rs b/engine/src/conversion/codegen_rs/fun_codegen.rs index 020f5157c..1b68e8c2a 100644 --- a/engine/src/conversion/codegen_rs/fun_codegen.rs +++ b/engine/src/conversion/codegen_rs/fun_codegen.rs @@ -34,6 +34,7 @@ use crate::{ }, api::{Pointerness, UnsafetyNeeded}, }, + minisyn::minisynize_vec, types::{Namespace, QualifiedName}, }; use crate::{ @@ -104,7 +105,7 @@ pub(super) fn gen_function( let params = analysis.params; let vis = analysis.vis; let kind = analysis.kind; - let doc_attrs = fun.doc_attrs; + let doc_attrs = minisynize_vec(fun.doc_attrs); let mut cpp_name_attr = Vec::new(); let mut impl_entry = None; @@ -169,10 +170,10 @@ pub(super) fn gen_function( FnKind::Method { .. } | FnKind::TraitMethod { .. } => None, FnKind::Function => match analysis.rust_rename_strategy { _ if analysis.rust_wrapper_needed => { - Some(Use::SpecificNameFromBindgen(make_ident(rust_name))) + Some(Use::SpecificNameFromBindgen(make_ident(rust_name).into())) } RustRenameStrategy::RenameInOutputMod(ref alias) => { - Some(Use::UsedFromCxxBridgeWithAlias(alias.clone())) + Some(Use::UsedFromCxxBridgeWithAlias(alias.clone().into())) } _ => Some(Use::UsedFromCxxBridge), }, @@ -262,10 +263,10 @@ impl<'a> FnGenerator<'a> { let mut any_conversion_requires_unsafe = false; let mut variable_counter = 0usize; for pd in self.param_details { - let wrapper_arg_name = if pd.self_type.is_some() && !avoid_self { + let wrapper_arg_name: syn::Pat = if pd.self_type.is_some() && !avoid_self { parse_quote!(self) } else { - pd.name.clone() + pd.name.clone().into() }; let rust_for_param = pd .conversion diff --git a/engine/src/conversion/codegen_rs/mod.rs b/engine/src/conversion/codegen_rs/mod.rs index c22b73797..abab612da 100644 --- a/engine/src/conversion/codegen_rs/mod.rs +++ b/engine/src/conversion/codegen_rs/mod.rs @@ -28,13 +28,11 @@ use syn::{ }; use crate::{ - conversion::{ - codegen_rs::{ - non_pod_struct::{make_non_pod, new_non_pod_struct}, - unqualify::{unqualify_params, unqualify_ret_type}, - }, - doc_attr::get_doc_attrs, + conversion::codegen_rs::{ + non_pod_struct::{make_non_pod, new_non_pod_struct}, + unqualify::{unqualify_params, unqualify_ret_type}, }, + minisyn::minisynize_punctuated, types::{make_ident, Namespace, QualifiedName}, }; use impl_item_creator::create_impl_items; @@ -51,6 +49,7 @@ use super::{ }, api::{AnalysisPhase, Api, SubclassName, TypeKind, TypedefKind}, convert_error::ErrorContextType, + doc_attr::get_doc_attrs, }; use super::{ api::{Layout, Provenance, RustSubclassFnDetails, SuperclassMethod, TraitImplSignature}, @@ -340,7 +339,7 @@ impl<'a> RsCodeGenerator<'a> { Use::UsedFromCxxBridge => Self::generate_cxx_use_stmt(name, None), Use::UsedFromBindgen => Self::generate_bindgen_use_stmt(name), Use::SpecificNameFromBindgen(id) => { - let name = QualifiedName::new(name.get_namespace(), id.clone()); + let name = QualifiedName::new(name.get_namespace(), id.clone().into()); Self::generate_bindgen_use_stmt(&name) } Use::Custom(item) => *item.clone(), @@ -483,9 +482,9 @@ impl<'a> RsCodeGenerator<'a> { fn #make_string_name(str_: &str) -> UniquePtr; ))], global_items: get_string_items(), - materializations: vec![Use::UsedFromCxxBridgeWithAlias(make_ident( - "make_string", - ))], + materializations: vec![Use::UsedFromCxxBridgeWithAlias( + make_ident("make_string").into(), + )], ..Default::default() } } @@ -498,14 +497,14 @@ impl<'a> RsCodeGenerator<'a> { self.config, ), Api::Const { const_item, .. } => RsCodegenResult { - bindgen_mod_items: vec![Item::Const(const_item)], + bindgen_mod_items: vec![Item::Const(const_item.into())], materializations: vec![Use::UsedFromBindgen], ..Default::default() }, Api::Typedef { analysis, .. } => RsCodegenResult { bindgen_mod_items: vec![match analysis.kind { - TypedefKind::Type(type_item) => Item::Type(type_item), - TypedefKind::Use(use_item, _) => Item::Use(use_item), + TypedefKind::Type(type_item) => Item::Type(type_item.into()), + TypedefKind::Use(use_item, _) => Item::Use(use_item.into()), }], materializations: vec![Use::UsedFromBindgen], ..Default::default() @@ -531,7 +530,7 @@ impl<'a> RsCodeGenerator<'a> { kind, constructors.move_constructor, constructors.destructor, - || Some((Item::Struct(details.item), doc_attrs)), + || Some((Item::Struct(details.item.into()), doc_attrs)), associated_methods, layout, is_generic, @@ -545,7 +544,7 @@ impl<'a> RsCodeGenerator<'a> { TypeKind::Pod, true, true, - || Some((Item::Enum(item), doc_attrs)), + || Some((Item::Enum(item.into()), doc_attrs)), associated_methods, None, false, @@ -623,7 +622,7 @@ impl<'a> RsCodeGenerator<'a> { } Api::RustSubclassFn { details, subclass, .. - } => Self::generate_subclass_fn(id, *details, subclass), + } => Self::generate_subclass_fn(id.into(), *details, subclass), Api::Subclass { name, superclass, .. } => { @@ -813,8 +812,8 @@ impl<'a> RsCodeGenerator<'a> { let ret = details.ret; let unsafe_token = details.requires_unsafe.wrapper_token(); let global_def = quote! { #unsafe_token fn #api_name(#params) #ret }; - let params = unqualify_params(params); - let ret = unqualify_ret_type(ret); + let params = unqualify_params(minisynize_punctuated(params)); + let ret = unqualify_ret_type(ret.into()); let method_name = details.method_name; let cxxbridge_decl: ForeignItemFn = parse_quote! { #unsafe_token fn #api_name(#params) #ret; }; @@ -872,7 +871,7 @@ impl<'a> RsCodeGenerator<'a> { fn generate_type( &self, name: &QualifiedName, - id: Ident, + id: crate::minisyn::Ident, type_kind: TypeKind, movable: bool, destroyable: bool, @@ -921,7 +920,7 @@ impl<'a> RsCodeGenerator<'a> { make_non_pod(s, layout); } else { // enum - item = Item::Struct(new_non_pod_struct(id.clone())); + item = Item::Struct(new_non_pod_struct(id.clone().into())); } } bindgen_mod_items.push(item); @@ -983,8 +982,9 @@ impl<'a> RsCodeGenerator<'a> { let super_id = SubclassName::get_super_fn_name(&Namespace::new(), &id.to_string()) .get_final_ident(); + let params = minisynize_punctuated(method.params.clone()); let param_names: Punctuated = - Self::args_from_sig(&method.params).collect(); + Self::args_from_sig(¶ms).collect(); let mut params = method.params.clone(); *(params.iter_mut().next().unwrap()) = match method.receiver_mutability { ReceiverMutability::Const => parse_quote!(&self), @@ -1028,7 +1028,7 @@ impl<'a> RsCodeGenerator<'a> { #(#mains)* } }); - materializations.push(Use::SpecificNameFromBindgen(supers_name)); + materializations.push(Use::SpecificNameFromBindgen(supers_name.into())); } else { bindgen_mod_items.push(parse_quote! { #[allow(non_snake_case)] @@ -1037,7 +1037,7 @@ impl<'a> RsCodeGenerator<'a> { } }); } - materializations.push(Use::SpecificNameFromBindgen(methods_name)); + materializations.push(Use::SpecificNameFromBindgen(methods_name.into())); } } @@ -1077,7 +1077,7 @@ impl<'a> RsCodeGenerator<'a> { #[doc = #err] pub struct #id; }), - Some(Use::SpecificNameFromBindgen(id)), + Some(Use::SpecificNameFromBindgen(id.into())), ), ErrorContextType::SanitizedItem(id) => ( // Guaranteed to be no impl blocks - populate directly in output mod. @@ -1209,7 +1209,7 @@ impl<'a> RsCodeGenerator<'a> { ForeignItem::Verbatim(for_extern_c_ts) } - fn find_output_mod_root(ns: &Namespace) -> impl Iterator { + fn find_output_mod_root(ns: &Namespace) -> impl Iterator { std::iter::repeat(make_ident("super")).take(ns.depth()) } } diff --git a/engine/src/conversion/convert_error.rs b/engine/src/conversion/convert_error.rs index 097d79d23..855b2359d 100644 --- a/engine/src/conversion/convert_error.rs +++ b/engine/src/conversion/convert_error.rs @@ -8,10 +8,10 @@ use indexmap::set::IndexSet as HashSet; +use crate::minisyn::Ident; use itertools::Itertools; use miette::{Diagnostic, SourceSpan}; use proc_macro2::Span; -use syn::Ident; use thiserror::Error; use crate::{ @@ -201,17 +201,17 @@ impl LocatedConvertErrorFromRust { /// Ensures that error contexts are always created using the constructors in this /// mod, therefore undergoing identifier sanitation. -#[derive(Clone)] +#[derive(Clone, Debug)] struct PhantomSanitized; /// The context of an error, e.g. whether it applies to a function or a method. /// This is used to generate suitable rustdoc in the output codegen so that /// the errors can be revealed in rust-analyzer-based IDEs, etc. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct ErrorContext(Box, PhantomSanitized); /// All idents in this structure are guaranteed to be something we can safely codegen for. -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum ErrorContextType { Item(Ident), SanitizedItem(Ident), diff --git a/engine/src/conversion/error_reporter.rs b/engine/src/conversion/error_reporter.rs index e7f018b5b..adea153cf 100644 --- a/engine/src/conversion/error_reporter.rs +++ b/engine/src/conversion/error_reporter.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syn::ItemEnum; +use crate::minisyn::ItemEnum; use super::{ api::{AnalysisPhase, Api, ApiName, FuncToConvert, StructDetails, TypedefKind}, diff --git a/engine/src/conversion/mod.rs b/engine/src/conversion/mod.rs index b9be1c62b..61d7d6dc5 100644 --- a/engine/src/conversion/mod.rs +++ b/engine/src/conversion/mod.rs @@ -28,9 +28,7 @@ use convert_error::ConvertErrorFromCpp; use itertools::Itertools; use syn::{Item, ItemMod}; -use crate::{ - conversion::analysis::deps::HasDependencies, CodegenOptions, CppFilePair, UnsafePolicy, -}; +use crate::{CodegenOptions, CppFilePair, UnsafePolicy}; use self::{ analysis::{ @@ -39,7 +37,6 @@ use self::{ casts::add_casts, check_names, constructor_deps::decorate_types_with_constructor_deps, - fun::FnPhase, gc::filter_apis_by_following_edges_from_allowlist, pod::analyze_pod_apis, remove_ignored::filter_apis_by_ignored_dependents, @@ -89,7 +86,7 @@ impl<'a> BridgeConverter<'a> { fn dump_apis(label: &str, apis: &ApiVec) { if LOG_APIS { log::info!( - "APIs after {}:\n{}", + "##### APIs after {}:\n{}", label, apis.iter() .map(|api| { format!(" {api:?}") }) @@ -99,19 +96,6 @@ impl<'a> BridgeConverter<'a> { } } - fn dump_apis_with_deps(label: &str, apis: &ApiVec) { - if LOG_APIS { - log::info!( - "APIs after {}:\n{}", - label, - apis.iter() - .map(|api| { format!(" {:?}, deps={}", api, api.format_deps()) }) - .sorted() - .join("\n") - ) - } - } - /// Convert a TokenStream of bindgen-generated bindings to a form /// suitable for cxx. /// @@ -174,9 +158,9 @@ impl<'a> BridgeConverter<'a> { // Annotate structs with a note of any copy/move constructors which // we may want to retain to avoid garbage collecting them later. let analyzed_apis = decorate_types_with_constructor_deps(analyzed_apis); - Self::dump_apis_with_deps("adding constructor deps", &analyzed_apis); + Self::dump_apis("adding constructor deps", &analyzed_apis); let analyzed_apis = discard_ignored_functions(analyzed_apis); - Self::dump_apis_with_deps("ignoring ignorable fns", &analyzed_apis); + Self::dump_apis("ignoring ignorable fns", &analyzed_apis); // Remove any APIs whose names are not compatible with cxx. let analyzed_apis = check_names(analyzed_apis); // During parsing or subsequent processing we might have encountered @@ -184,14 +168,14 @@ impl<'a> BridgeConverter<'a> { // There might be other items depending on such things. Let's remove them // too. let analyzed_apis = filter_apis_by_ignored_dependents(analyzed_apis); - Self::dump_apis_with_deps("removing ignored dependents", &analyzed_apis); + Self::dump_apis("removing ignored dependents", &analyzed_apis); // We now garbage collect the ones we don't need... let mut analyzed_apis = filter_apis_by_following_edges_from_allowlist(analyzed_apis, self.config); // Determine what variably-sized C types (e.g. int) we need to include analysis::ctypes::append_ctype_information(&mut analyzed_apis); - Self::dump_apis_with_deps("GC", &analyzed_apis); + Self::dump_apis("GC", &analyzed_apis); // And finally pass them to the code gen phases, which outputs // code suitable for cxx to consume. let cxxgen_header_name = codegen_options diff --git a/engine/src/conversion/parse/bindgen_semantic_attributes.rs b/engine/src/conversion/parse/bindgen_semantic_attributes.rs index 6fba17853..f2dd7d7d7 100644 --- a/engine/src/conversion/parse/bindgen_semantic_attributes.rs +++ b/engine/src/conversion/parse/bindgen_semantic_attributes.rs @@ -59,12 +59,12 @@ impl BindgenSemanticAttributes { if self.has_attr("unused_template_param") { Err(ConvertErrorWithContext( ConvertErrorFromCpp::UnusedTemplateParam, - Some(ErrorContext::new_for_item(id_for_context.clone())), + Some(ErrorContext::new_for_item(id_for_context.clone().into())), )) } else if self.get_cpp_visibility() != CppVisibility::Public { Err(ConvertErrorWithContext( ConvertErrorFromCpp::NonPublicNestedType, - Some(ErrorContext::new_for_item(id_for_context.clone())), + Some(ErrorContext::new_for_item(id_for_context.clone().into())), )) } else { Ok(()) @@ -154,12 +154,12 @@ impl BindgenSemanticAttributes { } else if a.is_ident("arg_type_reference") { let r: Result = a.parse_args(); if let Ok(ls) = r { - results.ref_params.insert(ls); + results.ref_params.insert(ls.into()); } } else if a.is_ident("arg_type_rvalue_reference") { let r: Result = a.parse_args(); if let Ok(ls) = r { - results.rvalue_ref_params.insert(ls); + results.rvalue_ref_params.insert(ls.into()); } } } diff --git a/engine/src/conversion/parse/parse_bindgen.rs b/engine/src/conversion/parse/parse_bindgen.rs index 39af9f08c..f49914540 100644 --- a/engine/src/conversion/parse/parse_bindgen.rs +++ b/engine/src/conversion/parse/parse_bindgen.rs @@ -42,7 +42,7 @@ pub(crate) struct ParseBindgen<'a> { } fn api_name(ns: &Namespace, id: Ident, attrs: &BindgenSemanticAttributes) -> ApiName { - ApiName::new_with_cpp_name(ns, id, attrs.get_original_name()) + ApiName::new_with_cpp_name(ns, id.into(), attrs.get_original_name()) } pub(crate) fn api_name_qualified( @@ -52,7 +52,7 @@ pub(crate) fn api_name_qualified( ) -> Result { match validate_ident_ok_for_cxx(&id.to_string()) { Err(e) => { - let ctx = ErrorContext::new_for_item(id); + let ctx = ErrorContext::new_for_item(id.into()); Err(ConvertErrorWithContext( ConvertErrorFromCpp::InvalidIdent(e), Some(ctx), @@ -99,13 +99,13 @@ impl<'a> ParseBindgen<'a> { ) -> Result<(), LocatedConvertErrorFromRust> { self.apis .extend(self.config.subclasses.iter().map(|sc| Api::Subclass { - name: SubclassName::new(sc.subclass.clone()), + name: SubclassName::new(sc.subclass.clone().into()), superclass: QualifiedName::new_from_cpp_name(&sc.superclass), })); for fun in &self.config.extern_rust_funs { let id = fun.sig.ident.clone(); self.apis.push(Api::RustFn { - name: ApiName::new_in_root_namespace(id), + name: ApiName::new_in_root_namespace(id.into()), details: fun.clone(), deps: super::extern_fun_signatures::assemble_extern_fun_deps( &fun.sig, @@ -117,7 +117,7 @@ impl<'a> ParseBindgen<'a> { self.apis.extend(unique_rust_types.into_iter().map(|path| { let id = path.get_final_ident(); Api::RustType { - name: ApiName::new_in_root_namespace(id.clone()), + name: ApiName::new_in_root_namespace(id.clone().into()), path: path.clone(), } })); @@ -127,7 +127,7 @@ impl<'a> ParseBindgen<'a> { .0 .iter() .map(|(cpp_definition, rust_id)| { - let name = ApiName::new_in_root_namespace(rust_id.clone()); + let name = ApiName::new_in_root_namespace(rust_id.clone().into()); Api::ConcreteType { name, cpp_definition: cpp_definition.clone(), @@ -236,7 +236,7 @@ impl<'a> ParseBindgen<'a> { if err.is_none() && name.cpp_name().contains("::") { err = Some(ConvertErrorWithContext( ConvertErrorFromCpp::ForwardDeclaredNestedType, - Some(ErrorContext::new_for_item(s.ident)), + Some(ErrorContext::new_for_item(s.ident.into())), )); } Some(UnanalyzedApi::ForwardDeclaration { name, err }) @@ -248,7 +248,7 @@ impl<'a> ParseBindgen<'a> { name, details: Box::new(StructDetails { layout: annotations.get_layout(), - item: s, + item: s.into(), has_rvalue_reference_fields, }), analysis: (), @@ -265,7 +265,7 @@ impl<'a> ParseBindgen<'a> { let annotations = BindgenSemanticAttributes::new(&e.attrs); let api = UnanalyzedApi::Enum { name: api_name_qualified(ns, e.ident.clone(), &annotations)?, - item: e, + item: e.into(), }; if !self.config.is_on_blocklist(&api.name().to_cpp_name()) { self.apis.push(api); @@ -304,7 +304,7 @@ impl<'a> ParseBindgen<'a> { UseTree::Rename(urn) => { let old_id = &urn.ident; let new_id = &urn.rename; - let new_tyname = QualifiedName::new(ns, new_id.clone()); + let new_tyname = QualifiedName::new(ns, new_id.clone().into()); assert!(segs.remove(0) == "self", "Path didn't start with self"); assert!( segs.remove(0) == "super", @@ -321,7 +321,7 @@ impl<'a> ParseBindgen<'a> { if new_tyname == old_tyname { return Err(ConvertErrorWithContext( ConvertErrorFromCpp::InfinitelyRecursiveTypedef(new_tyname), - Some(ErrorContext::new_for_item(new_id.clone())), + Some(ErrorContext::new_for_item(new_id.clone().into())), )); } let annotations = BindgenSemanticAttributes::new(&use_item.attrs); @@ -331,7 +331,7 @@ impl<'a> ParseBindgen<'a> { parse_quote! { pub use #old_path as #new_id; }, - Box::new(Type::Path(old_path)), + Box::new(Type::Path(old_path).into()), ), old_tyname: Some(old_tyname), analysis: (), @@ -366,7 +366,7 @@ impl<'a> ParseBindgen<'a> { if enum_type_name_valid { self.apis.push(UnanalyzedApi::Const { name: api_name(ns, const_item.ident.clone(), &annotations), - const_item, + const_item: const_item.into(), }); } Ok(()) @@ -377,7 +377,7 @@ impl<'a> ParseBindgen<'a> { // same name - see test_issue_264. self.apis.push(UnanalyzedApi::Typedef { name: api_name(ns, ity.ident.clone(), &annotations), - item: TypedefKind::Type(ity), + item: TypedefKind::Type(ity.into()), old_tyname: None, analysis: (), }); diff --git a/engine/src/conversion/parse/parse_foreign_mod.rs b/engine/src/conversion/parse/parse_foreign_mod.rs index 3070ad13b..ea82ff8f5 100644 --- a/engine/src/conversion/parse/parse_foreign_mod.rs +++ b/engine/src/conversion/parse/parse_foreign_mod.rs @@ -15,6 +15,7 @@ use crate::conversion::{ convert_error::ConvertErrorWithContext, convert_error::ErrorContext, }; +use crate::minisyn::{minisynize_punctuated, minisynize_vec}; use crate::{ conversion::ConvertErrorFromCpp, types::{Namespace, QualifiedName}, @@ -72,11 +73,11 @@ impl ParseForeignMod { self.funcs_to_convert.push(FuncToConvert { provenance: Provenance::Bindgen, self_ty: None, - ident: item.sig.ident, - doc_attrs, - inputs: item.sig.inputs, - output: item.sig.output, - vis: item.vis, + ident: item.sig.ident.into(), + doc_attrs: minisynize_vec(doc_attrs), + inputs: minisynize_punctuated(item.sig.inputs), + output: item.sig.output.into(), + vis: item.vis.into(), virtualness: annotations.get_virtualness(), cpp_vis: annotations.get_cpp_visibility(), special_member: annotations.special_member_kind(), @@ -94,7 +95,7 @@ impl ParseForeignMod { } ForeignItem::Static(item) => Err(ConvertErrorWithContext( ConvertErrorFromCpp::StaticData(item.ident.to_string()), - Some(ErrorContext::new_for_item(item.ident)), + Some(ErrorContext::new_for_item(item.ident.into())), )), _ => Err(ConvertErrorWithContext( ConvertErrorFromCpp::UnexpectedForeignItem, @@ -118,7 +119,7 @@ impl ParseForeignMod { }; self.method_receivers.insert( effective_fun_name, - QualifiedName::new(&self.ns, ty_id.clone()), + QualifiedName::new(&self.ns, ty_id.clone().into()), ); } } diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 15a39da0d..3988ab27a 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -17,6 +17,7 @@ mod ast_discoverer; mod conversion; mod cxxbridge; mod known_types; +mod minisyn; mod output_generators; mod parse_callbacks; mod parse_file; diff --git a/engine/src/minisyn.rs b/engine/src/minisyn.rs new file mode 100644 index 000000000..e675baad2 --- /dev/null +++ b/engine/src/minisyn.rs @@ -0,0 +1,187 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Newtype wrappers for `syn` types implementing a different +//! `Debug` implementation that results in more concise output. + +use std::fmt::Display; + +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::punctuated::{Pair, Punctuated}; + +macro_rules! minisyn_no_parse { + ($syntype:ident) => { + /// Equivalent to the identically-named `syn` type except + /// that its `Debug` implementation is more concise. + #[derive(Clone, Hash, Eq, PartialEq)] + pub struct $syntype(pub ::syn::$syntype); + impl std::fmt::Debug for $syntype { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{}", self.0.to_token_stream().to_string()) + } + } + impl ToTokens for $syntype + where + ::syn::$syntype: ToTokens, + { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.0.to_tokens(tokens) + } + + fn to_token_stream(&self) -> TokenStream { + self.0.to_token_stream() + } + fn into_token_stream(self) -> TokenStream + where + Self: Sized, + { + self.0.into_token_stream() + } + } + impl std::ops::Deref for $syntype { + type Target = ::syn::$syntype; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl std::ops::DerefMut for $syntype { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl std::convert::From<::syn::$syntype> for $syntype { + fn from(inner: ::syn::$syntype) -> Self { + Self(inner) + } + } + impl std::convert::From<$syntype> for syn::$syntype { + fn from(inner: $syntype) -> Self { + inner.0 + } + } + }; +} + +macro_rules! minisyn { + ($syntype:ident) => { + minisyn_no_parse!($syntype); + + impl syn::parse::Parse for $syntype { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result { + syn::parse::Parse::parse(input).map(Self) + } + } + }; +} + +minisyn!(ItemMod); +minisyn_no_parse!(Attribute); +minisyn_no_parse!(AssocConst); +minisyn_no_parse!(AssocType); +minisyn!(Expr); +minisyn!(ExprAssign); +minisyn!(ExprAwait); +minisyn!(ExprBinary); +minisyn!(ExprBlock); +minisyn!(ExprBreak); +minisyn!(ExprConst); +minisyn!(ExprCast); +minisyn!(ExprField); +minisyn_no_parse!(ExprGroup); +minisyn!(ExprLet); +minisyn!(ExprParen); +minisyn!(ExprReference); +minisyn!(ExprTry); +minisyn!(ExprUnary); +minisyn_no_parse!(Field); +minisyn_no_parse!(Fields); +minisyn!(ForeignItem); +minisyn!(FnArg); +minisyn!(GenericArgument); +minisyn!(GenericParam); +minisyn!(Ident); +minisyn!(ImplItem); +minisyn!(Item); +minisyn!(ItemConst); +minisyn!(ItemEnum); +minisyn!(ItemForeignMod); +minisyn!(ItemStruct); +minisyn!(ItemType); +minisyn!(ItemUse); +minisyn!(LitBool); +minisyn!(LitInt); +minisyn!(Macro); +minisyn_no_parse!(Pat); +minisyn_no_parse!(PatType); +minisyn_no_parse!(PatReference); +minisyn_no_parse!(PatSlice); +minisyn_no_parse!(PatTuple); +minisyn!(Path); +minisyn_no_parse!(PathArguments); +minisyn!(PathSegment); +minisyn!(Receiver); +minisyn!(ReturnType); +minisyn!(Signature); +minisyn!(Stmt); +minisyn!(TraitItem); +minisyn!(Type); +minisyn!(TypeArray); +minisyn!(TypeGroup); +minisyn!(TypeParamBound); +minisyn!(TypeParen); +minisyn!(TypePath); +minisyn!(TypePtr); +minisyn!(TypeReference); +minisyn!(TypeSlice); +minisyn!(Visibility); + +/// Converts a `syn::Punctuated` from being full of `syn` types to being +/// full of `minisyn` types or vice-versa. +pub(crate) fn minisynize_punctuated(input: Punctuated) -> Punctuated +where + T1: Into, +{ + input + .into_pairs() + .map(|p| match p { + Pair::Punctuated(t, p) => Pair::Punctuated(t.into(), p), + Pair::End(t) => Pair::End(t.into()), + }) + .collect() +} + +/// Converts a `Vec` from being full of `syn` types to being +/// full of `minisyn` types or vice-versa. +pub(crate) fn minisynize_vec(input: Vec) -> Vec +where + T1: Into, +{ + input.into_iter().map(Into::into).collect() +} + +impl Ident { + pub(crate) fn new(string: &str, span: proc_macro2::Span) -> Self { + Self(syn::Ident::new(string, span)) + } +} + +impl Display for Ident { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0.to_string()) + } +} + +impl PartialEq for Ident +where + T: AsRef + ?Sized, +{ + fn eq(&self, rhs: &T) -> bool { + self.0.eq(rhs) + } +} diff --git a/engine/src/types.rs b/engine/src/types.rs index deb3525fb..f7eaae0cc 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -6,12 +6,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::minisyn::Ident; use itertools::Itertools; use proc_macro2::Span; use quote::ToTokens; use std::iter::Peekable; use std::{fmt::Display, sync::Arc}; -use syn::{parse_quote, Ident, PathSegment, TypePath}; +use syn::{parse_quote, PathSegment, TypePath}; use thiserror::Error; use crate::known_types::known_types; @@ -85,7 +86,7 @@ impl<'a> IntoIterator for &'a Namespace { /// either. It doesn't directly have functionality to convert /// from one to the other; `replace_type_path_without_arguments` /// does that. -#[derive(Debug, PartialEq, PartialOrd, Eq, Hash, Clone)] +#[derive(PartialEq, PartialOrd, Eq, Hash, Clone)] pub struct QualifiedName(Namespace, String); impl QualifiedName { @@ -225,6 +226,12 @@ impl Display for QualifiedName { } } +impl std::fmt::Debug for QualifiedName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(self, f) + } +} + /// Problems representing C++ identifiers in a way which is compatible with /// cxx. #[derive(Error, Clone, Debug)]