Skip to content

Only whitelist items for which we intend to generate bindings #827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,10 @@ impl CodeGenerator for Item {
result: &mut CodegenResult<'a>,
whitelisted_items: &ItemSet,
_extra: &()) {
if !self.is_enabled_for_codegen(ctx) {
return;
}

if self.is_hidden(ctx) || result.seen(self.id()) {
debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \
self = {:?}",
Expand All @@ -316,19 +320,13 @@ impl CodeGenerator for Item {
module.codegen(ctx, result, whitelisted_items, self);
}
ItemKind::Function(ref fun) => {
if ctx.options().codegen_config.functions {
fun.codegen(ctx, result, whitelisted_items, self);
}
fun.codegen(ctx, result, whitelisted_items, self);
}
ItemKind::Var(ref var) => {
if ctx.options().codegen_config.vars {
var.codegen(ctx, result, whitelisted_items, self);
}
var.codegen(ctx, result, whitelisted_items, self);
}
ItemKind::Type(ref ty) => {
if ctx.options().codegen_config.types {
ty.codegen(ctx, result, whitelisted_items, self);
}
ty.codegen(ctx, result, whitelisted_items, self);
}
}
}
Expand Down Expand Up @@ -419,6 +417,7 @@ impl CodeGenerator for Var {
item: &Item) {
use ir::var::VarType;
debug!("<Var as CodeGenerator>::codegen: item = {:?}", item);
debug_assert!(item.is_enabled_for_codegen(ctx));

let canonical_name = item.canonical_name(ctx);

Expand Down Expand Up @@ -522,6 +521,7 @@ impl CodeGenerator for Type {
whitelisted_items: &ItemSet,
item: &Item) {
debug!("<Type as CodeGenerator>::codegen: item = {:?}", item);
debug_assert!(item.is_enabled_for_codegen(ctx));

match *self.kind() {
TypeKind::Void |
Expand Down Expand Up @@ -705,6 +705,8 @@ impl<'a> CodeGenerator for Vtable<'a> {
_whitelisted_items: &ItemSet,
item: &Item) {
assert_eq!(item.id(), self.item_id);
debug_assert!(item.is_enabled_for_codegen(ctx));

// For now, generate an empty struct, later we should generate function
// pointers and whatnot.
let attributes = vec![attributes::repr("C")];
Expand Down Expand Up @@ -745,6 +747,8 @@ impl CodeGenerator for TemplateInstantiation {
result: &mut CodegenResult<'a>,
_whitelisted_items: &ItemSet,
item: &Item) {
debug_assert!(item.is_enabled_for_codegen(ctx));

// Although uses of instantiations don't need code generation, and are
// just converted to rust types in fields, vars, etc, we take this
// opportunity to generate tests for their layout here. If the
Expand Down Expand Up @@ -1376,6 +1380,7 @@ impl CodeGenerator for CompInfo {
whitelisted_items: &ItemSet,
item: &Item) {
debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item);
debug_assert!(item.is_enabled_for_codegen(ctx));

// Don't output classes with template parameters that aren't types, and
// also don't output template specializations, neither total or partial.
Expand Down Expand Up @@ -1897,6 +1902,18 @@ impl MethodCodegen for Method {
result: &mut CodegenResult<'a>,
whitelisted_items: &ItemSet,
_parent: &CompInfo) {
assert!({
let cc = &ctx.options().codegen_config;
match self.kind() {
MethodKind::Constructor => cc.constructors,
MethodKind::Destructor => cc.destructors,
MethodKind::VirtualDestructor => cc.destructors,
MethodKind::Static |
MethodKind::Normal |
MethodKind::Virtual => cc.methods,
}
});

if self.is_virtual() {
return; // FIXME
}
Expand Down Expand Up @@ -2287,6 +2304,7 @@ impl CodeGenerator for Enum {
_whitelisted_items: &ItemSet,
item: &Item) {
debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item);
debug_assert!(item.is_enabled_for_codegen(ctx));

let name = item.canonical_name(ctx);
let enum_ty = item.expect_type();
Expand Down Expand Up @@ -3026,6 +3044,7 @@ impl CodeGenerator for Function {
_whitelisted_items: &ItemSet,
item: &Item) {
debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
debug_assert!(item.is_enabled_for_codegen(ctx));

// Similar to static member variables in a class template, we can't
// generate bindings to template functions, because the set of
Expand Down Expand Up @@ -3202,7 +3221,9 @@ impl CodeGenerator for ObjCInterface {
ctx: &BindgenContext,
result: &mut CodegenResult<'a>,
_whitelisted_items: &ItemSet,
_: &Item) {
item: &Item) {
debug_assert!(item.is_enabled_for_codegen(ctx));

let mut impl_items = vec![];
let mut trait_items = vec![];

Expand Down
1 change: 1 addition & 0 deletions src/ir/cant_derive_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl<'ctx, 'gen> CantDeriveDebugAnalysis<'ctx, 'gen> {
EdgeKind::TemplateParameterDefinition => true,

EdgeKind::Constructor |
EdgeKind::Destructor |
EdgeKind::FunctionReturn |
EdgeKind::FunctionParameter |
EdgeKind::InnerType |
Expand Down
6 changes: 5 additions & 1 deletion src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1534,7 +1534,11 @@ impl Trace for CompInfo {
}

for method in self.methods() {
tracer.visit_kind(method.signature, EdgeKind::Method);
if method.is_destructor() {
tracer.visit_kind(method.signature, EdgeKind::Destructor);
} else {
tracer.visit_kind(method.signature, EdgeKind::Method);
}
}

for &ctor in self.constructors() {
Expand Down
6 changes: 4 additions & 2 deletions src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ pub struct WhitelistedItems<'ctx, 'gen>
'gen,
ItemSet,
Vec<ItemId>,
fn(Edge) -> bool>,
for<'a> fn(&'a BindgenContext, Edge) -> bool>,
}

impl<'ctx, 'gen> Iterator for WhitelistedItems<'ctx, 'gen>
Expand Down Expand Up @@ -215,7 +215,7 @@ impl<'ctx, 'gen> WhitelistedItems<'ctx, 'gen>
where R: IntoIterator<Item = ItemId>,
{
let predicate = if ctx.options().whitelist_recursively {
traversal::all_edges
traversal::codegen_edges
} else {
traversal::no_edges
};
Expand Down Expand Up @@ -1573,6 +1573,8 @@ impl<'ctx> BindgenContext<'ctx> {
assert!(self.current_module == self.root_module);

let roots = self.items()
// Only consider items that are enabled for codegen.
.filter(|&(_, item)| item.is_enabled_for_codegen(self))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(It may make sense to merge this with the filter below, your call)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of like having it separate, because the latter filter's function is pretty big, and its nice to just separate it out and not worry about it anymore.

.filter(|&(_, item)| {
// If nothing is explicitly whitelisted, then everything is fair
// game.
Expand Down
57 changes: 48 additions & 9 deletions src/ir/function.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
//! Intermediate representation for C/C++ functions and methods.

use super::comp::MethodKind;
use super::context::{BindgenContext, ItemId};
use super::dot::DotAttributes;
use super::item::Item;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
use clang;
use clang_sys::CXCallingConv;
use clang_sys::{self, CXCallingConv};
use ir::derive::CanTriviallyDeriveDebug;
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use std::io;
use syntax::abi;

/// What kind of a function are we looking at?
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FunctionKind {
/// A plain, free function.
Function,
/// A method of some kind.
Method(MethodKind),
}

impl FunctionKind {
fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
Some(match cursor.kind() {
clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
clang_sys::CXCursor_Constructor => FunctionKind::Method(MethodKind::Constructor),
clang_sys::CXCursor_Destructor => FunctionKind::Method(MethodKind::Destructor),
clang_sys::CXCursor_CXXMethod => {
if cursor.method_is_virtual() {
FunctionKind::Method(MethodKind::Virtual)
} else if cursor.method_is_static() {
FunctionKind::Method(MethodKind::Static)
} else {
FunctionKind::Method(MethodKind::Normal)
}
}
_ => return None,
})
}
}

/// A function declaration, with a signature, arguments, and argument names.
///
/// The argument names vector must be the same length as the ones in the
Expand All @@ -29,20 +59,25 @@ pub struct Function {

/// The doc comment on the function, if any.
comment: Option<String>,

/// The kind of function this is.
kind: FunctionKind,
}

impl Function {
/// Construct a new function.
pub fn new(name: String,
mangled_name: Option<String>,
sig: ItemId,
comment: Option<String>)
comment: Option<String>,
kind: FunctionKind)
-> Self {
Function {
name: name,
mangled_name: mangled_name,
signature: sig,
comment: comment,
kind: kind,
}
}

Expand All @@ -60,6 +95,11 @@ impl Function {
pub fn signature(&self) -> ItemId {
self.signature
}

/// Get this function's kind.
pub fn kind(&self) -> FunctionKind {
self.kind
}
}

impl DotAttributes for Function {
Expand All @@ -70,6 +110,7 @@ impl DotAttributes for Function {
where W: io::Write,
{
if let Some(ref mangled) = self.mangled_name {
let mangled: String = mangled.chars().flat_map(|c| c.escape_default()).collect();
try!(writeln!(out,
"<tr><td>mangled name</td><td>{}</td></tr>",
mangled));
Expand Down Expand Up @@ -356,12 +397,10 @@ impl ClangSubItemParser for Function {
context: &mut BindgenContext)
-> Result<ParseResult<Self>, ParseError> {
use clang_sys::*;
match cursor.kind() {
CXCursor_FunctionDecl |
CXCursor_Constructor |
CXCursor_Destructor |
CXCursor_CXXMethod => {}
_ => return Err(ParseError::Continue),

let kind = match FunctionKind::from_cursor(&cursor) {
None => return Err(ParseError::Continue),
Some(k) => k,
};

debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
Expand Down Expand Up @@ -414,7 +453,7 @@ impl ClangSubItemParser for Function {

let comment = cursor.raw_comment();

let function = Self::new(name, mangled_name, sig, comment);
let function = Self::new(name, mangled_name, sig, comment, kind);
Ok(ParseResult::New(function, Some(cursor)))
}
}
Expand Down
24 changes: 23 additions & 1 deletion src/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
use super::super::codegen::CONSTIFIED_ENUM_MODULE_REPR_NAME;
use super::annotations::Annotations;
use super::comment;
use super::comp::MethodKind;
use super::context::{BindgenContext, ItemId, PartialType};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::dot::DotAttributes;
use super::function::Function;
use super::function::{Function, FunctionKind};
use super::item_kind::ItemKind;
use super::layout::Opaque;
use super::module::Module;
Expand Down Expand Up @@ -874,6 +875,27 @@ impl Item {
_ => false,
}
}

/// Is this item of a kind that is enabled for code generation?
pub fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool {
let cc = &ctx.options().codegen_config;
match *self.kind() {
ItemKind::Module(..) => true,
ItemKind::Var(_) => cc.vars,
ItemKind::Type(_) => cc.types,
ItemKind::Function(ref f) => {
match f.kind() {
FunctionKind::Function => cc.functions,
FunctionKind::Method(MethodKind::Constructor) => cc.constructors,
FunctionKind::Method(MethodKind::Destructor) |
FunctionKind::Method(MethodKind::VirtualDestructor) => cc.destructors,
FunctionKind::Method(MethodKind::Static) |
FunctionKind::Method(MethodKind::Normal) |
FunctionKind::Method(MethodKind::Virtual) => cc.methods,
}
}
}
}
}

impl IsOpaque for ItemId {
Expand Down
1 change: 1 addition & 0 deletions src/ir/named.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> {
EdgeKind::BaseMember |
EdgeKind::Field |
EdgeKind::Constructor |
EdgeKind::Destructor |
EdgeKind::VarType |
EdgeKind::FunctionReturn |
EdgeKind::FunctionParameter |
Expand Down
Loading