Skip to content

Commit f7adf26

Browse files
committed
Whitelisting codegen, v1
1 parent b07ea62 commit f7adf26

File tree

5 files changed

+166
-25
lines changed

5 files changed

+166
-25
lines changed

src/bin/bindgen.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Usage:
2828
[--dtor-attr=<attr>...] \
2929
[--opaque-type=<type>...] \
3030
[--blacklist-type=<type>...] \
31+
[--whitelist-type=<type>...] \
3132
<input-header> \
3233
[-- <clang-args>...]
3334
@@ -92,6 +93,9 @@ Options:
9293
--ignore-methods Avoid generating all kind of methods.
9394
--opaque-type=<type> Mark a type as opaque.
9495
--blacklist-type=<type> Mark a type as hidden.
96+
--whitelist-type=<type> Whitelist the type. If this set is not empty,
97+
then all the non-whitelisted types (or
98+
dependant) won't be generated.
9599
96100
<clang-args> Options other than stated above are passed
97101
directly through to clang.
@@ -122,6 +126,7 @@ struct Args {
122126
flag_ignore_methods: bool,
123127
flag_opaque_type: Vec<String>,
124128
flag_blacklist_type: Vec<String>,
129+
flag_whitelist_type: Vec<String>,
125130
arg_clang_args: Vec<String>,
126131
}
127132

@@ -171,6 +176,7 @@ impl Into<ParseResult<(BindgenOptions, Box<io::Write>)>> for Args {
171176
options.ignore_methods = self.flag_ignore_methods;
172177
options.opaque_types.extend(self.flag_opaque_type.drain(..));
173178
options.hidden_types.extend(self.flag_blacklist_type.drain(..));
179+
options.whitelisted_types.extend(self.flag_whitelist_type.drain(..));
174180
options.clang_args.extend(self.arg_clang_args.drain(..));
175181
options.clang_args.push(self.arg_input_header);
176182

src/codegen/mod.rs

Lines changed: 122 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use ir::layout::Layout;
1212

1313
use std::ops;
1414
use std::mem;
15+
use std::collections::BTreeSet;
1516
use std::collections::hash_map::{HashMap, Entry};
1617

1718
use syntax::abi::Abi;
@@ -489,26 +490,6 @@ impl<'a> Bitfield<'a> {
489490
}
490491
}
491492

492-
fn type_for_bitfield_width(ctx: &BindgenContext, width: u32, is_arg: bool) -> P<ast::Ty> {
493-
let input_type = if width > 16 {
494-
"u32"
495-
} else if width > 8 {
496-
"u16"
497-
} else if width > 1 {
498-
"u8"
499-
} else {
500-
if is_arg {
501-
"bool"
502-
} else {
503-
"u8"
504-
}
505-
};
506-
507-
let ident = ctx.rust_ident_raw(input_type);
508-
quote_ty!(ctx.ext_cx(), $ident)
509-
}
510-
511-
512493
fn codegen_fields(self,
513494
ctx: &BindgenContext,
514495
fields: &mut Vec<ast::StructField>,
@@ -1400,14 +1381,130 @@ impl CodeGenerator for Function {
14001381
}
14011382
}
14021383

