From cf406e964062549531b9b928f601be341a079c09 Mon Sep 17 00:00:00 2001 From: Alastair Daivis Date: Mon, 6 Jan 2020 18:45:38 -0500 Subject: [PATCH] Support 'swift_name' attributes on generated functions Fixes #420 --- docs.md | 15 +++ src/bindgen/config.rs | 5 +- src/bindgen/ir/function.rs | 103 +++++++++++++-- src/bindgen/parser.rs | 133 ++++++++++++++------ src/bindgen/utilities.rs | 15 +++ tests/expectations/both/swift_name.c | 53 ++++++++ tests/expectations/both/swift_name.compat.c | 61 +++++++++ tests/expectations/swift_name.c | 53 ++++++++ tests/expectations/swift_name.compat.c | 61 +++++++++ tests/expectations/swift_name.cpp | 58 +++++++++ tests/expectations/tag/swift_name.c | 53 ++++++++ tests/expectations/tag/swift_name.compat.c | 61 +++++++++ tests/rust/swift_name.rs | 123 ++++++++++++++++++ tests/rust/swift_name.toml | 4 + 14 files changed, 750 insertions(+), 48 deletions(-) create mode 100644 tests/expectations/both/swift_name.c create mode 100644 tests/expectations/both/swift_name.compat.c create mode 100644 tests/expectations/swift_name.c create mode 100644 tests/expectations/swift_name.compat.c create mode 100644 tests/expectations/swift_name.cpp create mode 100644 tests/expectations/tag/swift_name.c create mode 100644 tests/expectations/tag/swift_name.compat.c create mode 100644 tests/rust/swift_name.rs create mode 100644 tests/rust/swift_name.toml diff --git a/docs.md b/docs.md index 725e31a..8b2c61e 100644 --- a/docs.md +++ b/docs.md @@ -293,7 +293,15 @@ All function attributes are just local overrides for the same options found in t * prefix * postfix +## Generating Swift Bindings +In addition to parsing function names in C/C++ header files, the Swift compiler can make use of the `swift_name` attribute on functions to generate more idiomatic names for imported functions and methods. + +This attribute is commonly used in Objective-C/C/C++ via the `NS_SWIFT_NAME` and `CF_SWIFT_NAME` macros. + +Given configuration in the cbindgen.toml, `cbindgen` can generate these attributes for you by guessing an appropriate method signature based on the existing function name (and type, if it is a method in an `impl` block). + +This is controlled by the `swift_name_macro` option in the cbindgen.toml. ## cbindgen.toml @@ -545,6 +553,13 @@ args = "horizontal" # default: nothing is emitted for must_use functions must_use = "MUST_USE_FUNC" +# An optional string that, if present, will be used to generate Swift function +# and method signatures for generated functions, for example "CF_SWIFT_NAME". +# If no such macro is available in your toolchain, you can define one using the +# `header` option in cbindgen.toml +# default: no swift_name function attributes are generated +swift_name_macro = "CF_SWIFT_NAME" + # A rule to use to rename function argument names. The renaming assumes the input # is the Rust standard snake_case, however it accepts all the different rename_args # inputs. This means many options here are no-ops or redundant. diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 620963a..d2994d7 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -279,12 +279,14 @@ pub struct FunctionConfig { pub prefix: Option, /// Optional text to output after each function declaration pub postfix: Option, - /// The way to annotation this function as #[must_use]. + /// The way to annotation this function as #[must_use] pub must_use: Option, /// The style to layout the args pub args: Layout, /// The rename rule to apply to function args pub rename_args: Option, + /// An optional macro to use when generating Swift function name attributes + pub swift_name_macro: Option, } impl Default for FunctionConfig { @@ -295,6 +297,7 @@ impl Default for FunctionConfig { must_use: None, args: Layout::Auto, rename_args: None, + swift_name_macro: None, } } } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index ada5a51..a54c34d 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -23,6 +23,9 @@ use crate::bindgen::writer::{Source, SourceWriter}; #[derive(Debug, Clone)] pub struct Function { pub path: Path, + /// Path to the self-type of the function + /// If the function is a method, this will contain the path of the type in the impl block + pub self_type_path: Option, pub ret: Type, pub args: Vec<(String, Type)>, pub extern_decl: bool, @@ -34,12 +37,16 @@ pub struct Function { impl Function { pub fn load( path: Path, + self_type_path: Option, sig: &syn::Signature, extern_decl: bool, attrs: &[syn::Attribute], mod_cfg: Option<&Cfg>, ) -> Result { - let args = sig.inputs.iter().try_skip_map(|x| x.as_ident_and_type())?; + let args = sig + .inputs + .iter() + .try_skip_map(|x| x.as_ident_and_type(self_type_path.as_ref()))?; let ret = match sig.output { syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void), syn::ReturnType::Type(_, ref ty) => { @@ -53,6 +60,7 @@ impl Function { Ok(Function { path, + self_type_path, ret, args, extern_decl, @@ -62,6 +70,35 @@ impl Function { }) } + pub fn swift_name(&self) -> String { + // If the symbol name starts with the type name, separate the two components with '.' + // so that Swift recognises the association between the method and the type + let (ref type_prefix, ref type_name) = if let Some(type_name) = &self.self_type_path { + let type_name = type_name.to_string(); + if !self.path.name().starts_with(&type_name) { + return self.path.to_string(); + } + (format!("{}.", type_name), type_name) + } else { + ("".to_string(), "".to_string()) + }; + + let item_name = self + .path + .name() + .trim_start_matches(type_name) + .trim_start_matches('_'); + + let item_args = { + let mut items = vec![]; + for (arg, _) in self.args.iter() { + items.push(format!("{}:", arg.as_str())); + } + items.join("") + }; + format!("{}{}({})", type_prefix, item_name, item_args) + } + pub fn path(&self) -> &Path { &self.path } @@ -160,12 +197,17 @@ impl Source for Function { } } cdecl::write_func(out, &func, false, void_prototype); + if !func.extern_decl { if let Some(ref postfix) = postfix { - out.write(" "); - write!(out, "{}", postfix); + write!(out, " {}", postfix); } } + + if let Some(ref swift_name_macro) = config.function.swift_name_macro { + write!(out, " {}({})", swift_name_macro, func.swift_name()); + } + out.write(";"); condition.write_after(config, out); @@ -203,6 +245,11 @@ impl Source for Function { write!(out, "{}", postfix); } } + + if let Some(ref swift_name_macro) = config.function.swift_name_macro { + write!(out, " {}({})", swift_name_macro, func.swift_name()); + } + out.write(";"); condition.write_after(config, out); @@ -221,17 +268,46 @@ impl Source for Function { } pub trait SynFnArgHelpers { - fn as_ident_and_type(&self) -> Result, String>; + fn as_ident_and_type( + &self, + self_type_path: Option<&Path>, + ) -> Result, String>; +} + +fn gen_self_type(self_type_path: &Path, receiver: &syn::Receiver) -> Result, String> { + fn _gen_self_type( + self_type_path: &Path, + receiver: &syn::Receiver, + ) -> Result { + Ok(match receiver.reference { + Some(_) => syn::Type::Reference(match receiver.mutability { + Some(_) => syn::parse_str(&format!("&mut {}", self_type_path))?, + None => syn::parse_str(&format!("&{}", self_type_path))?, + }), + None => syn::Type::Path(syn::parse_str(self_type_path.name())?), + }) + } + + Type::load(&Box::new( + _gen_self_type(self_type_path, receiver) + .map_err(|e| format!("Failed to generate self type: {}", e))?, + )) } impl SynFnArgHelpers for syn::FnArg { - fn as_ident_and_type(&self) -> Result, String> { + fn as_ident_and_type( + &self, + self_type_path: Option<&Path>, + ) -> Result, String> { match self { &syn::FnArg::Typed(syn::PatType { ref pat, ref ty, .. }) => match **pat { syn::Pat::Ident(syn::PatIdent { ref ident, .. }) => { - if let Some(x) = Type::load(ty)? { + if let Some(mut x) = Type::load(ty)? { + if let Some(self_type_path) = self_type_path { + x.replace_self_with(self_type_path) + } Ok(Some((ident.to_string(), x))) } else { Ok(None) @@ -239,7 +315,20 @@ impl SynFnArgHelpers for syn::FnArg { } _ => Err("Parameter has an unsupported type.".to_owned()), }, - _ => Err("Parameter has an unsupported type.".to_owned()), + &syn::FnArg::Receiver(ref receiver) => { + if let Some(self_type_path) = self_type_path { + if let Some(x) = gen_self_type(self_type_path, receiver)? { + Ok(Some(("self".to_string(), x))) + } else { + Ok(None) + } + } else { + Err( + "Parameter has an unsupported type (Self type found in free function)" + .to_owned(), + ) + } + } } } } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 1e0e816..6988144 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -465,6 +465,24 @@ impl Parse { if has_assoc_const { impls_with_assoc_consts.push(item_impl); } + + if let syn::Type::Path(ref path) = *item_impl.self_ty { + if let Some(type_name) = path.path.get_ident() { + for method in item_impl.items.iter().filter_map(|item| match item { + syn::ImplItem::Method(method) => Some(method), + _ => None, + }) { + self.load_syn_method( + config, + binding_crate_name, + crate_name, + mod_cfg, + Path::new(type_name.to_string()), + method, + ) + } + } + } } syn::Item::Macro(ref item) => { self.load_builtin_macro(config, crate_name, mod_cfg, item) @@ -523,7 +541,7 @@ impl Parse { return; } let path = Path::new(function.sig.ident.to_string()); - match Function::load(path, &function.sig, true, &function.attrs, mod_cfg) { + match Function::load(path, None, &function.sig, true, &function.attrs, mod_cfg) { Ok(func) => { info!("Take {}::{}.", crate_name, &function.sig.ident); @@ -540,6 +558,29 @@ impl Parse { } } + /// Loads a `fn` declaration inside an `impl` block, if the type is a simple identifier + fn load_syn_method( + &mut self, + config: &Config, + binding_crate_name: &str, + crate_name: &str, + mod_cfg: Option<&Cfg>, + self_type: Path, + item: &syn::ImplItemMethod, + ) { + self.load_fn_declaration( + config, + binding_crate_name, + crate_name, + mod_cfg, + item, + Some(self_type), + &item.sig, + &item.vis, + &item.attrs, + ) + } + /// Loads a `fn` declaration fn load_syn_fn( &mut self, @@ -548,6 +589,31 @@ impl Parse { crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemFn, + ) { + self.load_fn_declaration( + config, + binding_crate_name, + crate_name, + mod_cfg, + item, + None, + &item.sig, + &item.vis, + &item.attrs, + ); + } + + fn load_fn_declaration( + &mut self, + config: &Config, + binding_crate_name: &str, + crate_name: &str, + mod_cfg: Option<&Cfg>, + named_symbol: &dyn SynItemFnHelpers, + self_type: Option, + sig: &syn::Signature, + vis: &syn::Visibility, + attrs: &[syn::Attribute], ) { if !config .parse @@ -555,58 +621,45 @@ impl Parse { { info!( "Skip {}::{} - (fn's outside of the binding crate are not used).", - crate_name, &item.sig.ident + crate_name, &sig.ident ); return; } - if let syn::Visibility::Public(_) = item.vis { - if item.sig.abi.is_omitted() || item.sig.abi.is_c() { - if let Some(exported_name) = item.exported_name() { - let path = Path::new(exported_name); - match Function::load(path, &item.sig, false, &item.attrs, mod_cfg) { - Ok(func) => { - info!("Take {}::{}.", crate_name, &item.sig.ident); + let loggable_item_name = { + let mut items = vec![]; + items.push(crate_name.to_owned()); + if let Some(ref self_type) = self_type { + items.push(self_type.to_string()); + } + items.push(sig.ident.to_string()); + items.join("::") + }; + if let syn::Visibility::Public(_) = vis { + if sig.abi.is_omitted() || sig.abi.is_c() { + if let Some(exported_name) = named_symbol.exported_name() { + let path = Path::new(exported_name); + match Function::load(path, self_type, &sig, false, &attrs, mod_cfg) { + Ok(func) => { + info!("Take {}.", loggable_item_name); self.functions.push(func); } Err(msg) => { - error!( - "Cannot use fn {}::{} ({}).", - crate_name, &item.sig.ident, msg - ); + error!("Cannot use fn {} ({}).", loggable_item_name, msg); } } - return; + } else { + warn!( + "Skipping {} - (not `no_mangle`, and has no `export_name` attribute)", + loggable_item_name + ); } + } else { + warn!("Skipping {} - (not `extern \"C\"`", loggable_item_name); } - } - - // TODO - if let syn::Visibility::Public(_) = item.vis { } else { - warn!("Skip {}::{} - (not `pub`).", crate_name, &item.sig.ident); - } - - if !(item.sig.abi.is_omitted() || item.sig.abi.is_c()) { - warn!( - "Skip {}::{} - (wrong ABI - not `extern` or `extern \"C\"`).", - crate_name, &item.sig.ident - ); - } - - if item.exported_name().is_none() { - warn!( - "Skip {}::{} - (not `no_mangle`, and has no `export_name` attribute)", - crate_name, &item.sig.ident - ); - } - - if item.sig.abi.is_some() && !(item.sig.abi.is_omitted() || item.sig.abi.is_c()) { - warn!( - "Skip {}::{} - (non `extern \"C\"`).", - crate_name, &item.sig.ident - ); + warn!("Skipping {} - (not `pub`)", loggable_item_name); } } diff --git a/src/bindgen/utilities.rs b/src/bindgen/utilities.rs index 4596b98..963b0a6 100644 --- a/src/bindgen/utilities.rs +++ b/src/bindgen/utilities.rs @@ -57,6 +57,20 @@ impl SynItemFnHelpers for syn::ItemFn { } } +impl SynItemFnHelpers for syn::ImplItemMethod { + fn exported_name(&self) -> Option { + self.attrs + .attr_name_value_lookup("export_name") + .or_else(|| { + if self.is_no_mangle() { + Some(self.sig.ident.to_string()) + } else { + None + } + }) + } +} + pub trait SynItemHelpers { /// Searches for attributes like `#[test]`. /// Example: @@ -138,6 +152,7 @@ impl_syn_item_helper!(syn::ItemUse); impl_syn_item_helper!(syn::ItemStatic); impl_syn_item_helper!(syn::ItemConst); impl_syn_item_helper!(syn::ItemFn); +impl_syn_item_helper!(syn::ImplItemMethod); impl_syn_item_helper!(syn::ItemMod); impl_syn_item_helper!(syn::ItemForeignMod); impl_syn_item_helper!(syn::ItemType); diff --git a/tests/expectations/both/swift_name.c b/tests/expectations/both/swift_name.c new file mode 100644 index 0000000..4a23851 --- /dev/null +++ b/tests/expectations/both/swift_name.c @@ -0,0 +1,53 @@ +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) + +#include +#include +#include +#include + +typedef struct Box_SelfTypeTestStruct Box_SelfTypeTestStruct; + +typedef struct Opaque Opaque; + +typedef struct PointerToOpaque { + Opaque *ptr; +} PointerToOpaque; + +typedef struct SelfTypeTestStruct { + uint8_t times; +} SelfTypeTestStruct; + +PointerToOpaque PointerToOpaque_create(uint8_t times) CF_SWIFT_NAME(PointerToOpaque.create(times:)); + +void PointerToOpaque_sayHello(PointerToOpaque self) +/*a comment!*/ CF_SWIFT_NAME(PointerToOpaque.sayHello(self:)); + +void SelfTypeTestStruct_should_exist_annotated_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_self(self:)); + +void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); + +void SelfTypeTestStruct_should_exist_mut_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_mut_unannotated(self:)); + +void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref(self:)); + +void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); + +void SelfTypeTestStruct_should_exist_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_unannotated(self:)); + +void SelfTypeTestStruct_should_not_exist_box(Box_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); + +void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); + +void free_function_should_exist_annotated_mut_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_mut_by_name(test_struct:)); + +void free_function_should_exist_ref(const SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref(test_struct:)); + +void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref_mut(test_struct:)); + +void free_function_should_not_exist_box(Box_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); + +void rust_print_hello_world(void) CF_SWIFT_NAME(rust_print_hello_world()); diff --git a/tests/expectations/both/swift_name.compat.c b/tests/expectations/both/swift_name.compat.c new file mode 100644 index 0000000..d5927ba --- /dev/null +++ b/tests/expectations/both/swift_name.compat.c @@ -0,0 +1,61 @@ +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) + +#include +#include +#include +#include + +typedef struct Box_SelfTypeTestStruct Box_SelfTypeTestStruct; + +typedef struct Opaque Opaque; + +typedef struct PointerToOpaque { + Opaque *ptr; +} PointerToOpaque; + +typedef struct SelfTypeTestStruct { + uint8_t times; +} SelfTypeTestStruct; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +PointerToOpaque PointerToOpaque_create(uint8_t times) CF_SWIFT_NAME(PointerToOpaque.create(times:)); + +void PointerToOpaque_sayHello(PointerToOpaque self) +/*a comment!*/ CF_SWIFT_NAME(PointerToOpaque.sayHello(self:)); + +void SelfTypeTestStruct_should_exist_annotated_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_self(self:)); + +void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); + +void SelfTypeTestStruct_should_exist_mut_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_mut_unannotated(self:)); + +void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref(self:)); + +void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); + +void SelfTypeTestStruct_should_exist_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_unannotated(self:)); + +void SelfTypeTestStruct_should_not_exist_box(Box_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); + +void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); + +void free_function_should_exist_annotated_mut_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_mut_by_name(test_struct:)); + +void free_function_should_exist_ref(const SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref(test_struct:)); + +void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref_mut(test_struct:)); + +void free_function_should_not_exist_box(Box_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); + +void rust_print_hello_world(void) CF_SWIFT_NAME(rust_print_hello_world()); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/swift_name.c b/tests/expectations/swift_name.c new file mode 100644 index 0000000..4f66ce7 --- /dev/null +++ b/tests/expectations/swift_name.c @@ -0,0 +1,53 @@ +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) + +#include +#include +#include +#include + +typedef struct Box_SelfTypeTestStruct Box_SelfTypeTestStruct; + +typedef struct Opaque Opaque; + +typedef struct { + Opaque *ptr; +} PointerToOpaque; + +typedef struct { + uint8_t times; +} SelfTypeTestStruct; + +PointerToOpaque PointerToOpaque_create(uint8_t times) CF_SWIFT_NAME(PointerToOpaque.create(times:)); + +void PointerToOpaque_sayHello(PointerToOpaque self) +/*a comment!*/ CF_SWIFT_NAME(PointerToOpaque.sayHello(self:)); + +void SelfTypeTestStruct_should_exist_annotated_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_self(self:)); + +void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); + +void SelfTypeTestStruct_should_exist_mut_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_mut_unannotated(self:)); + +void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref(self:)); + +void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); + +void SelfTypeTestStruct_should_exist_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_unannotated(self:)); + +void SelfTypeTestStruct_should_not_exist_box(Box_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); + +void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); + +void free_function_should_exist_annotated_mut_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_mut_by_name(test_struct:)); + +void free_function_should_exist_ref(const SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref(test_struct:)); + +void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref_mut(test_struct:)); + +void free_function_should_not_exist_box(Box_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); + +void rust_print_hello_world(void) CF_SWIFT_NAME(rust_print_hello_world()); diff --git a/tests/expectations/swift_name.compat.c b/tests/expectations/swift_name.compat.c new file mode 100644 index 0000000..55bcc7b --- /dev/null +++ b/tests/expectations/swift_name.compat.c @@ -0,0 +1,61 @@ +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) + +#include +#include +#include +#include + +typedef struct Box_SelfTypeTestStruct Box_SelfTypeTestStruct; + +typedef struct Opaque Opaque; + +typedef struct { + Opaque *ptr; +} PointerToOpaque; + +typedef struct { + uint8_t times; +} SelfTypeTestStruct; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +PointerToOpaque PointerToOpaque_create(uint8_t times) CF_SWIFT_NAME(PointerToOpaque.create(times:)); + +void PointerToOpaque_sayHello(PointerToOpaque self) +/*a comment!*/ CF_SWIFT_NAME(PointerToOpaque.sayHello(self:)); + +void SelfTypeTestStruct_should_exist_annotated_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_self(self:)); + +void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); + +void SelfTypeTestStruct_should_exist_mut_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_mut_unannotated(self:)); + +void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref(self:)); + +void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); + +void SelfTypeTestStruct_should_exist_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_unannotated(self:)); + +void SelfTypeTestStruct_should_not_exist_box(Box_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); + +void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); + +void free_function_should_exist_annotated_mut_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_mut_by_name(test_struct:)); + +void free_function_should_exist_ref(const SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref(test_struct:)); + +void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref_mut(test_struct:)); + +void free_function_should_not_exist_box(Box_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); + +void rust_print_hello_world(void) CF_SWIFT_NAME(rust_print_hello_world()); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/swift_name.cpp b/tests/expectations/swift_name.cpp new file mode 100644 index 0000000..ba2d9eb --- /dev/null +++ b/tests/expectations/swift_name.cpp @@ -0,0 +1,58 @@ +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) + +#include +#include +#include +#include + +template +struct Box; + +struct Opaque; + +struct PointerToOpaque { + Opaque *ptr; +}; + +struct SelfTypeTestStruct { + uint8_t times; +}; + +extern "C" { + +PointerToOpaque PointerToOpaque_create(uint8_t times) CF_SWIFT_NAME(PointerToOpaque.create(times:)); + +void PointerToOpaque_sayHello(PointerToOpaque self) +/*a comment!*/ CF_SWIFT_NAME(PointerToOpaque.sayHello(self:)); + +void SelfTypeTestStruct_should_exist_annotated_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_by_name(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_self(self:)); + +void SelfTypeTestStruct_should_exist_annotated_self(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); + +void SelfTypeTestStruct_should_exist_mut_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_mut_unannotated(self:)); + +void SelfTypeTestStruct_should_exist_ref(const SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref(self:)); + +void SelfTypeTestStruct_should_exist_ref_mut(SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); + +void SelfTypeTestStruct_should_exist_unannotated(SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_unannotated(self:)); + +void SelfTypeTestStruct_should_not_exist_box(Box self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); + +void free_function_should_exist_annotated_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); + +void free_function_should_exist_annotated_mut_by_name(SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_mut_by_name(test_struct:)); + +void free_function_should_exist_ref(const SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref(test_struct:)); + +void free_function_should_exist_ref_mut(SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref_mut(test_struct:)); + +void free_function_should_not_exist_box(Box boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); + +void rust_print_hello_world() CF_SWIFT_NAME(rust_print_hello_world()); + +} // extern "C" diff --git a/tests/expectations/tag/swift_name.c b/tests/expectations/tag/swift_name.c new file mode 100644 index 0000000..927d05b --- /dev/null +++ b/tests/expectations/tag/swift_name.c @@ -0,0 +1,53 @@ +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) + +#include +#include +#include +#include + +struct Box_SelfTypeTestStruct; + +struct Opaque; + +struct PointerToOpaque { + struct Opaque *ptr; +}; + +struct SelfTypeTestStruct { + uint8_t times; +}; + +struct PointerToOpaque PointerToOpaque_create(uint8_t times) CF_SWIFT_NAME(PointerToOpaque.create(times:)); + +void PointerToOpaque_sayHello(struct PointerToOpaque self) +/*a comment!*/ CF_SWIFT_NAME(PointerToOpaque.sayHello(self:)); + +void SelfTypeTestStruct_should_exist_annotated_by_name(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_by_name(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_self(self:)); + +void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); + +void SelfTypeTestStruct_should_exist_mut_unannotated(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_mut_unannotated(self:)); + +void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref(self:)); + +void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); + +void SelfTypeTestStruct_should_exist_unannotated(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_unannotated(self:)); + +void SelfTypeTestStruct_should_not_exist_box(struct Box_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); + +void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); + +void free_function_should_exist_annotated_mut_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_mut_by_name(test_struct:)); + +void free_function_should_exist_ref(const struct SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref(test_struct:)); + +void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref_mut(test_struct:)); + +void free_function_should_not_exist_box(struct Box_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); + +void rust_print_hello_world(void) CF_SWIFT_NAME(rust_print_hello_world()); diff --git a/tests/expectations/tag/swift_name.compat.c b/tests/expectations/tag/swift_name.compat.c new file mode 100644 index 0000000..a4cfcd1 --- /dev/null +++ b/tests/expectations/tag/swift_name.compat.c @@ -0,0 +1,61 @@ +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) + +#include +#include +#include +#include + +struct Box_SelfTypeTestStruct; + +struct Opaque; + +struct PointerToOpaque { + struct Opaque *ptr; +}; + +struct SelfTypeTestStruct { + uint8_t times; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct PointerToOpaque PointerToOpaque_create(uint8_t times) CF_SWIFT_NAME(PointerToOpaque.create(times:)); + +void PointerToOpaque_sayHello(struct PointerToOpaque self) +/*a comment!*/ CF_SWIFT_NAME(PointerToOpaque.sayHello(self:)); + +void SelfTypeTestStruct_should_exist_annotated_by_name(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_by_name(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_by_name(self:)); + +void SelfTypeTestStruct_should_exist_annotated_mut_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_mut_self(self:)); + +void SelfTypeTestStruct_should_exist_annotated_self(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_annotated_self(self:)); + +void SelfTypeTestStruct_should_exist_mut_unannotated(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_mut_unannotated(self:)); + +void SelfTypeTestStruct_should_exist_ref(const struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref(self:)); + +void SelfTypeTestStruct_should_exist_ref_mut(struct SelfTypeTestStruct *self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_ref_mut(self:)); + +void SelfTypeTestStruct_should_exist_unannotated(struct SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_exist_unannotated(self:)); + +void SelfTypeTestStruct_should_not_exist_box(struct Box_SelfTypeTestStruct self) CF_SWIFT_NAME(SelfTypeTestStruct.should_not_exist_box(self:)); + +void free_function_should_exist_annotated_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_by_name(test_struct:)); + +void free_function_should_exist_annotated_mut_by_name(struct SelfTypeTestStruct test_struct) CF_SWIFT_NAME(free_function_should_exist_annotated_mut_by_name(test_struct:)); + +void free_function_should_exist_ref(const struct SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref(test_struct:)); + +void free_function_should_exist_ref_mut(struct SelfTypeTestStruct *test_struct) CF_SWIFT_NAME(free_function_should_exist_ref_mut(test_struct:)); + +void free_function_should_not_exist_box(struct Box_SelfTypeTestStruct boxed) CF_SWIFT_NAME(free_function_should_not_exist_box(boxed:)); + +void rust_print_hello_world(void) CF_SWIFT_NAME(rust_print_hello_world()); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/rust/swift_name.rs b/tests/rust/swift_name.rs new file mode 100644 index 0000000..b1af1cc --- /dev/null +++ b/tests/rust/swift_name.rs @@ -0,0 +1,123 @@ +#[export_name="rust_print_hello_world"] +pub extern fn say_hello() { + println!("Hello, World!"); +} + +#[repr(C)] +pub struct SelfTypeTestStruct { + times: u8, +} + +impl SelfTypeTestStruct { + #[export_name="SelfTypeTestStruct_should_exist_ref"] + #[no_mangle] + pub extern fn should_exist_ref(&self) { + println!("should_exist_ref"); + } + + #[export_name="SelfTypeTestStruct_should_exist_ref_mut"] + #[no_mangle] + pub extern fn should_exist_ref_mut(&mut self) { + println!("should_exist_ref_mut"); + } + + #[export_name="SelfTypeTestStruct_should_not_exist_box"] + #[no_mangle] + pub extern fn should_not_exist_box(self: Box) { + println!("should_not_exist_box"); + } + + #[export_name="SelfTypeTestStruct_should_exist_annotated_self"] + #[no_mangle] + pub extern fn should_exist_annotated_self(self: Self) { + println!("should_exist_annotated_self"); + } + + #[export_name="SelfTypeTestStruct_should_exist_annotated_mut_self"] + #[no_mangle] + #[allow(unused_mut)] + pub extern fn should_exist_annotated_mut_self(mut self: Self) { + println!("should_exist_annotated_mut_self"); + } + + #[export_name="SelfTypeTestStruct_should_exist_annotated_by_name"] + #[no_mangle] + pub extern fn should_exist_annotated_by_name(self: SelfTypeTestStruct) { + println!("should_exist_annotated_by_name"); + } + + #[export_name="SelfTypeTestStruct_should_exist_annotated_mut_by_name"] + #[no_mangle] + #[allow(unused_mut)] + pub extern fn should_exist_annotated_mut_by_name(mut self: SelfTypeTestStruct) { + println!("should_exist_annotated_mut_by_name"); + } + + #[export_name="SelfTypeTestStruct_should_exist_unannotated"] + #[no_mangle] + pub extern fn should_exist_unannotated(self) { + println!("should_exist_unannotated"); + } + + #[export_name="SelfTypeTestStruct_should_exist_mut_unannotated"] + #[no_mangle] + #[allow(unused_mut)] + pub extern fn should_exist_mut_unannotated(mut self) { + println!("should_exist_mut_unannotated"); + } +} + +#[no_mangle] +#[allow(unused_variables)] +pub extern fn free_function_should_exist_ref(test_struct: &SelfTypeTestStruct) { + println!("free_function_should_exist_ref"); +} + +#[no_mangle] +#[allow(unused_variables)] +pub extern fn free_function_should_exist_ref_mut(test_struct: &mut SelfTypeTestStruct) { + println!("free_function_should_exist_ref_mut"); +} + +#[no_mangle] +#[allow(unused_variables)] +pub extern fn free_function_should_not_exist_box(boxed: Box) { + println!("free_function_should_not_exist_box"); +} + +#[no_mangle] +#[allow(unused_variables)] +pub extern fn free_function_should_exist_annotated_by_name(test_struct: SelfTypeTestStruct) { + println!("free_function_should_exist_annotated_by_name"); +} + +#[no_mangle] +#[allow(unused_mut)] +#[allow(unused_variables)] +pub extern fn free_function_should_exist_annotated_mut_by_name(mut test_struct: SelfTypeTestStruct) { + println!("free_function_should_exist_annotated_mut_by_name"); +} + +struct Opaque { + times: u8 +} + +#[repr(C)] +pub struct PointerToOpaque { ptr: *mut Opaque } + +impl PointerToOpaque { + #[export_name="PointerToOpaque_create"] + pub extern fn create(times: u8) -> PointerToOpaque { + PointerToOpaque { ptr: Box::into_raw(Box::new(Opaque { times })) } + } + + /// cbindgen:postfix=/*a comment!*/ + #[export_name="PointerToOpaque_sayHello"] + pub extern fn say_hello(self: PointerToOpaque) { + if let Some(nonnull) = std::ptr::NonNull::new(self.ptr) { + for _ in 0 .. unsafe { nonnull.as_ref().times } { + println!("Hello!") + } + } + } +} \ No newline at end of file diff --git a/tests/rust/swift_name.toml b/tests/rust/swift_name.toml new file mode 100644 index 0000000..2aec3e2 --- /dev/null +++ b/tests/rust/swift_name.toml @@ -0,0 +1,4 @@ +header = "#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name)))" + +[fn] +swift_name_macro = "CF_SWIFT_NAME" \ No newline at end of file