diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | ci/before_install.sh | 15 | ||||
-rw-r--r-- | src/clang.rs | 19 | ||||
-rw-r--r-- | src/codegen/mod.rs | 144 | ||||
-rw-r--r-- | src/ir/function.rs | 2 | ||||
-rw-r--r-- | src/ir/mod.rs | 1 | ||||
-rw-r--r-- | src/ir/objc.rs | 99 | ||||
-rw-r--r-- | src/ir/ty.rs | 43 | ||||
-rw-r--r-- | src/lib.rs | 12 | ||||
-rw-r--r-- | src/options.rs | 3 | ||||
-rw-r--r-- | tests/expectations/Cargo.toml | 1 | ||||
-rw-r--r-- | tests/expectations/tests/constant-non-specialized-tp.rs | 24 | ||||
-rw-r--r-- | tests/expectations/tests/objc_interface.rs | 15 | ||||
-rw-r--r-- | tests/expectations/tests/objc_interface_type.rs | 33 | ||||
-rw-r--r-- | tests/expectations/tests/objc_method.rs | 17 | ||||
-rw-r--r-- | tests/headers/constant-non-specialized-tp.hpp | 15 | ||||
-rw-r--r-- | tests/headers/objc_interface.h | 8 | ||||
-rw-r--r-- | tests/headers/objc_interface_type.h | 13 | ||||
-rw-r--r-- | tests/headers/objc_method.h | 7 | ||||
-rw-r--r-- | tests/tests.rs | 8 |
20 files changed, 461 insertions, 19 deletions
diff --git a/.travis.yml b/.travis.yml index dd271f22..47af4eeb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ addons: os: - linux + - osx rust: - stable diff --git a/ci/before_install.sh b/ci/before_install.sh index 06c75218..ebe4f4fb 100644 --- a/ci/before_install.sh +++ b/ci/before_install.sh @@ -1,6 +1,11 @@ set -e pushd ~ +# Workaround for Travis CI macOS bug (https://github.com/travis-ci/travis-ci/issues/6307) +if [ "${TRAVIS_OS_NAME}" == "osx" ]; then + rvm get head || true +fi + function llvm_version_triple() { if [ "$1" == "3.8" ]; then echo "3.8.0" @@ -18,9 +23,17 @@ function llvm_download() { tar -xf ${LLVM}.tar.xz -C llvm --strip-components=1 export LLVM_CONFIG_PATH=`pwd`/llvm/bin/llvm-config + if [ "${TRAVIS_OS_NAME}" == "osx" ]; then + cp llvm/lib/libclang.dylib /usr/local/lib/libclang.dylib + fi } -llvm_download linux-gnu-ubuntu-14.04 + +if [ "${TRAVIS_OS_NAME}" == "linux" ]; then + llvm_download linux-gnu-ubuntu-14.04 +else + llvm_download apple-darwin +fi popd set +e diff --git a/src/clang.rs b/src/clang.rs index 9cf51436..a40abfca 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -201,14 +201,14 @@ impl Cursor { } /// Is the referent a template specialization? - pub fn is_template(&self) -> bool { + pub fn is_template_specialization(&self) -> bool { self.specialized().is_some() } /// Is the referent a fully specialized template specialization without any /// remaining free template arguments? pub fn is_fully_specialized_template(&self) -> bool { - self.is_template() && self.num_template_args().unwrap_or(0) > 0 + self.is_template_specialization() && self.num_template_args().unwrap_or(0) > 0 } /// Is the referent a template specialization that still has remaining free @@ -217,9 +217,17 @@ impl Cursor { if self.is_toplevel() { return false; } + let parent = self.semantic_parent(); - (parent.is_template() && !parent.is_fully_specialized_template()) || - parent.is_in_non_fully_specialized_template() + if parent.is_fully_specialized_template() { + return false; + } + + if !parent.is_template_like() { + return parent.is_in_non_fully_specialized_template(); + } + + return true; } /// Is this cursor pointing a valid referent? @@ -688,7 +696,8 @@ impl Type { CXType_Pointer | CXType_RValueReference | CXType_LValueReference | - CXType_MemberPointer => { + CXType_MemberPointer | + CXType_ObjCObjectPointer => { let ret = Type { x: unsafe { clang_getPointeeType(self.x) }, }; diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 436c2bd7..9dd3b6b9 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -13,6 +13,7 @@ use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath}; use ir::item_kind::ItemKind; use ir::layout::Layout; use ir::module::Module; +use ir::objc::ObjCInterface; use ir::ty::{Type, TypeKind}; use ir::type_collector::ItemSet; use ir::var::Var; @@ -87,6 +88,9 @@ struct CodegenResult<'a> { /// Whether an incomplete array has been generated at least once. saw_incomplete_array: bool, + /// Whether Objective C types have been seen at least once. + saw_objc: bool, + items_seen: HashSet<ItemId>, /// The set of generated function/var names, needed because in C/C++ is /// legal to do something like: @@ -119,6 +123,7 @@ impl<'a> CodegenResult<'a> { items: vec![], saw_union: false, saw_incomplete_array: false, + saw_objc: false, codegen_id: codegen_id, items_seen: Default::default(), functions_seen: Default::default(), @@ -140,6 +145,10 @@ impl<'a> CodegenResult<'a> { self.saw_incomplete_array = true; } + fn saw_objc(&mut self) { + self.saw_objc = true; + } + fn seen(&self, item: ItemId) -> bool { self.items_seen.contains(&item) } @@ -184,6 +193,7 @@ impl<'a> CodegenResult<'a> { self.saw_union |= new.saw_union; self.saw_incomplete_array |= new.saw_incomplete_array; + self.saw_objc |= new.saw_objc; new.items } @@ -359,6 +369,9 @@ impl CodeGenerator for Module { if ctx.need_bindegen_complex_type() { utils::prepend_complex_type(ctx, &mut *result); } + if result.saw_objc { + utils::prepend_objc_header(ctx, &mut *result); + } } }; @@ -623,6 +636,9 @@ impl CodeGenerator for Type { TypeKind::Enum(ref ei) => { ei.codegen(ctx, result, whitelisted_items, item) } + TypeKind::ObjCInterface(ref interface) => { + interface.codegen(ctx, result, whitelisted_items, item) + } ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } @@ -2111,6 +2127,9 @@ impl ToRustTy for Type { let ident = ctx.rust_ident(&name); quote_ty!(ctx.ext_cx(), $ident) } + TypeKind::ObjCInterface(..) => { + quote_ty!(ctx.ext_cx(), id) + }, ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } @@ -2144,10 +2163,22 @@ impl ToRustTy for FunctionSig { // the array type derivation. // // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html - let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() { - t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span()) - } else { - arg_item.to_rust_ty(ctx) + let arg_ty = match *arg_ty.canonical_type(ctx).kind() { + TypeKind::Array(t, _) => { + t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span()) + }, + TypeKind::Pointer(inner) => { + let inner = ctx.resolve_item(inner); + let inner_ty = inner.expect_type(); + if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { + quote_ty!(ctx.ext_cx(), id) + } else { + arg_item.to_rust_ty(ctx) + } + }, + _ => { + arg_item.to_rust_ty(ctx) + } }; let arg_name = match *name { @@ -2263,6 +2294,85 @@ impl CodeGenerator for Function { } } +impl CodeGenerator for ObjCInterface { + type Extra = Item; + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + _: &Item) { + let mut impl_items = vec![]; + let mut trait_items = vec![]; + + for method in self.methods() { + let method_name = ctx.rust_ident(method.name()); + + let body = quote_stmt!(ctx.ext_cx(), msg_send![self, $method_name]) + .unwrap(); + let block = ast::Block { + stmts: vec![body], + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span: ctx.span(), + }; + + let sig = aster::AstBuilder::new() + .method_sig() + .unsafe_() + .fn_decl() + .self_() + .build(ast::SelfKind::Value(ast::Mutability::Immutable)) + .build(ast::FunctionRetTy::Default(ctx.span())); + let attrs = vec![]; + + let impl_item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(method.rust_name()), + vis: ast::Visibility::Inherited, // Public, + attrs: attrs.clone(), + node: ast::ImplItemKind::Method(sig.clone(), P(block)), + defaultness: ast::Defaultness::Final, + span: ctx.span(), + }; + + let trait_item = ast::TraitItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(method.rust_name()), + attrs: attrs, + node: ast::TraitItemKind::Method(sig, None), + span: ctx.span(), + }; + + impl_items.push(impl_item); + trait_items.push(trait_item) + } + + + let trait_block = aster::AstBuilder::new() + .item() + .pub_() + .trait_(self.name()) + .with_items(trait_items) + .build(); + + let ty_for_impl = quote_ty!(ctx.ext_cx(), id); + let impl_block = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id(self.name()) + .build() + .with_items(impl_items) + .build_ty(ty_for_impl); + + result.push(trait_block); + result.push(impl_block); + result.saw_objc(); + } +} + + + pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { context.gen(|context| { let counter = Cell::new(0); @@ -2296,6 +2406,32 @@ mod utils { use syntax::ast; use syntax::ptr::P; + + pub fn prepend_objc_header(ctx: &BindgenContext, + result: &mut Vec<P<ast::Item>>) { + let use_objc = if ctx.options().objc_extern_crate { + quote_item!(ctx.ext_cx(), + use objc; + ).unwrap() + } else { + quote_item!(ctx.ext_cx(), + #[macro_use] + extern crate objc; + ).unwrap() + }; + + + let id_type = quote_item!(ctx.ext_cx(), + #[allow(non_camel_case_types)] + pub type id = *mut objc::runtime::Object; + ) + .unwrap(); + + let items = vec![use_objc, id_type]; + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + pub fn prepend_union_types(ctx: &BindgenContext, result: &mut Vec<P<ast::Item>>) { let prefix = ctx.trait_prefix(); diff --git a/src/ir/function.rs b/src/ir/function.rs index 6e205f1b..a50edfde 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -93,7 +93,7 @@ fn get_abi(cc: CXCallingConv) -> abi::Abi { pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> { // We early return here because libclang may crash in some case // if we pass in a variable inside a partial specialized template. - // See servo/rust-bindgen#67. + // See servo/rust-bindgen#67, and servo/rust-bindgen#462. if cursor.is_in_non_fully_specialized_template() { return None; } diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 73793b16..d424fcdf 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -17,3 +17,4 @@ pub mod module; pub mod ty; pub mod type_collector; pub mod var; +pub mod objc; diff --git a/src/ir/objc.rs b/src/ir/objc.rs new file mode 100644 index 00000000..b9fe280b --- /dev/null +++ b/src/ir/objc.rs @@ -0,0 +1,99 @@ +//! Objective C types + +use clang; +use clang_sys::CXChildVisit_Continue; +use clang_sys::CXCursor_ObjCInstanceMethodDecl; +// use clang_sys::CXCursor_ObjCSuperClassRef; +use super::context::BindgenContext; + +/// Objective C interface as used in TypeKind +/// +/// Also protocols are parsed as this type +#[derive(Debug)] +pub struct ObjCInterface { + /// The name + /// like, NSObject + name: String, + + /// List of the methods defined in this interfae + methods: Vec<ObjCInstanceMethod>, +} + +/// The objective c methods +#[derive(Debug)] +pub struct ObjCInstanceMethod { + /// The original method selector name + /// like, dataWithBytes:length: + name: String, + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + rust_name: String, +} + +impl ObjCInterface { + fn new(name: &str) -> ObjCInterface { + ObjCInterface { + name: name.to_owned(), + methods: Vec::new(), + } + } + + /// The name + /// like, NSObject + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// List of the methods defined in this interfae + pub fn methods(&self) -> &Vec<ObjCInstanceMethod> { + &self.methods + } + + /// Parses the Objective C interface from the cursor + pub fn from_ty(cursor: &clang::Cursor, + _ctx: &mut BindgenContext) + -> Option<Self> { + let name = cursor.spelling(); + let mut interface = Self::new(&name); + + cursor.visit(|cursor| { + match cursor.kind() { + CXCursor_ObjCInstanceMethodDecl => { + let name = cursor.spelling(); + let method = ObjCInstanceMethod::new(&name); + + interface.methods.push(method); + } + _ => {} + } + CXChildVisit_Continue + }); + Some(interface) + } +} + +impl ObjCInstanceMethod { + fn new(name: &str) -> ObjCInstanceMethod { + let split_name: Vec<&str> = name.split(':').collect(); + + let rust_name = split_name.join("_"); + + ObjCInstanceMethod { + name: name.to_owned(), + rust_name: rust_name.to_owned(), + } + } + + /// The original method selector name + /// like, dataWithBytes:length: + pub fn name(&self) -> &str { + self.name.as_ref() + } + + /// Method name as converted to rust + /// like, dataWithBytes_length_ + pub fn rust_name(&self) -> &str { + self.rust_name.as_ref() + } +} diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 5474aa57..1246057b 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -10,6 +10,7 @@ use super::function::FunctionSig; use super::int::IntKind; use super::item::Item; use super::layout::Layout; +use super::objc::ObjCInterface; use super::type_collector::{ItemSet, TypeCollector}; /// The base representation of a type in bindgen. @@ -179,8 +180,12 @@ impl Type { /// Is this a incomplete array type? pub fn is_incomplete_array(&self, ctx: &BindgenContext) -> Option<ItemId> { match self.kind { - TypeKind::Array(item, len) => if len == 0 { Some(item) } else { None }, - TypeKind::ResolvedTypeRef(inner) => ctx.resolve_type(inner).is_incomplete_array(ctx), + TypeKind::Array(item, len) => { + if len == 0 { Some(item) } else { None } + } + TypeKind::ResolvedTypeRef(inner) => { + ctx.resolve_type(inner).is_incomplete_array(ctx) + } _ => None, } } @@ -287,7 +292,7 @@ impl Type { let mut remaining = chars; let valid = (first.is_alphabetic() || first == '_') && - remaining.all(|c| c.is_alphanumeric() || c == '_'); + remaining.all(|c| c.is_alphanumeric() || c == '_'); !valid } @@ -324,7 +329,8 @@ impl Type { TypeKind::Void | TypeKind::NullPtr | TypeKind::BlockPointer | - TypeKind::Pointer(..) => Some(self), + TypeKind::Pointer(..) | + TypeKind::ObjCInterface(..) => Some(self), TypeKind::ResolvedTypeRef(inner) | TypeKind::Alias(inner) | @@ -492,6 +498,9 @@ pub enum TypeKind { /// A named type, that is, a template parameter. Named, + + /// Objective C interface. Always referenced through a pointer + ObjCInterface(ObjCInterface), } impl Type { @@ -525,6 +534,8 @@ impl Type { TypeKind::BlockPointer | TypeKind::Pointer(..) => false, + TypeKind::ObjCInterface(..) => true, // dunno? + TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing!"); } @@ -566,7 +577,16 @@ impl Type { debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types); let canonical_ty = ty.canonical_type(); - let kind = match ty.kind() { + + // Parse objc protocols as if they were interfaces + let mut ty_kind = ty.kind(); + if let Some(loc) = location { + if loc.kind() == CXCursor_ObjCProtocolDecl { + ty_kind = CXType_ObjCInterface; + } + } + + let kind = match ty_kind { CXType_Unexposed if *ty != canonical_ty && canonical_ty.kind() != CXType_Invalid && // Sometime clang desugars some types more than @@ -720,8 +740,7 @@ impl Type { } }; - TypeKind::TemplateAlias(inner_type, - args) + TypeKind::TemplateAlias(inner_type, args) } CXCursor_TemplateRef => { let referenced = location.referenced().unwrap(); @@ -819,6 +838,7 @@ impl Type { // // We might need to, though, if the context is already in the // process of resolving them. + CXType_ObjCObjectPointer | CXType_MemberPointer | CXType_Pointer => { let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(), @@ -900,6 +920,11 @@ impl Type { parent_id, ctx); } + CXType_ObjCInterface => { + let interface = ObjCInterface::from_ty(&location.unwrap(), ctx) + .expect("Not a valid objc interface?"); + TypeKind::ObjCInterface(interface) + } _ => { error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}", ty.kind(), @@ -954,6 +979,10 @@ impl TypeCollector for Type { types.insert(id); } + TypeKind::ObjCInterface(_) => { + // TODO: + } + // None of these variants have edges to other items and types. TypeKind::UnresolvedTypeRef(_, _, None) | TypeKind::Named | @@ -198,6 +198,13 @@ impl Builder { self } + /// Generate '#[macro_use] extern crate objc;' instead of 'use objc;' + /// in the prologue of the files generated from objective-c files + pub fn objc_extern_crate(mut self, doit: bool) -> Self { + self.options.objc_extern_crate = doit; + self + } + /// Generate a C/C++ file that includes the header and has dummy uses of /// every type defined in the header. pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder { @@ -542,6 +549,10 @@ pub struct BindgenOptions { /// Wether to whitelist types recursively. Defaults to true. pub whitelist_recursively: bool, + + /// Intead of emitting 'use objc;' to files generated from objective c files, + /// generate '#[macro_use] extern crate objc;' + pub objc_extern_crate: bool, } impl BindgenOptions { @@ -588,6 +599,7 @@ impl Default for BindgenOptions { conservative_inline_namespaces: false, generate_comments: true, whitelist_recursively: true, + objc_extern_crate: false, } } } diff --git a/src/options.rs b/src/options.rs index 307ea6b0..535eac4b 100644 --- a/src/options.rs +++ b/src/options.rs @@ -49,6 +49,9 @@ pub fn builder_from_flags<I>(args: I) Arg::with_name("no-recursive-whitelist") .long("no-recursive-whitelist") .help("Avoid whitelisting types recursively"), + Arg::with_name("objc-extern-crate") + .long("objc-extern-crate") + .help("Use extern crate instead of use for objc"), Arg::with_name("builtins") .long("builtins") .help("Output bindings for builtin definitions, e.g. \ diff --git a/tests/expectations/Cargo.toml b/tests/expectations/Cargo.toml index 034aa141..e0da6d5a 100644 --- a/tests/expectations/Cargo.toml +++ b/tests/expectations/Cargo.toml @@ -9,3 +9,4 @@ authors = [ ] [dependencies] +objc = "0.2" diff --git a/tests/expectations/tests/constant-non-specialized-tp.rs b/tests/expectations/tests/constant-non-specialized-tp.rs new file mode 100644 index 00000000..bbadf8a2 --- /dev/null +++ b/tests/expectations/tests/constant-non-specialized-tp.rs @@ -0,0 +1,24 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Test<Args> { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData<Args>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Outer<T> { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData<T>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Outer_Inner<T> { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData<T>, +} diff --git a/tests/expectations/tests/objc_interface.rs b/tests/expectations/tests/objc_interface.rs new file mode 100644 index 00000000..027cf57e --- /dev/null +++ b/tests/expectations/tests/objc_interface.rs @@ -0,0 +1,15 @@ +/* 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 { } +impl Foo for id { } +pub trait bar { } +impl bar for id { } diff --git a/tests/expectations/tests/objc_interface_type.rs b/tests/expectations/tests/objc_interface_type.rs new file mode 100644 index 00000000..2d68ee50 --- /dev/null +++ b/tests/expectations/tests/objc_interface_type.rs @@ -0,0 +1,33 @@ +/* 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 { } +impl Foo for id { } +#[repr(C)] +#[derive(Debug, Copy)] +pub struct FooStruct { + pub foo: *mut id, +} +#[test] +fn bindgen_test_layout_FooStruct() { + assert_eq!(::std::mem::size_of::<FooStruct>() , 8usize); + assert_eq!(::std::mem::align_of::<FooStruct>() , 8usize); +} +impl Clone for FooStruct { + fn clone(&self) -> Self { *self } +} +extern "C" { + pub fn fooFunc(foo: id); +} +extern "C" { + #[link_name = "kFoo"] + pub static mut kFoo: *const id; +} diff --git a/tests/expectations/tests/objc_method.rs b/tests/expectations/tests/objc_method.rs new file mode 100644 index 00000000..e2db24f6 --- /dev/null +++ b/tests/expectations/tests/objc_method.rs @@ -0,0 +1,17 @@ +/* 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 method(self); +} +impl Foo for id { + unsafe fn method(self) { msg_send!(self , method) } +} diff --git a/tests/headers/constant-non-specialized-tp.hpp b/tests/headers/constant-non-specialized-tp.hpp new file mode 100644 index 00000000..539c2887 --- /dev/null +++ b/tests/headers/constant-non-specialized-tp.hpp @@ -0,0 +1,15 @@ +// bindgen-flags: -- -std=c++11 + +// This test ensure we protect ourselves from an LLVM crash. + +template <class... Args> +struct Test { + static constexpr bool x[] = {Args::x...}; +}; + +template<typename... T> +struct Outer { + struct Inner { + static constexpr int value[] = { T::value... }; + }; +}; diff --git a/tests/headers/objc_interface.h b/tests/headers/objc_interface.h new file mode 100644 index 00000000..af84bf92 --- /dev/null +++ b/tests/headers/objc_interface.h @@ -0,0 +1,8 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +@interface Foo +@end + +@protocol bar +@end diff --git a/tests/headers/objc_interface_type.h b/tests/headers/objc_interface_type.h new file mode 100644 index 00000000..31d33664 --- /dev/null +++ b/tests/headers/objc_interface_type.h @@ -0,0 +1,13 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +@interface Foo +@end + +struct FooStruct { + Foo *foo; +}; + +void fooFunc(Foo *foo); + +static const Foo *kFoo; diff --git a/tests/headers/objc_method.h b/tests/headers/objc_method.h new file mode 100644 index 00000000..91645f16 --- /dev/null +++ b/tests/headers/objc_method.h @@ -0,0 +1,7 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +@interface Foo +- (void)method; +// TODO: argument methods +@end diff --git a/tests/tests.rs b/tests/tests.rs index 05c8ad2c..2886f8db 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -76,7 +76,7 @@ fn create_bindgen_builder(header: &PathBuf) // Scoop up bindgen-flags from test header let mut flags = Vec::with_capacity(2); - for line in reader.lines().take(2) { + for line in reader.lines().take(3) { let line = try!(line); if line.contains("bindgen-flags: ") { let extra_flags = line.split("bindgen-flags: ") @@ -87,6 +87,12 @@ fn create_bindgen_builder(header: &PathBuf) } else if line.contains("bindgen-unstable") && cfg!(feature = "llvm_stable") { return Ok(None); + } else if line.contains("bindgen-osx-only") { + let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"]; + flags = prepend_flags.into_iter() + .map(ToString::to_string) + .chain(flags) + .collect(); } } |