summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-03-04 15:18:57 -0800
committerGitHub <noreply@github.com>2017-03-04 15:18:57 -0800
commit6320ed2514d93fdbbd429a6d67ee9e8bfdfcb297 (patch)
tree385954c782cac23a90382ee3932310246e12dbaf
parentb71c7ba46b5992e00cc05d9d5788b9cecbcb6305 (diff)
parent35159dc4f6decb6d00199aeca8630fbfe8fb5d53 (diff)
Auto merge of #557 - scoopr:objc, r=emilio
objc: Implement whitelist tracing This implements the tracing facility to enable whitelisting. The most ugly thing is the collecting of the protocol ItemIds that a interface conforms to. I couldn't use the Item::from_ty because the protocols aren't actually types (in clang), I'm just making them look like one, as thats how they behave in bindgens perspective. So I resorted in linear search of all ItemIds, as it was easyish to implement (local to objc.rs), but there are several good avenues to make that faster if it needs to. The change to naming the types with the rust_name is also a suspect, I'm not totally sure of all the consequences but this allows the protocols/categories to be disambiguated, otherwise there could be multiple type items with the same name. Somehow I feel that I'm forgetting another rationale as well, from when I originally wrote that line few days ago. Locally I also got a test failure, but to me that does not seem like it was caused by these changes. In call-conv-field.rs: ```diff extern "stdcall" { - #[link_name = "_bar@0"] + #[link_name = "bar@0"] pub fn bar(); } ```
-rw-r--r--src/ir/objc.rs52
-rw-r--r--src/ir/ty.rs5
-rw-r--r--tests/expectations/tests/objc_whitelist.rs25
-rw-r--r--tests/headers/objc_whitelist.h22
4 files changed, 101 insertions, 3 deletions
diff --git a/src/ir/objc.rs b/src/ir/objc.rs
index 963c8e20..485bda8a 100644
--- a/src/ir/objc.rs
+++ b/src/ir/objc.rs
@@ -1,13 +1,16 @@
//! Objective C types
-use super::context::BindgenContext;
+use super::context::{BindgenContext, ItemId};
use super::function::FunctionSig;
+use super::traversal::{Trace, Tracer};
+use super::ty::TypeKind;
use clang;
use clang_sys::CXChildVisit_Continue;
use clang_sys::CXCursor_ObjCCategoryDecl;
use clang_sys::CXCursor_ObjCClassRef;
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
use clang_sys::CXCursor_ObjCProtocolDecl;
+use clang_sys::CXCursor_ObjCProtocolRef;
/// Objective C interface as used in TypeKind
///
@@ -22,6 +25,8 @@ pub struct ObjCInterface {
is_protocol: bool,
+ conforms_to: Vec<ItemId>,
+
/// List of the methods defined in this interfae
methods: Vec<ObjCInstanceMethod>,
}
@@ -46,6 +51,7 @@ impl ObjCInterface {
name: name.to_owned(),
category: None,
is_protocol: false,
+ conforms_to: Vec::new(),
methods: Vec::new(),
}
}
@@ -97,6 +103,34 @@ impl ObjCInterface {
interface.category = Some(cursor.spelling());
}
}
+ CXCursor_ObjCProtocolRef => {
+ // Gather protocols this interface conforms to
+ let needle = format!("protocol_{}", c.spelling());
+ let items_map = ctx.items();
+ debug!("Interface {} conforms to {}, find the item", interface.name, needle);
+
+ for (id, item) in items_map
+ {
+ if let Some(ty) = item.as_type() {
+ match *ty.kind() {
+ TypeKind::ObjCInterface(ref protocol) => {
+ if protocol.is_protocol
+ {
+ debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name());
+ if Some(needle.as_ref()) == ty.name()
+ {
+ debug!("Found conforming protocol {:?}", item);
+ interface.conforms_to.push(*id);
+ break;
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+
+ }
CXCursor_ObjCInstanceMethodDecl => {
let name = c.spelling();
let signature =
@@ -168,3 +202,19 @@ impl ObjCInstanceMethod {
.join("")
}
}
+
+impl Trace for ObjCInterface {
+ type Extra = ();
+
+ fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
+ where T: Tracer,
+ {
+ for method in &self.methods {
+ method.signature.trace(context, tracer, &());
+ }
+
+ for protocol in &self.conforms_to {
+ tracer.visit(*protocol);
+ }
+ }
+}
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 329f4f54..51652000 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -1268,6 +1268,7 @@ impl Type {
CXType_ObjCInterface => {
let interface = ObjCInterface::from_ty(&location.unwrap(), ctx)
.expect("Not a valid objc interface?");
+ name = interface.rust_name();
TypeKind::ObjCInterface(interface)
}
_ => {
@@ -1325,8 +1326,8 @@ impl Trace for Type {
tracer.visit(id);
}
- TypeKind::ObjCInterface(_) => {
- // TODO:
+ TypeKind::ObjCInterface(ref interface) => {
+ interface.trace(context, tracer, &());
}
// None of these variants have edges to other items and types.
diff --git a/tests/expectations/tests/objc_whitelist.rs b/tests/expectations/tests/objc_whitelist.rs
new file mode 100644
index 00000000..332453f1
--- /dev/null
+++ b/tests/expectations/tests/objc_whitelist.rs
@@ -0,0 +1,25 @@
+/* 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 protocol_SomeProtocol {
+ unsafe fn protocolMethod(self);
+}
+impl protocol_SomeProtocol for id {
+ unsafe fn protocolMethod(self) { msg_send!(self , protocolMethod) }
+}
+pub trait WhitelistMe {
+ unsafe fn method(self);
+}
+impl WhitelistMe for id {
+ unsafe fn method(self) { msg_send!(self , method) }
+}
+pub trait WhitelistMe_InterestingCategory { }
+impl WhitelistMe_InterestingCategory for id { }
diff --git a/tests/headers/objc_whitelist.h b/tests/headers/objc_whitelist.h
new file mode 100644
index 00000000..7cbe43d6
--- /dev/null
+++ b/tests/headers/objc_whitelist.h
@@ -0,0 +1,22 @@
+// bindgen-flags: --objc-extern-crate --whitelist-type WhitelistMe --whitelist-type WhitelistMe_InterestingCategory -- -x objective-c
+// bindgen-osx-only
+
+
+// Protocol should be included, since it is used by the WhitelistMe
+@protocol SomeProtocol
+-(void)protocolMethod;
+@end
+
+// The whitelisted item
+@interface WhitelistMe <SomeProtocol>
+-(void)method;
+@end
+
+// This was also explicitly whitelisted
+@interface WhitelistMe (InterestingCategory)
+@end
+
+// This was not automatically whitelisted
+@interface WhitelistMe (IgnoredCategory)
+@end
+