Skip to content

Commit

Permalink
Add --allowlist-file option
Browse files Browse the repository at this point in the history
  • Loading branch information
daviddrysdale authored and emilio committed Feb 18, 2022
1 parent ddfa28f commit e180d14
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 1 deletion.
2 changes: 2 additions & 0 deletions book/src/allowlisting.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ transitively used by a definition that matches them.
* [`bindgen::Builder::allowlist_type`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.allowlist_type)
* [`bindgen::Builder::allowlist_function`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.allowlist_function)
* [`bindgen::Builder::allowlist_var`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.allowlist_var)
* [`bindgen::Builder::allowlist_file`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.allowlist_file)

### Command Line

* `--allowlist-type <type>`
* `--allowlist-function <function>`
* `--allowlist-var <var>`
* `--allowlist-file <path>`

### Annotations

Expand Down
20 changes: 19 additions & 1 deletion src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2296,7 +2296,8 @@ If you encounter an error missing from this list, please file an issue or a PR!"
// game.
if self.options().allowlisted_types.is_empty() &&
self.options().allowlisted_functions.is_empty() &&
self.options().allowlisted_vars.is_empty()
self.options().allowlisted_vars.is_empty() &&
self.options().allowlisted_files.is_empty()
{
return true;
}
Expand All @@ -2307,6 +2308,23 @@ If you encounter an error missing from this list, please file an issue or a PR!"
return true;
}

// Items with a source location in an explicitly allowlisted file
// are always included.
if !self.options().allowlisted_files.is_empty() {
if let Some(location) = item.location() {
let (file, _, _, _) = location.location();
if let Some(filename) = file.name() {
if self
.options()
.allowlisted_files
.matches(&filename)
{
return true;
}
}
}
}

