summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen/ir/item.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/bindgen/ir/item.rs')
-rw-r--r--third_party/rust/bindgen/ir/item.rs2034
1 files changed, 2034 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/ir/item.rs b/third_party/rust/bindgen/ir/item.rs
new file mode 100644
index 0000000000..2941eb81e2
--- /dev/null
+++ b/third_party/rust/bindgen/ir/item.rs
@@ -0,0 +1,2034 @@
+//! Bindgen's core intermediate representation type.
+
+use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME};
+use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult};
+use super::annotations::Annotations;
+use super::comp::{CompKind, MethodKind};
+use super::context::{BindgenContext, ItemId, PartialType, TypeId};
+use super::derive::{
+ CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
+ CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
+};
+use super::dot::DotAttributes;
+use super::function::{Function, FunctionKind};
+use super::item_kind::ItemKind;
+use super::layout::Opaque;
+use super::module::Module;
+use super::template::{AsTemplateParam, TemplateParameters};
+use super::traversal::{EdgeKind, Trace, Tracer};
+use super::ty::{Type, TypeKind};
+use crate::clang;
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
+
+use lazycell::LazyCell;
+
+use std::cell::Cell;
+use std::collections::BTreeSet;
+use std::fmt::Write;
+use std::io;
+use std::iter;
+
+/// A trait to get the canonical name from an item.
+///
+/// This is the trait that will eventually isolate all the logic related to name
+/// mangling and that kind of stuff.
+///
+/// This assumes no nested paths, at some point I'll have to make it a more
+/// complex thing.
+///
+/// This name is required to be safe for Rust, that is, is not expected to
+/// return any rust keyword from here.
+pub(crate) trait ItemCanonicalName {
+ /// Get the canonical name for this item.
+ fn canonical_name(&self, ctx: &BindgenContext) -> String;
+}
+
+/// The same, but specifies the path that needs to be followed to reach an item.
+///
+/// To contrast with canonical_name, here's an example:
+///
+/// ```c++
+/// namespace foo {
+/// const BAR = 3;
+/// }
+/// ```
+///
+/// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical
+/// name is just `"BAR"`.
+pub(crate) trait ItemCanonicalPath {
+ /// Get the namespace-aware canonical path for this item. This means that if
+ /// namespaces are disabled, you'll get a single item, and otherwise you get
+ /// the whole path.
+ fn namespace_aware_canonical_path(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Vec<String>;
+
+ /// Get the canonical path for this item.
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>;
+}
+
+/// A trait for determining if some IR thing is opaque or not.
+pub(crate) trait IsOpaque {
+ /// Extra context the IR thing needs to determine if it is opaque or not.
+ type Extra;
+
+ /// Returns `true` if the thing is opaque, and `false` otherwise.
+ ///
+ /// May only be called when `ctx` is in the codegen phase.
+ fn is_opaque(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool;
+}
+
+/// A trait for determining if some IR thing has type parameter in array or not.
+pub(crate) trait HasTypeParamInArray {
+ /// Returns `true` if the thing has Array, and `false` otherwise.
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait for determining if some IR thing has float or not.
+pub(crate) trait HasFloat {
+ /// Returns `true` if the thing has float, and `false` otherwise.
+ fn has_float(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait for iterating over an item and its parents and up its ancestor chain
+/// up to (but not including) the implicit root module.
+pub(crate) trait ItemAncestors {
+ /// Get an iterable over this item's ancestors.
+ fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>;
+}
+
+#[cfg(feature = "__testing_only_extra_assertions")]
+type DebugOnlyItemSet = ItemSet;
+
+#[cfg(not(feature = "__testing_only_extra_assertions"))]
+struct DebugOnlyItemSet;
+
+#[cfg(not(feature = "__testing_only_extra_assertions"))]
+impl DebugOnlyItemSet {
+ fn new() -> Self {
+ DebugOnlyItemSet
+ }
+
+ fn contains(&self, _id: &ItemId) -> bool {
+ false
+ }
+
+ fn insert(&mut self, _id: ItemId) {}
+}
+
+/// An iterator over an item and its ancestors.
+pub(crate) struct ItemAncestorsIter<'a> {
+ item: ItemId,
+ ctx: &'a BindgenContext,
+ seen: DebugOnlyItemSet,
+}
+
+impl<'a> ItemAncestorsIter<'a> {
+ fn new<Id: Into<ItemId>>(ctx: &'a BindgenContext, id: Id) -> Self {
+ ItemAncestorsIter {
+ item: id.into(),
+ ctx,
+ seen: DebugOnlyItemSet::new(),
+ }
+ }
+}
+
+impl<'a> Iterator for ItemAncestorsIter<'a> {
+ type Item = ItemId;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let item = self.ctx.resolve_item(self.item);
+
+ if item.parent_id() == self.item {
+ None
+ } else {
+ self.item = item.parent_id();
+
+ extra_assert!(!self.seen.contains(&item.id()));
+ self.seen.insert(item.id());
+
+ Some(item.id())
+ }
+ }
+}
+
+impl<T> AsTemplateParam for T
+where
+ T: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> Option<TypeId> {
+ ctx.resolve_item((*self).into()).as_template_param(ctx, &())
+ }
+}
+
+impl AsTemplateParam for Item {
+ type Extra = ();
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> Option<TypeId> {
+ self.kind.as_template_param(ctx, self)
+ }
+}
+
+impl AsTemplateParam for ItemKind {
+ type Extra = Item;
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> Option<TypeId> {
+ match *self {
+ ItemKind::Type(ref ty) => ty.as_template_param(ctx, item),
+ ItemKind::Module(..) |
+ ItemKind::Function(..) |
+ ItemKind::Var(..) => None,
+ }
+ }
+}
+
+impl<T> ItemCanonicalName for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item(*self).canonical_name(ctx)
+ }
+}
+
+impl<T> ItemCanonicalPath for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn namespace_aware_canonical_path(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Vec<String> {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item(*self).namespace_aware_canonical_path(ctx)
+ }
+
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item(*self).canonical_path(ctx)
+ }
+}
+
+impl<T> ItemAncestors for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> {
+ ItemAncestorsIter::new(ctx, *self)
+ }
+}
+
+impl ItemAncestors for Item {
+ fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> {
+ self.id().ancestors(ctx)
+ }
+}
+
+impl<Id> Trace for Id
+where
+ Id: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, extra: &())
+ where
+ T: Tracer,
+ {
+ ctx.resolve_item(*self).trace(ctx, tracer, extra);
+ }
+}
+
+impl Trace for Item {
+ type Extra = ();
+
+ fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &())
+ where
+ T: Tracer,
+ {
+ // Even if this item is blocklisted/hidden, we want to trace it. It is
+ // traversal iterators' consumers' responsibility to filter items as
+ // needed. Generally, this filtering happens in the implementation of
+ // `Iterator` for `allowlistedItems`. Fully tracing blocklisted items is
+ // necessary for things like the template parameter usage analysis to
+ // function correctly.
+
+ match *self.kind() {
+ ItemKind::Type(ref ty) => {
+ // There are some types, like resolved type references, where we
+ // don't want to stop collecting types even though they may be
+ // opaque.
+ if ty.should_be_traced_unconditionally() ||
+ !self.is_opaque(ctx, &())
+ {
+ ty.trace(ctx, tracer, self);
+ }
+ }
+ ItemKind::Function(ref fun) => {
+ // Just the same way, it has not real meaning for a function to
+ // be opaque, so we trace across it.
+ tracer.visit(fun.signature().into());
+ }
+ ItemKind::Var(ref var) => {
+ tracer.visit_kind(var.ty().into(), EdgeKind::VarType);
+ }
+ ItemKind::Module(_) => {
+ // Module -> children edges are "weak", and we do not want to
+ // trace them. If we did, then allowlisting wouldn't work as
+ // expected: everything in every module would end up
+ // allowlisted.
+ //
+ // TODO: make a new edge kind for module -> children edges and
+ // filter them during allowlisting traversals.
+ }
+ }
+ }
+}
+
+impl CanDeriveDebug for Item {
+ fn can_derive_debug(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_debug(ctx)
+ }
+}
+
+impl CanDeriveDefault for Item {
+ fn can_derive_default(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_default(ctx)
+ }
+}
+
+impl CanDeriveCopy for Item {
+ fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_copy(ctx)
+ }
+}
+
+impl CanDeriveHash for Item {
+ fn can_derive_hash(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_hash(ctx)
+ }
+}
+
+impl CanDerivePartialOrd for Item {
+ fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_partialord(ctx)
+ }
+}
+
+impl CanDerivePartialEq for Item {
+ fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_partialeq(ctx)
+ }
+}
+
+impl CanDeriveEq for Item {
+ fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_eq(ctx)
+ }
+}
+
+impl CanDeriveOrd for Item {
+ fn can_derive_ord(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_ord(ctx)
+ }
+}
+
+/// An item is the base of the bindgen representation, it can be either a
+/// module, a type, a function, or a variable (see `ItemKind` for more
+/// information).
+///
+/// Items refer to each other by `ItemId`. Every item has its parent's
+/// ID. Depending on the kind of item this is, it may also refer to other items,
+/// such as a compound type item referring to other types. Collectively, these
+/// references form a graph.
+///
+/// The entry-point to this graph is the "root module": a meta-item used to hold
+/// all top-level items.
+///
+/// An item may have a comment, and annotations (see the `annotations` module).
+///
+/// Note that even though we parse all the types of annotations in comments, not
+/// all of them apply to every item. Those rules are described in the
+/// `annotations` module.
+#[derive(Debug)]
+pub(crate) struct Item {
+ /// This item's ID.
+ id: ItemId,
+
+ /// The item's local ID, unique only amongst its siblings. Only used for
+ /// anonymous items.
+ ///
+ /// Lazily initialized in local_id().
+ ///
+ /// Note that only structs, unions, and enums get a local type ID. In any
+ /// case this is an implementation detail.
+ local_id: LazyCell<usize>,
+
+ /// The next local ID to use for a child or template instantiation.
+ next_child_local_id: Cell<usize>,
+
+ /// A cached copy of the canonical name, as returned by `canonical_name`.
+ ///
+ /// This is a fairly used operation during codegen so this makes bindgen
+ /// considerably faster in those cases.
+ canonical_name: LazyCell<String>,
+
+ /// The path to use for allowlisting and other name-based checks, as
+ /// returned by `path_for_allowlisting`, lazily constructed.
+ path_for_allowlisting: LazyCell<Vec<String>>,
+
+ /// A doc comment over the item, if any.
+ comment: Option<String>,
+ /// Annotations extracted from the doc comment, or the default ones
+ /// otherwise.
+ annotations: Annotations,
+ /// An item's parent ID. This will most likely be a class where this item
+ /// was declared, or a module, etc.
+ ///
+ /// All the items have a parent, except the root module, in which case the
+ /// parent ID is its own ID.
+ parent_id: ItemId,
+ /// The item kind.
+ kind: ItemKind,
+ /// The source location of the item.
+ location: Option<clang::SourceLocation>,
+}
+
+impl AsRef<ItemId> for Item {
+ fn as_ref(&self) -> &ItemId {
+ &self.id
+ }
+}
+
+impl Item {
+ /// Construct a new `Item`.
+ pub(crate) fn new(
+ id: ItemId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ parent_id: ItemId,
+ kind: ItemKind,
+ location: Option<clang::SourceLocation>,
+ ) -> Self {
+ debug_assert!(id != parent_id || kind.is_module());
+ Item {
+ id,
+ local_id: LazyCell::new(),
+ next_child_local_id: Cell::new(1),
+ canonical_name: LazyCell::new(),
+ path_for_allowlisting: LazyCell::new(),
+ parent_id,
+ comment,
+ annotations: annotations.unwrap_or_default(),
+ kind,
+ location,
+ }
+ }
+
+ /// Construct a new opaque item type.
+ pub(crate) fn new_opaque_type(
+ with_id: ItemId,
+ ty: &clang::Type,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ let location = ty.declaration().location();
+ let ty = Opaque::from_clang_ty(ty, ctx);
+ let kind = ItemKind::Type(ty);
+ let parent = ctx.root_module().into();
+ ctx.add_item(
+ Item::new(with_id, None, None, parent, kind, Some(location)),
+ None,
+ None,
+ );
+ with_id.as_type_id_unchecked()
+ }
+
+ /// Get this `Item`'s identifier.
+ pub(crate) fn id(&self) -> ItemId {
+ self.id
+ }
+
+ /// Get this `Item`'s parent's identifier.
+ ///
+ /// For the root module, the parent's ID is its own ID.
+ pub(crate) fn parent_id(&self) -> ItemId {
+ self.parent_id
+ }
+
+ /// Set this item's parent ID.
+ ///
+ /// This is only used so replacements get generated in the proper module.
+ pub(crate) fn set_parent_for_replacement<Id: Into<ItemId>>(
+ &mut self,
+ id: Id,
+ ) {
+ self.parent_id = id.into();
+ }
+
+ /// Returns the depth this item is indented to.
+ ///
+ /// FIXME(emilio): This may need fixes for the enums within modules stuff.
+ pub(crate) fn codegen_depth(&self, ctx: &BindgenContext) -> usize {
+ if !ctx.options().enable_cxx_namespaces {
+ return 0;
+ }
+
+ self.ancestors(ctx)
+ .filter(|id| {
+ ctx.resolve_item(*id).as_module().map_or(false, |module| {
+ !module.is_inline() ||
+ ctx.options().conservative_inline_namespaces
+ })
+ })
+ .count() +
+ 1
+ }
+
+ /// Get this `Item`'s comment, if it has any, already preprocessed and with
+ /// the right indentation.
+ pub(crate) fn comment(&self, ctx: &BindgenContext) -> Option<String> {
+ if !ctx.options().generate_comments {
+ return None;
+ }
+
+ self.comment
+ .as_ref()
+ .map(|comment| ctx.options().process_comment(comment))
+ }
+
+ /// What kind of item is this?
+ pub(crate) fn kind(&self) -> &ItemKind {
+ &self.kind
+ }
+
+ /// Get a mutable reference to this item's kind.
+ pub(crate) fn kind_mut(&mut self) -> &mut ItemKind {
+ &mut self.kind
+ }
+
+ /// Where in the source is this item located?
+ pub(crate) 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
+ /// below this item's lexical scope, meaning that this can be useful for
+ /// generating relatively stable identifiers within a scope.
+ pub(crate) fn local_id(&self, ctx: &BindgenContext) -> usize {
+ *self.local_id.borrow_with(|| {
+ let parent = ctx.resolve_item(self.parent_id);
+ parent.next_child_local_id()
+ })
+ }
+
+ /// Get an identifier that differentiates a child of this item of other
+ /// related items.
+ ///
+ /// This is currently used for anonymous items, and template instantiation
+ /// tests, in both cases in order to reduce noise when system headers are at
+ /// place.
+ pub(crate) fn next_child_local_id(&self) -> usize {
+ let local_id = self.next_child_local_id.get();
+ self.next_child_local_id.set(local_id + 1);
+ local_id
+ }
+
+ /// Returns whether this item is a top-level item, from the point of view of
+ /// bindgen.
+ ///
+ /// This point of view changes depending on whether namespaces are enabled
+ /// or not. That way, in the following example:
+ ///
+ /// ```c++
+ /// namespace foo {
+ /// static int var;
+ /// }
+ /// ```
+ ///
+ /// `var` would be a toplevel item if namespaces are disabled, but won't if
+ /// they aren't.
+ ///
+ /// This function is used to determine when the codegen phase should call
+ /// `codegen` on an item, since any item that is not top-level will be
+ /// generated by its parent.
+ pub(crate) fn is_toplevel(&self, ctx: &BindgenContext) -> bool {
+ // FIXME: Workaround for some types falling behind when parsing weird
+ // stl classes, for example.
+ if ctx.options().enable_cxx_namespaces &&
+ self.kind().is_module() &&
+ self.id() != ctx.root_module()
+ {
+ return false;
+ }
+
+ let mut parent = self.parent_id;
+ loop {
+ let parent_item = match ctx.resolve_item_fallible(parent) {
+ Some(item) => item,
+ None => return false,
+ };
+
+ if parent_item.id() == ctx.root_module() {
+ return true;
+ } else if ctx.options().enable_cxx_namespaces ||
+ !parent_item.kind().is_module()
+ {
+ return false;
+ }
+
+ parent = parent_item.parent_id();
+ }
+ }
+
+ /// Get a reference to this item's underlying `Type`. Panic if this is some
+ /// other kind of item.
+ pub(crate) fn expect_type(&self) -> &Type {
+ self.kind().expect_type()
+ }
+
+ /// Get a reference to this item's underlying `Type`, or `None` if this is
+ /// some other kind of item.
+ pub(crate) fn as_type(&self) -> Option<&Type> {
+ self.kind().as_type()
+ }
+
+ /// Get a reference to this item's underlying `Function`. Panic if this is
+ /// some other kind of item.
+ pub(crate) fn expect_function(&self) -> &Function {
+ self.kind().expect_function()
+ }
+
+ /// Is this item a module?
+ pub(crate) fn is_module(&self) -> bool {
+ matches!(self.kind, ItemKind::Module(..))
+ }
+
+ /// Get this item's annotations.
+ pub(crate) fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+
+ /// Whether this item should be blocklisted.
+ ///
+ /// This may be due to either annotations or to other kind of configuration.
+ pub(crate) fn is_blocklisted(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ if self.annotations.hide() {
+ return true;
+ }
+
+ if !ctx.options().blocklisted_files.is_empty() {
+ if let Some(location) = &self.location {
+ let (file, _, _, _) = location.location();
+ if let Some(filename) = file.name() {
+ if ctx.options().blocklisted_files.matches(filename) {
+ return true;
+ }
+ }
+ }
+ }
+
+ let path = self.path_for_allowlisting(ctx);
+ let name = path[1..].join("::");
+ ctx.options().blocklisted_items.matches(&name) ||
+ match self.kind {
+ ItemKind::Type(..) => {
+ ctx.options().blocklisted_types.matches(&name) ||
+ ctx.is_replaced_type(path, self.id)
+ }
+ ItemKind::Function(..) => {
+ ctx.options().blocklisted_functions.matches(&name)
+ }
+ ItemKind::Var(..) => {
+ ctx.options().blocklisted_vars.matches(&name)
+ }
+ // TODO: Add namespace blocklisting?
+ ItemKind::Module(..) => false,
+ }
+ }
+
+ /// Take out item NameOptions
+ pub(crate) fn name<'a>(
+ &'a self,
+ ctx: &'a BindgenContext,
+ ) -> NameOptions<'a> {
+ NameOptions::new(self, ctx)
+ }
+
+ /// Get the target item ID for name generation.
+ fn name_target(&self, ctx: &BindgenContext) -> ItemId {
+ let mut targets_seen = DebugOnlyItemSet::new();
+ let mut item = self;
+
+ loop {
+ extra_assert!(!targets_seen.contains(&item.id()));
+ targets_seen.insert(item.id());
+
+ if self.annotations().use_instead_of().is_some() {
+ return self.id();
+ }
+
+ match *item.kind() {
+ ItemKind::Type(ref ty) => match *ty.kind() {
+ TypeKind::ResolvedTypeRef(inner) => {
+ item = ctx.resolve_item(inner);
+ }
+ TypeKind::TemplateInstantiation(ref inst) => {
+ item = ctx.resolve_item(inst.template_definition());
+ }
+ _ => return item.id(),
+ },
+ _ => return item.id(),
+ }
+ }
+ }
+
+ /// Create a fully disambiguated name for an item, including template
+ /// parameters if it is a type
+ pub(crate) fn full_disambiguated_name(
+ &self,
+ ctx: &BindgenContext,
+ ) -> String {
+ let mut s = String::new();
+ let level = 0;
+ self.push_disambiguated_name(ctx, &mut s, level);
+ s
+ }
+
+ /// Helper function for full_disambiguated_name
+ fn push_disambiguated_name(
+ &self,
+ ctx: &BindgenContext,
+ to: &mut String,
+ level: u8,
+ ) {
+ to.push_str(&self.canonical_name(ctx));
+ if let ItemKind::Type(ref ty) = *self.kind() {
+ if let TypeKind::TemplateInstantiation(ref inst) = *ty.kind() {
+ to.push_str(&format!("_open{}_", level));
+ for arg in inst.template_arguments() {
+ arg.into_resolver()
+ .through_type_refs()
+ .resolve(ctx)
+ .push_disambiguated_name(ctx, to, level + 1);
+ to.push('_');
+ }
+ to.push_str(&format!("close{}", level));
+ }
+ }
+ }
+
+ /// Get this function item's name, or `None` if this item is not a function.
+ fn func_name(&self) -> Option<&str> {
+ match *self.kind() {
+ ItemKind::Function(ref func) => Some(func.name()),
+ _ => None,
+ }
+ }
+
+ /// Get the overload index for this method. If this is not a method, return
+ /// `None`.
+ fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
+ self.func_name().and_then(|func_name| {
+ let parent = ctx.resolve_item(self.parent_id());
+ if let ItemKind::Type(ref ty) = *parent.kind() {
+ if let TypeKind::Comp(ref ci) = *ty.kind() {
+ // All the constructors have the same name, so no need to
+ // resolve and check.
+ return ci
+ .constructors()
+ .iter()
+ .position(|c| *c == self.id())
+ .or_else(|| {
+ ci.methods()
+ .iter()
+ .filter(|m| {
+ let item = ctx.resolve_item(m.signature());
+ let func = item.expect_function();
+ func.name() == func_name
+ })
+ .position(|m| m.signature() == self.id())
+ });
+ }
+ }
+
+ None
+ })
+ }
+
+ /// Get this item's base name (aka non-namespaced name).
+ fn base_name(&self, ctx: &BindgenContext) -> String {
+ if let Some(path) = self.annotations().use_instead_of() {
+ return path.last().unwrap().clone();
+ }
+
+ match *self.kind() {
+ ItemKind::Var(ref var) => var.name().to_owned(),
+ ItemKind::Module(ref module) => {
+ module.name().map(ToOwned::to_owned).unwrap_or_else(|| {
+ format!("_bindgen_mod_{}", self.exposed_id(ctx))
+ })
+ }
+ ItemKind::Type(ref ty) => {
+ ty.sanitized_name(ctx).map(Into::into).unwrap_or_else(|| {
+ format!("_bindgen_ty_{}", self.exposed_id(ctx))
+ })
+ }
+ ItemKind::Function(ref fun) => {
+ let mut name = fun.name().to_owned();
+
+ if let Some(idx) = self.overload_index(ctx) {
+ if idx > 0 {
+ write!(&mut name, "{}", idx).unwrap();
+ }
+ }
+
+ name
+ }
+ }
+ }
+
+ fn is_anon(&self) -> bool {
+ match self.kind() {
+ ItemKind::Module(module) => module.name().is_none(),
+ ItemKind::Type(ty) => ty.name().is_none(),
+ ItemKind::Function(_) => false,
+ ItemKind::Var(_) => false,
+ }
+ }
+
+ /// Get the canonical name without taking into account the replaces
+ /// annotation.
+ ///
+ /// This is the base logic used to implement hiding and replacing via
+ /// annotations, and also to implement proper name mangling.
+ ///
+ /// The idea is that each generated type in the same "level" (read: module
+ /// or namespace) has a unique canonical name.
+ ///
+ /// This name should be derived from the immutable state contained in the
+ /// type and the parent chain, since it should be consistent.
+ ///
+ /// If `BindgenOptions::disable_nested_struct_naming` is true then returned
+ /// name is the inner most non-anonymous name plus all the anonymous base names
+ /// that follows.
+ pub(crate) fn real_canonical_name(
+ &self,
+ ctx: &BindgenContext,
+ opt: &NameOptions,
+ ) -> String {
+ let target = ctx.resolve_item(self.name_target(ctx));
+
+ // Short-circuit if the target has an override, and just use that.
+ if let Some(path) = target.annotations.use_instead_of() {
+ if ctx.options().enable_cxx_namespaces {
+ return path.last().unwrap().clone();
+ }
+ return path.join("_");
+ }
+
+ let base_name = target.base_name(ctx);
+
+ // Named template type arguments are never namespaced, and never
+ // mangled.
+ if target.is_template_param(ctx, &()) {
+ return base_name;
+ }
+
+ // Ancestors' ID iter
+ let mut ids_iter = target
+ .parent_id()
+ .ancestors(ctx)
+ .filter(|id| *id != ctx.root_module())
+ .take_while(|id| {
+ // Stop iterating ancestors once we reach a non-inline namespace
+ // when opt.within_namespaces is set.
+ !opt.within_namespaces || !ctx.resolve_item(*id).is_module()
+ })
+ .filter(|id| {
+ if !ctx.options().conservative_inline_namespaces {
+ if let ItemKind::Module(ref module) =
+ *ctx.resolve_item(*id).kind()
+ {
+ return !module.is_inline();
+ }
+ }
+
+ true
+ });
+
+ let ids: Vec<_> = if ctx.options().disable_nested_struct_naming {
+ let mut ids = Vec::new();
+
+ // If target is anonymous we need find its first named ancestor.
+ if target.is_anon() {
+ for id in ids_iter.by_ref() {
+ ids.push(id);
+
+ if !ctx.resolve_item(id).is_anon() {
+ break;
+ }
+ }
+ }
+
+ ids
+ } else {
+ ids_iter.collect()
+ };
+
+ // Concatenate this item's ancestors' names together.
+ let mut names: Vec<_> = ids
+ .into_iter()
+ .map(|id| {
+ let item = ctx.resolve_item(id);
+ let target = ctx.resolve_item(item.name_target(ctx));
+ target.base_name(ctx)
+ })
+ .filter(|name| !name.is_empty())
+ .collect();
+
+ names.reverse();
+
+ if !base_name.is_empty() {
+ names.push(base_name);
+ }
+
+ if ctx.options().c_naming {
+ if let Some(prefix) = self.c_naming_prefix() {
+ names.insert(0, prefix.to_string());
+ }
+ }
+
+ let name = names.join("_");
+
+ let name = if opt.user_mangled == UserMangled::Yes {
+ ctx.options()
+ .last_callback(|callbacks| callbacks.item_name(&name))
+ .unwrap_or(name)
+ } else {
+ name
+ };
+
+ ctx.rust_mangle(&name).into_owned()
+ }
+
+ /// The exposed ID that represents an unique ID among the siblings of a
+ /// given item.
+ pub(crate) fn exposed_id(&self, ctx: &BindgenContext) -> String {
+ // Only use local ids for enums, classes, structs and union types. All
+ // other items use their global ID.
+ let ty_kind = self.kind().as_type().map(|t| t.kind());
+ if let Some(ty_kind) = ty_kind {
+ match *ty_kind {
+ TypeKind::Comp(..) |
+ TypeKind::TemplateInstantiation(..) |
+ TypeKind::Enum(..) => return self.local_id(ctx).to_string(),
+ _ => {}
+ }
+ }
+
+ // Note that this `id_` prefix prevents (really unlikely) collisions
+ // between the global ID and the local ID of an item with the same
+ // parent.
+ format!("id_{}", self.id().as_usize())
+ }
+
+ /// Get a reference to this item's `Module`, or `None` if this is not a
+ /// `Module` item.
+ pub(crate) fn as_module(&self) -> Option<&Module> {
+ match self.kind {
+ ItemKind::Module(ref module) => Some(module),
+ _ => None,
+ }
+ }
+
+ /// Get a mutable reference to this item's `Module`, or `None` if this is
+ /// not a `Module` item.
+ pub(crate) fn as_module_mut(&mut self) -> Option<&mut Module> {
+ match self.kind {
+ ItemKind::Module(ref mut module) => Some(module),
+ _ => None,
+ }
+ }
+
+ /// Returns whether the item is a constified module enum
+ fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool {
+ // Do not jump through aliases, except for aliases that point to a type
+ // with the same name, since we dont generate coe for them.
+ let item = self.id.into_resolver().through_type_refs().resolve(ctx);
+ let type_ = match *item.kind() {
+ ItemKind::Type(ref type_) => type_,
+ _ => return false,
+ };
+
+ match *type_.kind() {
+ TypeKind::Enum(ref enum_) => {
+ enum_.computed_enum_variation(ctx, self) ==
+ EnumVariation::ModuleConsts
+ }
+ TypeKind::Alias(inner_id) => {
+ // TODO(emilio): Make this "hop through type aliases that aren't
+ // really generated" an option in `ItemResolver`?
+ let inner_item = ctx.resolve_item(inner_id);
+ let name = item.canonical_name(ctx);
+
+ if inner_item.canonical_name(ctx) == name {
+ inner_item.is_constified_enum_module(ctx)
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+ }
+
+ /// Is this item of a kind that is enabled for code generation?
+ pub(crate) fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool {
+ let cc = &ctx.options().codegen_config;
+ match *self.kind() {
+ ItemKind::Module(..) => true,
+ ItemKind::Var(_) => cc.vars(),
+ ItemKind::Type(_) => cc.types(),
+ ItemKind::Function(ref f) => match f.kind() {
+ FunctionKind::Function => cc.functions(),
+ FunctionKind::Method(MethodKind::Constructor) => {
+ cc.constructors()
+ }
+ FunctionKind::Method(MethodKind::Destructor) |
+ FunctionKind::Method(MethodKind::VirtualDestructor {
+ ..
+ }) => cc.destructors(),
+ FunctionKind::Method(MethodKind::Static) |
+ FunctionKind::Method(MethodKind::Normal) |
+ FunctionKind::Method(MethodKind::Virtual { .. }) => {
+ cc.methods()
+ }
+ },
+ }
+ }
+
+ /// Returns the path we should use for allowlisting / blocklisting, which
+ /// doesn't include user-mangling.
+ pub(crate) fn path_for_allowlisting(
+ &self,
+ ctx: &BindgenContext,
+ ) -> &Vec<String> {
+ self.path_for_allowlisting
+ .borrow_with(|| self.compute_path(ctx, UserMangled::No))
+ }
+
+ fn compute_path(
+ &self,
+ ctx: &BindgenContext,
+ mangled: UserMangled,
+ ) -> Vec<String> {
+ if let Some(path) = self.annotations().use_instead_of() {
+ let mut ret =
+ vec![ctx.resolve_item(ctx.root_module()).name(ctx).get()];
+ ret.extend_from_slice(path);
+ return ret;
+ }
+
+ let target = ctx.resolve_item(self.name_target(ctx));
+ let mut path: Vec<_> = target
+ .ancestors(ctx)
+ .chain(iter::once(ctx.root_module().into()))
+ .map(|id| ctx.resolve_item(id))
+ .filter(|item| {
+ item.id() == target.id() ||
+ item.as_module().map_or(false, |module| {
+ !module.is_inline() ||
+ ctx.options().conservative_inline_namespaces
+ })
+ })
+ .map(|item| {
+ ctx.resolve_item(item.name_target(ctx))
+ .name(ctx)
+ .within_namespaces()
+ .user_mangled(mangled)
+ .get()
+ })
+ .collect();
+ path.reverse();
+ path
+ }
+
+ /// Returns a prefix for the canonical name when C naming is enabled.
+ fn c_naming_prefix(&self) -> Option<&str> {
+ let ty = match self.kind {
+ ItemKind::Type(ref ty) => ty,
+ _ => return None,
+ };
+
+ Some(match ty.kind() {
+ TypeKind::Comp(ref ci) => match ci.kind() {
+ CompKind::Struct => "struct",
+ CompKind::Union => "union",
+ },
+ TypeKind::Enum(..) => "enum",
+ _ => return None,
+ })
+ }
+
+ /// Whether this is a `#[must_use]` type.
+ pub(crate) fn must_use(&self, ctx: &BindgenContext) -> bool {
+ self.annotations().must_use_type() || ctx.must_use_type_by_name(self)
+ }
+}
+
+impl<T> IsOpaque for T
+where
+ T: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item((*self).into()).is_opaque(ctx, &())
+ }
+}
+
+impl IsOpaque for Item {
+ type Extra = ();
+
+ fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ self.annotations.opaque() ||
+ self.as_type().map_or(false, |ty| ty.is_opaque(ctx, self)) ||
+ ctx.opaque_by_name(self.path_for_allowlisting(ctx))
+ }
+}
+
+impl<T> HasVtable for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ let id: ItemId = (*self).into();
+ id.as_type_id(ctx).map_or(false, |id| {
+ !matches!(ctx.lookup_has_vtable(id), HasVtableResult::No)
+ })
+ }
+
+ fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool {
+ let id: ItemId = (*self).into();
+ id.as_type_id(ctx).map_or(false, |id| {
+ matches!(ctx.lookup_has_vtable(id), HasVtableResult::SelfHasVtable)
+ })
+ }
+}
+
+impl HasVtable for Item {
+ fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ self.id().has_vtable(ctx)
+ }
+
+ fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool {
+ self.id().has_vtable_ptr(ctx)
+ }
+}
+
+impl<T> Sizedness for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult {
+ let id: ItemId = (*self).into();
+ id.as_type_id(ctx)
+ .map_or(SizednessResult::default(), |id| ctx.lookup_sizedness(id))
+ }
+}
+
+impl Sizedness for Item {
+ fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult {
+ self.id().sizedness(ctx)
+ }
+}
+
+impl<T> HasTypeParamInArray for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_type_param_in_array(*self)
+ }
+}
+
+impl HasTypeParamInArray for Item {
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_type_param_in_array(self.id())
+ }
+}
+
+impl<T> HasFloat for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn has_float(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_float(*self)
+ }
+}
+
+impl HasFloat for Item {
+ fn has_float(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_float(self.id())
+ }
+}
+
+/// A set of items.
+pub(crate) type ItemSet = BTreeSet<ItemId>;
+
+impl DotAttributes for Item {
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(
+ out,
+ "<tr><td>{:?}</td></tr>
+ <tr><td>name</td><td>{}</td></tr>",
+ self.id,
+ self.name(ctx).get()
+ )?;
+
+ if self.is_opaque(ctx, &()) {
+ writeln!(out, "<tr><td>opaque</td><td>true</td></tr>")?;
+ }
+
+ self.kind.dot_attributes(ctx, out)
+ }
+}
+
+impl<T> TemplateParameters for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ ctx.resolve_item_fallible(*self)
+ .map_or(vec![], |item| item.self_template_params(ctx))
+ }
+}
+
+impl TemplateParameters for Item {
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ self.kind.self_template_params(ctx)
+ }
+}
+
+impl TemplateParameters for ItemKind {
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ match *self {
+ ItemKind::Type(ref ty) => ty.self_template_params(ctx),
+ // If we start emitting bindings to explicitly instantiated
+ // functions, then we'll need to check ItemKind::Function for
+ // template params.
+ ItemKind::Function(_) | ItemKind::Module(_) | ItemKind::Var(_) => {
+ vec![]
+ }
+ }
+ }
+}
+
+// An utility function to handle recursing inside nested types.
+fn visit_child(
+ cur: clang::Cursor,
+ id: ItemId,
+ ty: &clang::Type,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ result: &mut Result<TypeId, ParseError>,
+) -> clang_sys::CXChildVisitResult {
+ use clang_sys::*;
+ if result.is_ok() {
+ return CXChildVisit_Break;
+ }
+
+ *result = Item::from_ty_with_id(id, ty, cur, parent_id, ctx);
+
+ match *result {
+ Ok(..) => CXChildVisit_Break,
+ Err(ParseError::Recurse) => {
+ cur.visit(|c| visit_child(c, id, ty, parent_id, ctx, result));
+ CXChildVisit_Continue
+ }
+ Err(ParseError::Continue) => CXChildVisit_Continue,
+ }
+}
+
+impl Item {
+ /// Create a builtin type.
+ pub(crate) fn builtin_type(
+ kind: TypeKind,
+ is_const: bool,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ // Feel free to add more here, I'm just lazy.
+ match kind {
+ TypeKind::Void |
+ TypeKind::Int(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Float(..) => {}
+ _ => panic!("Unsupported builtin type"),
+ }
+
+ let ty = Type::new(None, None, kind, is_const);
+ let id = ctx.next_item_id();
+ let module = ctx.root_module().into();
+ ctx.add_item(
+ Item::new(id, None, None, module, ItemKind::Type(ty), None),
+ None,
+ None,
+ );
+ id.as_type_id_unchecked()
+ }
+
+ /// Parse this item from the given Clang cursor.
+ pub(crate) fn parse(
+ cursor: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> Result<ItemId, ParseError> {
+ use crate::ir::var::Var;
+ use clang_sys::*;
+
+ if !cursor.is_valid() {
+ return Err(ParseError::Continue);
+ }
+
+ let comment = cursor.raw_comment();
+ let annotations = Annotations::new(&cursor);
+
+ let current_module = ctx.current_module().into();
+ let relevant_parent_id = parent_id.unwrap_or(current_module);
+
+ #[allow(clippy::missing_docs_in_private_items)]
+ macro_rules! try_parse {
+ ($what:ident) => {
+ match $what::parse(cursor, ctx) {
+ Ok(ParseResult::New(item, declaration)) => {
+ let id = ctx.next_item_id();
+
+ ctx.add_item(
+ Item::new(
+ id,
+ comment,
+ annotations,
+ relevant_parent_id,
+ ItemKind::$what(item),
+ Some(cursor.location()),
+ ),
+ declaration,
+ Some(cursor),
+ );
+ return Ok(id);
+ }
+ Ok(ParseResult::AlreadyResolved(id)) => {
+ return Ok(id);
+ }
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {}
+ }
+ };
+ }
+
+ try_parse!(Module);
+
+ // NOTE: Is extremely important to parse functions and vars **before**
+ // types. Otherwise we can parse a function declaration as a type
+ // (which is legal), and lose functions to generate.
+ //
+ // In general, I'm not totally confident this split between
+ // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but
+ // I guess we can try.
+ try_parse!(Function);
+ try_parse!(Var);
+
+ // Types are sort of special, so to avoid parsing template classes
+ // twice, handle them separately.
+ {
+ let definition = cursor.definition();
+ let applicable_cursor = definition.unwrap_or(cursor);
+
+ let relevant_parent_id = match definition {
+ Some(definition) => {
+ if definition != cursor {
+ ctx.add_semantic_parent(definition, relevant_parent_id);
+ return Ok(Item::from_ty_or_ref(
+ applicable_cursor.cur_type(),
+ cursor,
+ parent_id,
+ ctx,
+ )
+ .into());
+ }
+ ctx.known_semantic_parent(definition)
+ .or(parent_id)
+ .unwrap_or_else(|| ctx.current_module().into())
+ }
+ None => relevant_parent_id,
+ };
+
+ match Item::from_ty(
+ &applicable_cursor.cur_type(),
+ applicable_cursor,
+ Some(relevant_parent_id),
+ ctx,
+ ) {
+ Ok(ty) => return Ok(ty.into()),
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {}
+ }
+ }
+
+ match cursor.kind() {
+ // On Clang 18+, extern "C" is reported accurately as a LinkageSpec.
+ // Older LLVM treat it as UnexposedDecl.
+ CXCursor_LinkageSpec | CXCursor_UnexposedDecl => {
+ Err(ParseError::Recurse)
+ }
+
+ // We allowlist cursors here known to be unhandled, to prevent being
+ // too noisy about this.
+ CXCursor_MacroDefinition |
+ CXCursor_MacroExpansion |
+ CXCursor_UsingDeclaration |
+ CXCursor_UsingDirective |
+ CXCursor_StaticAssert |
+ CXCursor_FunctionTemplate => {
+ debug!(
+ "Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(),
+ cursor
+ );
+ Err(ParseError::Continue)
+ }
+
+ CXCursor_InclusionDirective => {
+ let file = cursor.get_included_file_name();
+ match file {
+ None => {
+ warn!("Inclusion of a nameless file in {:?}", cursor);
+ }
+ Some(included_file) => {
+ for cb in &ctx.options().parse_callbacks {
+ cb.include_file(&included_file);
+ }
+
+ ctx.add_dep(included_file.into_boxed_str());
+ }
+ }
+ Err(ParseError::Continue)
+ }
+
+ _ => {
+ // ignore toplevel operator overloads
+ let spelling = cursor.spelling();
+ if !spelling.starts_with("operator") {
+ warn!(
+ "Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(),
+ cursor
+ );
+ }
+ Err(ParseError::Continue)
+ }
+ }
+ }
+
+ /// Parse this item from the given Clang type, or if we haven't resolved all
+ /// the other items this one depends on, an unresolved reference.
+ pub(crate) fn from_ty_or_ref(
+ ty: clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ let id = ctx.next_item_id();
+ Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx)
+ }
+
+ /// Parse a C++ type. If we find a reference to a type that has not been
+ /// defined yet, use `UnresolvedTypeRef` as a placeholder.
+ ///
+ /// This logic is needed to avoid parsing items with the incorrect parent
+ /// and it's sort of complex to explain, so I'll just point to
+ /// `tests/headers/typeref.hpp` to see the kind of constructs that forced
+ /// this.
+ ///
+ /// Typerefs are resolved once parsing is completely done, see
+ /// `BindgenContext::resolve_typerefs`.
+ pub(crate) fn from_ty_or_ref_with_id(
+ potential_id: ItemId,
+ ty: clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ debug!(
+ "from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}",
+ potential_id, ty, location, parent_id
+ );
+
+ if ctx.collected_typerefs() {
+ debug!("refs already collected, resolving directly");
+ return Item::from_ty_with_id(
+ potential_id,
+ &ty,
+ location,
+ parent_id,
+ ctx,
+ )
+ .unwrap_or_else(|_| Item::new_opaque_type(potential_id, &ty, ctx));
+ }
+
+ if let Some(ty) = ctx.builtin_or_resolved_ty(
+ potential_id,
+ parent_id,
+ &ty,
+ Some(location),
+ ) {
+ debug!("{:?} already resolved: {:?}", ty, location);
+ return ty;
+ }
+
+ debug!("New unresolved type reference: {:?}, {:?}", ty, location);
+
+ let is_const = ty.is_const();
+ let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id);
+ let current_module = ctx.current_module();
+
+ ctx.add_item(
+ Item::new(
+ potential_id,
+ None,
+ None,
+ parent_id.unwrap_or_else(|| current_module.into()),
+ ItemKind::Type(Type::new(None, None, kind, is_const)),
+ Some(location.location()),
+ ),
+ None,
+ None,
+ );
+ potential_id.as_type_id_unchecked()
+ }
+
+ /// Parse this item from the given Clang type. See [`Item::from_ty_with_id`].
+ pub(crate) fn from_ty(
+ ty: &clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> Result<TypeId, ParseError> {
+ let id = ctx.next_item_id();
+ Item::from_ty_with_id(id, ty, location, parent_id, ctx)
+ }
+
+ /// This is one of the trickiest methods you'll find (probably along with
+ /// some of the ones that handle templates in `BindgenContext`).
+ ///
+ /// This method parses a type, given the potential ID of that type (if
+ /// parsing it was correct), an optional location we're scanning, which is
+ /// critical some times to obtain information, an optional parent item ID,
+ /// that will, if it's `None`, become the current module ID, and the
+ /// context.
+ pub(crate) fn from_ty_with_id(
+ id: ItemId,
+ ty: &clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> Result<TypeId, ParseError> {
+ use clang_sys::*;
+
+ debug!(
+ "Item::from_ty_with_id: {:?}\n\
+ \tty = {:?},\n\
+ \tlocation = {:?}",
+ id, ty, location
+ );
+
+ if ty.kind() == clang_sys::CXType_Unexposed ||
+ location.cur_type().kind() == clang_sys::CXType_Unexposed
+ {
+ if ty.is_associated_type() ||
+ location.cur_type().is_associated_type()
+ {
+ return Ok(Item::new_opaque_type(id, ty, ctx));
+ }
+
+ if let Some(param_id) = Item::type_param(None, location, ctx) {
+ return Ok(ctx.build_ty_wrapper(id, param_id, None, ty));
+ }
+ }
+
+ // Treat all types that are declared inside functions as opaque. The Rust binding
+ // won't be able to do anything with them anyway.
+ //
+ // (If we don't do this check here, we can have subtle logic bugs because we generally
+ // ignore function bodies. See issue #2036.)
+ if let Some(ref parent) = ty.declaration().fallible_semantic_parent() {
+ if FunctionKind::from_cursor(parent).is_some() {
+ debug!("Skipping type declared inside function: {:?}", ty);
+ return Ok(Item::new_opaque_type(id, ty, ctx));
+ }
+ }
+
+ let decl = {
+ let canonical_def = ty.canonical_type().declaration().definition();
+ canonical_def.unwrap_or_else(|| ty.declaration())
+ };
+
+ let comment = location
+ .raw_comment()
+ .or_else(|| decl.raw_comment())
+ .or_else(|| location.raw_comment());
+
+ let annotations =
+ Annotations::new(&decl).or_else(|| Annotations::new(&location));
+
+ if let Some(ref annotations) = annotations {
+ if let Some(replaced) = annotations.use_instead_of() {
+ ctx.replace(replaced, id);
+ }
+ }
+
+ if let Some(ty) =
+ ctx.builtin_or_resolved_ty(id, parent_id, ty, Some(location))
+ {
+ return Ok(ty);
+ }
+
+ // First, check we're not recursing.
+ let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
+ let declaration_to_look_for = if valid_decl {
+ decl.canonical()
+ } else if location.kind() == CXCursor_ClassTemplate {
+ valid_decl = true;
+ location
+ } else {
+ decl
+ };
+
+ if valid_decl {
+ if let Some(partial) = ctx
+ .currently_parsed_types()
+ .iter()
+ .find(|ty| *ty.decl() == declaration_to_look_for)
+ {
+ debug!("Avoiding recursion parsing type: {:?}", ty);
+ // Unchecked because we haven't finished this type yet.
+ return Ok(partial.id().as_type_id_unchecked());
+ }
+ }
+
+ let current_module = ctx.current_module().into();
+ let partial_ty = PartialType::new(declaration_to_look_for, id);
+ if valid_decl {
+ ctx.begin_parsing(partial_ty);
+ }
+
+ let result = Type::from_clang_ty(id, ty, location, parent_id, ctx);
+ let relevant_parent_id = parent_id.unwrap_or(current_module);
+ let ret = match result {
+ Ok(ParseResult::AlreadyResolved(ty)) => {
+ Ok(ty.as_type_id_unchecked())
+ }
+ Ok(ParseResult::New(item, declaration)) => {
+ ctx.add_item(
+ Item::new(
+ id,
+ comment,
+ annotations,
+ relevant_parent_id,
+ ItemKind::Type(item),
+ Some(location.location()),
+ ),
+ declaration,
+ Some(location),
+ );
+ Ok(id.as_type_id_unchecked())
+ }
+ Err(ParseError::Continue) => Err(ParseError::Continue),
+ Err(ParseError::Recurse) => {
+ debug!("Item::from_ty recursing in the ast");
+ let mut result = Err(ParseError::Recurse);
+
+ // Need to pop here, otherwise we'll get stuck.
+ //
+ // TODO: Find a nicer interface, really. Also, the
+ // declaration_to_look_for suspiciously shares a lot of
+ // logic with ir::context, so we should refactor that.
+ if valid_decl {
+ let finished = ctx.finish_parsing();
+ assert_eq!(*finished.decl(), declaration_to_look_for);
+ }
+
+ location.visit(|cur| {
+ visit_child(cur, id, ty, parent_id, ctx, &mut result)
+ });
+
+ if valid_decl {
+ let partial_ty =
+ PartialType::new(declaration_to_look_for, id);
+ ctx.begin_parsing(partial_ty);
+ }
+
+ // If we have recursed into the AST all we know, and we still
+ // haven't found what we've got, let's just try and make a named
+ // type.
+ //
+ // This is what happens with some template members, for example.
+ if let Err(ParseError::Recurse) = result {
+ warn!(
+ "Unknown type, assuming named template type: \
+ id = {:?}; spelling = {}",
+ id,
+ ty.spelling()
+ );
+ Item::type_param(Some(id), location, ctx)
+ .map(Ok)
+ .unwrap_or(Err(ParseError::Recurse))
+ } else {
+ result
+ }
+ }
+ };
+
+ if valid_decl {
+ let partial_ty = ctx.finish_parsing();
+ assert_eq!(*partial_ty.decl(), declaration_to_look_for);
+ }
+
+ ret
+ }
+
+ /// A named type is a template parameter, e.g., the `T` in `Foo<T>`. They're always local so
+ /// it's the only exception when there's no declaration for a type.
+ pub(crate) fn type_param(
+ with_id: Option<ItemId>,
+ location: clang::Cursor,
+ ctx: &mut BindgenContext,
+ ) -> Option<TypeId> {
+ let ty = location.cur_type();
+
+ debug!(
+ "Item::type_param:\n\
+ \twith_id = {:?},\n\
+ \tty = {} {:?},\n\
+ \tlocation: {:?}",
+ with_id,
+ ty.spelling(),
+ ty,
+ location
+ );
+
+ if ty.kind() != clang_sys::CXType_Unexposed {
+ // If the given cursor's type's kind is not Unexposed, then we
+ // aren't looking at a template parameter. This check may need to be
+ // updated in the future if they start properly exposing template
+ // type parameters.
+ return None;
+ }
+
+ let ty_spelling = ty.spelling();
+
+ // Clang does not expose any information about template type parameters
+ // via their clang::Type, nor does it give us their canonical cursors
+ // the straightforward way. However, there are three situations from
+ // which we can find the definition of the template type parameter, if
+ // the cursor is indeed looking at some kind of a template type
+ // parameter or use of one:
+ //
+ // 1. The cursor is pointing at the template type parameter's
+ // definition. This is the trivial case.
+ //
+ // (kind = TemplateTypeParameter, ...)
+ //
+ // 2. The cursor is pointing at a TypeRef whose referenced() cursor is
+ // situation (1).
+ //
+ // (kind = TypeRef,
+ // referenced = (kind = TemplateTypeParameter, ...),
+ // ...)
+ //
+ // 3. The cursor is pointing at some use of a template type parameter
+ // (for example, in a FieldDecl), and this cursor has a child cursor
+ // whose spelling is the same as the parent's type's spelling, and whose
+ // kind is a TypeRef of the situation (2) variety.
+ //
+ // (kind = FieldDecl,
+ // type = (kind = Unexposed,
+ // spelling = "T",
+ // ...),
+ // children =
+ // (kind = TypeRef,
+ // spelling = "T",
+ // referenced = (kind = TemplateTypeParameter,
+ // spelling = "T",
+ // ...),
+ // ...)
+ // ...)
+ //
+ // TODO: The alternative to this hacky pattern matching would be to
+ // maintain proper scopes of template parameters while parsing and use
+ // de Brujin indices to access template parameters, which clang exposes
+ // in the cursor's type's canonical type's spelling:
+ // "type-parameter-x-y". That is probably a better approach long-term,
+ // but maintaining these scopes properly would require more changes to
+ // the whole libclang -> IR parsing code.
+
+ fn is_template_with_spelling(
+ refd: &clang::Cursor,
+ spelling: &str,
+ ) -> bool {
+ lazy_static! {
+ static ref ANON_TYPE_PARAM_RE: regex::Regex =
+ regex::Regex::new(r"^type\-parameter\-\d+\-\d+$").unwrap();
+ }
+
+ if refd.kind() != clang_sys::CXCursor_TemplateTypeParameter {
+ return false;
+ }
+
+ let refd_spelling = refd.spelling();
+ refd_spelling == spelling ||
+ // Allow for anonymous template parameters.
+ (refd_spelling.is_empty() && ANON_TYPE_PARAM_RE.is_match(spelling.as_ref()))
+ }
+
+ let definition = if is_template_with_spelling(&location, &ty_spelling) {
+ // Situation (1)
+ location
+ } else if location.kind() == clang_sys::CXCursor_TypeRef {
+ // Situation (2)
+ match location.referenced() {
+ Some(refd)
+ if is_template_with_spelling(&refd, &ty_spelling) =>
+ {
+ refd
+ }
+ _ => return None,
+ }
+ } else {
+ // Situation (3)
+ let mut definition = None;
+
+ location.visit(|child| {
+ let child_ty = child.cur_type();
+ if child_ty.kind() == clang_sys::CXCursor_TypeRef &&
+ child_ty.spelling() == ty_spelling
+ {
+ match child.referenced() {
+ Some(refd)
+ if is_template_with_spelling(
+ &refd,
+ &ty_spelling,
+ ) =>
+ {
+ definition = Some(refd);
+ return clang_sys::CXChildVisit_Break;
+ }
+ _ => {}
+ }
+ }
+
+ clang_sys::CXChildVisit_Continue
+ });
+
+ definition?
+ };
+ assert!(is_template_with_spelling(&definition, &ty_spelling));
+
+ // Named types are always parented to the root module. They are never
+ // referenced with namespace prefixes, and they can't inherit anything
+ // from their parent either, so it is simplest to just hang them off
+ // something we know will always exist.
+ let parent = ctx.root_module().into();
+
+ if let Some(id) = ctx.get_type_param(&definition) {
+ if let Some(with_id) = with_id {
+ return Some(ctx.build_ty_wrapper(
+ with_id,
+ id,
+ Some(parent),
+ &ty,
+ ));
+ } else {
+ return Some(id);
+ }
+ }
+
+ // See tests/headers/const_tparam.hpp and
+ // tests/headers/variadic_tname.hpp.
+ let name = ty_spelling.replace("const ", "").replace('.', "");
+
+ let id = with_id.unwrap_or_else(|| ctx.next_item_id());
+ let item = Item::new(
+ id,
+ None,
+ None,
+ parent,
+ ItemKind::Type(Type::named(name)),
+ Some(location.location()),
+ );
+ ctx.add_type_param(item, definition);
+ Some(id.as_type_id_unchecked())
+ }
+}
+
+impl ItemCanonicalName for Item {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ self.canonical_name
+ .borrow_with(|| {
+ let in_namespace = ctx.options().enable_cxx_namespaces ||
+ ctx.options().disable_name_namespacing;
+
+ if in_namespace {
+ self.name(ctx).within_namespaces().get()
+ } else {
+ self.name(ctx).get()
+ }
+ })
+ .clone()
+ }
+}
+
+impl ItemCanonicalPath for Item {
+ fn namespace_aware_canonical_path(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Vec<String> {
+ let mut path = self.canonical_path(ctx);
+
+ // ASSUMPTION: (disable_name_namespacing && cxx_namespaces)
+ // is equivalent to
+ // disable_name_namespacing
+ if ctx.options().disable_name_namespacing {
+ // Only keep the last item in path
+ let split_idx = path.len() - 1;
+ path = path.split_off(split_idx);
+ } else if !ctx.options().enable_cxx_namespaces {
+ // Ignore first item "root"
+ path = vec![path[1..].join("_")];
+ }
+
+ if self.is_constified_enum_module(ctx) {
+ path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into());
+ }
+
+ path
+ }
+
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ self.compute_path(ctx, UserMangled::Yes)
+ }
+}
+
+/// Whether to use the user-mangled name (mangled by the `item_name` callback or
+/// not.
+///
+/// Most of the callers probably want just yes, but the ones dealing with
+/// allowlisting and blocklisting don't.
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum UserMangled {
+ No,
+ Yes,
+}
+
+/// Builder struct for naming variations, which hold inside different
+/// flags for naming options.
+#[derive(Debug)]
+pub(crate) struct NameOptions<'a> {
+ item: &'a Item,
+ ctx: &'a BindgenContext,
+ within_namespaces: bool,
+ user_mangled: UserMangled,
+}
+
+impl<'a> NameOptions<'a> {
+ /// Construct a new `NameOptions`
+ pub(crate) fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self {
+ NameOptions {
+ item,
+ ctx,
+ within_namespaces: false,
+ user_mangled: UserMangled::Yes,
+ }
+ }
+
+ /// Construct the name without the item's containing C++ namespaces mangled
+ /// into it. In other words, the item's name within the item's namespace.
+ pub(crate) fn within_namespaces(&mut self) -> &mut Self {
+ self.within_namespaces = true;
+ self
+ }
+
+ fn user_mangled(&mut self, user_mangled: UserMangled) -> &mut Self {
+ self.user_mangled = user_mangled;
+ self
+ }
+
+ /// Construct a name `String`
+ pub(crate) fn get(&self) -> String {
+ self.item.real_canonical_name(self.ctx, self)
+ }
+}