Skip to content

Commit fcc7b57

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 a22b762 commit fcc7b57

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

src/ir/context.rs

+116
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use super::item::{Item, ItemCanonicalName, ItemId};
1212
use super::item_kind::ItemKind;
1313
use super::module::Module;
1414
use super::ty::{FloatKind, Type, TypeKind};
15+
use super::type_collector::{ItemSet, TypeCollector};
1516
use syntax::ast::Ident;
1617
use syntax::codemap::{DUMMY_SP, Span};
1718
use syntax::ext::base::ExtCtxt;
@@ -814,4 +815,119 @@ impl<'ctx> BindgenContext<'ctx> {
814815

815816
self.current_module = previous_id;
816817
}
818+
819+
/// Iterate over all (explicitly or transitively) whitelisted items.
820+
///
821+
/// If no items are explicitly whitelisted, then all items are considered
822+
/// whitelisted.
823+
pub fn whitelisted_items<'me>(&'me self)
824+
-> WhitelistedItemsIter<'me, 'ctx> {
825+
assert!(self.in_codegen_phase());
826+
assert!(self.current_module == self.root_module);
827+
828+
let roots = self.items()
829+
.filter(|&(_, item)| {
830+
// If nothing is explicitly whitelisted, then everything is fair
831+
// game.
832+
if self.options().whitelisted_types.is_empty() &&
833+
self.options().whitelisted_functions.is_empty() &&
834+
self.options().whitelisted_vars.is_empty() {
835+
return true;
836+
}
837+
838+
let name = item.canonical_name(self);
839+
match *item.kind() {
840+
ItemKind::Module(..) => false,
841+
ItemKind::Function(_) => {
842+
self.options().whitelisted_functions.matches(&name)
843+
}
844+
ItemKind::Var(_) => {
845+
self.options().whitelisted_vars.matches(&name)
846+
}
847+
ItemKind::Type(ref ty) => {
848+
if self.options().whitelisted_types.matches(&name) {
849+
return true;
850+
}
851+
852+
// Unnamed top-level enums are special and we whitelist
853+
// them via the `whitelisted_vars` filter, since they're
854+
// effectively top-level constants, and there's no way
855+
// for them to be referenced consistently.
856+
if let TypeKind::Enum(ref enum_) = *ty.kind() {
857+
if ty.name().is_none() &&
858+
enum_.variants().iter().any(|variant| {
859+
self.options()
860+
.whitelisted_vars
861+
.matches(&variant.name())
862+
}) {
863+
return true;
864+
}
865+
}
866+
867+
false
868+
}
869+
}
870+
})
871+
.map(|(&id, _)| id);
872+
873+
let seen: ItemSet = roots.collect();
874+
875+
// The .rev() preserves the expected ordering traversal, resulting in
876+
// more stable-ish bindgen-generated names for anonymous types (like
877+
// unions).
878+
let to_iterate = seen.iter().cloned().rev().collect();
879+
880+
WhitelistedItemsIter {
881+
ctx: self,
882+
seen: seen,
883+
to_iterate: to_iterate,
884+
}
885+
}
886+
}
887+
888+
/// An iterator over whitelisted items.
889+
///
890+
/// See `BindgenContext::whitelisted_items` for more information.
891+
pub struct WhitelistedItemsIter<'ctx, 'gen>
892+
where 'gen: 'ctx,
893+
{
894+
ctx: &'ctx BindgenContext<'gen>,
895+
896+
// The set of whitelisted items we have seen. If you think of traversing
897+
// whitelisted items like GC tracing, this is the mark bits, and contains
898+
// both black and gray items.
899+
seen: ItemSet,
900+
901+
// The set of whitelisted items that we have seen but have yet to iterate
902+
// over and collect transitive references from. To return to the GC analogy,
903+
// this is the mark stack, containing the set of gray items which we have
904+
// not finished tracing yet.
905+
to_iterate: Vec<ItemId>,
906+
}
907+
908+
impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen>
909+
where 'gen: 'ctx,
910+
{
911+
type Item = ItemId;
912+
913+
fn next(&mut self) -> Option<Self::Item> {
914+
let id = match self.to_iterate.pop() {
915+
None => return None,
916+
Some(id) => id,
917+
};
918+
919+
debug_assert!(self.seen.contains(&id));
920+
921+
let mut sub_types = ItemSet::new();
922+
id.collect_types(self.ctx, &mut sub_types, &());
923+
924+
for id in sub_types {
925+
if !self.seen.contains(&id) {
926+
self.to_iterate.push(id);
927+
self.seen.insert(id);
928+
}
929+
}
930+
931+
Some(id)
932+
}
817933
}

0 commit comments

Comments
 (0)