Skip to content

objc: Support method arguments #475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,14 @@ impl Cursor {
pub fn evaluate(&self) -> Option<EvalResult> {
EvalResult::new(*self)
}

/// Return the result type for this cursor
pub fn ret_type(&self) -> Option<Type> {
let rt = Type {
x: unsafe { clang_getCursorResultType(self.x) },
};
if rt.is_valid() { Some(rt) } else { None }
}
}

extern "C" fn visit_children<Visitor>(cur: CXCursor,
Expand Down Expand Up @@ -1363,6 +1371,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
prefix,
type_to_str(ty.kind())));
}
if let Some(ty) = c.ret_type() {
print_indent(depth, format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())));
}

if let Some(refd) = c.referenced() {
if refd != *c {
Expand Down
165 changes: 99 additions & 66 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2153,61 +2153,8 @@ impl ToRustTy for FunctionSig {

fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P<ast::Ty> {
// TODO: we might want to consider ignoring the reference return value.
let return_item = ctx.resolve_item(self.return_type());
let ret =
if let TypeKind::Void = *return_item.kind().expect_type().kind() {
ast::FunctionRetTy::Default(ctx.span())
} else {
ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx))
};

let mut unnamed_arguments = 0;
let arguments = self.argument_types().iter().map(|&(ref name, ty)| {
let arg_item = ctx.resolve_item(ty);
let arg_ty = arg_item.kind().expect_type();

// From the C90 standard[1]:
//
// A declaration of a parameter as "array of type" shall be
// adjusted to "qualified pointer to type", where the type
// qualifiers (if any) are those specified within the [ and ] of
// the array type derivation.
//
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
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 {
Some(ref name) => ctx.rust_mangle(name).into_owned(),
None => {
unnamed_arguments += 1;
format!("arg{}", unnamed_arguments)
}
};

assert!(!arg_name.is_empty());

ast::Arg {
ty: arg_ty,
pat: aster::AstBuilder::new().pat().id(arg_name),
id: ast::DUMMY_NODE_ID,
}
}).collect::<Vec<_>>();
let ret = utils::fnsig_return_ty(ctx, &self);
let arguments = utils::fnsig_arguments(ctx, &self);

let decl = P(ast::FnDecl {
inputs: arguments,
Expand All @@ -2217,7 +2164,7 @@ impl ToRustTy for FunctionSig {

let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
unsafety: ast::Unsafety::Unsafe,
abi: self.abi(),
abi: self.abi().expect("Invalid abi for function!"),
lifetimes: vec![],
decl: decl,
}));
Expand Down Expand Up @@ -2297,7 +2244,8 @@ impl CodeGenerator for Function {
vis: ast::Visibility::Public,
};

let item = ForeignModBuilder::new(signature.abi())
let item = ForeignModBuilder::new(signature.abi()
.expect("Invalid abi for function!"))
.with_foreign_item(foreign_item)
.build(ctx);

Expand All @@ -2316,9 +2264,36 @@ impl CodeGenerator for ObjCInterface {
let mut trait_items = vec![];

for method in self.methods() {
let method_name = ctx.rust_ident(method.name());
let signature = method.signature();
let fn_args = utils::fnsig_arguments(ctx, signature);
let fn_ret = utils::fnsig_return_ty(ctx, signature);
let sig = aster::AstBuilder::new()
.method_sig()
.unsafe_()
.fn_decl()
.self_()
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
.with_args(fn_args.clone())
.build(fn_ret);

// Collect the actual used argument names
let arg_names: Vec<_> = fn_args.iter()
.map(|ref arg| {
match arg.pat.node {
ast::PatKind::Ident(_, ref spanning, _) => {
spanning.node.name.as_str().to_string()
}
_ => {
panic!("odd argument!");
}
}
})
.collect();

let body = quote_stmt!(ctx.ext_cx(), msg_send![self, $method_name])
let methods_and_args =
ctx.rust_ident(&method.format_method_call(&arg_names));
let body =
quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args])
.unwrap();
let block = ast::Block {
stmts: vec![body],
Expand All @@ -2327,13 +2302,6 @@ impl CodeGenerator for ObjCInterface {
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 {
Expand Down Expand Up @@ -2697,4 +2665,69 @@ mod utils {
_ => panic!("How did this happen exactly?"),
}
}

pub fn fnsig_return_ty(ctx: &BindgenContext,
sig: &super::FunctionSig)
-> ast::FunctionRetTy {
let return_item = ctx.resolve_item(sig.return_type());
if let TypeKind::Void = *return_item.kind().expect_type().kind() {
ast::FunctionRetTy::Default(ctx.span())
} else {
ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx))
}
}

pub fn fnsig_arguments(ctx: &BindgenContext,
sig: &super::FunctionSig)
-> Vec<ast::Arg> {
use super::ToPtr;
let mut unnamed_arguments = 0;
sig.argument_types().iter().map(|&(ref name, ty)| {
let arg_item = ctx.resolve_item(ty);
let arg_ty = arg_item.kind().expect_type();

// From the C90 standard[1]:
//
// A declaration of a parameter as "array of type" shall be
// adjusted to "qualified pointer to type", where the type
// qualifiers (if any) are those specified within the [ and ] of
// the array type derivation.
//
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
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 {
Some(ref name) => ctx.rust_mangle(name).into_owned(),
None => {
unnamed_arguments += 1;
format!("arg{}", unnamed_arguments)
}
};

assert!(!arg_name.is_empty());

ast::Arg {
ty: arg_ty,
pat: aster::AstBuilder::new().pat().id(arg_name),
id: ast::DUMMY_NODE_ID,
}
}).collect::<Vec<_>>()
}

}
35 changes: 23 additions & 12 deletions src/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,19 @@ pub struct FunctionSig {
is_variadic: bool,

/// The ABI of this function.
abi: abi::Abi,
abi: Option<abi::Abi>,
}

fn get_abi(cc: CXCallingConv) -> abi::Abi {
fn get_abi(cc: CXCallingConv) -> Option<abi::Abi> {
use clang_sys::*;
match cc {
CXCallingConv_Default => abi::Abi::C,
CXCallingConv_C => abi::Abi::C,
CXCallingConv_X86StdCall => abi::Abi::Stdcall,
CXCallingConv_X86FastCall => abi::Abi::Fastcall,
CXCallingConv_AAPCS => abi::Abi::Aapcs,
CXCallingConv_X86_64Win64 => abi::Abi::Win64,
CXCallingConv_Default => Some(abi::Abi::C),
CXCallingConv_C => Some(abi::Abi::C),
CXCallingConv_X86StdCall => Some(abi::Abi::Stdcall),
CXCallingConv_X86FastCall => Some(abi::Abi::Fastcall),
CXCallingConv_AAPCS => Some(abi::Abi::Aapcs),
CXCallingConv_X86_64Win64 => Some(abi::Abi::Win64),
CXCallingConv_Invalid => None,
other => panic!("unsupported calling convention: {:?}", other),
}
}
Expand Down Expand Up @@ -116,7 +117,7 @@ impl FunctionSig {
pub fn new(return_type: ItemId,
arguments: Vec<(Option<String>, ItemId)>,
is_variadic: bool,
abi: abi::Abi)
abi: Option<abi::Abi>)
-> Self {
FunctionSig {
return_type: return_type,
Expand Down Expand Up @@ -154,7 +155,8 @@ impl FunctionSig {
let mut args: Vec<_> = match cursor.kind() {
CXCursor_FunctionDecl |
CXCursor_Constructor |
CXCursor_CXXMethod => {
CXCursor_CXXMethod |
CXCursor_ObjCInstanceMethodDecl => {
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
// to get parameter names and types.
cursor.args()
Expand Down Expand Up @@ -218,10 +220,19 @@ impl FunctionSig {
}
}

let ty_ret_type = try!(ty.ret_type().ok_or(ParseError::Continue));
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl {
try!(cursor.ret_type().ok_or(ParseError::Continue))
} else {
try!(ty.ret_type().ok_or(ParseError::Continue))
};
let ret = Item::from_ty_or_ref(ty_ret_type, None, None, ctx);
let abi = get_abi(ty.call_conv());

if abi.is_none() {
assert_eq!(cursor.kind(), CXCursor_ObjCInstanceMethodDecl,
"Invalid ABI for function signature")
}

Ok(Self::new(ret, args, ty.is_variadic(), abi))
}

Expand All @@ -236,7 +247,7 @@ impl FunctionSig {
}

/// Get this function signature's ABI.
pub fn abi(&self) -> abi::Abi {
pub fn abi(&self) -> Option<abi::Abi> {
self.abi
}

Expand Down
Loading