Skip to content

Commit

Permalink
Auto merge of #475 - scoopr:objc, r=emilio
Browse files Browse the repository at this point in the history
objc: Support method arguments

Welp, I attempted to get the method arguments working.

I must confess, that I have not ran this against actual objective c code yet though.
  • Loading branch information
bors-servo authored Feb 6, 2017
2 parents 2fdb02f + bc87b2a commit 7fa654c
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 85 deletions.
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

0 comments on commit 7fa654c

Please sign in to comment.