summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parser.rs66
-rw-r--r--tests/expectations/nsStyleAutoArray.rs23
-rw-r--r--tests/expectations/template.rs26
-rw-r--r--tests/headers/nsStyleAutoArray.hpp57
-rw-r--r--tests/headers/template.hpp33
5 files changed, 195 insertions, 10 deletions
diff --git a/src/parser.rs b/src/parser.rs
index 78f60709..26a03ed2 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -213,7 +213,7 @@ fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) {
ctx.current_module_mut().globals.push(name);
}
-fn fwd_decl<F:FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) {
+fn fwd_decl<F: FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) {
let def = cursor.definition();
if cursor == &def {
f(ctx);
@@ -568,10 +568,11 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// NB: Overwritten in the case of non-integer bitfield
let mut ty = conv_ty_resolving_typedefs(ctx,
- &cursor.cur_type(),
+ &cursor_ty,
cursor,
is_class_typedef);
+
use std::cell::BorrowState;
if let Some(child_ci) = ty.get_outermost_composite() {
if let BorrowState::Unused = child_ci.borrow_state() {
@@ -579,10 +580,12 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
let child_cursor = child_ci.parser_cursor.unwrap();
// TODO: This is lame, ideally we should use cursors.
- // The problem this is trying to solve is
- // tests/headers/inner_template_self.hpp.
+ // The problem this loop is trying to solve is
+ // tests/headers/inner_template_self.hpp, and templates with
+ // incomplete types.
//
- // The problem with this is that clang treats the *prev*
+ // The problem with this is that, in the first case (see the
+ // CXCursor_ClassDecl branch below) clang treats the *prev*
// field as a Class Declaration instead of a Class Template,
// so we have to check now for the name and the module id.
//
@@ -594,11 +597,44 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// Also, there could be more complex cases, like a templated
// type in an inner type declaration, that this is
// completely unable to catch.
- if child_cursor.kind() == CXCursor_ClassDecl &&
- child_ci.args.is_empty() &&
- child_ci.name == ci.name &&
- child_ci.module_id == ci.module_id {
- child_ci.args = ci.args.clone();
+ //
+ // In the second case (the CXCursor_ClassTemplate branch),
+ // we're not able to retrieve the template parameters of an
+ // incomplete type via the declaration or anything like
+ // that. We can inspect the AST and deduct them though,
+ // since there's a leading CXCursor_TemplateRef.
+ if child_ci.args.is_empty() {
+ // println!("child: {:?} {:?}, {:?}, {:?}", cursor.spelling(),
+ // type_to_str(cursor_ty.kind()),
+ // type_to_str(child_cursor.cur_type().kind()),
+ // kind_to_str(child_cursor.kind()));
+ match child_cursor.kind() {
+ CXCursor_ClassDecl => {
+ child_ci.args = ci.args.clone();
+ }
+ CXCursor_ClassTemplate => {
+ let mut found_invalid_template_ref = false;
+ cursor.visit(|c, _| {
+ // println!("ichild: {:?} {:?}, {:?}", c.spelling(),
+ // kind_to_str(c.kind()),
+ // type_to_str(c.cur_type().kind()));
+ if c.kind() == CXCursor_TemplateRef &&
+ c.cur_type().kind() == CXType_Invalid {
+ found_invalid_template_ref = true;
+ }
+ if found_invalid_template_ref &&
+ c.kind() == CXCursor_TypeRef {
+ child_ci.args.push(TNamed(Rc::new(RefCell::new(
+ TypeInfo::new(c.spelling(),
+ ctx.current_module_id,
+ TVoid,
+ Layout::zero())))));
+ }
+ CXChildVisit_Continue
+ })
+ }
+ _ => {}
+ }
}
}
}
@@ -728,6 +764,13 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
let new_name = [&*ci.name, &*ci2.borrow().name].join("_").to_owned();
ci2.borrow_mut().name = new_name;
+ // This clear() is needed because of the speculation we do on
+ // incomplete types inside visit_composite() members.
+ //
+ // If this type ends up being complete, we're going to really
+ // parse them now, so we should reset them.
+ ci2.borrow_mut().args.clear();
+
// Propagate template arguments and typedefs to inner structs
ci2.borrow_mut().args.extend(ci.args.clone().into_iter());
ci2.borrow_mut().typedefs.extend(ci.typedefs.clone().into_iter());
@@ -998,6 +1041,9 @@ fn visit_top(cursor: &Cursor,
fwd_decl(ctx, cursor, move |ctx_| {
let decl = decl_name(ctx_, cursor);
let ci = decl.compinfo();
+ // This clear() is needed because of the speculation we do
+ // on incomplete types inside visit_composite() members.
+ ci.borrow_mut().args.clear();
cursor.visit(|c, p| {
let mut ci_ = ci.borrow_mut();
visit_composite(c, p, ctx_, &mut ci_)
diff --git a/tests/expectations/nsStyleAutoArray.rs b/tests/expectations/nsStyleAutoArray.rs
new file mode 100644
index 00000000..28207639
--- /dev/null
+++ b/tests/expectations/nsStyleAutoArray.rs
@@ -0,0 +1,23 @@
+/* automatically generated by rust-bindgen */
+
+
+#![feature(const_fn)]
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Struct_nsTArray<T> {
+ pub mBuff: *mut T,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Struct_nsStyleAutoArray<T> {
+ pub mFirstElement: T,
+ pub mOtherElements: Struct_nsTArray<T>,
+}
+#[repr(i32)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum nsStyleAutoArray_WithSingleInitialElement {
+ WITH_SINGLE_INITIAL_ELEMENT = 0,
+}
diff --git a/tests/expectations/template.rs b/tests/expectations/template.rs
index 63f2d952..8f8d02c1 100644
--- a/tests/expectations/template.rs
+++ b/tests/expectations/template.rs
@@ -74,6 +74,32 @@ fn bindgen_test_layout_Struct_POD() {
assert_eq!(::std::mem::size_of::<Struct_POD>() , 4usize);
assert_eq!(::std::mem::align_of::<Struct_POD>() , 4usize);
}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Struct_NestedBase<T, U> {
+ pub buff: *mut T,
+ pub _phantom0: ::std::marker::PhantomData<U>,
+}
+/**
+ * <div rustbindgen replaces="NestedReplaced"></div>
+ */
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Struct_NestedReplaced<T> {
+ pub buff: *mut T,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Struct_NestedContainer<T> {
+ pub c: T,
+ pub nested: Struct_NestedReplaced<T>,
+ pub inc: Struct_Incomplete<T>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Struct_Incomplete<T> {
+ pub d: T,
+}
extern "C" {
#[link_name = "_Z3bar3FooIiiE"]
pub fn bar(foo: Struct_Foo<::std::os::raw::c_int, ::std::os::raw::c_int>);
diff --git a/tests/headers/nsStyleAutoArray.hpp b/tests/headers/nsStyleAutoArray.hpp
new file mode 100644
index 00000000..950152c0
--- /dev/null
+++ b/tests/headers/nsStyleAutoArray.hpp
@@ -0,0 +1,57 @@
+
+template<typename T>
+class nsTArray {
+ T* mBuff;
+};
+
+template<typename T>
+class nsStyleAutoArray
+{
+public:
+ // This constructor places a single element in mFirstElement.
+ enum WithSingleInitialElement { WITH_SINGLE_INITIAL_ELEMENT };
+ explicit nsStyleAutoArray(WithSingleInitialElement) {}
+ nsStyleAutoArray(const nsStyleAutoArray& aOther) { *this = aOther; }
+ nsStyleAutoArray& operator=(const nsStyleAutoArray& aOther) {
+ mFirstElement = aOther.mFirstElement;
+ mOtherElements = aOther.mOtherElements;
+ return *this;
+ }
+
+ bool operator==(const nsStyleAutoArray& aOther) const {
+ return Length() == aOther.Length() &&
+ mFirstElement == aOther.mFirstElement &&
+ mOtherElements == aOther.mOtherElements;
+ }
+ bool operator!=(const nsStyleAutoArray& aOther) const {
+ return !(*this == aOther);
+ }
+
+ unsigned long Length() const {
+ return mOtherElements.Length() + 1;
+ }
+ const T& operator[](unsigned long aIndex) const {
+ return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1];
+ }
+ T& operator[](unsigned long aIndex) {
+ return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1];
+ }
+
+ void EnsureLengthAtLeast(unsigned long aMinLen) {
+ if (aMinLen > 0) {
+ mOtherElements.EnsureLengthAtLeast(aMinLen - 1);
+ }
+ }
+
+ void SetLengthNonZero(unsigned long aNewLen) {
+ mOtherElements.SetLength(aNewLen - 1);
+ }
+
+ void TruncateLengthNonZero(unsigned long aNewLen) {
+ mOtherElements.TruncateLength(aNewLen - 1);
+ }
+
+private:
+ T mFirstElement;
+ nsTArray<T> mOtherElements;
+};
diff --git a/tests/headers/template.hpp b/tests/headers/template.hpp
index e53ecbc8..0fd8337d 100644
--- a/tests/headers/template.hpp
+++ b/tests/headers/template.hpp
@@ -55,3 +55,36 @@ class Opaque {
class POD {
Opaque<int> opaque_member;
};
+
+/**
+ * <div rustbindgen replaces="NestedReplaced"></div>
+ */
+template<typename T>
+class Nested {
+ T* buff;
+};
+
+template<typename T, typename U>
+class NestedBase {
+ T* buff;
+};
+
+template<typename T>
+class NestedReplaced: public NestedBase<T, int> {
+};
+
+template<typename T>
+class Incomplete;
+
+template<typename T>
+class NestedContainer {
+ T c;
+private:
+ NestedReplaced<T> nested;
+ Incomplete<T> inc;
+};
+
+template<typename T>
+class Incomplete {
+ T d;
+};