summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-05-03 14:48:02 -0500
committerGitHub <noreply@github.com>2017-05-03 14:48:02 -0500
commit765671df1a6b93fccf7460043be865055de7ceb2 (patch)
tree83f2d370b530749c21eb9e16d6866ae4237dd0ee
parent8e9b3884961802a8c5c102ecfff06419e9695199 (diff)
parent335e5c726608e73af062315bcd76cf639e27330c (diff)
Auto merge of #673 - scoopr:objc, r=emilio
objc: Fixes to properly parse most of Foundation I had half of these just lying around in my commit queue for a while, having problems with the template param thing. Incidentally, either some other fixes made it work, or I had accidentally built against clang 4.0, which I guess doesn't work with the current approach. With these I'm able to parse and generate code for Foundation.framework, with regex ^NS.* (and skipping that one id redefine). Also needed --no-doc-comments, that I guess generated comment for an enum in the wrong place, didn't look at that.
-rw-r--r--src/codegen/mod.rs28
-rw-r--r--src/ir/function.rs4
-rw-r--r--src/ir/ty.rs18
-rw-r--r--src/options.rs4
-rw-r--r--tests/expectations/tests/objc_method_clash.rs22
-rw-r--r--tests/expectations/tests/objc_property_fnptr.rs35
-rw-r--r--tests/expectations/tests/objc_template.rs18
-rw-r--r--tests/headers/objc_method_clash.h7
-rw-r--r--tests/headers/objc_property_fnptr.h8
-rw-r--r--tests/headers/objc_template.h6
10 files changed, 141 insertions, 9 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 39b115fa..697c140f 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -2805,7 +2805,8 @@ impl CodeGenerator for Function {
fn objc_method_codegen(ctx: &BindgenContext,
method: &ObjCMethod,
- class_name: Option<&str>)
+ class_name: Option<&str>,
+ prefix: &str)
-> (ast::ImplItem, ast::TraitItem) {
let signature = method.signature();
let fn_args = utils::fnsig_arguments(ctx, signature);
@@ -2864,9 +2865,11 @@ fn objc_method_codegen(ctx: &BindgenContext,
let attrs = vec![];
+ let method_name = format!("{}{}", prefix, method.rust_name());
+
let impl_item = ast::ImplItem {
id: ast::DUMMY_NODE_ID,
- ident: ctx.rust_ident(method.rust_name()),
+ ident: ctx.rust_ident(&method_name),
vis: ast::Visibility::Inherited, // Public,
attrs: attrs.clone(),
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
@@ -2876,7 +2879,7 @@ fn objc_method_codegen(ctx: &BindgenContext,
let trait_item = ast::TraitItem {
id: ast::DUMMY_NODE_ID,
- ident: ctx.rust_ident(method.rust_name()),
+ ident: ctx.rust_ident(&method_name),
attrs: attrs,
node: ast::TraitItemKind::Method(sig, None),
span: ctx.span(),
@@ -2898,14 +2901,23 @@ impl CodeGenerator for ObjCInterface {
for method in self.methods() {
let (impl_item, trait_item) =
- objc_method_codegen(ctx, method, None);
+ objc_method_codegen(ctx, method, None, "");
impl_items.push(impl_item);
trait_items.push(trait_item)
}
+ let instance_method_names : Vec<_> = self.methods().iter().map( { |m| m.rust_name() } ).collect();
+
for class_method in self.class_methods() {
+
+ let ambiquity = instance_method_names.contains(&class_method.rust_name());
+ let prefix = if ambiquity {
+ "class_"
+ } else {
+ ""
+ };
let (impl_item, trait_item) =
- objc_method_codegen(ctx, class_method, Some(self.name()));
+ objc_method_codegen(ctx, class_method, Some(self.name()), prefix);
impl_items.push(impl_item);
trait_items.push(trait_item)
}
@@ -2982,13 +2994,13 @@ mod utils {
result: &mut Vec<P<ast::Item>>) {
let use_objc = if ctx.options().objc_extern_crate {
quote_item!(ctx.ext_cx(),
- use objc;
+ #[macro_use]
+ extern crate objc;
)
.unwrap()
} else {
quote_item!(ctx.ext_cx(),
- #[macro_use]
- extern crate objc;
+ use objc;
)
.unwrap()
};
diff --git a/src/ir/function.rs b/src/ir/function.rs
index 23503b05..01689734 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -284,7 +284,9 @@ impl FunctionSig {
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
cursor.kind() == CXCursor_ObjCClassMethodDecl {
- try!(cursor.ret_type().ok_or(ParseError::Continue))
+ try!(ty.ret_type()
+ .or_else(|| cursor.ret_type())
+ .ok_or(ParseError::Continue))
} else {
try!(ty.ret_type().ok_or(ParseError::Continue))
};
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index c3f26572..a9054e98 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -836,6 +836,24 @@ impl Type {
_ => {}
}
+ // Objective C template type parameter
+ // FIXME: This is probably wrong, we are attempting to find the
+ // objc template params, which seem to manifest as a typedef.
+ // We are rewriting them as id to suppress multiple conflicting
+ // typedefs at root level
+ if ty_kind == CXType_Typedef {
+ let is_template_type_param = ty.declaration().kind() == CXCursor_TemplateTypeParameter;
+ let is_canonical_objcpointer = canonical_ty.kind() == CXType_ObjCObjectPointer;
+
+ // We have found a template type for objc interface
+ if is_canonical_objcpointer && is_template_type_param {
+ // Objective-C generics are just ids with fancy name.
+ // To keep it simple, just name them ids
+ name = "id".to_owned();
+ }
+
+ }
+
if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
// Sorry! (Not sorry)
warn!("Found a partial template specialization; bindgen does not \
diff --git a/src/options.rs b/src/options.rs
index ca54dbc6..bbf9c0dd 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -341,6 +341,10 @@ pub fn builder_from_flags<I>
builder = builder.whitelist_recursively(false);
}
+ if matches.is_present("objc-extern-crate") {
+ builder = builder.objc_extern_crate(true);
+ }
+
if let Some(opaque_types) = matches.values_of("opaque-type") {
for ty in opaque_types {
builder = builder.opaque_type(ty);
diff --git a/tests/expectations/tests/objc_method_clash.rs b/tests/expectations/tests/objc_method_clash.rs
new file mode 100644
index 00000000..07dedc4c
--- /dev/null
+++ b/tests/expectations/tests/objc_method_clash.rs
@@ -0,0 +1,22 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+#![cfg(target_os="macos")]
+
+#[macro_use]
+extern crate objc;
+#[allow(non_camel_case_types)]
+pub type id = *mut objc::runtime::Object;
+pub trait Foo {
+ unsafe fn foo(self);
+ unsafe fn class_foo();
+}
+impl Foo for id {
+ unsafe fn foo(self) { msg_send!(self , foo) }
+ unsafe fn class_foo() {
+ msg_send!(objc :: runtime :: Class :: get ( "Foo" ) . expect (
+ "Couldn\'t find Foo" ) , foo)
+ }
+}
diff --git a/tests/expectations/tests/objc_property_fnptr.rs b/tests/expectations/tests/objc_property_fnptr.rs
new file mode 100644
index 00000000..044f25d1
--- /dev/null
+++ b/tests/expectations/tests/objc_property_fnptr.rs
@@ -0,0 +1,35 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+#![cfg(target_os="macos")]
+
+#[macro_use]
+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 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> {
+ msg_send!(self , func)
+ }
+ unsafe fn setFunc_(self,
+ func:
+ ::std::option::Option<unsafe extern "C" fn()
+ ->
+ ::std::os::raw::c_int>) {
+ msg_send!(self , setFunc:func )
+ }
+}
diff --git a/tests/expectations/tests/objc_template.rs b/tests/expectations/tests/objc_template.rs
new file mode 100644
index 00000000..e5a874c6
--- /dev/null
+++ b/tests/expectations/tests/objc_template.rs
@@ -0,0 +1,18 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+#![cfg(target_os="macos")]
+
+#[macro_use]
+extern crate objc;
+#[allow(non_camel_case_types)]
+pub type id = *mut objc::runtime::Object;
+pub trait Foo {
+ unsafe fn get(self)
+ -> id;
+}
+impl Foo for id {
+ unsafe fn get(self) -> id { msg_send!(self , get) }
+}
diff --git a/tests/headers/objc_method_clash.h b/tests/headers/objc_method_clash.h
new file mode 100644
index 00000000..a56e39db
--- /dev/null
+++ b/tests/headers/objc_method_clash.h
@@ -0,0 +1,7 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// bindgen-osx-only
+
+@interface Foo
++ (void)foo;
+- (void)foo;
+@end
diff --git a/tests/headers/objc_property_fnptr.h b/tests/headers/objc_property_fnptr.h
new file mode 100644
index 00000000..8312ba4a
--- /dev/null
+++ b/tests/headers/objc_property_fnptr.h
@@ -0,0 +1,8 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// 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
diff --git a/tests/headers/objc_template.h b/tests/headers/objc_template.h
new file mode 100644
index 00000000..62398eb7
--- /dev/null
+++ b/tests/headers/objc_template.h
@@ -0,0 +1,6 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// bindgen-osx-only
+
+@interface Foo<__covariant ObjectType>
+- (ObjectType)get;
+@end