1384+
type ItemSet = BTreeSet<ItemId>;
1385+
1386+
trait TypeCollector {
1387+
type Extra;
1388+
1389+
fn collect_types(&self,
1390+
context: &BindgenContext,
1391+
types: &mut ItemSet,
1392+
extra: &Self::Extra);
1393+
}
1394+
1395+
impl TypeCollector for ItemId {
1396+
type Extra = ();
1397+
1398+
fn collect_types(&self,
1399+
context: &BindgenContext,
1400+
types: &mut ItemSet,
1401+
extra: &()) {
1402+
context.resolve_item(*self).collect_types(context, types, extra);
1403+
}
1404+
}
1405+
1406+
impl TypeCollector for Item {
1407+
type Extra = ();
1408+
1409+
fn collect_types(&self,
1410+
context: &BindgenContext,
1411+
types: &mut ItemSet,
1412+
_extra: &()) {
1413+
// NB: non-toplevel items are generated by their parents.
1414+
if self.hidden(context) || !self.is_toplevel(context) || types.contains(&self.id()) {
1415+
return;
1416+
}
1417+
1418+
match *self.kind() {
1419+
ItemKind::Type(ref ty) => {
1420+
types.insert(self.id());
1421+
if !self.opaque(context) {
1422+
ty.collect_types(context, types, self);
1423+
}
1424+
}
1425+
_ => {}, // FIXME.
1426+
}
1427+
}
1428+
}
1429+
1430+
impl TypeCollector for Type {
1431+
type Extra = Item;
1432+
1433+
fn collect_types(&self,
1434+
context: &BindgenContext,
1435+
types: &mut ItemSet,
1436+
item: &Item) {
1437+
match *self.kind() {
1438+
TypeKind::Comp(ref ci) => ci.collect_types(context, types, item),
1439+
TypeKind::Alias(_, ref inner) => inner.collect_types(context, types, &()),
1440+
_ => {},
1441+
}
1442+
}
1443+
}
1444+
1445+
impl TypeCollector for CompInfo {
1446+
type Extra = Item;
1447+
1448+
fn collect_types(&self,
1449+
context: &BindgenContext,
1450+
types: &mut ItemSet,
1451+
item: &Item) {
1452+
let applicable_template_args = item.applicable_template_args(context);
1453+
for arg in applicable_template_args {
1454+
arg.collect_types(context, types, &());
1455+
}
1456+
1457+
for base in self.base_members() {
1458+
base.collect_types(context, types, &());
1459+
}
1460+
1461+
for field in self.fields() {
1462+
field.ty().collect_types(context, types, &());
1463+
}
1464+
1465+
// FIXME(emilio): Methods, VTable?
1466+
}
1467+
}
1468+
14031469
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
14041470
context.gen(|context| {
14051471
let mut result = CodegenResult::new();
1406-
for (_item_id, item) in context.items() {
1407-
// Non-toplevel item parents are the responsible one for generating
1408-
// them.
1409-
if item.is_toplevel(context) {
1410-
item.codegen(context, &mut result, &());
1472+
1473+
debug!("codegen: {:?}", context.options());
1474+
1475+
// If the whitelisted types set is empty, just generate everything.
1476+
if context.options().whitelisted_types.is_empty() {
1477+
for (_item_id, item) in context.items() {
1478+
// Non-toplevel item parents are the responsible one for generating
1479+
// them.
1480+
if item.is_toplevel(context) {
1481+
item.codegen(context, &mut result, &());
1482+
}
1483+
}
1484+
} else {
1485+
// Recursively collect all the types dependent on the whitelisted
1486+
// types, then generate them.
1487+
//
1488+
// FIXME(emilio): This pass is probably slow, but it can't be faster
1489+
// than docopt anyway :)
1490+
let mut types = ItemSet::new();
1491+
for (_item_id, item) in context.items() {
1492+
// FIXME(emilio): This only works for types, but we need to
1493+
// eventually come with a coherent history for functions...
1494+
//
1495+
// Whitelisting any type touched by a function seems overkill,
1496+
// maybe another pass whitelisting functions that only contain
1497+
// whitelisted types?
1498+
if item.kind().is_type() && item.is_toplevel(context) {
1499+
let name = item.canonical_name(context);
1500+
if context.options().whitelisted_types.contains(&name) {
1501+
item.collect_types(context, &mut types, &());
1502+
}
1503+
}
1504+
}
1505+
1506+
for item_id in types.iter() {
1507+
context.resolve_item(*item_id).codegen(context, &mut result, &());
14111508
}
14121509
}
14131510
let saw_union = result.saw_union;

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ impl<'a> Builder<'a> {
7171
self
7272
}
7373

74+
pub fn whitelisted_type<T: Into<String>>(&mut self, arg: T) -> &mut Self {
75+
self.options.whitelisted_types.insert(arg.into());
76+
self
77+
}
78+
7479
pub fn raw_line<T: Into<String>>(&mut self, arg: T) -> &mut Self {
7580
self.options.raw_lines.push(arg.into());
7681
self
@@ -155,6 +160,7 @@ pub struct BindgenOptions {
155160
pub match_pat: HashSet<String>,
156161
pub hidden_types: HashSet<String>,
157162
pub opaque_types: HashSet<String>,
163+
pub whitelisted_types: HashSet<String>,
158164
pub builtins: bool,
159165
pub rust_enums: bool,
160166
pub links: Vec<(String, LinkType)>,
@@ -187,6 +193,7 @@ impl Default for BindgenOptions {
187193
match_pat: Default::default(),
188194
hidden_types: Default::default(),
189195
opaque_types: Default::default(),
196+
whitelisted_types: Default::default(),
190197
builtins: false,
191198
rust_enums: true,
192199
links: vec![],

tests/expectations/whitelist_basic.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
pub struct WhitelistMe<T> {
9+
pub foo: ::std::os::raw::c_int,
10+
pub bar: WhitelistMe_Inner<T>,
11+
pub _phantom_0: ::std::marker::PhantomData<T>,
12+
}
13+
#[repr(C)]
14+
pub struct WhitelistMe_Inner<T> {
15+
pub bar: T,
16+
}

tests/headers/whitelist_basic.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// bindgen-flags: --whitelist-type WhitelistMe
2+
3+
template<typename T>
4+
class WhitelistMe {
5+
class Inner {
6+
T bar;
7+
};
8+
9+
int foo;
10+
Inner bar;
11+
};
12+
13+
struct DontWhitelistMe {
14+
void* foo;
15+
};

0 commit comments

Comments
 (0)