Skip to content

Add ParseCallbacks::allow_item() and ParseCallbacks::block_item(). #3245

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
48 changes: 48 additions & 0 deletions bindgen-tests/tests/expectations/tests/allow-item-callback.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions bindgen-tests/tests/expectations/tests/block-item-callback.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions bindgen-tests/tests/headers/allow-item-callback.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// bindgen-parse-callbacks: allow-item

struct allowed_my_struct {
int a;
};

union allowed_my_union {
int a;
double b;
};

enum allowed_my_enum {
ALLOWED_MY_ENUM_A,
ALLOWED_MY_ENUM_B,
};

static const int allowed_my_const = 10;

struct non_allowed_my_struct {
int a;
};

union non_allowed_my_union {
int a;
double b;
};

enum non_allowed_my_enum {
NON_ALLOWED_MY_ENUM_A,
NON_ALLOWED_MY_ENUM_B,
};

static const int non_allowed_my_const = 10;
33 changes: 33 additions & 0 deletions bindgen-tests/tests/headers/block-item-callback.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// bindgen-parse-callbacks: block-item

struct blocked_my_struct {
int a;
};

union blocked_my_union {
int a;
double b;
};

enum blocked_my_enum {
BLOCKED_MY_ENUM_A,
BLOCKED_MY_ENUM_B,
};

static const int blocked_my_const = 10;

struct non_blocked_my_struct {
int a;
};

union non_blocked_my_union {
int a;
double b;
};

enum non_blocked_my_enum {
NON_BLOCKED_MY_ENUM_A,
NON_BLOCKED_MY_ENUM_B,
};

static const int non_blocked_my_const = 10;
20 changes: 20 additions & 0 deletions bindgen-tests/tests/parse_callbacks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,24 @@ impl ParseCallbacks for OperatorRename {
}
}

#[derive(Debug)]
struct AllowItem;

impl ParseCallbacks for AllowItem {
fn allow_item(&self, item: ItemInfo) -> bool {
item.name.starts_with("allowed_")
}
}

#[derive(Debug)]
struct BlockItem;

impl ParseCallbacks for BlockItem {
fn block_item(&self, item: ItemInfo) -> bool {
item.name.starts_with("blocked_")
}
}

pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
match cb {
"enum-variant-rename" => Box::new(EnumVariantRename),
Expand All @@ -168,6 +186,8 @@ pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
"wrap-as-variadic-fn" => Box::new(WrapAsVariadicFn),
"type-visibility" => Box::new(TypeVisibility),
"operator-rename" => Box::new(OperatorRename),
"allow-item" => Box::new(AllowItem),
"block-item" => Box::new(BlockItem),
call_back => {
if let Some(prefix) =
call_back.strip_prefix("remove-function-prefix-")
Expand Down
18 changes: 18 additions & 0 deletions bindgen/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@ pub trait ParseCallbacks: fmt::Debug {
/// This will get called everytime an item (currently struct, union, and alias) is found with some information about it
fn new_item_found(&self, _id: DiscoveredItemId, _item: DiscoveredItem) {}

/// Generate bindings for the given item.
///
/// This method is called after processing the `allowlist_*` options.
///
/// The default implementation is to allow the given item.
fn allow_item(&self, _item: ItemInfo) -> bool {
true
}

/// Block bindings for the given item.
///
/// This method is called after processing the `blocklist_*` options.
///
/// The default implementation is to not block the given item.
fn block_item(&self, _item: ItemInfo) -> bool {
false
}

// TODO add callback for ResolvedTypeRef
}

Expand Down
20 changes: 17 additions & 3 deletions bindgen/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use super::BindgenOptions;

use crate::callbacks::{
AttributeInfo, DeriveInfo, DiscoveredItem, DiscoveredItemId, FieldInfo,
TypeKind as DeriveTypeKind,
ItemInfo, ItemKind as CallbackItemKind, TypeKind as DeriveTypeKind,
};
use crate::codegen::error::Error;
use crate::ir::analysis::{HasVtable, Sizedness};
Expand Down Expand Up @@ -4942,7 +4942,14 @@ fn objc_method_codegen(
// Item::process_before_codegen; however, ObjC methods are not currently
// made into function items.
let name = format!("{rust_class_name}::{prefix}{}", method.rust_name());
if ctx.options().blocklisted_items.matches(name) {
let item_info = ItemInfo {
name: &name,
kind: CallbackItemKind::Function,
};
if ctx.options().blocklisted_items.matches(&name) ||
ctx.options()
.for_any_callback(|cb| cb.block_item(item_info))
{
return;
}

Expand Down Expand Up @@ -5259,6 +5266,7 @@ pub(crate) mod utils {
use super::helpers::BITFIELD_UNIT;
use super::serialize::CSerialize;
use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
use crate::callbacks::{ItemInfo, ItemKind as CallbackItemKind};
use crate::ir::context::BindgenContext;
use crate::ir::context::TypeId;
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
Expand Down Expand Up @@ -5389,8 +5397,14 @@ pub(crate) mod utils {
ctx: &BindgenContext,
result: &mut Vec<proc_macro2::TokenStream>,
) {
let item_info = ItemInfo {
name: BITFIELD_UNIT,
kind: CallbackItemKind::Type,
};
if ctx.options().blocklisted_items.matches(BITFIELD_UNIT) ||
ctx.options().blocklisted_types.matches(BITFIELD_UNIT)
ctx.options().blocklisted_types.matches(BITFIELD_UNIT) ||
ctx.options()
.for_any_callback(|cb| cb.block_item(item_info))
{
return;
}
Expand Down
9 changes: 9 additions & 0 deletions bindgen/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, Type, TypeKind};
use crate::clang::{self, ABIKind, Cursor};
use crate::codegen::CodegenError;
use crate::ir::item::ItemCanonicalName;
use crate::BindgenOptions;
use crate::{Entry, HashMap, HashSet};

Expand Down Expand Up @@ -2519,6 +2520,14 @@ If you encounter an error missing from this list, please file an issue or a PR!"
}
}
})
.filter(|&(_, item)| {
let item_info = crate::callbacks::ItemInfo {
name: &item.canonical_name(self),
kind: item.callback_item_kind(),
};
self.options()
.for_all_callbacks(|cb| cb.allow_item(item_info))
})
.map(|(id, _)| id)
.collect::<Vec<_>>();

Expand Down
27 changes: 18 additions & 9 deletions bindgen/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,10 @@ impl Item {

let path = self.path_for_allowlisting(ctx);
let name = path[1..].join("::");
let item_info = ItemInfo {
name: &name,
kind: self.callback_item_kind(),
};
ctx.options().blocklisted_items.matches(&name) ||
match self.kind {
ItemKind::Type(..) => {
Expand All @@ -667,7 +671,9 @@ impl Item {
}
// TODO: Add namespace blocklisting?
ItemKind::Module(..) => false,
}
} ||
ctx.options()
.for_any_callback(|cb| cb.block_item(item_info))
}

/// Take out item `NameOptions`
Expand Down Expand Up @@ -818,6 +824,16 @@ impl Item {
}
}

/// Get the callback item kind of this item.
pub(crate) fn callback_item_kind(&self) -> crate::callbacks::ItemKind {
match self.kind() {
ItemKind::Module(..) => crate::callbacks::ItemKind::Module,
ItemKind::Type(..) => crate::callbacks::ItemKind::Type,
ItemKind::Function(..) => crate::callbacks::ItemKind::Function,
ItemKind::Var(..) => crate::callbacks::ItemKind::Var,
}
}

/// Get the canonical name without taking into account the replaces
/// annotation.
///
Expand Down Expand Up @@ -925,14 +941,7 @@ impl Item {
let name = if opt.user_mangled == UserMangled::Yes {
let item_info = ItemInfo {
name: &name,
kind: match self.kind() {
ItemKind::Module(..) => crate::callbacks::ItemKind::Module,
ItemKind::Type(..) => crate::callbacks::ItemKind::Type,
ItemKind::Function(..) => {
crate::callbacks::ItemKind::Function
}
ItemKind::Var(..) => crate::callbacks::ItemKind::Var,
},
kind: self.callback_item_kind(),
};
ctx.options()
.last_callback(|callbacks| callbacks.item_name(item_info))
Expand Down
14 changes: 14 additions & 0 deletions bindgen/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,20 @@ impl BindgenOptions {
self.parse_callbacks.iter().for_each(|cb| f(cb.as_ref()));
}

fn for_all_callbacks(
&self,
f: impl Fn(&dyn callbacks::ParseCallbacks) -> bool,
) -> bool {
self.parse_callbacks.iter().all(|cb| f(cb.as_ref()))
}

fn for_any_callback(
&self,
f: impl Fn(&dyn callbacks::ParseCallbacks) -> bool,
) -> bool {
self.parse_callbacks.iter().any(|cb| f(cb.as_ref()))
}

fn process_comment(&self, comment: &str) -> String {
let comment = comment::preprocess(comment);
self.last_callback(|cb| cb.process_comment(&comment))
Expand Down