summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md4
-rwxr-xr-xsrc/clang.rs124
-rw-r--r--src/ir/annotations.rs19
-rw-r--r--src/ir/comp.rs4
-rw-r--r--src/ir/function.rs3
-rw-r--r--src/ir/ty.rs6
-rw-r--r--tests/tests.rs33
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();