From 6bb16ba6971601ffe277830344552ba71e431b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 23 Dec 2018 18:45:27 +0100 Subject: [PATCH 1/3] regex_set: Derive Default instead of manually implementing it. --- src/regex_set.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/regex_set.rs b/src/regex_set.rs index d26e95c92d..3e77e0644e 100644 --- a/src/regex_set.rs +++ b/src/regex_set.rs @@ -4,7 +4,7 @@ use regex::RegexSet as RxSet; use std::cell::Cell; /// A dynamic set of regular expressions. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct RegexSet { items: Vec, matched: Vec>, @@ -76,13 +76,3 @@ impl RegexSet { false } } - -impl Default for RegexSet { - fn default() -> Self { - RegexSet { - items: vec![], - matched: vec![], - set: None, - } - } -} From eb85a2ba79a1a9e562e08d0cd6dd0c9e55d6f05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 23 Dec 2018 18:47:04 +0100 Subject: [PATCH 2/3] regex_set: Avoid allocations in unmatched_items(). --- src/regex_set.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/regex_set.rs b/src/regex_set.rs index 3e77e0644e..a0b34bb60d 100644 --- a/src/regex_set.rs +++ b/src/regex_set.rs @@ -32,15 +32,16 @@ impl RegexSet { &self.items[..] } - /// Returns regexes in the set which didn't match any strings yet - pub fn unmatched_items(&self) -> Vec { - let mut items = vec![]; - for (i, item) in self.items.iter().enumerate() { - if !self.matched[i].get() { - items.push(item.clone()); + /// Returns an iterator over regexes in the set which didn't match any + /// strings yet. + pub fn unmatched_items(&self) -> impl Iterator { + self.items.iter().enumerate().filter_map(move |(i, item)| { + if self.matched[i].get() { + return None; } - } - items + + Some(item) + }) } /// Construct a RegexSet from the set of entries we've accumulated. From 3923851bd1faea0f801bef1363ceebb07d23e1e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 23 Dec 2018 18:52:08 +0100 Subject: [PATCH 3/3] Allow to turn off the matches recording introduced in #1469. --- src/lib.rs | 51 +++++++++++++++++++++++++++++++++++------------- src/options.rs | 8 ++++++++ src/regex_set.rs | 35 ++++++++++++++++++++++----------- 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 637dcbfc4c..a906d4afee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -509,6 +509,10 @@ impl Builder { ); } + if !self.options.record_matches { + output_vector.push("--no-record-matches".into()); + } + if !self.options.rustfmt_bindings { output_vector.push("--no-rustfmt-bindings".into()); } @@ -1137,6 +1141,12 @@ impl Builder { self } + /// Set whether we should record matched items in our regex sets. + pub fn record_matches(mut self, doit: bool) -> Self { + self.options.record_matches = doit; + self + } + /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt /// options are used. pub fn rustfmt_configuration_file(mut self, path: Option) -> Self { @@ -1486,6 +1496,12 @@ struct BindgenOptions { /// Features to enable, derived from `rust_target` rust_features: RustFeatures, + /// Whether we should record which items in the regex sets ever matched. + /// + /// This may be a bit slower, but will enable reporting of unused whitelist + /// items via the `error!` log. + record_matches: bool, + /// Whether rustfmt should format the generated bindings. rustfmt_bindings: bool, @@ -1511,20 +1527,26 @@ impl ::std::panic::UnwindSafe for BindgenOptions {} impl BindgenOptions { fn build(&mut self) { - self.whitelisted_vars.build(); - self.whitelisted_types.build(); - self.whitelisted_functions.build(); - self.blacklisted_types.build(); - self.blacklisted_functions.build(); - self.blacklisted_items.build(); - self.opaque_types.build(); - self.bitfield_enums.build(); - self.constified_enums.build(); - self.constified_enum_modules.build(); - self.rustified_enums.build(); - self.no_partialeq_types.build(); - self.no_copy_types.build(); - self.no_hash_types.build(); + let mut regex_sets = [ + &mut self.whitelisted_vars, + &mut self.whitelisted_types, + &mut self.whitelisted_functions, + &mut self.blacklisted_types, + &mut self.blacklisted_functions, + &mut self.blacklisted_items, + &mut self.opaque_types, + &mut self.bitfield_enums, + &mut self.constified_enums, + &mut self.constified_enum_modules, + &mut self.rustified_enums, + &mut self.no_partialeq_types, + &mut self.no_copy_types, + &mut self.no_hash_types, + ]; + let record_matches = self.record_matches; + for regex_set in &mut regex_sets { + regex_set.build(record_matches); + } } /// Update rust target version @@ -1601,6 +1623,7 @@ impl Default for BindgenOptions { enable_mangling: true, prepend_enum_name: true, time_phases: false, + record_matches: true, rustfmt_bindings: true, rustfmt_configuration_file: None, no_partialeq_types: Default::default(), diff --git a/src/options.rs b/src/options.rs index 9d37543ac3..e9c1b0321a 100644 --- a/src/options.rs +++ b/src/options.rs @@ -277,6 +277,10 @@ where Useful when debugging bindgen, using C-Reduce, or when \ filing issues. The resulting file will be named \ something like `__bindgen.i` or `__bindgen.ii`."), + Arg::with_name("no-record-matches") + .long("no-record-matches") + .help("Do not record matching items in the regex sets. \ + This disables reporting of unused items."), Arg::with_name("no-rustfmt-bindings") .long("no-rustfmt-bindings") .help("Do not format the generated bindings with rustfmt."), @@ -591,6 +595,10 @@ where builder.dump_preprocessed_input()?; } + if matches.is_present("no-record-matches") { + builder = builder.record_matches(false); + } + let no_rustfmt_bindings = matches.is_present("no-rustfmt-bindings"); if no_rustfmt_bindings { builder = builder.rustfmt_bindings(false); diff --git a/src/regex_set.rs b/src/regex_set.rs index a0b34bb60d..4e82282457 100644 --- a/src/regex_set.rs +++ b/src/regex_set.rs @@ -7,8 +7,12 @@ use std::cell::Cell; #[derive(Debug, Default)] pub struct RegexSet { items: Vec, + /// Whether any of the items in the set was ever matched. The length of this + /// vector is exactly the length of `items`. matched: Vec>, set: Option, + /// Whether we should record matching items in the `matched` vector or not. + record_matches: bool, } impl RegexSet { @@ -36,7 +40,7 @@ impl RegexSet { /// strings yet. pub fn unmatched_items(&self) -> impl Iterator { self.items.iter().enumerate().filter_map(move |(i, item)| { - if self.matched[i].get() { + if !self.record_matches || self.matched[i].get() { return None; } @@ -48,8 +52,9 @@ impl RegexSet { /// /// Must be called before calling `matches()`, or it will always return /// false. - pub fn build(&mut self) { + pub fn build(&mut self, record_matches: bool) { let items = self.items.iter().map(|item| format!("^{}$", item)); + self.record_matches = record_matches; self.set = match RxSet::new(items) { Ok(x) => Some(x), Err(e) => { @@ -65,15 +70,23 @@ impl RegexSet { S: AsRef, { let s = string.as_ref(); - if let Some(set) = self.set.as_ref() { - let matches = set.matches(s); - if matches.matched_any() { - for i in matches.iter() { - self.matched[i].set(true); - } - return true; - } + let set = match self.set { + Some(ref set) => set, + None => return false, + }; + + if !self.record_matches { + return set.is_match(s); + } + + let matches = set.matches(s); + if !matches.matched_any() { + return false; + } + for i in matches.iter() { + self.matched[i].set(true); } - false + + true } }