summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/function.rs49
-rw-r--r--tests/expectations/tests/func_with_func_ptr_arg.rs19
-rw-r--r--tests/headers/func_with_func_ptr_arg.h2
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));