usesuper::context::{BindgenContext, ItemId}; usesuper::item::ItemSet; use std::collections::{BTreeMap, VecDeque};
/// An outgoing edge in the IR graph is a reference from some item to another /// item: /// /// from --> to /// /// The `from` is left implicit: it is the concrete `Trace` implementer which /// yielded this outgoing edge. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) struct Edge {
to: ItemId,
kind: EdgeKind,
}
impl Edge { /// Construct a new edge whose referent is `to` and is of the given `kind`. pub(crate) fn new(to: ItemId, kind: EdgeKind) -> Edge {
Edge { to, kind }
}
}
/// The kind of edge reference. This is useful when we wish to only consider /// certain kinds of edges for a particular traversal or analysis. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum EdgeKind { /// A generic, catch-all edge.
Generic,
/// An edge from a template declaration, to the definition of a named type /// parameter. For example, the edge from `Foo<T>` to `T` in the following /// snippet: /// /// ```C++ /// template<typename T> /// class Foo { }; /// ```
TemplateParameterDefinition,
/// An edge from a template instantiation to the template declaration that /// is being instantiated. For example, the edge from `Foo<int>` to /// to `Foo<T>`: /// /// ```C++ /// template<typename T> /// class Foo { }; /// /// using Bar = Foo<ant>; /// ```
TemplateDeclaration,
/// An edge from a template instantiation to its template argument. For /// example, `Foo<Bar>` to `Bar`: /// /// ```C++ /// template<typename T> /// class Foo { }; /// /// class Bar { }; /// /// using FooBar = Foo<Bar>; /// ```
TemplateArgument,
/// An edge from a compound type to one of its base member types. For /// example, the edge from `Bar` to `Foo`: /// /// ```C++ /// class Foo { }; /// /// class Bar : public Foo { }; /// ```
BaseMember,
/// An edge from a compound type to the types of one of its fields. For /// example, the edge from `Foo` to `int`: /// /// ```C++ /// class Foo { /// int x; /// }; /// ```
Field,
/// An edge from an class or struct type to an inner type member. For /// example, the edge from `Foo` to `Foo::Bar` here: /// /// ```C++ /// class Foo { /// struct Bar { }; /// }; /// ```
InnerType,
/// An edge from an class or struct type to an inner static variable. For /// example, the edge from `Foo` to `Foo::BAR` here: /// /// ```C++ /// class Foo { /// static const char* BAR; /// }; /// ```
InnerVar,
/// An edge from a class or struct type to one of its method functions. For /// example, the edge from `Foo` to `Foo::bar`: /// /// ```C++ /// class Foo { /// bool bar(int x, int y); /// }; /// ```
Method,
/// An edge from a class or struct type to one of its constructor /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`: /// /// ```C++ /// class Foo { /// int my_x; /// int my_y; /// /// public: /// Foo(int x, int y); /// }; /// ```
Constructor,
/// An edge from a class or struct type to its destructor function. For /// example, the edge from `Doggo` to `Doggo::~Doggo()`: /// /// ```C++ /// struct Doggo { /// char* wow; /// /// public: /// ~Doggo(); /// }; /// ```
Destructor,
/// An edge from a function declaration to its return type. For example, the /// edge from `foo` to `int`: /// /// ```C++ /// int foo(char* string); /// ```
FunctionReturn,
/// An edge from a function declaration to one of its parameter types. For /// example, the edge from `foo` to `char*`: /// /// ```C++ /// int foo(char* string); /// ```
FunctionParameter,
/// An edge from a static variable to its type. For example, the edge from /// `FOO` to `const char*`: /// /// ```C++ /// static const char* FOO; /// ```
VarType,
/// An edge from a non-templated alias or typedef to the referenced type.
TypeReference,
}
/// A predicate to allow visiting only sub-sets of the whole IR graph by /// excluding certain edges from being followed by the traversal. /// /// The predicate must return true if the traversal should follow this edge /// and visit everything that is reachable through it. pub(crate) type TraversalPredicate = for<'a> fn(&'a BindgenContext, Edge) -> bool;
/// A `TraversalPredicate` implementation that follows all edges, and therefore /// traversals using this predicate will see the whole IR graph reachable from /// the traversal's roots. pub(crate) fn all_edges(_: &BindgenContext, _: Edge) -> bool { true
}
/// A `TraversalPredicate` implementation that only follows /// `EdgeKind::InnerType` edges, and therefore traversals using this predicate /// will only visit the traversal's roots and their inner types. This is used /// in no-recursive-allowlist mode, where inner types such as anonymous /// structs/unions still need to be processed. pub(crate) fn only_inner_type_edges(_: &BindgenContext, edge: Edge) -> bool {
edge.kind == EdgeKind::InnerType
}
/// A `TraversalPredicate` implementation that only follows edges to items that /// are enabled for code generation. This lets us skip considering items for /// which are not reachable from code generation. pub(crate) fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool { let cc = &ctx.options().codegen_config; match edge.kind {
EdgeKind::Generic => {
ctx.resolve_item(edge.to).is_enabled_for_codegen(ctx)
}
// We statically know the kind of item that non-generic edges can point // to, so we don't need to actually resolve the item and check // `Item::is_enabled_for_codegen`.
EdgeKind::TemplateParameterDefinition |
EdgeKind::TemplateArgument |
EdgeKind::TemplateDeclaration |
EdgeKind::BaseMember |
EdgeKind::Field |
EdgeKind::InnerType |
EdgeKind::FunctionReturn |
EdgeKind::FunctionParameter |
EdgeKind::VarType |
EdgeKind::TypeReference => cc.types(),
EdgeKind::InnerVar => cc.vars(),
EdgeKind::Method => cc.methods(),
EdgeKind::Constructor => cc.constructors(),
EdgeKind::Destructor => cc.destructors(),
}
}
/// The storage for the set of items that have been seen (although their /// outgoing edges might not have been fully traversed yet) in an active /// traversal. pub(crate) trait TraversalStorage<'ctx> { /// Construct a new instance of this TraversalStorage, for a new traversal. fn new(ctx: &'ctx BindgenContext) -> Self;
/// Add the given item to the storage. If the item has never been seen /// before, return `true`. Otherwise, return `false`. /// /// The `from` item is the item from which we discovered this item, or is /// `None` if this item is a root. fn add(&mutself, from: Option<ItemId>, item: ItemId) -> bool;
}
/// A `TraversalStorage` implementation that keeps track of how we first reached /// each item. This is useful for providing debug assertions with meaningful /// diagnostic messages about dangling items. #[derive(Debug)] pub(crate) struct Paths<'ctx>(BTreeMap<ItemId, ItemId>, &'ctx BindgenContext);
ifself.1.resolve_item_fallible(item).is_none() { letmut path = vec![]; letmut current = item; loop { let predecessor = *self.0.get(¤t).expect( "We know we found this item id, so it must have a \
predecessor",
); if predecessor == current { break;
}
path.push(predecessor);
current = predecessor;
}
path.reverse();
panic!( "Found reference to dangling id = {:?}\nvia path = {:?}",
item, path
);
}
newly_discovered
}
}
/// The queue of seen-but-not-yet-traversed items. /// /// Using a FIFO queue with a traversal will yield a breadth-first traversal, /// while using a LIFO queue will result in a depth-first traversal of the IR /// graph. pub(crate) trait TraversalQueue: Default { /// Add a newly discovered item to the queue. fn push(&mutself, item: ItemId);
/// Pop the next item to traverse, if any. fn next(&mutself) -> Option<ItemId>;
}
/// Something that can receive edges from a `Trace` implementation. pub(crate) trait Tracer { /// Note an edge between items. Called from within a `Trace` implementation. fn visit_kind(&mutself, item: ItemId, kind: EdgeKind);
/// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`. fn visit(&mutself, item: ItemId) { self.visit_kind(item, EdgeKind::Generic);
}
}
impl<F> Tracer for F where
F: FnMut(ItemId, EdgeKind),
{ fn visit_kind(&mutself, item: ItemId, kind: EdgeKind) {
(*self)(item, kind)
}
}
/// Trace all of the outgoing edges to other items. Implementations should call /// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` /// for each of their outgoing edges. pub(crate) trait Trace { /// If a particular type needs extra information beyond what it has in /// `self` and `context` to find its referenced items, its implementation /// can define this associated type, forcing callers to pass the needed /// information through. type Extra;
/// Trace all of this item's outgoing edges to other items. fn trace<T>(
&self,
context: &BindgenContext,
tracer: &mut T,
extra: &Self::Extra,
) where
T: Tracer;
}
/// An graph traversal of the transitive closure of references between items. /// /// See `BindgenContext::allowlisted_items` for more information. pub(crate) struct ItemTraversal<'ctx, Storage, Queue> where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
{
ctx: &'ctx BindgenContext,
/// The set of items we have seen thus far in this traversal.
seen: Storage,
/// The set of items that we have seen, but have yet to traverse.
queue: Queue,
/// The predicate that determines which edges this traversal will follow.
predicate: TraversalPredicate,
/// The item we are currently traversing.
currently_traversing: Option<ItemId>,
}
impl<'ctx, Storage, Queue> ItemTraversal<'ctx, Storage, Queue> where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
{ /// Begin a new traversal, starting from the given roots. pub(crate) fn new<R>(
ctx: &'ctx BindgenContext,
roots: R,
predicate: TraversalPredicate,
) -> ItemTraversal<'ctx, Storage, Queue> where
R: IntoIterator<Item = ItemId>,
{ letmut seen = Storage::new(ctx); letmut queue = Queue::default();
for id in roots {
seen.add(None, id);
queue.push(id);
}
impl<'ctx, Storage, Queue> Tracer for ItemTraversal<'ctx, Storage, Queue> where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
{ fn visit_kind(&mutself, item: ItemId, kind: EdgeKind) { let edge = Edge::new(item, kind); if !(self.predicate)(self.ctx, edge) { return;
}
let is_newly_discovered = self.seen.add(self.currently_traversing, item); if is_newly_discovered { self.queue.push(item)
}
}
}
impl<'ctx, Storage, Queue> Iterator for ItemTraversal<'ctx, Storage, Queue> where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
{ type Item = ItemId;
fn next(&mutself) -> Option<Self::Item> { let id = self.queue.next()?;
let newly_discovered = self.seen.add(None, id);
debug_assert!(
!newly_discovered, "should have already seen anything we get out of our queue"
);
debug_assert!( self.ctx.resolve_item_fallible(id).is_some(), "should only get IDs of actual items in our context during traversal"
);
/// An iterator to find any dangling items. /// /// See `BindgenContext::assert_no_dangling_item_traversal` for more /// information. pub(crate) type AssertNoDanglingItemsTraversal<'ctx> =
ItemTraversal<'ctx, Paths<'ctx>, VecDeque<ItemId>>;
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.