diff options
-rw-r--r-- | src/ir/function.rs | 49 | ||||
-rw-r--r-- | tests/expectations/tests/func_with_func_ptr_arg.rs | 19 | ||||
-rw-r--r-- | tests/headers/func_with_func_ptr_arg.h | 2 |
3 files changed, 49 insertions, 21 deletions
diff --git a/src/ir/function.rs b/src/ir/function.rs index 5ae7583d..b20cc634 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -314,24 +314,37 @@ fn args_from_ty_and_cursor( 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!() - } + let cursor_args = cursor.args().unwrap().into_iter(); + let type_args = ty.args().unwrap_or_default().into_iter(); + + // Argument types can be found in either the cursor or the type, but argument names may only be + // found on the cursor. We often have access to both a type and a cursor for each argument, but + // in some cases we may only have one. + // + // Prefer using the type as the source of truth for the argument's type, but fall back to + // inspecting the cursor (this happens for Objective C interfaces). + // + // Prefer using the cursor for the argument's type, but fall back to using the parent's cursor + // (this happens for function pointer return types). + cursor_args + .map(Some) + .chain(std::iter::repeat(None)) + .zip( + type_args + .map(Some) + .chain(std::iter::repeat(None)) + ) + .take_while(|(cur, ty)| cur.is_some() || ty.is_some()) + .map(|(arg_cur, arg_ty)| { + let name = arg_cur + .map(|a| a.spelling()) + .and_then(|name| if name.is_empty() { None} else { Some(name) }); + + let cursor = arg_cur.unwrap_or(*cursor); + let ty = arg_ty.unwrap_or(cursor.cur_type()); + (name, Item::from_ty_or_ref(ty, cursor, None, ctx)) + }) + .collect() } impl FunctionSig { diff --git a/tests/expectations/tests/func_with_func_ptr_arg.rs b/tests/expectations/tests/func_with_func_ptr_arg.rs index fed557b8..3cb82102 100644 --- a/tests/expectations/tests/func_with_func_ptr_arg.rs +++ b/tests/expectations/tests/func_with_func_ptr_arg.rs @@ -1,9 +1,22 @@ /* 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 +)] extern "C" { pub fn foo(bar: ::std::option::Option<unsafe extern "C" fn()>); } +extern "C" { + pub fn bar( + one: ::std::option::Option< + unsafe extern "C" fn(a: ::std::os::raw::c_int, b: ::std::os::raw::c_int), + >, + two: ::std::option::Option< + unsafe extern "C" fn(c: ::std::os::raw::c_int, d: ::std::os::raw::c_int), + >, + ); +} diff --git a/tests/headers/func_with_func_ptr_arg.h b/tests/headers/func_with_func_ptr_arg.h index 629c84ab..e9abcae6 100644 --- a/tests/headers/func_with_func_ptr_arg.h +++ b/tests/headers/func_with_func_ptr_arg.h @@ -1 +1,3 @@ void foo(void (*bar)()); + +void bar(void (*one)(int a, int b), void (*two)(int c, int d)); |