diff options
-rw-r--r-- | CONTRIBUTING.md | 4 | ||||
-rwxr-xr-x | src/clang.rs | 124 | ||||
-rw-r--r-- | src/ir/annotations.rs | 19 | ||||
-rw-r--r-- | src/ir/comp.rs | 4 | ||||
-rw-r--r-- | src/ir/function.rs | 3 | ||||
-rw-r--r-- | src/ir/ty.rs | 6 | ||||
-rw-r--r-- | tests/tests.rs | 33 |
7 files changed, 124 insertions, 69 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f1e39d8..001ad0e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,6 +39,10 @@ Additionally, you may want to build and test with the `_docs` feature to ensure that you aren't forgetting to document types and functions. CI will catch it if you forget, but the turn around will be a lot slower ;) +``` +$ cargo build --features "llvm_stable _docs" +``` + ## Testing <span id="tests"/> ### Overview <span id="tests-overview"/> diff --git a/src/clang.rs b/src/clang.rs index c0934055..32eab978 100755 --- a/src/clang.rs +++ b/src/clang.rs @@ -645,19 +645,22 @@ impl Type { } /// If this type is a class template specialization, return its number of - /// template arguments. Otherwise, return -1. - pub fn num_template_args(&self) -> c_int { - unsafe { - clang_Type_getNumTemplateArguments(self.x) + /// template arguments. Otherwise, return None. + pub fn num_template_args(&self) -> Option<u32> { + let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; + if n >= 0 { + Some(n as u32) + } else { + debug_assert_eq!(n, -1); + None } } /// Get the type of the `i`th template argument for this template /// specialization. - pub fn template_arg_type(&self, i: c_int) -> Type { - unsafe { - Type { x: clang_Type_getTemplateArgumentAsType(self.x, i) } - } + pub fn template_arg_type(&self, i: u32) -> Type { + let n = i as c_int; + Type { x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, n) } } } /// Given that this type is a pointer type, return the type that it points @@ -678,9 +681,12 @@ impl Type { /// Given that this type is an array or vector type, return its number of /// elements. - pub fn num_elements(&self) -> usize { - unsafe { - clang_getNumElements(self.x) as usize + pub fn num_elements(&self) -> Option<usize> { + let num_elements_returned = unsafe { clang_getNumElements(self.x) }; + if num_elements_returned != -1 { + Some(num_elements_returned as usize) + } else { + None } } @@ -714,9 +720,12 @@ impl Type { /// Given that this type is a function type, get the type of its return /// value. - pub fn ret_type(&self) -> Type { - unsafe { - Type { x: clang_getResultType(self.x) } + pub fn ret_type(&self) -> Option<Type> { + let rt = Type { x: unsafe { clang_getResultType(self.x) } }; + if rt.kind() == CXType_Invalid { + None + } else { + Some(rt) } } @@ -785,17 +794,12 @@ impl Comment { } } - /// Get the number of children this comment node has. - pub fn num_children(&self) -> c_uint { - unsafe { - clang_Comment_getNumChildren(self.x) - } - } - - /// Get this comment's `idx`th child comment - pub fn get_child(&self, idx: c_uint) -> Comment { - unsafe { - Comment { x: clang_Comment_getChild(self.x, idx) } + /// Get this comment's children comment + pub fn get_children(&self) -> CommentChildrenIterator { + CommentChildrenIterator { + parent: self.x, + length: unsafe { clang_Comment_getNumChildren(self.x) }, + index: 0 } } @@ -807,27 +811,63 @@ impl Comment { } } - /// Given that this comment is an HTML start tag, get the number of HTML - /// attributes it has. - pub fn get_num_tag_attrs(&self) -> c_uint { - unsafe { - clang_HTMLStartTag_getNumAttrs(self.x) + /// Given that this comment is an HTML start tag, get its attributes. + pub fn get_tag_attrs(&self) -> CommentAttributesIterator { + CommentAttributesIterator { + x: self.x, + length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, + index: 0 } } +} - /// Given that this comment is an HTML start tag, get the `idx`th - /// attribute's name. - pub fn get_tag_attr_name(&self, idx: c_uint) -> String { - unsafe { - String_ { x: clang_HTMLStartTag_getAttrName(self.x, idx) }.to_string() +/// An iterator for a comment's children +pub struct CommentChildrenIterator { + parent: CXComment, + length: c_uint, + index: c_uint +} + +impl Iterator for CommentChildrenIterator { + type Item = Comment; + fn next(&mut self) -> Option<Comment> { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some( Comment { x: unsafe { clang_Comment_getChild(self.parent, idx) } } ) + } else { + None } } +} - /// Given that this comment is an HTML start tag, get the `idx`th - /// attribute's value. - pub fn get_tag_attr_value(&self, idx: c_uint) -> String { - unsafe { - String_ { x: clang_HTMLStartTag_getAttrValue(self.x, idx) }.to_string() +/// An HTML start tag comment attribute +pub struct CommentAttribute { + /// HTML start tag attribute name + pub name: String, + /// HTML start tag attribute value + pub value: String +} + +/// An iterator for a comment's attributes +pub struct CommentAttributesIterator { + x: CXComment, + length: c_uint, + index: c_uint +} + +impl Iterator for CommentAttributesIterator { + type Item = CommentAttribute; + fn next(&mut self) -> Option<CommentAttribute> { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some( CommentAttribute { + name: String_ { x: unsafe { clang_HTMLStartTag_getAttrName(self.x, idx) } }.to_string(), + value: String_ { x: unsafe { clang_HTMLStartTag_getAttrValue(self.x, idx) } }.to_string() + }) + } else { + None } } } @@ -1042,9 +1082,11 @@ impl Diagnostic { clang_getDiagnosticSeverity(self.x) } } +} +impl Drop for Diagnostic { /// Destroy this diagnostic message. - pub fn dispose(&self) { + fn drop(&mut self) { unsafe { clang_disposeDiagnostic(self.x); } diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs index f0d9715e..0ceb676d 100644 --- a/src/ir/annotations.rs +++ b/src/ir/annotations.rs @@ -133,27 +133,24 @@ impl Annotations { use clangll::CXComment_HTMLStartTag; if comment.kind() == CXComment_HTMLStartTag && comment.get_tag_name() == "div" && - comment.get_num_tag_attrs() > 1 && - comment.get_tag_attr_name(0) == "rustbindgen" { + comment.get_tag_attrs().next().map_or(false, |attr| attr.name == "rustbindgen") { *matched = true; - for i in 0..comment.get_num_tag_attrs() { - let value = comment.get_tag_attr_value(i); - let name = comment.get_tag_attr_name(i); - match name.as_str() { + for attr in comment.get_tag_attrs() { + match attr.name.as_str() { "opaque" => self.opaque = true, "hide" => self.hide = true, "nocopy" => self.disallow_copy = true, - "replaces" => self.use_instead_of = Some(value), - "private" => self.private_fields = Some(value != "false"), + "replaces" => self.use_instead_of = Some(attr.value), + "private" => self.private_fields = Some(attr.value != "false"), "accessor" - => self.accessor_kind = Some(parse_accessor(&value)), + => self.accessor_kind = Some(parse_accessor(&attr.value)), _ => {}, } } } - for i in 0..comment.num_children() { - self.parse(&comment.get_child(i), matched); + for child in comment.get_children() { + self.parse(&child, matched); } } } diff --git a/src/ir/comp.rs b/src/ir/comp.rs index a8583607..b9e9ec8b 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -492,8 +492,8 @@ impl CompInfo { ci.template_args = match ty.num_template_args() { // In forward declarations and not specializations, etc, they are in // the ast, we'll meet them in CXCursor_TemplateTypeParameter - -1 => vec![], - len => { + None => vec![], + Some(len) => { let mut list = Vec::with_capacity(len as usize); for i in 0..len { let arg_type = ty.template_arg_type(i); diff --git a/src/ir/function.rs b/src/ir/function.rs index 2693eddf..0cf23f43 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -186,7 +186,8 @@ impl FunctionSig { } } - let ret = try!(Item::from_ty(&ty.ret_type(), None, None, ctx)); + let ty_ret_type = try!(ty.ret_type().ok_or(ParseError::Continue)); + let ret = try!(Item::from_ty(&ty_ret_type, None, None, ctx)); let abi = get_abi(ty.call_conv()); Ok(Self::new(ret, args, ty.is_variadic(), abi)) diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 2cb4762c..9881c653 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -500,13 +500,13 @@ impl Type { // tests/headers/func_ptr_in_struct.h), so we do a // guess here trying to see if it has a valid return // type. - if ty.ret_type().kind() != CXType_Invalid { + if ty.ret_type().is_some() { let signature = try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx)); TypeKind::Function(signature) // Same here, with template specialisations we can safely assume // this is a Comp(..) - } else if ty.num_template_args() > 0 { + } else if ty.num_template_args().unwrap_or(0) > 0 { debug!("Template specialization: {:?}", ty); let complex = CompInfo::from_ty(potential_id, ty, location, ctx) @@ -696,7 +696,7 @@ impl Type { CXType_ConstantArray => { let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx) .expect("Not able to resolve array element?"); - TypeKind::Array(inner, ty.num_elements()) + TypeKind::Array(inner, ty.num_elements().unwrap()) } // A complex number is always a real and an imaginary part, so // represent that as a two-item array. diff --git a/tests/tests.rs b/tests/tests.rs index 1f8864e0..4cecc2c2 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -10,6 +10,8 @@ use std::io::Read; use std::path::{Path, PathBuf}; use std::process; +const TEST_BATCH_DEFAULT_SIZE: usize = 16; + fn spawn_run_bindgen<P, Q, R>(run_bindgen: P, bindgen: Q, header: R) -> process::Child where P: AsRef<Path>, Q: AsRef<Path>, @@ -83,25 +85,34 @@ fn run_bindgen_tests() { Some(Some("hpp")) => true, _ => false, } + }).collect::<Vec<_>>(); + + let batch_size = env::var("BINDGEN_TEST_BATCH_SIZE") + .ok() + .and_then(|x| x.parse::<usize>().ok()) + .unwrap_or(TEST_BATCH_DEFAULT_SIZE); + + // Spawn `batch_size` children to run in parallel and wait on all of them + // before processing the next batch. This puts a limit on the resources + // consumed when testing, so that we don't overload the system. + + let children = tests.chunks(batch_size).map(|x| { + x.iter().map(|entry| { + let child = spawn_run_bindgen(run_bindgen.clone(), bindgen.clone(), entry.path()); + (entry.path(), child) + }).collect::<Vec<_>>() }); - // Spawn one child at a time and wait on it as number of process - // is the number of test files. - - let children = tests.map(|entry| { - let child = spawn_run_bindgen(run_bindgen.clone(), bindgen.clone(), entry.path()); - (entry.path(), child) - }); - - let failures: Vec<_> = children - .filter_map(|(path, mut child)| { + let failures: Vec<_> = children.flat_map(|x| { + x.into_iter().filter_map(|(path, mut child)| { let passed = child.wait() .expect("Should wait on child process") .success(); if passed { None } else { Some((path, child)) } }) - .collect(); + }) + .collect(); let num_failures = failures.len(); |