//! 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 std::cell::{Cell, OnceCell}; use std::collections::BTreeSet; use std::fmt::Write; use std::io; use std::iter; use std::sync::OnceLock; /// 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; /// Get the canonical path for this item. fn canonical_path(&self, ctx: &BindgenContext) -> Vec; } /// 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 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>(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 { 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 AsTemplateParam for T where T: Copy + Into, { type Extra = (); fn as_template_param( &self, ctx: &BindgenContext, _: &(), ) -> Option { ctx.resolve_item((*self).into()).as_template_param(ctx, &()) } } impl AsTemplateParam for Item { type Extra = (); fn as_template_param( &self, ctx: &BindgenContext, _: &(), ) -> Option { self.kind.as_template_param(ctx, self) } } impl AsTemplateParam for ItemKind { type Extra = Item; fn as_template_param( &self, ctx: &BindgenContext, item: &Item, ) -> Option { match *self { ItemKind::Type(ref ty) => ty.as_template_param(ctx, item), ItemKind::Module(..) | ItemKind::Function(..) | ItemKind::Var(..) => None, } } } impl ItemCanonicalName for T where T: Copy + Into, { 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 ItemCanonicalPath for T where T: Copy + Into, { fn namespace_aware_canonical_path( &self, ctx: &BindgenContext, ) -> Vec { 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 { debug_assert!( ctx.in_codegen_phase(), "You're not supposed to call this yet" ); ctx.resolve_item(*self).canonical_path(ctx) } } impl ItemAncestors for T where T: Copy + Into, { 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 Trace for Id where Id: Copy + Into, { type Extra = (); fn trace(&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(&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: OnceCell, /// The next local ID to use for a child or template instantiation. next_child_local_id: Cell, /// 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: OnceCell, /// The path to use for allowlisting and other name-based checks, as /// returned by `path_for_allowlisting`, lazily constructed. path_for_allowlisting: OnceCell>, /// A doc comment over the item, if any. comment: Option, /// 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, } impl AsRef for Item { fn as_ref(&self) -> &ItemId { &self.id } } impl Item { /// Construct a new `Item`. pub(crate) fn new( id: ItemId, comment: Option, annotations: Option, parent_id: ItemId, kind: ItemKind, location: Option, ) -> Self { debug_assert!(id != parent_id || kind.is_module()); Item { id, local_id: OnceCell::new(), next_child_local_id: Cell::new(1), canonical_name: OnceCell::new(), path_for_allowlisting: OnceCell::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>( &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 { 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.get_or_init(|| { 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 { 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 this item's original C++ name, including any containing types, but without /// the namespace name. For nested types, the C++ name differs from the Rust name, e.g. /// a nested C++ type `A::B` would correspond to the Rust type `A_B`. /// If the item or any of its containing types is anonymous, returns None. pub fn original_name(&self, ctx: &BindgenContext) -> Option { let target = ctx.resolve_item(self.name_target(ctx)); // Get item and all ancestors until the first enclosing namespace. let ancestors: Vec<_> = target .ancestors(ctx) .map(|id| ctx.resolve_item(id)) .take_while(|item| !item.is_module()) .collect(); if ancestors.iter().any(|item| item.is_anon()) { return None; } let mut names: Vec<_> = ancestors .iter() .map(|item| { let target = ctx.resolve_item(item.name_target(ctx)); target.base_name(ctx) }) .filter(|name| !name.is_empty()) .collect(); names.reverse(); Some(names.join("::")) } /// 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( TypeKind::Comp(..) | TypeKind::TemplateInstantiation(..) | TypeKind::Enum(..), ) = ty_kind { 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 { self.path_for_allowlisting .get_or_init(|| self.compute_path(ctx, UserMangled::No)) } fn compute_path( &self, ctx: &BindgenContext, mangled: UserMangled, ) -> Vec { 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 IsOpaque for T where T: Copy + Into, { 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 HasVtable for T where T: Copy + Into, { 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 Sizedness for T where T: Copy + Into, { 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 HasTypeParamInArray for T where T: Copy + Into, { 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()) } } /// A set of items. pub(crate) type ItemSet = BTreeSet; impl DotAttributes for Item { fn dot_attributes( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "{:?} name{}", self.id, self.name(ctx).get() )?; if self.is_opaque(ctx, &()) { writeln!(out, "opaquetrue")?; } self.kind.dot_attributes(ctx, out) } } impl TemplateParameters for T where T: Copy + Into, { fn self_template_params(&self, ctx: &BindgenContext) -> Vec { 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 { self.kind.self_template_params(ctx) } } impl TemplateParameters for ItemKind { fn self_template_params(&self, ctx: &BindgenContext) -> Vec { 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, ctx: &mut BindgenContext, result: &mut Result, ) -> 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, ctx: &mut BindgenContext, ) -> Result { 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, 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, 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, ctx: &mut BindgenContext, ) -> Result { 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, ctx: &mut BindgenContext, ) -> Result { 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`. 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, location: clang::Cursor, ctx: &mut BindgenContext, ) -> Option { 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 { static ANON_TYPE_PARAM_RE: OnceLock = OnceLock::new(); let anon_type_param_re = ANON_TYPE_PARAM_RE.get_or_init(|| { 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 .get_or_init(|| { 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 { 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 { 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) } }