Skip to content

Commit a5e9153

Browse files
committed
Add a method for iterating over whitelisted items
This commit adds the `BindgenContext::whitelisted_items` method and `WhitelistedItemsIter` iterator. Together, they can be used to iterate over whielisted items' transitive closure.
1 parent ba2fb4f commit a5e9153

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

src/ir/context.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::item::{Item, ItemCanonicalName, ItemId};
55
use super::item_kind::ItemKind;
66
use super::int::IntKind;
77
use super::module::Module;
8+
use super::type_collector::{ItemSet, TypeCollector};
89
use clang::{self, Cursor};
910
use std::borrow::{Cow, Borrow};
1011
use std::collections::btree_map::{self, BTreeMap};
@@ -772,4 +773,108 @@ impl<'ctx> BindgenContext<'ctx> {
772773

773774
self.current_module = previous_id;
774775
}
776+
777+
/// Iterate over all (explicitly or transitively) whitelisted items.
778+
///
779+
/// If no items are explicitly whitelisted, then all items are considered
780+
/// whitelisted.
781+
pub fn whitelisted_items<'me>(&'me self) -> WhitelistedItemsIter<'me, 'ctx> {
782+
assert!(self.in_codegen_phase());
783+
assert!(self.current_module == self.root_module);
784+
785+
let roots = self.items()
786+
.filter(|&(_, item)| {
787+
// If nothing is explicitly whitelisted, then everything is fair
788+
// game.
789+
if self.options().whitelisted_types.is_empty() &&
790+
self.options().whitelisted_functions.is_empty() &&
791+
self.options().whitelisted_vars.is_empty() {
792+
return true;
793+
}
794+
795+
let name = item.canonical_name(self);
796+
match *item.kind() {
797+
ItemKind::Module(..) => false,
798+
ItemKind::Function(_) => self.options().whitelisted_functions.matches(&name),
799+
ItemKind::Var(_) => self.options().whitelisted_vars.matches(&name),
800+
ItemKind::Type(ref ty) => {
801+
if self.options().whitelisted_types.matches(&name) {
802+
return true;
803+
}
804+
805+
// Unnamed top-level enums are special and we whitelist
806+
// them via the `whitelisted_vars` filter, since they're
807+
// effectively top-level constants, and there's no way
808+
// for them to be referenced consistently.
809+
if let TypeKind::Enum(ref enum_) = *ty.kind() {
810+
if ty.name().is_none() &&
811+
enum_.variants().iter().any(|variant| {
812+
self.options().whitelisted_vars.matches(&variant.name())
813+
}) {
814+
return true;
815+
}
816+
}
817+
818+
false
819+
}
820+
}
821+
})
822+
.map(|(&id, _)| id);
823+
824+
let seen: ItemSet = roots.collect();
825+
let to_iterate = seen.iter().cloned().collect();
826+
827+
WhitelistedItemsIter {
828+
ctx: self,
829+
seen: seen,
830+
to_iterate: to_iterate,
831+
}
832+
}
833+
}
834+
835+
/// An iterator over whitelisted items.
836+
///
837+
/// See `BindgenContext::whitelisted_items` for more information.
838+
pub struct WhitelistedItemsIter<'ctx, 'gen>
839+
where 'gen: 'ctx
840+
{
841+
ctx: &'ctx BindgenContext<'gen>,
842+
843+
// The set of whitelisted items we have seen. If you think of traversing
844+
// whitelisted items like GC tracing, this is the mark bits, and contains
845+
// both black and gray items.
846+
seen: ItemSet,
847+
848+
// The set of whitelisted items that we have seen but have yet to iterate
849+
// over and collect transitive references from. To return to the GC analogy,
850+
// this is the mark stack, containing the set of gray items which we have
851+
// not finished tracing yet.
852+
to_iterate: Vec<ItemId>,
853+
}
854+
855+
impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen>
856+
where 'gen: 'ctx
857+
{
858+
type Item = ItemId;
859+
860+
fn next(&mut self) -> Option<Self::Item> {
861+
let id = match self.to_iterate.pop() {
862+
None => return None,
863+
Some(id) => id,
864+
};
865+
866+
debug_assert!(self.seen.contains(&id));
867+
868+
let mut sub_types = ItemSet::new();
869+
id.collect_types(self.ctx, &mut sub_types, &());
870+
871+
for id in sub_types {
872+
if !self.seen.contains(&id) {
873+
self.to_iterate.push(id);
874+
self.seen.insert(id);
875+
}
876+
}
877+
878+
return Some(id);
879+
}
775880
}

0 commit comments

Comments
 (0)