Skip to content

Commit 600b282

Browse files
committed
Whitelisting codegen, v1
1 parent b07ea62 commit 600b282

File tree

8 files changed

+240
-69
lines changed

8 files changed

+240
-69
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: 165 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,173 @@ 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+
if self.hidden(context) || types.contains(&self.id()) {
1414+
return;
1415+
}
1416+
1417+
println!("Collecting: {:?}", self.id());
1418+
1419+
match *self.kind() {
1420+
ItemKind::Type(ref ty) => {
1421+
types.insert(self.id());
1422+
if !self.opaque(context) {
1423+
ty.collect_types(context, types, self);
1424+
}
1425+
}
1426+
_ => {}, // FIXME.
1427+
}
1428+
}
1429+
}
1430+
1431+
impl TypeCollector for Type {
1432+
type Extra = Item;
1433+
1434+
fn collect_types(&self,
1435+
context: &BindgenContext,
1436+
types: &mut ItemSet,
1437+
item: &Item) {
1438+
match *self.kind() {
1439+
TypeKind::Pointer(inner) |
1440+
TypeKind::Reference(inner) |
1441+
TypeKind::Array(inner, _) |
1442+
TypeKind::Alias(_, inner) |
1443+
TypeKind::Named(_, Some(inner))
1444+
=> inner.collect_types(context, types, &()),
1445+
1446+
TypeKind::TemplateRef(inner, ref template_args) => {
1447+
inner.collect_types(context, types, &());
1448+
for item in template_args {
1449+
item.collect_types(context, types, &());
1450+
}
1451+
}
1452+
TypeKind::Comp(ref ci) => ci.collect_types(context, types, item),
1453+
// FIXME: Pending types!
1454+
ref other @ _ => {
1455+
println!("Ignoring: {:?}", other);
1456+
},
1457+
}
1458+
}
1459+
}
1460+
1461+
impl TypeCollector for CompInfo {
1462+
type Extra = Item;
1463+
1464+
fn collect_types(&self,
1465+
context: &BindgenContext,
1466+
types: &mut ItemSet,
1467+
item: &Item) {
1468+
if let Some(template) = self.specialized_template() {
1469+
template.collect_types(context, types, &());
1470+
}
1471+
1472+
let applicable_template_args = item.applicable_template_args(context);
1473+
for arg in applicable_template_args {
1474+
arg.collect_types(context, types, &());
1475+
}
1476+
1477+
for base in self.base_members() {
1478+
base.collect_types(context, types, &());
1479+
}
1480+
1481+
for field in self.fields() {
1482+
field.ty().collect_types(context, types, &());
1483+
}
1484+
1485+
for ty in self.inner_types() {
1486+
ty.collect_types(context, types, &());
1487+
}
1488+
1489+
// FIXME(emilio): Methods, VTable?
1490+
}
1491+
}
1492+
14031493
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
14041494
context.gen(|context| {
14051495
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, &());
1496+
1497+
debug!("codegen: {:?}", context.options());
1498+
1499+
// If the whitelisted types set is empty, just generate everything.
1500+
if context.options().whitelisted_types.is_empty() {
1501+
for (_item_id, item) in context.items() {
1502+
// Non-toplevel item parents are the responsible one for generating
1503+
// them.
1504+
if item.is_toplevel(context) {
1505+
item.codegen(context, &mut result, &());
1506+
}
1507+
}
1508+
} else {
1509+
// Recursively collect all the types dependent on the whitelisted
1510+
// types, then generate them.
1511+
//
1512+
// FIXME(emilio): This pass is probably slow, but it can't be faster
1513+
// than docopt anyway :)
1514+
let mut types = ItemSet::new();
1515+
for (_item_id, item) in context.items() {
1516+
// FIXME(emilio): This only works for types, but we need to
1517+
// eventually come with a coherent history for functions...
1518+
//
1519+
// Whitelisting any type touched by a function seems overkill,
1520+
// maybe another pass whitelisting functions that only contain
1521+
// whitelisted types?
1522+
if item.kind().is_type() && item.is_toplevel(context) {
1523+
let name = item.canonical_name(context);
1524+
if context.options().whitelisted_types.contains(&name) {
1525+
item.collect_types(context, &mut types, &());
1526+
}
1527+
}
1528+
}
1529+
1530+
fn contains_parent(ctx: &BindgenContext, types: &ItemSet, id: ItemId) -> bool {
1531+
let item = ctx.resolve_item(id);
1532+
let mut last = id;
1533+
let mut current = item.parent_id();
1534+
1535+
while last != current {
1536+
if types.contains(&current) {
1537+
return true;
1538+
}
1539+
last = current;
1540+
current = ctx.resolve_item(current).parent_id();
1541+
}
1542+
1543+
false
1544+
}
1545+
1546+
for item_id in types.iter() {
1547+
let item = context.resolve_item(*item_id);
1548+
if item.is_toplevel(context) || !contains_parent(context, &types, *item_id) {
1549+
item.codegen(context, &mut result, &());
1550+
}
14111551
}
14121552
}
14131553
let saw_union = result.saw_union;

src/ir/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ impl<'ctx> BindgenContext<'ctx> {
372372
ty: &clang::Type,
373373
location: Option<clang::Cursor>) -> Option<ItemId> {
374374
use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization};
375-
debug!("builtin_or_resolved_ty: {:?}, {:?}", ty, location);
375+
debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}", ty, location, parent_id);
376376
let mut declaration = ty.declaration();
377377
if !declaration.is_valid() {
378378
if let Some(location) = location {

src/ir/item.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -410,19 +410,21 @@ impl ClangItemParser for Item {
410410
context: &mut BindgenContext) -> Result<ItemId, ParseError> {
411411
use clangll::*;
412412

413-
let decl = ty.declaration();
414-
let definition = decl.definition();
415-
let decl = if definition.is_valid() {
416-
definition
417-
} else {
418-
decl
413+
let decl = {
414+
let decl = ty.declaration();
415+
let definition = decl.definition();
416+
if definition.is_valid() {
417+
definition
418+
} else {
419+
decl
420+
}
419421
};
420422

421423
let comment =
422-
definition.raw_comment()
423-
.or_else(|| location.as_ref().and_then(|l| l.raw_comment()));
424+
decl.raw_comment()
425+
.or_else(|| location.as_ref().and_then(|l| l.raw_comment()));
424426
let annotations =
425-
Annotations::new(&definition)
427+
Annotations::new(&decl)
426428
.or_else(|| location.as_ref().and_then(|l| Annotations::new(l)));
427429

428430
if let Some(ty) = context.builtin_or_resolved_ty(parent_id, ty, location) {

src/ir/module.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::context::BindgenContext;
22
use super::item::{ItemId, Item};
33
use clang;
44
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
5+
use parse_one;
56

67
/// A module, as in, a C++ namespace.
78
#[derive(Clone, Debug)]
@@ -38,26 +39,9 @@ impl ClangSubItemParser for Module {
3839
use clangll::*;
3940
match cursor.kind() {
4041
CXCursor_Namespace => {
41-
// FIXME: This shouldn't be at parse time, but at codegen time,
42-
// move there once we have enough confidence in our namespace
43-
// parsing implementation.
44-
if !ctx.options().enable_cxx_namespaces {
45-
return Err(ParseError::Recurse)
46-
}
47-
4842
let module_id = ctx.module(cursor);
4943
ctx.with_module(module_id, |ctx, children| {
50-
// FIXME: deduplicate this and src/lib.rs
51-
cursor.visit(|cur, _| {
52-
match Item::parse(*cur, None, ctx) {
53-
Ok(id) => {
54-
children.push(id);
55-
CXChildVisit_Continue
56-
}
57-
Err(ParseError::Continue) => CXChildVisit_Continue,
58-
Err(ParseError::Recurse) => CXChildVisit_Recurse,
59-
}
60-
});
44+
cursor.visit(|cursor, _| parse_one(ctx, *cursor, Some(module_id), children))
6145
});
6246

6347
Ok(ParseResult::AlreadyResolved(module_id))

0 commit comments

Comments
 (0)