let name = item.path_for_allowlisting(self)[1..].join("::");
debug!("allowlisted_items: testing {:?}", name);
match *item.kind() {
Expand Down
5 changes: 5 additions & 0 deletions src/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,11 @@ impl Item {
&mut self.kind
}

/// Where in the source is this item located?
pub fn location(&self) -> Option<&clang::SourceLocation> {
self.location.as_ref()
}

/// Get an identifier that differentiates this item from its siblings.
///
/// This should stay relatively stable in the face of code motion outside or
Expand Down
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ impl Builder {
(&self.options.allowlisted_functions, "--allowlist-function"),
(&self.options.allowlisted_types, "--allowlist-type"),
(&self.options.allowlisted_vars, "--allowlist-var"),
(&self.options.allowlisted_files, "--allowlist-file"),
(&self.options.no_partialeq_types, "--no-partialeq"),
(&self.options.no_copy_types, "--no-copy"),
(&self.options.no_debug_types, "--no-debug"),
Expand Down Expand Up @@ -908,6 +909,12 @@ impl Builder {
self
}

/// Allowlist the given file so that its contents appear in the generated bindings.
pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.allowlisted_files.insert(arg);
self
}

/// Deprecated: use allowlist_var instead.
#[deprecated(note = "use allowlist_var instead")]
pub fn whitelist_var<T: AsRef<str>>(self, arg: T) -> Builder {
Expand Down Expand Up @@ -1705,6 +1712,9 @@ struct BindgenOptions {
/// Allowlisted variables. See docs for `allowlisted_types` for more.
allowlisted_vars: RegexSet,

/// The set of files whose contents should be allowlisted.
allowlisted_files: RegexSet,

/// The default style of code to generate for enums
default_enum_style: codegen::EnumVariation,

Expand Down Expand Up @@ -1984,6 +1994,7 @@ impl BindgenOptions {
&mut self.allowlisted_vars,
&mut self.allowlisted_types,
&mut self.allowlisted_functions,
&mut self.allowlisted_files,
&mut self.blocklisted_types,
&mut self.blocklisted_functions,
&mut self.blocklisted_items,
Expand Down Expand Up @@ -2042,6 +2053,7 @@ impl Default for BindgenOptions {
allowlisted_types: Default::default(),
allowlisted_functions: Default::default(),
allowlisted_vars: Default::default(),
allowlisted_files: Default::default(),
default_enum_style: Default::default(),
bitfield_enums: Default::default(),
newtype_enums: Default::default(),
Expand Down
14 changes: 14 additions & 0 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,14 @@ where
.takes_value(true)
.multiple_occurrences(true)
.number_of_values(1),
Arg::new("allowlist-file")
.alias("allowlist-file")
.long("allowlist-file")
.help("Allowlist all contents of <path>.")
.value_name("path")
.takes_value(true)
.multiple_occurrences(true)
.number_of_values(1),
Arg::new("verbose")
.long("verbose")
.help("Print verbose error messages."),
Expand Down Expand Up @@ -871,6 +879,12 @@ where
}
}

if let Some(hidden_files) = matches.values_of("allowlist-file") {
for file in hidden_files {
builder = builder.allowlist_file(file);
}
}

if let Some(args) = matches.values_of("clang-args") {
for arg in args {
builder = builder.clang_arg(arg);
Expand Down
154 changes: 154 additions & 0 deletions tests/expectations/tests/allowlist-file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]

pub const SOME_DEFUN: u32 = 123;
extern "C" {
#[link_name = "\u{1}_Z12SomeFunctionv"]
pub fn SomeFunction();
}
extern "C" {
pub static mut someVar: ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct someClass {
pub _address: u8,
}
#[test]
fn bindgen_test_layout_someClass() {
assert_eq!(
::std::mem::size_of::<someClass>(),
1usize,
concat!("Size of: ", stringify!(someClass))
);
assert_eq!(
::std::mem::align_of::<someClass>(),
1usize,
concat!("Alignment of ", stringify!(someClass))
);
}
extern "C" {
#[link_name = "\u{1}_ZN9someClass16somePublicMethodEi"]
pub fn someClass_somePublicMethod(
this: *mut someClass,
foo: ::std::os::raw::c_int,
);
}
impl someClass {
#[inline]
pub unsafe fn somePublicMethod(&mut self, foo: ::std::os::raw::c_int) {
someClass_somePublicMethod(self, foo)
}
}
extern "C" {
pub fn ExternFunction();
}
extern "C" {
#[link_name = "\u{1}_ZN3foo18NamespacedFunctionEv"]
pub fn foo_NamespacedFunction();
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct StructWithAllowlistedDefinition {
pub other: *mut StructWithAllowlistedFwdDecl,
}
#[test]
fn bindgen_test_layout_StructWithAllowlistedDefinition() {
assert_eq!(
::std::mem::size_of::<StructWithAllowlistedDefinition>(),
8usize,
concat!("Size of: ", stringify!(StructWithAllowlistedDefinition))
);
assert_eq!(
::std::mem::align_of::<StructWithAllowlistedDefinition>(),
8usize,
concat!("Alignment of ", stringify!(StructWithAllowlistedDefinition))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<StructWithAllowlistedDefinition>())).other
as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(StructWithAllowlistedDefinition),
"::",
stringify!(other)
)
);
}
impl Default for StructWithAllowlistedDefinition {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct StructWithAllowlistedFwdDecl {
pub b: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_StructWithAllowlistedFwdDecl() {
assert_eq!(
::std::mem::size_of::<StructWithAllowlistedFwdDecl>(),
4usize,
concat!("Size of: ", stringify!(StructWithAllowlistedFwdDecl))
);
assert_eq!(
::std::mem::align_of::<StructWithAllowlistedFwdDecl>(),
4usize,
concat!("Alignment of ", stringify!(StructWithAllowlistedFwdDecl))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<StructWithAllowlistedFwdDecl>())).b
as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(StructWithAllowlistedFwdDecl),
"::",
stringify!(b)
)
);
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct AllowlistMe {
pub foo: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_AllowlistMe() {
assert_eq!(
::std::mem::size_of::<AllowlistMe>(),
4usize,
concat!("Size of: ", stringify!(AllowlistMe))
);
assert_eq!(
::std::mem::align_of::<AllowlistMe>(),
4usize,
concat!("Alignment of ", stringify!(AllowlistMe))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<AllowlistMe>())).foo as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(AllowlistMe),
"::",
stringify!(foo)
)
);
}
21 changes: 21 additions & 0 deletions tests/headers/allowlist-file.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// bindgen-flags: --allowlist-file ".*/allowlisted/file.*" --allowlist-type AllowlistMe -- -Itests/headers


// Forward declaration of struct that's defined in an allowlisted file.
struct StructWithAllowlistedDefinition;

#include "allowlisted/file.hpp"

// Actual definition of struct that has a forward declaration in an allowlisted file.
struct StructWithAllowlistedFwdDecl {
int b;
};

class Ignored {
char c;
};

// Also have an explicitly allowlisted type
class AllowlistMe {
int foo;
};
22 changes: 22 additions & 0 deletions tests/headers/allowlisted/file.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
void SomeFunction();
extern int someVar;
#define SOME_DEFUN 123

class someClass {
void somePrivateMethod();
public:
void somePublicMethod(int foo);
};

extern "C" void ExternFunction();

namespace foo {
void NamespacedFunction();
}


struct StructWithAllowlistedFwdDecl;

struct StructWithAllowlistedDefinition {
StructWithAllowlistedFwdDecl* other;
};

0 comments on commit e180d14

Please sign in to comment.