summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2016-12-12 16:11:43 +0100
committerEmilio Cobos Álvarez <emilio@crisal.io>2016-12-13 14:33:01 +0100
commit883ff74e5f20b68b41f322daa582d9208eece65a (patch)
tree10f0c8aa40dad4a9b48d8a705761074fff9036d3
parent5d9c48e59b49135db1ecfd4ff8c3dbab8ed05086 (diff)
Add support for constructors, and integration tests.
-rw-r--r--.travis.yml2
-rw-r--r--Cargo.toml1
-rw-r--r--bindgen-integration/Cargo.toml12
-rw-r--r--bindgen-integration/build.rs28
-rw-r--r--bindgen-integration/cpp/Test.cc15
-rw-r--r--bindgen-integration/cpp/Test.h10
-rw-r--r--bindgen-integration/src/lib.rs28
-rw-r--r--libbindgen/src/codegen/helpers.rs22
-rw-r--r--libbindgen/src/codegen/mod.rs96
-rw-r--r--libbindgen/src/ir/comp.rs70
-rw-r--r--libbindgen/src/ir/function.rs13
-rw-r--r--libbindgen/src/ir/item.rs23
-rw-r--r--libbindgen/src/lib.rs4
-rw-r--r--libbindgen/tests/expectations/tests/constructors.rs67
-rw-r--r--libbindgen/tests/headers/constructors.hpp13
15 files changed, 332 insertions, 72 deletions
diff --git a/.travis.yml b/.travis.yml
index 8d7047aa..f7fbf2b4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -37,6 +37,8 @@ script:
- cd ../../../bindgen
- cargo test --features "$BINDGEN_FEATURES"
- cargo test --release --features "$BINDGEN_FEATURES"
+ - cd ../bindgen-integration
+ - cargo test
notifications:
webhooks: http://build.servo.org:54856/travis
diff --git a/Cargo.toml b/Cargo.toml
index 0ca737c7..106e652b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,7 @@
[workspace]
members = [
"bindgen",
+ "bindgen-integration",
"libbindgen",
"libbindgen/tests/expectations",
]
diff --git a/bindgen-integration/Cargo.toml b/bindgen-integration/Cargo.toml
new file mode 100644
index 00000000..04f0f84c
--- /dev/null
+++ b/bindgen-integration/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "bindgen-integration"
+description = "A package to test various bindgen features"
+version = "0.1.0"
+authors = ["Emilio Cobos Álvarez <emilio@crisal.io>"]
+workspace = ".."
+publish = false
+build = "build.rs"
+
+[build-dependencies]
+libbindgen = { path = "../libbindgen" }
+gcc = "0.3"
diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs
new file mode 100644
index 00000000..ff8ba172
--- /dev/null
+++ b/bindgen-integration/build.rs
@@ -0,0 +1,28 @@
+extern crate libbindgen;
+extern crate gcc;
+
+use std::env;
+use std::path::PathBuf;
+use libbindgen::Builder;
+
+fn main() {
+ gcc::Config::new()
+ .cpp(true)
+ .file("cpp/Test.cc")
+ .compile("libtest.a");
+
+ let bindings = Builder::default()
+ .no_unstable_rust()
+ .header("cpp/Test.h")
+ .clang_arg("-x")
+ .clang_arg("c++")
+ .clang_arg("-std=c++11")
+ .generate()
+ .expect("Unable to generate bindings");
+
+
+ let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
+ bindings
+ .write_to_file(out_path.join("test.rs"))
+ .expect("Couldn't write bindings!");
+}
diff --git a/bindgen-integration/cpp/Test.cc b/bindgen-integration/cpp/Test.cc
new file mode 100644
index 00000000..d9c13a76
--- /dev/null
+++ b/bindgen-integration/cpp/Test.cc
@@ -0,0 +1,15 @@
+#include "Test.h"
+
+const char* Test::name() {
+ return "Test";
+}
+
+Test::Test(int foo)
+ : m_int(foo)
+ , m_double(0.0)
+{}
+
+Test::Test(double foo)
+ : m_int(0)
+ , m_double(foo)
+{}
diff --git a/bindgen-integration/cpp/Test.h b/bindgen-integration/cpp/Test.h
new file mode 100644
index 00000000..2e15bb49
--- /dev/null
+++ b/bindgen-integration/cpp/Test.h
@@ -0,0 +1,10 @@
+#pragma once
+
+class Test final {
+ int m_int;
+ double m_double;
+public:
+ static const char* name();
+ Test(int foo);
+ Test(double foo);
+};
diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs
new file mode 100644
index 00000000..4f239510
--- /dev/null
+++ b/bindgen-integration/src/lib.rs
@@ -0,0 +1,28 @@
+mod bindings {
+ include!(concat!(env!("OUT_DIR"), "/test.rs"));
+}
+
+use std::ffi::CStr;
+
+#[test]
+fn test_static_method() {
+ let c_str = unsafe { bindings::Test::name() };
+ let name = unsafe {
+ CStr::from_ptr(c_str).to_string_lossy().into_owned()
+ };
+ assert_eq!(name, "Test", "Calling a static C++ method works!");
+}
+
+#[test]
+fn test_constructor() {
+ let test = unsafe { bindings::Test::new(5) };
+ assert_eq!(test.m_int, 5);
+ assert_eq!(test.m_double, 0.0);
+}
+
+#[test]
+fn test_overload() {
+ let test = unsafe { bindings::Test::new1(5.0) };
+ assert_eq!(test.m_int, 0);
+ assert_eq!(test.m_double, 5.0);
+}
diff --git a/libbindgen/src/codegen/helpers.rs b/libbindgen/src/codegen/helpers.rs
index f1a0f314..c09f0071 100644
--- a/libbindgen/src/codegen/helpers.rs
+++ b/libbindgen/src/codegen/helpers.rs
@@ -75,6 +75,7 @@ impl BlobTyBuilder {
pub mod ast_ty {
use aster;
use ir::context::BindgenContext;
+ use ir::function::FunctionSig;
use ir::ty::FloatKind;
use syntax::ast;
use syntax::ptr::P;
@@ -164,4 +165,25 @@ pub mod ast_ty {
let kind = ast::LitKind::FloatUnsuffixed(interned_str);
aster::AstBuilder::new().expr().lit().build_lit(kind)
}
+
+ pub fn arguments_from_signature(signature: &FunctionSig,
+ ctx: &BindgenContext)
+ -> Vec<P<ast::Expr>> {
+ // TODO: We need to keep in sync the argument names, so we should unify
+ // this with the other loop that decides them.
+ let mut unnamed_arguments = 0;
+ signature.argument_types()
+ .iter()
+ .map(|&(ref name, _ty)| {
+ let arg_name = match *name {
+ Some(ref name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ unnamed_arguments += 1;
+ format!("arg{}", unnamed_arguments)
+ }
+ };
+ aster::expr::ExprBuilder::new().id(arg_name)
+ })
+ .collect::<Vec<_>>()
+ }
}
diff --git a/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs
index 31946964..f3181de7 100644
--- a/libbindgen/src/codegen/mod.rs
+++ b/libbindgen/src/codegen/mod.rs
@@ -4,7 +4,7 @@ mod helpers;
use aster;
use ir::annotations::FieldAccessorKind;
-use ir::comp::{CompInfo, CompKind, Field, Method};
+use ir::comp::{CompInfo, CompKind, Field, Method, MethodKind};
use ir::context::{BindgenContext, ItemId};
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use ir::function::{Function, FunctionSig};
@@ -1181,15 +1181,28 @@ impl CodeGenerator for CompInfo {
result.push(item);
}
+ let mut method_names = Default::default();
if ctx.options().codegen_config.methods {
- let mut method_names = Default::default();
for method in self.methods() {
+ assert!(method.kind() != MethodKind::Constructor);
method.codegen_method(ctx,
&mut methods,
&mut method_names,
result,
whitelisted_items,
- item);
+ self);
+ }
+ }
+
+ if ctx.options().codegen_config.constructors {
+ for sig in self.constructors() {
+ Method::new(MethodKind::Constructor, *sig, /* const */ false)
+ .codegen_method(ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ whitelisted_items,
+ self);
}
}
}
@@ -1242,7 +1255,7 @@ trait MethodCodegen {
method_names: &mut HashMap<String, usize>,
result: &mut CodegenResult<'a>,
whitelisted_items: &ItemSet,
- parent: &Item);
+ parent: &CompInfo);
}
impl MethodCodegen for Method {
@@ -1252,18 +1265,21 @@ impl MethodCodegen for Method {
method_names: &mut HashMap<String, usize>,
result: &mut CodegenResult<'a>,
whitelisted_items: &ItemSet,
- _parent: &Item) {
+ _parent: &CompInfo) {
if self.is_virtual() {
return; // FIXME
}
// First of all, output the actual function.
- ctx.resolve_item(self.signature())
- .codegen(ctx, result, whitelisted_items, &());
-
let function_item = ctx.resolve_item(self.signature());
+ function_item.codegen(ctx, result, whitelisted_items, &());
+
let function = function_item.expect_function();
- let mut name = function.name().to_owned();
let signature_item = ctx.resolve_item(function.signature());
+ let mut name = match self.kind() {
+ MethodKind::Constructor => "new".into(),
+ _ => function.name().to_owned(),
+ };
+
let signature = match *signature_item.expect_type().kind() {
TypeKind::Function(ref sig) => sig,
_ => panic!("How in the world?"),
@@ -1283,7 +1299,7 @@ impl MethodCodegen for Method {
let function_name = function_item.canonical_name(ctx);
let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item)
.unwrap();
- if !self.is_static() {
+ if !self.is_static() && !self.is_constructor() {
let mutability = if self.is_const() {
ast::Mutability::Immutable
} else {
@@ -1319,32 +1335,38 @@ impl MethodCodegen for Method {
};
}
+ // If it's a constructor, we always return `Self`, and we inject the
+ // "this" parameter, so there's no need to ask the user for it.
+ //
+ // Note that constructors in Clang are represented as functions with
+ // return-type = void.
+ if self.is_constructor() {
+ fndecl.inputs.remove(0);
+ fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), Self));
+ }
+
let sig = ast::MethodSig {
unsafety: ast::Unsafety::Unsafe,
abi: Abi::Rust,
- decl: P(fndecl.clone()),
+ decl: P(fndecl),
generics: ast::Generics::default(),
constness: respan(ctx.span(), ast::Constness::NotConst),
};
- // TODO: We need to keep in sync the argument names, so we should unify
- // this with the other loop that decides them.
- let mut unnamed_arguments = 0;
- let mut exprs = signature.argument_types()
- .iter()
- .map(|&(ref name, _ty)| {
- let arg_name = match *name {
- Some(ref name) => ctx.rust_mangle(name).into_owned(),
- None => {
- unnamed_arguments += 1;
- format!("arg{}", unnamed_arguments)
- }
- };
- aster::expr::ExprBuilder::new().id(arg_name)
- })
- .collect::<Vec<_>>();
+ let mut exprs =
+ helpers::ast_ty::arguments_from_signature(&signature, ctx);
+
+ let mut stmts = vec![];
- if !self.is_static() {
+ // If it's a constructor, we need to insert an extra parameter with a
+ // variable called `tmp` we're going to create.
+ if self.is_constructor() {
+ let tmp_variable_decl =
+ quote_stmt!(ctx.ext_cx(), let mut tmp = ::std::mem::uninitialized())
+ .unwrap();
+ stmts.push(tmp_variable_decl);
+ exprs[0] = quote_expr!(ctx.ext_cx(), &mut tmp);
+ } else if !self.is_static() {
assert!(!exprs.is_empty());
exprs[0] = if self.is_const() {
quote_expr!(ctx.ext_cx(), &*self)
@@ -1359,14 +1381,18 @@ impl MethodCodegen for Method {
.with_args(exprs)
.build();
+ stmts.push(ast::Stmt {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::StmtKind::Expr(call),
+ span: ctx.span(),
+ });
+
+ if self.is_constructor() {
+ stmts.push(quote_stmt!(ctx.ext_cx(), tmp).unwrap());
+ }
+
let block = ast::Block {
- stmts: vec![
- ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- node: ast::StmtKind::Expr(call),
- span: ctx.span(),
- }
- ],
+ stmts: stmts,
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Default,
span: ctx.span(),
diff --git a/libbindgen/src/ir/comp.rs b/libbindgen/src/ir/comp.rs
index d2ace023..c351a152 100644
--- a/libbindgen/src/ir/comp.rs
+++ b/libbindgen/src/ir/comp.rs
@@ -23,6 +23,9 @@ pub enum CompKind {
/// The kind of C++ method.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MethodKind {
+ /// A constructor. We represent it as method for convenience, to avoid code
+ /// duplication.
+ Constructor,
/// A static method.
Static,
/// A normal method.
@@ -45,7 +48,7 @@ pub struct Method {
impl Method {
/// Construct a new `Method`.
- fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
+ pub fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
Method {
kind: kind,
signature: signature,
@@ -58,6 +61,11 @@ impl Method {
self.kind
}
+ /// Is this a constructor?
+ pub fn is_constructor(&self) -> bool {
+ self.kind == MethodKind::Constructor
+ }
+
/// Is this a virtual method?
pub fn is_virtual(&self) -> bool {
self.kind == MethodKind::Virtual
@@ -167,6 +175,9 @@ pub struct CompInfo {
/// The method declarations inside this class, if in C++ mode.
methods: Vec<Method>,
+ /// The different constructors this struct or class contains.
+ constructors: Vec<ItemId>,
+
/// Vector of classes this one inherits from.
base_members: Vec<ItemId>,
@@ -235,6 +246,7 @@ impl CompInfo {
fields: vec![],
template_args: vec![],
methods: vec![],
+ constructors: vec![],
base_members: vec![],
ref_template: None,
inner_types: vec![],
@@ -454,6 +466,10 @@ impl CompInfo {
&self.methods
}
+ pub fn constructors(&self) -> &[ItemId] {
+ &self.constructors
+ }
+
/// What kind of compound type is this?
pub fn kind(&self) -> CompKind {
self.kind
@@ -651,14 +667,15 @@ impl CompInfo {
.expect("BaseSpecifier");
ci.base_members.push(type_id);
}
+ CXCursor_Constructor |
+ CXCursor_Destructor |
CXCursor_CXXMethod => {
let is_virtual = cur.method_is_virtual();
let is_static = cur.method_is_static();
debug_assert!(!(is_static && is_virtual), "How?");
- if !ci.has_vtable {
- ci.has_vtable = is_virtual;
- }
+ ci.has_destructor |= cur.kind() == CXCursor_Destructor;
+ ci.has_vtable |= is_virtual;
let linkage = cur.linkage();
if linkage != CXLinkage_External {
@@ -699,30 +716,34 @@ impl CompInfo {
// NB: This gets us an owned `Function`, not a
// `FunctionSig`.
- let method_signature =
+ let signature =
Item::parse(cur, Some(potential_id), ctx)
.expect("CXXMethod");
- let is_const = cur.method_is_const();
- let method_kind = if is_static {
- MethodKind::Static
- } else if is_virtual {
- MethodKind::Virtual
- } else {
- MethodKind::Normal
- };
-
- let method =
- Method::new(method_kind, method_signature, is_const);
-
- ci.methods.push(method);
- }
- CXCursor_Destructor => {
- if cur.method_is_virtual() {
- // FIXME: Push to the method list?
- ci.has_vtable = true;
+ match cur.kind() {
+ CXCursor_Constructor => {
+ ci.constructors.push(signature);
+ }
+ // TODO(emilio): Bind the destructor?
+ CXCursor_Destructor => {},
+ CXCursor_CXXMethod => {
+ let is_const = cur.method_is_const();
+ let method_kind = if is_static {
+ MethodKind::Static
+ } else if is_virtual {
+ MethodKind::Virtual
+ } else {
+ MethodKind::Normal
+ };
+
+ let method = Method::new(method_kind,
+ signature,
+ is_const);
+
+ ci.methods.push(method);
+ }
+ _ => unreachable!("How can we see this here?"),
}
- ci.has_destructor = true;
}
CXCursor_NonTypeTemplateParameter => {
ci.has_non_type_template_params = true;
@@ -746,7 +767,6 @@ impl CompInfo {
// Intentionally not handled
CXCursor_CXXAccessSpecifier |
CXCursor_CXXFinalAttr |
- CXCursor_Constructor |
CXCursor_FunctionTemplate |
CXCursor_ConversionFunction => {}
_ => {
diff --git a/libbindgen/src/ir/function.rs b/libbindgen/src/ir/function.rs
index 5a864cfc..c4c26c62 100644
--- a/libbindgen/src/ir/function.rs
+++ b/libbindgen/src/ir/function.rs
@@ -147,6 +147,7 @@ impl FunctionSig {
};
let mut args: Vec<_> = match cursor.kind() {
CXCursor_FunctionDecl |
+ CXCursor_Constructor |
CXCursor_CXXMethod => {
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
// to get parameter names and types.
@@ -184,10 +185,12 @@ impl FunctionSig {
}
};
- if cursor.kind() == CXCursor_CXXMethod {
- let is_const = cursor.method_is_const();
- let is_virtual = cursor.method_is_virtual();
- let is_static = cursor.method_is_static();
+ let is_method = cursor.kind() == CXCursor_CXXMethod;
+
+ if is_method || cursor.kind() == CXCursor_Constructor {
+ let is_const = is_method && cursor.method_is_const();
+ let is_virtual = is_method && cursor.method_is_virtual();
+ let is_static = is_method && cursor.method_is_static();
if !is_static && !is_virtual {
let class = Item::parse(cursor.semantic_parent(), None, ctx)
.expect("Expected to parse the class");
@@ -240,6 +243,8 @@ impl ClangSubItemParser for Function {
use clangll::*;
match cursor.kind() {
CXCursor_FunctionDecl |
+ CXCursor_Constructor |
+ CXCursor_Destructor |
CXCursor_CXXMethod => {}
_ => return Err(ParseError::Continue),
};
diff --git a/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs
index 6601216e..11ec7d99 100644
--- a/libbindgen/src/ir/item.rs
+++ b/libbindgen/src/ir/item.rs
@@ -654,19 +654,26 @@ impl Item {
/// Get the overload index for this method. If this is not a method, return
/// `None`.
- fn method_overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
+ fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
self.func_name().and_then(|func_name| {
let parent = ctx.resolve_item(self.parent_id());
if let ItemKind::Type(ref ty) = *parent.kind() {
if let TypeKind::Comp(ref ci) = *ty.kind() {
- return ci.methods()
+ // All the constructors have the same name, so no need to
+ // resolve and check.
+ return ci.constructors()
.iter()
- .filter(|method| {
- let item = ctx.resolve_item(method.signature());
- let func = item.expect_function();
- func.name() == func_name
+ .position(|c| *c == self.id())
+ .or_else(|| {
+ ci.methods()
+ .iter()
+ .filter(|m| {
+ let item = ctx.resolve_item(m.signature());
+ let func = item.expect_function();
+ func.name() == func_name
+ })
+ .position(|m| m.signature() == self.id())
})
- .position(|method| method.signature() == self.id());
}
}
@@ -704,7 +711,7 @@ impl Item {
ItemKind::Function(ref fun) => {
let mut name = fun.name().to_owned();
- if let Some(idx) = self.method_overload_index(ctx) {
+ if let Some(idx) = self.overload_index(ctx) {
if idx > 0 {
write!(&mut name, "{}", idx).unwrap();
}
diff --git a/libbindgen/src/lib.rs b/libbindgen/src/lib.rs
index 29580f36..2ff61f90 100644
--- a/libbindgen/src/lib.rs
+++ b/libbindgen/src/lib.rs
@@ -108,6 +108,8 @@ pub struct CodegenConfig {
pub vars: bool,
/// Whether to generate methods.
pub methods: bool,
+ /// Whether to generate constructors.
+ pub constructors: bool,
}
impl CodegenConfig {
@@ -118,6 +120,7 @@ impl CodegenConfig {
types: true,
vars: true,
methods: true,
+ constructors: true,
}
}
@@ -128,6 +131,7 @@ impl CodegenConfig {
types: false,
vars: false,
methods: false,
+ constructors: false,
}
}
}
diff --git a/libbindgen/tests/expectations/tests/constructors.rs b/libbindgen/tests/expectations/tests/constructors.rs
new file mode 100644
index 00000000..80c14057
--- /dev/null
+++ b/libbindgen/tests/expectations/tests/constructors.rs
@@ -0,0 +1,67 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct TestOverload {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_TestOverload() {
+ assert_eq!(::std::mem::size_of::<TestOverload>() , 1usize);
+ assert_eq!(::std::mem::align_of::<TestOverload>() , 1usize);
+}
+extern "C" {
+ #[link_name = "_ZN12TestOverloadC1Ei"]
+ pub fn TestOverload_TestOverload(this: *mut TestOverload,
+ arg1: ::std::os::raw::c_int);
+}
+extern "C" {
+ #[link_name = "_ZN12TestOverloadC1Ed"]
+ pub fn TestOverload_TestOverload1(this: *mut TestOverload, arg1: f64);
+}
+impl Clone for TestOverload {
+ fn clone(&self) -> Self { *self }
+}
+impl TestOverload {
+ #[inline]
+ pub unsafe fn new(arg1: ::std::os::raw::c_int) -> Self {
+ let mut tmp = ::std::mem::uninitialized();
+ TestOverload_TestOverload(&mut tmp, arg1);
+ tmp
+ }
+ #[inline]
+ pub unsafe fn new1(arg1: f64) -> Self {
+ let mut tmp = ::std::mem::uninitialized();
+ TestOverload_TestOverload1(&mut tmp, arg1);
+ tmp
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct TestPublicNoArgs {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_TestPublicNoArgs() {
+ assert_eq!(::std::mem::size_of::<TestPublicNoArgs>() , 1usize);
+ assert_eq!(::std::mem::align_of::<TestPublicNoArgs>() , 1usize);
+}
+extern "C" {
+ #[link_name = "_ZN16TestPublicNoArgsC1Ev"]
+ pub fn TestPublicNoArgs_TestPublicNoArgs(this: *mut TestPublicNoArgs);
+}
+impl Clone for TestPublicNoArgs {
+ fn clone(&self) -> Self { *self }
+}
+impl TestPublicNoArgs {
+ #[inline]
+ pub unsafe fn new() -> Self {
+ let mut tmp = ::std::mem::uninitialized();
+ TestPublicNoArgs_TestPublicNoArgs(&mut tmp);
+ tmp
+ }
+}
diff --git a/libbindgen/tests/headers/constructors.hpp b/libbindgen/tests/headers/constructors.hpp
new file mode 100644
index 00000000..d4174889
--- /dev/null
+++ b/libbindgen/tests/headers/constructors.hpp
@@ -0,0 +1,13 @@
+
+class TestOverload {
+ // This one shouldnt' be generated.
+ TestOverload();
+public:
+ TestOverload(int);
+ TestOverload(double);
+};
+
+class TestPublicNoArgs {
+public:
+ TestPublicNoArgs();
+};