diff options
-rw-r--r-- | src/clang.rs | 53 | ||||
-rw-r--r-- | src/ir/function.rs | 45 | ||||
-rw-r--r-- | src/ir/item.rs | 1 | ||||
-rw-r--r-- | tests/expectations/tests/block_return_type.rs | 16 | ||||
-rw-r--r-- | tests/expectations/tests/func_ptr_return_type.rs | 18 | ||||
-rw-r--r-- | tests/expectations/tests/objc_property_fnptr.rs | 28 | ||||
-rw-r--r-- | tests/headers/block_return_type.h | 4 | ||||
-rw-r--r-- | tests/headers/func_ptr_return_type.h | 1 | ||||
-rw-r--r-- | tests/headers/objc_property_fnptr.h | 2 |
9 files changed, 128 insertions, 40 deletions
diff --git a/src/clang.rs b/src/clang.rs index 8a3e3c68..10bf054a 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -550,33 +550,27 @@ impl Cursor { /// Given that this cursor's referent is a function, return cursors to its /// parameters. + /// + /// Returns None if the cursor's referent is not a function/method call or + /// declaration. pub fn args(&self) -> Option<Vec<Cursor>> { - // XXX: We might want to use and keep num_args // match self.kind() { // CXCursor_FunctionDecl | // CXCursor_CXXMethod => { - unsafe { - let w = clang_Cursor_getNumArguments(self.x); - if w == -1 { - None - } else { - let num = w as u32; - - let mut args = vec![]; - for i in 0..num { - args.push(Cursor { - x: clang_Cursor_getArgument(self.x, i as c_uint), - }); + self.num_args().ok().map(|num| { + (0..num).map(|i| { + Cursor { + x: unsafe { clang_Cursor_getArgument(self.x, i as c_uint) }, } - Some(args) - } - } + }) + .collect() + }) } /// Given that this cursor's referent is a function/method call or /// declaration, return the number of arguments it takes. /// - /// Returns -1 if the cursor's referent is not a function/method call or + /// Returns Err if the cursor's referent is not a function/method call or /// declaration. pub fn num_args(&self) -> Result<u32, ()> { unsafe { @@ -1017,6 +1011,31 @@ impl Type { }) } + /// Given that this type is a function prototype, return the types of its parameters. + /// + /// Returns None if the type is not a function prototype. + pub fn args(&self) -> Option<Vec<Type>> { + self.num_args().ok().map(|num| { + (0..num).map(|i| { + Type { + x: unsafe { clang_getArgType(self.x, i as c_uint) }, + } + }) + .collect() + }) + } + + /// Given that this type is a function prototype, return the number of arguments it takes. + /// + /// Returns Err if the type is not a function prototype. + pub fn num_args(&self) -> Result<u32, ()> { + unsafe { + let w = clang_getNumArgTypes(self.x); + if w == -1 { Err(()) } else { Ok(w as u32) } + } + } + + /// Given that this type is a pointer type, return the type that it points /// to. pub fn pointee_type(&self) -> Option<Type> { diff --git a/src/ir/function.rs b/src/ir/function.rs index fae6e056..5ae7583d 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -309,6 +309,31 @@ pub fn cursor_mangling( Some(mangling) } +fn args_from_ty_and_cursor( + ty: &clang::Type, + cursor: &clang::Cursor, + ctx: &mut BindgenContext, +) -> Vec<(Option<String>, TypeId)> { + match (cursor.args(), ty.args()) { + (Some(cursor_args), Some(ty_args)) => { + ty_args.iter().enumerate().map(|(i, ty)| { + let name = cursor_args.get(i) + .map(|c| c.spelling()) + .and_then(|name| if name.is_empty() { None } else { Some(name) }); + (name, Item::from_ty_or_ref(*ty, *cursor, None, ctx)) + }).collect() + } + (Some(cursor_args), None) => { + cursor_args.iter().map(|cursor| { + let name = cursor.spelling(); + let name = if name.is_empty() { None } else { Some(name) }; + (name, Item::from_ty_or_ref(cursor.cur_type(), *cursor, None, ctx)) + }).collect() + } + _ => panic!() + } +} + impl FunctionSig { /// Construct a new function signature. pub fn new( @@ -363,28 +388,14 @@ impl FunctionSig { ty.declaration() }; - let mut args: Vec<_> = match kind { + let mut args = match kind { CXCursor_FunctionDecl | CXCursor_Constructor | CXCursor_CXXMethod | CXCursor_ObjCInstanceMethodDecl | CXCursor_ObjCClassMethodDecl => { - // For CXCursor_FunctionDecl, cursor.args() is the reliable way - // to get parameter names and types. - cursor - .args() - .unwrap() - .iter() - .map(|arg| { - let arg_ty = arg.cur_type(); - let name = arg.spelling(); - let name = - if name.is_empty() { None } else { Some(name) }; - let ty = Item::from_ty_or_ref(arg_ty, *arg, None, ctx); - (name, ty) - }) - .collect() - } + args_from_ty_and_cursor(&ty, &cursor, ctx) + }, _ => { // For non-CXCursor_FunctionDecl, visiting the cursor's children // is the only reliable way to get parameter names. diff --git a/src/ir/item.rs b/src/ir/item.rs index a54cbb82..eec64695 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -1449,6 +1449,7 @@ impl ClangItemParser for Item { let is_const = ty.is_const(); let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id); let current_module = ctx.current_module(); + ctx.add_item( Item::new( potential_id, diff --git a/tests/expectations/tests/block_return_type.rs b/tests/expectations/tests/block_return_type.rs new file mode 100644 index 00000000..7779540c --- /dev/null +++ b/tests/expectations/tests/block_return_type.rs @@ -0,0 +1,16 @@ +/* automatically generated by rust-bindgen */ + +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] +#![cfg(target_os = "macos")] + +extern crate block; +extern "C" { + pub fn func() -> _bindgen_ty_id_4; +} +pub type _bindgen_ty_id_4 = + *const ::block::Block<(::std::os::raw::c_int, ::std::os::raw::c_int), ::std::os::raw::c_int>; diff --git a/tests/expectations/tests/func_ptr_return_type.rs b/tests/expectations/tests/func_ptr_return_type.rs new file mode 100644 index 00000000..3a2c9001 --- /dev/null +++ b/tests/expectations/tests/func_ptr_return_type.rs @@ -0,0 +1,18 @@ +/* automatically generated by rust-bindgen */ + +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +extern "C" { + pub fn func() -> ::std::option::Option< + unsafe extern "C" fn( + arg1: ::std::os::raw::c_int, + arg2: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >; +} + diff --git a/tests/expectations/tests/objc_property_fnptr.rs b/tests/expectations/tests/objc_property_fnptr.rs index 4f98f9fb..94ebfad6 100644 --- a/tests/expectations/tests/objc_property_fnptr.rs +++ b/tests/expectations/tests/objc_property_fnptr.rs @@ -1,7 +1,11 @@ /* automatically generated by rust-bindgen */ - -#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] #![cfg(target_os = "macos")] #[macro_use] @@ -9,14 +13,30 @@ extern crate objc; #[allow(non_camel_case_types)] pub type id = *mut objc::runtime::Object; pub trait Foo { - unsafe fn func(self) -> ::std::option::Option<unsafe extern "C" fn() -> ::std::os::raw::c_int>; + unsafe fn func( + self, + ) -> ::std::option::Option< + unsafe extern "C" fn( + arg1: ::std::os::raw::c_char, + arg2: ::std::os::raw::c_short, + arg3: f32, + ) -> ::std::os::raw::c_int, + >; unsafe fn setFunc_( self, func: ::std::option::Option<unsafe extern "C" fn() -> ::std::os::raw::c_int>, ); } impl Foo for id { - unsafe fn func(self) -> ::std::option::Option<unsafe extern "C" fn() -> ::std::os::raw::c_int> { + unsafe fn func( + self, + ) -> ::std::option::Option< + unsafe extern "C" fn( + arg1: ::std::os::raw::c_char, + arg2: ::std::os::raw::c_short, + arg3: f32, + ) -> ::std::os::raw::c_int, + > { msg_send!(self, func) } unsafe fn setFunc_( diff --git a/tests/headers/block_return_type.h b/tests/headers/block_return_type.h new file mode 100644 index 00000000..be76cb59 --- /dev/null +++ b/tests/headers/block_return_type.h @@ -0,0 +1,4 @@ +// bindgen-flags: --generate-block --block-extern-crate -- -fblocks +// bindgen-osx-only + +int (^func(void))(int, int); diff --git a/tests/headers/func_ptr_return_type.h b/tests/headers/func_ptr_return_type.h new file mode 100644 index 00000000..d529edc7 --- /dev/null +++ b/tests/headers/func_ptr_return_type.h @@ -0,0 +1 @@ +int (*func(void))(int, int); diff --git a/tests/headers/objc_property_fnptr.h b/tests/headers/objc_property_fnptr.h index 8312ba4a..bac0c779 100644 --- a/tests/headers/objc_property_fnptr.h +++ b/tests/headers/objc_property_fnptr.h @@ -2,7 +2,5 @@ // bindgen-osx-only @interface Foo -// FIXME: We are not generating valid code for this -// but at least we should not die @property int (*func)(char, short, float); @end |