diff options
author | Matthew Maurer <mmaurer@google.com> | 2023-06-28 21:15:44 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-06-28 21:15:44 +0000 |
commit | dff14bfb1eb52af0bc812483a760e2be896ccaf7 (patch) | |
tree | c6735723e0c4e0a71c5472143c03b23e5330993f | |
parent | f0884fc0c4a525619e0d0ca0a697d7555b49de6b (diff) | |
parent | a15fc56dc17e5bf7af8c3414dbeaad91b3d40a2b (diff) | |
download | bindgen-dff14bfb1eb52af0bc812483a760e2be896ccaf7.tar.gz |
Update to 0.65.1 am: 0c91f92a37 am: a12b261650 am: a15fc56dc1
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/bindgen/+/2624796
Change-Id: I551bf31d4918b4175313b6b33895f2273ee17e6b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
54 files changed, 4162 insertions, 3127 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 32c33e6..820d6ff 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "ae6817256ac557981906e93a1f866349db85053e" + "sha1": "7d243056d335fdc4537f7bca73c06d01aae24ddc" }, "path_in_vcs": "bindgen" }
\ No newline at end of file @@ -42,26 +42,29 @@ rust_library_host { name: "libbindgen", crate_name: "bindgen", cargo_env_compat: true, - cargo_pkg_version: "0.64.0", + cargo_pkg_version: "0.65.1", srcs: [ "lib.rs", ":copy_bindgen_build_out", ], edition: "2018", features: [ - "cli", + "__cli", + "annotate-snippets", "experimental", "runtime", "which", "which-rustfmt", ], rustlibs: [ - "libbitflags-1.3.2", + "libannotate_snippets", + "libbitflags", "libcexpr", "libclang_sys", "liblazy_static", "liblazycell", "libpeeking_take_while", + "libprettyplease", "libproc_macro2", "libquote", "libregex", @@ -13,7 +13,7 @@ edition = "2018" rust-version = "1.60.0" name = "bindgen" -version = "0.64.0" +version = "0.65.1" authors = [ "Jyun-Yan You <jyyou.tw@gmail.com>", "Emilio Cobos Álvarez <emilio@crisal.io>", @@ -39,7 +39,12 @@ repository = "https://github.com/rust-lang/rust-bindgen" [lib] name = "bindgen" -path = "./lib.rs" +path = "lib.rs" + +[dependencies.annotate-snippets] +version = "0.9.1" +features = ["color"] +optional = true [dependencies.bitflags] version = "1.0.3" @@ -64,6 +69,9 @@ optional = true [dependencies.peeking_take_while] version = "0.1.2" +[dependencies.prettyplease] +version = "0.2.0" + [dependencies.proc-macro2] version = "1" default-features = false @@ -87,7 +95,7 @@ version = "1.0.1" version = "1" [dependencies.syn] -version = "2" +version = "2.0" features = [ "full", "extra-traits", @@ -100,17 +108,16 @@ optional = true default-features = false [features] -cli = [] +__cli = [] default = [ "logging", "runtime", "which-rustfmt", ] -experimental = [] +experimental = ["annotate-snippets"] logging = ["log"] runtime = ["clang-sys/runtime"] static = ["clang-sys/static"] -testing_only_docs = [] testing_only_extra_assertions = [] testing_only_libclang_5 = [] testing_only_libclang_9 = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index bc53be5..838524f 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -14,7 +14,7 @@ readme = "../README.md" repository = "https://github.com/rust-lang/rust-bindgen" documentation = "https://docs.rs/bindgen" homepage = "https://rust-lang.github.io/rust-bindgen/" -version = "0.64.0" +version = "0.65.1" edition = "2018" build = "build.rs" # If you change this, also update README.md and msrv in .github/workflows/bindgen.yml @@ -22,7 +22,7 @@ rust-version = "1.60.0" [lib] name = "bindgen" -path = "./lib.rs" +path = "lib.rs" [dependencies] bitflags = "1.0.3" @@ -32,9 +32,11 @@ lazycell = "1" lazy_static = "1" peeking_take_while = "0.1.2" quote = { version = "1", default-features = false } -syn = { version = "1.0.99", features = ["full", "extra-traits", "visit-mut"]} +syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"]} regex = { version = "1.5", default-features = false , features = ["std", "unicode"] } which = { version = "4.2.1", optional = true, default-features = false } +prettyplease = { version = "0.2.0" } +annotate-snippets = { version = "0.9.1", features = ["color"], optional = true } shlex = "1" rustc-hash = "1.0.1" proc-macro2 = { version = "1", default-features = false } @@ -47,12 +49,11 @@ static = ["clang-sys/static"] runtime = ["clang-sys/runtime"] # Dynamically discover a `rustfmt` binary using the `which` crate which-rustfmt = ["which"] -cli = [] -experimental = [] +__cli = [] +experimental = ["annotate-snippets"] # These features only exist for CI testing -- don't use them if you're not hacking # on bindgen! -testing_only_docs = [] testing_only_extra_assertions = [] testing_only_libclang_9 = [] testing_only_libclang_5 = [] @@ -11,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/bindgen/bindgen-0.64.0.crate" + value: "https://static.crates.io/crates/bindgen/bindgen-0.65.1.crate" } - version: "0.64.0" + version: "0.65.1" license_type: NOTICE last_upgrade_date { year: 2023 - month: 2 - day: 16 + month: 6 + day: 9 } } diff --git a/callbacks.rs b/callbacks.rs index dc20e25..5824466 100644 --- a/callbacks.rs +++ b/callbacks.rs @@ -25,7 +25,7 @@ impl Default for MacroParsingBehavior { /// A trait to allow configuring different kinds of types in different /// situations. pub trait ParseCallbacks: fmt::Debug { - #[cfg(feature = "cli")] + #[cfg(feature = "__cli")] #[doc(hidden)] fn cli_args(&self) -> Vec<String> { vec![] @@ -45,6 +45,15 @@ pub trait ParseCallbacks: fmt::Debug { None } + /// This function will run for every extern variable and function. The returned value determines + /// the link name in the bindings. + fn generated_link_name_override( + &self, + _item_info: ItemInfo<'_>, + ) -> Option<String> { + None + } + /// The integer kind an integer macro should have, given a name and the /// value of that macro, or `None` if you want the default to be chosen. fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> { @@ -93,6 +102,10 @@ pub trait ParseCallbacks: fmt::Debug { /// This will be called on every file inclusion, with the full path of the included file. fn include_file(&self, _filename: &str) {} + /// This will be called every time `bindgen` reads an environment variable whether it has any + /// content or not. + fn read_env_var(&self, _key: &str) {} + /// This will be called to determine whether a particular blocklisted type /// implements a trait or not. This will be used to implement traits on /// other types containing the blocklisted type. @@ -146,7 +159,7 @@ pub enum TypeKind { Union, } -/// An struct providing information about the item being passed to `ParseCallbacks::generated_name_override`. +/// A struct providing information about the item being passed to [`ParseCallbacks::generated_name_override`]. #[non_exhaustive] pub struct ItemInfo<'a> { /// The name of the item diff --git a/cargo2android.json b/cargo2android.json index fd62b50..ea1fdc2 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,6 +1,6 @@ { "copy-out": true, - "features": "cli,experimental,runtime,which-rustfmt", + "features": "__cli,experimental,runtime,which-rustfmt", "host-first-multilib": true, "run": true } @@ -2,6 +2,7 @@ //! `clang_sys` module. #![allow(non_upper_case_globals, dead_code)] +#![deny(clippy::missing_docs_in_private_items)] use crate::ir::context::BindgenContext; use clang_sys::*; @@ -16,7 +17,7 @@ use std::{mem, ptr, slice}; /// /// Values of this type can be used to check for different attributes using the `has_attrs` /// function. -pub struct Attribute { +pub(crate) struct Attribute { name: &'static [u8], kind: Option<CXCursorKind>, token_kind: CXTokenKind, @@ -24,7 +25,7 @@ pub struct Attribute { impl Attribute { /// A `warn_unused_result` attribute. - pub const MUST_USE: Self = Self { + pub(crate) const MUST_USE: Self = Self { name: b"warn_unused_result", // FIXME(emilio): clang-sys doesn't expose `CXCursor_WarnUnusedResultAttr` (from clang 9). kind: Some(440), @@ -32,14 +33,14 @@ impl Attribute { }; /// A `_Noreturn` attribute. - pub const NO_RETURN: Self = Self { + pub(crate) const NO_RETURN: Self = Self { name: b"_Noreturn", kind: None, token_kind: CXToken_Keyword, }; /// A `[[noreturn]]` attribute. - pub const NO_RETURN_CPP: Self = Self { + pub(crate) const NO_RETURN_CPP: Self = Self { name: b"noreturn", kind: None, token_kind: CXToken_Identifier, @@ -50,7 +51,7 @@ impl Attribute { /// /// We call the AST node pointed to by the cursor the cursor's "referent". #[derive(Copy, Clone)] -pub struct Cursor { +pub(crate) struct Cursor { x: CXCursor, } @@ -72,7 +73,7 @@ impl Cursor { /// available. /// /// The USR can be used to compare entities across translation units. - pub fn usr(&self) -> Option<String> { + pub(crate) fn usr(&self) -> Option<String> { let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) }; if s.is_empty() { None @@ -82,17 +83,17 @@ impl Cursor { } /// Is this cursor's referent a declaration? - pub fn is_declaration(&self) -> bool { + pub(crate) fn is_declaration(&self) -> bool { unsafe { clang_isDeclaration(self.kind()) != 0 } } /// Is this cursor's referent an anonymous record or so? - pub fn is_anonymous(&self) -> bool { + pub(crate) fn is_anonymous(&self) -> bool { unsafe { clang_Cursor_isAnonymous(self.x) != 0 } } /// Get this cursor's referent's spelling. - pub fn spelling(&self) -> String { + pub(crate) fn spelling(&self) -> String { unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) } } @@ -100,18 +101,18 @@ impl Cursor { /// /// This is not necessarily a valid identifier. It includes extra /// information, such as parameters for a function, etc. - pub fn display_name(&self) -> String { + pub(crate) fn display_name(&self) -> String { unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } } /// Get the mangled name of this cursor's referent. - pub fn mangling(&self) -> String { + pub(crate) fn mangling(&self) -> String { unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) } } /// Gets the C++ manglings for this cursor, or an error if the manglings /// are not available. - pub fn cxx_manglings(&self) -> Result<Vec<String>, ()> { + pub(crate) fn cxx_manglings(&self) -> Result<Vec<String>, ()> { use clang_sys::*; unsafe { let manglings = clang_Cursor_getCXXManglings(self.x); @@ -131,7 +132,7 @@ impl Cursor { } /// Returns whether the cursor refers to a built-in definition. - pub fn is_builtin(&self) -> bool { + pub(crate) fn is_builtin(&self) -> bool { let (file, _, _, _) = self.location().location(); file.name().is_none() } @@ -153,7 +154,7 @@ impl Cursor { /// /// void Foo::method() { /* ... */ } /// ``` - pub fn lexical_parent(&self) -> Cursor { + pub(crate) fn lexical_parent(&self) -> Cursor { unsafe { Cursor { x: clang_getCursorLexicalParent(self.x), @@ -165,7 +166,7 @@ impl Cursor { /// /// See documentation for `lexical_parent` for details on semantic vs /// lexical parents. - pub fn fallible_semantic_parent(&self) -> Option<Cursor> { + pub(crate) fn fallible_semantic_parent(&self) -> Option<Cursor> { let sp = unsafe { Cursor { x: clang_getCursorSemanticParent(self.x), @@ -181,7 +182,7 @@ impl Cursor { /// /// See documentation for `lexical_parent` for details on semantic vs /// lexical parents. - pub fn semantic_parent(&self) -> Cursor { + pub(crate) fn semantic_parent(&self) -> Cursor { self.fallible_semantic_parent().unwrap() } @@ -191,7 +192,7 @@ impl Cursor { /// /// NOTE: This may not return `Some` for partial template specializations, /// see #193 and #194. - pub fn num_template_args(&self) -> Option<u32> { + pub(crate) fn num_template_args(&self) -> Option<u32> { // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while // `clang_Cursor_getNumTemplateArguments` is totally unreliable. // Therefore, try former first, and only fallback to the latter if we @@ -225,7 +226,7 @@ impl Cursor { /// bindgen assumes there will only be one of them alive at a time, and /// disposes it on drop. That can change if this would be required, but I /// think we can survive fine without it. - pub fn translation_unit(&self) -> Cursor { + pub(crate) fn translation_unit(&self) -> Cursor { assert!(self.is_valid()); unsafe { let tu = clang_Cursor_getTranslationUnit(self.x); @@ -238,7 +239,7 @@ impl Cursor { } /// Is the referent a top level construct? - pub fn is_toplevel(&self) -> bool { + pub(crate) fn is_toplevel(&self) -> bool { let mut semantic_parent = self.fallible_semantic_parent(); while semantic_parent.is_some() && @@ -259,7 +260,7 @@ impl Cursor { /// There are a few kinds of types that we need to treat specially, mainly /// not tracking the type declaration but the location of the cursor, given /// clang doesn't expose a proper declaration for these types. - pub fn is_template_like(&self) -> bool { + pub(crate) fn is_template_like(&self) -> bool { matches!( self.kind(), CXCursor_ClassTemplate | @@ -269,28 +270,28 @@ impl Cursor { } /// Is this Cursor pointing to a function-like macro definition? - pub fn is_macro_function_like(&self) -> bool { + pub(crate) fn is_macro_function_like(&self) -> bool { unsafe { clang_Cursor_isMacroFunctionLike(self.x) != 0 } } /// Get the kind of referent this cursor is pointing to. - pub fn kind(&self) -> CXCursorKind { + pub(crate) fn kind(&self) -> CXCursorKind { self.x.kind } /// Returns true if the cursor is a definition - pub fn is_definition(&self) -> bool { + pub(crate) fn is_definition(&self) -> bool { unsafe { clang_isCursorDefinition(self.x) != 0 } } /// Is the referent a template specialization? - pub fn is_template_specialization(&self) -> bool { + pub(crate) fn is_template_specialization(&self) -> bool { self.specialized().is_some() } /// Is the referent a fully specialized template specialization without any /// remaining free template arguments? - pub fn is_fully_specialized_template(&self) -> bool { + pub(crate) fn is_fully_specialized_template(&self) -> bool { self.is_template_specialization() && self.kind() != CXCursor_ClassTemplatePartialSpecialization && self.num_template_args().unwrap_or(0) > 0 @@ -298,7 +299,7 @@ impl Cursor { /// Is the referent a template specialization that still has remaining free /// template arguments? - pub fn is_in_non_fully_specialized_template(&self) -> bool { + pub(crate) fn is_in_non_fully_specialized_template(&self) -> bool { if self.is_toplevel() { return false; } @@ -316,7 +317,7 @@ impl Cursor { } /// Is the referent any kind of template parameter? - pub fn is_template_parameter(&self) -> bool { + pub(crate) fn is_template_parameter(&self) -> bool { matches!( self.kind(), CXCursor_TemplateTemplateParameter | @@ -326,7 +327,7 @@ impl Cursor { } /// Does the referent's type or value depend on a template parameter? - pub fn is_dependent_on_template_parameter(&self) -> bool { + pub(crate) fn is_dependent_on_template_parameter(&self) -> bool { fn visitor( found_template_parameter: &mut bool, cur: Cursor, @@ -366,12 +367,12 @@ impl Cursor { } /// Is this cursor pointing a valid referent? - pub fn is_valid(&self) -> bool { + pub(crate) fn is_valid(&self) -> bool { unsafe { clang_isInvalid(self.kind()) == 0 } } /// Get the source location for the referent. - pub fn location(&self) -> SourceLocation { + pub(crate) fn location(&self) -> SourceLocation { unsafe { SourceLocation { x: clang_getCursorLocation(self.x), @@ -380,12 +381,12 @@ impl Cursor { } /// Get the source location range for the referent. - pub fn extent(&self) -> CXSourceRange { + pub(crate) fn extent(&self) -> CXSourceRange { unsafe { clang_getCursorExtent(self.x) } } /// Get the raw declaration comment for this referent, if one exists. - pub fn raw_comment(&self) -> Option<String> { + pub(crate) fn raw_comment(&self) -> Option<String> { let s = unsafe { cxstring_into_string(clang_Cursor_getRawCommentText(self.x)) }; @@ -397,7 +398,7 @@ impl Cursor { } /// Get the referent's parsed comment. - pub fn comment(&self) -> Comment { + pub(crate) fn comment(&self) -> Comment { unsafe { Comment { x: clang_Cursor_getParsedComment(self.x), @@ -406,7 +407,7 @@ impl Cursor { } /// Get the referent's type. - pub fn cur_type(&self) -> Type { + pub(crate) fn cur_type(&self) -> Type { unsafe { Type { x: clang_getCursorType(self.x), @@ -417,7 +418,7 @@ impl Cursor { /// Given that this cursor's referent is a reference to another type, or is /// a declaration, get the cursor pointing to the referenced type or type of /// the declared thing. - pub fn definition(&self) -> Option<Cursor> { + pub(crate) fn definition(&self) -> Option<Cursor> { unsafe { let ret = Cursor { x: clang_getCursorDefinition(self.x), @@ -433,7 +434,7 @@ impl Cursor { /// Given that this cursor's referent is reference type, get the cursor /// pointing to the referenced type. - pub fn referenced(&self) -> Option<Cursor> { + pub(crate) fn referenced(&self) -> Option<Cursor> { unsafe { let ret = Cursor { x: clang_getCursorReferenced(self.x), @@ -452,7 +453,7 @@ impl Cursor { /// Many types can be declared multiple times before finally being properly /// defined. This method allows us to get the canonical cursor for the /// referent type. - pub fn canonical(&self) -> Cursor { + pub(crate) fn canonical(&self) -> Cursor { unsafe { Cursor { x: clang_getCanonicalCursor(self.x), @@ -463,7 +464,7 @@ impl Cursor { /// Given that this cursor points to either a template specialization or a /// template instantiation, get a cursor pointing to the template definition /// that is being specialized. - pub fn specialized(&self) -> Option<Cursor> { + pub(crate) fn specialized(&self) -> Option<Cursor> { unsafe { let ret = Cursor { x: clang_getSpecializedCursorTemplate(self.x), @@ -478,14 +479,14 @@ impl Cursor { /// Assuming that this cursor's referent is a template declaration, get the /// kind of cursor that would be generated for its specializations. - pub fn template_kind(&self) -> CXCursorKind { + pub(crate) fn template_kind(&self) -> CXCursorKind { unsafe { clang_getTemplateCursorKind(self.x) } } /// Traverse this cursor's referent and its children. /// /// Call the given function on each AST node traversed. - pub fn visit<Visitor>(&self, mut visitor: Visitor) + pub(crate) fn visit<Visitor>(&self, mut visitor: Visitor) where Visitor: FnMut(Cursor) -> CXChildVisitResult, { @@ -496,7 +497,7 @@ impl Cursor { } /// Collect all of this cursor's children into a vec and return them. - pub fn collect_children(&self) -> Vec<Cursor> { + pub(crate) fn collect_children(&self) -> Vec<Cursor> { let mut children = vec![]; self.visit(|c| { children.push(c); @@ -506,7 +507,7 @@ impl Cursor { } /// Does this cursor have any children? - pub fn has_children(&self) -> bool { + pub(crate) fn has_children(&self) -> bool { let mut has_children = false; self.visit(|_| { has_children = true; @@ -516,7 +517,7 @@ impl Cursor { } /// Does this cursor have at least `n` children? - pub fn has_at_least_num_children(&self, n: usize) -> bool { + pub(crate) fn has_at_least_num_children(&self, n: usize) -> bool { assert!(n > 0); let mut num_left = n; self.visit(|_| { @@ -533,7 +534,7 @@ impl Cursor { /// Returns whether the given location contains a cursor with the given /// kind in the first level of nesting underneath (doesn't look /// recursively). - pub fn contains_cursor(&self, kind: CXCursorKind) -> bool { + pub(crate) fn contains_cursor(&self, kind: CXCursorKind) -> bool { let mut found = false; self.visit(|c| { @@ -549,17 +550,17 @@ impl Cursor { } /// Is the referent an inlined function? - pub fn is_inlined_function(&self) -> bool { + pub(crate) fn is_inlined_function(&self) -> bool { unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } } /// Is the referent a defaulted function? - pub fn is_defaulted_function(&self) -> bool { + pub(crate) fn is_defaulted_function(&self) -> bool { unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 } } /// Is the referent a deleted function? - pub fn is_deleted_function(&self) -> bool { + pub(crate) fn is_deleted_function(&self) -> bool { // Unfortunately, libclang doesn't yet have an API for checking if a // member function is deleted, but the following should be a good // enough approximation. @@ -575,13 +576,13 @@ impl Cursor { } /// Is the referent a bit field declaration? - pub fn is_bit_field(&self) -> bool { + pub(crate) fn is_bit_field(&self) -> bool { unsafe { clang_Cursor_isBitField(self.x) != 0 } } /// Get a cursor to the bit field's width expression, or `None` if it's not /// a bit field. - pub fn bit_width_expr(&self) -> Option<Cursor> { + pub(crate) fn bit_width_expr(&self) -> Option<Cursor> { if !self.is_bit_field() { return None; } @@ -605,7 +606,7 @@ impl Cursor { /// Get the width of this cursor's referent bit field, or `None` if the /// referent is not a bit field or if the width could not be evaluated. - pub fn bit_width(&self) -> Option<u32> { + pub(crate) fn bit_width(&self) -> Option<u32> { // It is not safe to check the bit width without ensuring it doesn't // depend on a template parameter. See // https://github.com/rust-lang/rust-bindgen/issues/2239 @@ -625,7 +626,7 @@ impl Cursor { /// Get the integer representation type used to hold this cursor's referent /// enum type. - pub fn enum_type(&self) -> Option<Type> { + pub(crate) fn enum_type(&self) -> Option<Type> { unsafe { let t = Type { x: clang_getEnumDeclIntegerType(self.x), @@ -641,7 +642,7 @@ impl Cursor { /// Get the boolean constant value for this cursor's enum variant referent. /// /// Returns None if the cursor's referent is not an enum variant. - pub fn enum_val_boolean(&self) -> Option<bool> { + pub(crate) fn enum_val_boolean(&self) -> Option<bool> { unsafe { if self.kind() == CXCursor_EnumConstantDecl { Some(clang_getEnumConstantDeclValue(self.x) != 0) @@ -654,7 +655,7 @@ impl Cursor { /// Get the signed constant value for this cursor's enum variant referent. /// /// Returns None if the cursor's referent is not an enum variant. - pub fn enum_val_signed(&self) -> Option<i64> { + pub(crate) fn enum_val_signed(&self) -> Option<i64> { unsafe { if self.kind() == CXCursor_EnumConstantDecl { #[allow(clippy::unnecessary_cast)] @@ -668,7 +669,7 @@ impl Cursor { /// Get the unsigned constant value for this cursor's enum variant referent. /// /// Returns None if the cursor's referent is not an enum variant. - pub fn enum_val_unsigned(&self) -> Option<u64> { + pub(crate) fn enum_val_unsigned(&self) -> Option<u64> { unsafe { if self.kind() == CXCursor_EnumConstantDecl { #[allow(clippy::unnecessary_cast)] @@ -680,7 +681,7 @@ impl Cursor { } /// Does this cursor have the given attributes? - pub fn has_attrs<const N: usize>( + pub(crate) fn has_attrs<const N: usize>( &self, attrs: &[Attribute; N], ) -> [bool; N] { @@ -718,7 +719,7 @@ impl Cursor { /// Given that this cursor's referent is a `typedef`, get the `Type` that is /// being aliased. - pub fn typedef_type(&self) -> Option<Type> { + pub(crate) fn typedef_type(&self) -> Option<Type> { let inner = Type { x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) }, }; @@ -733,12 +734,12 @@ impl Cursor { /// Get the linkage kind for this cursor's referent. /// /// This only applies to functions and variables. - pub fn linkage(&self) -> CXLinkageKind { + pub(crate) fn linkage(&self) -> CXLinkageKind { unsafe { clang_getCursorLinkage(self.x) } } /// Get the visibility of this cursor's referent. - pub fn visibility(&self) -> CXVisibilityKind { + pub(crate) fn visibility(&self) -> CXVisibilityKind { unsafe { clang_getCursorVisibility(self.x) } } @@ -747,7 +748,7 @@ impl Cursor { /// /// Returns None if the cursor's referent is not a function/method call or /// declaration. - pub fn args(&self) -> Option<Vec<Cursor>> { + pub(crate) fn args(&self) -> Option<Vec<Cursor>> { // match self.kind() { // CXCursor_FunctionDecl | // CXCursor_CXXMethod => { @@ -765,7 +766,7 @@ impl Cursor { /// /// Returns Err if the cursor's referent is not a function/method call or /// declaration. - pub fn num_args(&self) -> Result<u32, ()> { + pub(crate) fn num_args(&self) -> Result<u32, ()> { unsafe { let w = clang_Cursor_getNumArguments(self.x); if w == -1 { @@ -777,7 +778,7 @@ impl Cursor { } /// Get the access specifier for this cursor's referent. - pub fn access_specifier(&self) -> CX_CXXAccessSpecifier { + pub(crate) fn access_specifier(&self) -> CX_CXXAccessSpecifier { unsafe { clang_getCXXAccessSpecifier(self.x) } } @@ -785,19 +786,19 @@ impl Cursor { /// /// Returns true if self.access_specifier() is `CX_CXXPublic` or /// `CX_CXXInvalidAccessSpecifier`. - pub fn public_accessible(&self) -> bool { + pub(crate) fn public_accessible(&self) -> bool { let access = self.access_specifier(); access == CX_CXXPublic || access == CX_CXXInvalidAccessSpecifier } /// Is this cursor's referent a field declaration that is marked as /// `mutable`? - pub fn is_mutable_field(&self) -> bool { + pub(crate) fn is_mutable_field(&self) -> bool { unsafe { clang_CXXField_isMutable(self.x) != 0 } } /// Get the offset of the field represented by the Cursor. - pub fn offset_of_field(&self) -> Result<usize, LayoutError> { + pub(crate) fn offset_of_field(&self) -> Result<usize, LayoutError> { let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) }; if offset < 0 { @@ -808,37 +809,37 @@ impl Cursor { } /// Is this cursor's referent a member function that is declared `static`? - pub fn method_is_static(&self) -> bool { + pub(crate) fn method_is_static(&self) -> bool { unsafe { clang_CXXMethod_isStatic(self.x) != 0 } } /// Is this cursor's referent a member function that is declared `const`? - pub fn method_is_const(&self) -> bool { + pub(crate) fn method_is_const(&self) -> bool { unsafe { clang_CXXMethod_isConst(self.x) != 0 } } /// Is this cursor's referent a member function that is virtual? - pub fn method_is_virtual(&self) -> bool { + pub(crate) fn method_is_virtual(&self) -> bool { unsafe { clang_CXXMethod_isVirtual(self.x) != 0 } } /// Is this cursor's referent a member function that is pure virtual? - pub fn method_is_pure_virtual(&self) -> bool { + pub(crate) fn method_is_pure_virtual(&self) -> bool { unsafe { clang_CXXMethod_isPureVirtual(self.x) != 0 } } /// Is this cursor's referent a struct or class with virtual members? - pub fn is_virtual_base(&self) -> bool { + pub(crate) fn is_virtual_base(&self) -> bool { unsafe { clang_isVirtualBase(self.x) != 0 } } /// Try to evaluate this cursor. - pub fn evaluate(&self) -> Option<EvalResult> { + pub(crate) fn evaluate(&self) -> Option<EvalResult> { EvalResult::new(*self) } /// Return the result type for this cursor - pub fn ret_type(&self) -> Option<Type> { + pub(crate) fn ret_type(&self) -> Option<Type> { let rt = Type { x: unsafe { clang_getCursorResultType(self.x) }, }; @@ -850,12 +851,12 @@ impl Cursor { } /// Gets the tokens that correspond to that cursor. - pub fn tokens(&self) -> RawTokens { + pub(crate) fn tokens(&self) -> RawTokens { RawTokens::new(self) } /// Gets the tokens that correspond to that cursor as `cexpr` tokens. - pub fn cexpr_tokens(self) -> Vec<cexpr::token::Token> { + pub(crate) fn cexpr_tokens(self) -> Vec<cexpr::token::Token> { self.tokens() .iter() .filter_map(|token| token.as_cexpr_token()) @@ -865,7 +866,7 @@ impl Cursor { /// Obtain the real path name of a cursor of InclusionDirective kind. /// /// Returns None if the cursor does not include a file, otherwise the file's full name - pub fn get_included_file_name(&self) -> Option<String> { + pub(crate) fn get_included_file_name(&self) -> Option<String> { let file = unsafe { clang_sys::clang_getIncludedFile(self.x) }; if file.is_null() { None @@ -878,7 +879,7 @@ impl Cursor { } /// A struct that owns the tokenizer result from a given cursor. -pub struct RawTokens<'a> { +pub(crate) struct RawTokens<'a> { cursor: &'a Cursor, tu: CXTranslationUnit, tokens: *mut CXToken, @@ -908,7 +909,7 @@ impl<'a> RawTokens<'a> { } /// Get an iterator over these tokens. - pub fn iter(&self) -> ClangTokenIterator { + pub(crate) fn iter(&self) -> ClangTokenIterator { ClangTokenIterator { tu: self.tu, raw: self.as_slice().iter(), @@ -934,19 +935,19 @@ impl<'a> Drop for RawTokens<'a> { /// slightly more convenient version of `CXToken` which owns the spelling /// string and extent. #[derive(Debug)] -pub struct ClangToken { +pub(crate) struct ClangToken { spelling: CXString, /// The extent of the token. This is the same as the relevant member from /// `CXToken`. - pub extent: CXSourceRange, + pub(crate) extent: CXSourceRange, /// The kind of the token. This is the same as the relevant member from /// `CXToken`. - pub kind: CXTokenKind, + pub(crate) kind: CXTokenKind, } impl ClangToken { /// Get the token spelling, without being converted to utf-8. - pub fn spelling(&self) -> &[u8] { + pub(crate) fn spelling(&self) -> &[u8] { let c_str = unsafe { CStr::from_ptr(clang_getCString(self.spelling) as *const _) }; @@ -954,7 +955,7 @@ impl ClangToken { } /// Converts a ClangToken to a `cexpr` token if possible. - pub fn as_cexpr_token(&self) -> Option<cexpr::token::Token> { + pub(crate) fn as_cexpr_token(&self) -> Option<cexpr::token::Token> { use cexpr::token; let kind = match self.kind { @@ -985,7 +986,7 @@ impl Drop for ClangToken { } /// An iterator over a set of Tokens. -pub struct ClangTokenIterator<'a> { +pub(crate) struct ClangTokenIterator<'a> { tu: CXTranslationUnit, raw: slice::Iter<'a, CXToken>, } @@ -1010,7 +1011,7 @@ impl<'a> Iterator for ClangTokenIterator<'a> { /// Checks whether the name looks like an identifier, i.e. is alphanumeric /// (including '_') and does not start with a digit. -pub fn is_valid_identifier(name: &str) -> bool { +pub(crate) fn is_valid_identifier(name: &str) -> bool { let mut chars = name.chars(); let first_valid = chars .next() @@ -1050,7 +1051,7 @@ impl Hash for Cursor { /// The type of a node in clang's AST. #[derive(Clone, Copy)] -pub struct Type { +pub(crate) struct Type { x: CXType, } @@ -1078,7 +1079,7 @@ impl fmt::Debug for Type { /// An error about the layout of a struct, class, or type. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum LayoutError { +pub(crate) enum LayoutError { /// Asked for the layout of an invalid type. Invalid, /// Asked for the layout of an incomplete type. @@ -1111,12 +1112,12 @@ impl ::std::convert::From<i32> for LayoutError { impl Type { /// Get this type's kind. - pub fn kind(&self) -> CXTypeKind { + pub(crate) fn kind(&self) -> CXTypeKind { self.x.kind } /// Get a cursor pointing to this type's declaration. - pub fn declaration(&self) -> Cursor { + pub(crate) fn declaration(&self) -> Cursor { unsafe { Cursor { x: clang_getTypeDeclaration(self.x), @@ -1125,7 +1126,7 @@ impl Type { } /// Get the canonical declaration of this type, if it is available. - pub fn canonical_declaration( + pub(crate) fn canonical_declaration( &self, location: Option<&Cursor>, ) -> Option<CanonicalTypeDeclaration> { @@ -1151,7 +1152,7 @@ impl Type { } /// Get a raw display name for this type. - pub fn spelling(&self) -> String { + pub(crate) fn spelling(&self) -> String { let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }; // Clang 5.0 introduced changes in the spelling API so it returned the // full qualified name. Let's undo that here. @@ -1165,7 +1166,7 @@ impl Type { } /// Is this type const qualified? - pub fn is_const(&self) -> bool { + pub(crate) fn is_const(&self) -> bool { unsafe { clang_isConstQualifiedType(self.x) != 0 } } @@ -1203,7 +1204,7 @@ impl Type { /// What is the size of this type? Paper over invalid types by returning `0` /// for them. - pub fn size(&self, ctx: &BindgenContext) -> usize { + pub(crate) fn size(&self, ctx: &BindgenContext) -> usize { let val = self.clang_size_of(ctx); if val < 0 { 0 @@ -1213,7 +1214,7 @@ impl Type { } /// What is the size of this type? - pub fn fallible_size( + pub(crate) fn fallible_size( &self, ctx: &BindgenContext, ) -> Result<usize, LayoutError> { @@ -1227,7 +1228,7 @@ impl Type { /// What is the alignment of this type? Paper over invalid types by /// returning `0`. - pub fn align(&self, ctx: &BindgenContext) -> usize { + pub(crate) fn align(&self, ctx: &BindgenContext) -> usize { let val = self.clang_align_of(ctx); if val < 0 { 0 @@ -1237,7 +1238,7 @@ impl Type { } /// What is the alignment of this type? - pub fn fallible_align( + pub(crate) fn fallible_align( &self, ctx: &BindgenContext, ) -> Result<usize, LayoutError> { @@ -1251,7 +1252,7 @@ impl Type { /// Get the layout for this type, or an error describing why it does not /// have a valid layout. - pub fn fallible_layout( + pub(crate) fn fallible_layout( &self, ctx: &BindgenContext, ) -> Result<crate::ir::layout::Layout, LayoutError> { @@ -1263,7 +1264,7 @@ impl Type { /// Get the number of template arguments this type has, or `None` if it is /// not some kind of template. - pub fn num_template_args(&self) -> Option<u32> { + pub(crate) fn num_template_args(&self) -> Option<u32> { let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; if n >= 0 { Some(n as u32) @@ -1275,7 +1276,7 @@ impl Type { /// If this type is a class template specialization, return its /// template arguments. Otherwise, return None. - pub fn template_args(&self) -> Option<TypeTemplateArgIterator> { + pub(crate) fn template_args(&self) -> Option<TypeTemplateArgIterator> { self.num_template_args().map(|n| TypeTemplateArgIterator { x: self.x, length: n, @@ -1286,7 +1287,7 @@ impl Type { /// Given that this type is a function prototype, return the types of its parameters. /// /// Returns None if the type is not a function prototype. - pub fn args(&self) -> Option<Vec<Type>> { + pub(crate) fn args(&self) -> Option<Vec<Type>> { self.num_args().ok().map(|num| { (0..num) .map(|i| Type { @@ -1299,7 +1300,7 @@ impl Type { /// Given that this type is a function prototype, return the number of arguments it takes. /// /// Returns Err if the type is not a function prototype. - pub fn num_args(&self) -> Result<u32, ()> { + pub(crate) fn num_args(&self) -> Result<u32, ()> { unsafe { let w = clang_getNumArgTypes(self.x); if w == -1 { @@ -1312,7 +1313,7 @@ impl Type { /// Given that this type is a pointer type, return the type that it points /// to. - pub fn pointee_type(&self) -> Option<Type> { + pub(crate) fn pointee_type(&self) -> Option<Type> { match self.kind() { CXType_Pointer | CXType_RValueReference | @@ -1332,7 +1333,7 @@ impl Type { /// Given that this type is an array, vector, or complex type, return the /// type of its elements. - pub fn elem_type(&self) -> Option<Type> { + pub(crate) fn elem_type(&self) -> Option<Type> { let current_type = Type { x: unsafe { clang_getElementType(self.x) }, }; @@ -1345,7 +1346,7 @@ impl Type { /// Given that this type is an array or vector type, return its number of /// elements. - pub fn num_elements(&self) -> Option<usize> { + pub(crate) fn num_elements(&self) -> Option<usize> { let num_elements_returned = unsafe { clang_getNumElements(self.x) }; if num_elements_returned != -1 { Some(num_elements_returned as usize) @@ -1356,7 +1357,7 @@ impl Type { /// Get the canonical version of this type. This sees through `typedef`s and /// aliases to get the underlying, canonical type. - pub fn canonical_type(&self) -> Type { + pub(crate) fn canonical_type(&self) -> Type { unsafe { Type { x: clang_getCanonicalType(self.x), @@ -1365,13 +1366,13 @@ impl Type { } /// Is this type a variadic function type? - pub fn is_variadic(&self) -> bool { + pub(crate) fn is_variadic(&self) -> bool { unsafe { clang_isFunctionTypeVariadic(self.x) != 0 } } /// Given that this type is a function type, get the type of its return /// value. - pub fn ret_type(&self) -> Option<Type> { + pub(crate) fn ret_type(&self) -> Option<Type> { let rt = Type { x: unsafe { clang_getResultType(self.x) }, }; @@ -1384,13 +1385,13 @@ impl Type { /// Given that this type is a function type, get its calling convention. If /// this is not a function type, `CXCallingConv_Invalid` is returned. - pub fn call_conv(&self) -> CXCallingConv { + pub(crate) fn call_conv(&self) -> CXCallingConv { unsafe { clang_getFunctionTypeCallingConv(self.x) } } /// For elaborated types (types which use `class`, `struct`, or `union` to /// disambiguate types from local bindings), get the underlying type. - pub fn named(&self) -> Type { + pub(crate) fn named(&self) -> Type { unsafe { Type { x: clang_Type_getNamedType(self.x), @@ -1399,17 +1400,17 @@ impl Type { } /// Is this a valid type? - pub fn is_valid(&self) -> bool { + pub(crate) fn is_valid(&self) -> bool { self.kind() != CXType_Invalid } /// Is this a valid and exposed type? - pub fn is_valid_and_exposed(&self) -> bool { + pub(crate) fn is_valid_and_exposed(&self) -> bool { self.is_valid() && self.kind() != CXType_Unexposed } /// Is this type a fully instantiated template? - pub fn is_fully_instantiated_template(&self) -> bool { + pub(crate) fn is_fully_instantiated_template(&self) -> bool { // Yep, the spelling of this containing type-parameter is extremely // nasty... But can happen in <type_traits>. Unfortunately I couldn't // reduce it enough :( @@ -1431,7 +1432,7 @@ impl Type { /// typename T::Associated member; /// }; /// ``` - pub fn is_associated_type(&self) -> bool { + pub(crate) fn is_associated_type(&self) -> bool { // This is terrible :( fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool { lazy_static! { @@ -1457,22 +1458,22 @@ impl Type { /// cursor match up in a canonical declaration relationship, and it simply /// cannot be otherwise. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct CanonicalTypeDeclaration(Type, Cursor); +pub(crate) struct CanonicalTypeDeclaration(Type, Cursor); impl CanonicalTypeDeclaration { /// Get the type. - pub fn ty(&self) -> &Type { + pub(crate) fn ty(&self) -> &Type { &self.0 } /// Get the type's canonical declaration cursor. - pub fn cursor(&self) -> &Cursor { + pub(crate) fn cursor(&self) -> &Cursor { &self.1 } } /// An iterator for a type's template arguments. -pub struct TypeTemplateArgIterator { +pub(crate) struct TypeTemplateArgIterator { x: CXType, length: u32, index: u32, @@ -1502,14 +1503,14 @@ impl ExactSizeIterator for TypeTemplateArgIterator { /// A `SourceLocation` is a file, line, column, and byte offset location for /// some source text. -pub struct SourceLocation { +pub(crate) struct SourceLocation { x: CXSourceLocation, } impl SourceLocation { /// Get the (file, line, column, byte offset) tuple for this source /// location. - pub fn location(&self) -> (File, usize, usize, usize) { + pub(crate) fn location(&self) -> (File, usize, usize, usize) { unsafe { let mut file = mem::zeroed(); let mut line = 0; @@ -1543,18 +1544,18 @@ impl fmt::Debug for SourceLocation { /// A comment in the source text. /// /// Comments are sort of parsed by Clang, and have a tree structure. -pub struct Comment { +pub(crate) struct Comment { x: CXComment, } impl Comment { /// What kind of comment is this? - pub fn kind(&self) -> CXCommentKind { + pub(crate) fn kind(&self) -> CXCommentKind { unsafe { clang_Comment_getKind(self.x) } } /// Get this comment's children comment - pub fn get_children(&self) -> CommentChildrenIterator { + pub(crate) fn get_children(&self) -> CommentChildrenIterator { CommentChildrenIterator { parent: self.x, length: unsafe { clang_Comment_getNumChildren(self.x) }, @@ -1564,12 +1565,12 @@ impl Comment { /// Given that this comment is the start or end of an HTML tag, get its tag /// name. - pub fn get_tag_name(&self) -> String { + pub(crate) fn get_tag_name(&self) -> String { unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) } } /// Given that this comment is an HTML start tag, get its attributes. - pub fn get_tag_attrs(&self) -> CommentAttributesIterator { + pub(crate) fn get_tag_attrs(&self) -> CommentAttributesIterator { CommentAttributesIterator { x: self.x, length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, @@ -1579,7 +1580,7 @@ impl Comment { } /// An iterator for a comment's children -pub struct CommentChildrenIterator { +pub(crate) struct CommentChildrenIterator { parent: CXComment, length: c_uint, index: c_uint, @@ -1601,15 +1602,15 @@ impl Iterator for CommentChildrenIterator { } /// An HTML start tag comment attribute -pub struct CommentAttribute { +pub(crate) struct CommentAttribute { /// HTML start tag attribute name - pub name: String, + pub(crate) name: String, /// HTML start tag attribute value - pub value: String, + pub(crate) value: String, } /// An iterator for a comment's attributes -pub struct CommentAttributesIterator { +pub(crate) struct CommentAttributesIterator { x: CXComment, length: c_uint, index: c_uint, @@ -1640,13 +1641,13 @@ impl Iterator for CommentAttributesIterator { } /// A source file. -pub struct File { +pub(crate) struct File { x: CXFile, } impl File { /// Get the name of this source file. - pub fn name(&self) -> Option<String> { + pub(crate) fn name(&self) -> Option<String> { if self.x.is_null() { return None; } @@ -1670,7 +1671,7 @@ fn cxstring_into_string(s: CXString) -> String { /// An `Index` is an environment for a set of translation units that will /// typically end up linked together in one final binary. -pub struct Index { +pub(crate) struct Index { x: CXIndex, } @@ -1681,7 +1682,7 @@ impl Index { /// headers are included when enumerating a translation unit's "locals". /// /// The `diag` parameter controls whether debugging diagnostics are enabled. - pub fn new(pch: bool, diag: bool) -> Index { + pub(crate) fn new(pch: bool, diag: bool) -> Index { unsafe { Index { x: clang_createIndex(pch as c_int, diag as c_int), @@ -1705,7 +1706,7 @@ impl Drop for Index { } /// A translation unit (or "compilation unit"). -pub struct TranslationUnit { +pub(crate) struct TranslationUnit { x: CXTranslationUnit, } @@ -1717,7 +1718,7 @@ impl fmt::Debug for TranslationUnit { impl TranslationUnit { /// Parse a source file into a translation unit. - pub fn parse( + pub(crate) fn parse( ix: &Index, file: &str, cmd_args: &[String], @@ -1753,7 +1754,7 @@ impl TranslationUnit { /// Get the Clang diagnostic information associated with this translation /// unit. - pub fn diags(&self) -> Vec<Diagnostic> { + pub(crate) fn diags(&self) -> Vec<Diagnostic> { unsafe { let num = clang_getNumDiagnostics(self.x) as usize; let mut diags = vec![]; @@ -1767,7 +1768,7 @@ impl TranslationUnit { } /// Get a cursor pointing to the root of this translation unit's AST. - pub fn cursor(&self) -> Cursor { + pub(crate) fn cursor(&self) -> Cursor { unsafe { Cursor { x: clang_getTranslationUnitCursor(self.x), @@ -1776,7 +1777,7 @@ impl TranslationUnit { } /// Is this the null translation unit? - pub fn is_null(&self) -> bool { + pub(crate) fn is_null(&self) -> bool { self.x.is_null() } } @@ -1790,14 +1791,14 @@ impl Drop for TranslationUnit { } /// A diagnostic message generated while parsing a translation unit. -pub struct Diagnostic { +pub(crate) struct Diagnostic { x: CXDiagnostic, } impl Diagnostic { /// Format this diagnostic message as a string, using the given option bit /// flags. - pub fn format(&self) -> String { + pub(crate) fn format(&self) -> String { unsafe { let opts = clang_defaultDiagnosticDisplayOptions(); cxstring_into_string(clang_formatDiagnostic(self.x, opts)) @@ -1805,7 +1806,7 @@ impl Diagnostic { } /// What is the severity of this diagnostic message? - pub fn severity(&self) -> CXDiagnosticSeverity { + pub(crate) fn severity(&self) -> CXDiagnosticSeverity { unsafe { clang_getDiagnosticSeverity(self.x) } } } @@ -1820,17 +1821,17 @@ impl Drop for Diagnostic { } /// A file which has not been saved to disk. -pub struct UnsavedFile { +pub(crate) struct UnsavedFile { x: CXUnsavedFile, /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in /// `CXUnsavedFile`. - pub name: CString, + pub(crate) name: CString, contents: CString, } impl UnsavedFile { /// Construct a new unsaved file with the given `name` and `contents`. - pub fn new(name: String, contents: String) -> UnsavedFile { + pub(crate) fn new(name: String, contents: String) -> UnsavedFile { let name = CString::new(name).unwrap(); let contents = CString::new(contents).unwrap(); let x = CXUnsavedFile { @@ -1853,17 +1854,17 @@ impl fmt::Debug for UnsavedFile { } /// Convert a cursor kind into a static string. -pub fn kind_to_str(x: CXCursorKind) -> String { +pub(crate) fn kind_to_str(x: CXCursorKind) -> String { unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } } /// Convert a type kind to a static string. -pub fn type_to_str(x: CXTypeKind) -> String { +pub(crate) fn type_to_str(x: CXTypeKind) -> String { unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } } /// Dump the Clang AST to stdout for debugging purposes. -pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { +pub(crate) fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { fn print_indent<S: AsRef<str>>(depth: isize, s: S) { for _ in 0..depth { print!(" "); @@ -2095,19 +2096,20 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { } /// Try to extract the clang version to a string -pub fn extract_clang_version() -> String { +pub(crate) fn extract_clang_version() -> String { unsafe { cxstring_into_string(clang_getClangVersion()) } } /// A wrapper for the result of evaluating an expression. #[derive(Debug)] -pub struct EvalResult { +pub(crate) struct EvalResult { x: CXEvalResult, + ty: Type, } impl EvalResult { /// Evaluate `cursor` and return the result. - pub fn new(cursor: Cursor) -> Option<Self> { + pub(crate) fn new(cursor: Cursor) -> Option<Self> { // Work around https://bugs.llvm.org/show_bug.cgi?id=42532, see: // * https://github.com/rust-lang/rust-bindgen/issues/283 // * https://github.com/rust-lang/rust-bindgen/issues/1590 @@ -2130,6 +2132,7 @@ impl EvalResult { } Some(EvalResult { x: unsafe { clang_Cursor_Evaluate(cursor.x) }, + ty: cursor.cur_type().canonical_type(), }) } @@ -2138,7 +2141,7 @@ impl EvalResult { } /// Try to get back the result as a double. - pub fn as_double(&self) -> Option<f64> { + pub(crate) fn as_double(&self) -> Option<f64> { match self.kind() { CXEval_Float => { Some(unsafe { clang_EvalResult_getAsDouble(self.x) }) @@ -2148,7 +2151,7 @@ impl EvalResult { } /// Try to get back the result as an integer. - pub fn as_int(&self) -> Option<i64> { + pub(crate) fn as_int(&self) -> Option<i64> { if self.kind() != CXEval_Int { return None; } @@ -2175,14 +2178,23 @@ impl EvalResult { /// Evaluates the expression as a literal string, that may or may not be /// valid utf-8. - pub fn as_literal_string(&self) -> Option<Vec<u8>> { - match self.kind() { - CXEval_StrLiteral => { + pub(crate) fn as_literal_string(&self) -> Option<Vec<u8>> { + if self.kind() != CXEval_StrLiteral { + return None; + } + + let char_ty = self.ty.pointee_type().or_else(|| self.ty.elem_type())?; + match char_ty.kind() { + CXType_Char_S | CXType_SChar | CXType_Char_U | CXType_UChar => { let ret = unsafe { CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) }; Some(ret.to_bytes().to_vec()) } + // FIXME: Support generating these. + CXType_Char16 => None, + CXType_Char32 => None, + CXType_WChar => None, _ => None, } } @@ -2196,16 +2208,16 @@ impl Drop for EvalResult { /// Target information obtained from libclang. #[derive(Debug)] -pub struct TargetInfo { +pub(crate) struct TargetInfo { /// The target triple. - pub triple: String, + pub(crate) triple: String, /// The width of the pointer _in bits_. - pub pointer_width: usize, + pub(crate) pointer_width: usize, } impl TargetInfo { /// Tries to obtain target information from libclang. - pub fn new(tu: &TranslationUnit) -> Self { + pub(crate) fn new(tu: &TranslationUnit) -> Self { let triple; let pointer_width; unsafe { diff --git a/codegen/dyngen.rs b/codegen/dyngen.rs index d8ea811..c067fad 100644 --- a/codegen/dyngen.rs +++ b/codegen/dyngen.rs @@ -5,7 +5,7 @@ use proc_macro2::Ident; /// Used to build the output tokens for dynamic bindings. #[derive(Default)] -pub struct DynamicItems { +pub(crate) struct DynamicItems { /// Tracks the tokens that will appears inside the library struct -- e.g.: /// ```ignore /// struct Lib { @@ -69,11 +69,11 @@ pub struct DynamicItems { } impl DynamicItems { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self::default() } - pub fn get_tokens( + pub(crate) fn get_tokens( &self, lib_ident: Ident, ctx: &BindgenContext, diff --git a/codegen/error.rs b/codegen/error.rs index c1bcf4e..ead3496 100644 --- a/codegen/error.rs +++ b/codegen/error.rs @@ -3,7 +3,7 @@ use std::fmt; /// Errors that can occur during code generation. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum Error { +pub(crate) enum Error { /// Tried to generate an opaque blob for a type that did not have a layout. NoLayoutForOpaqueBlob, @@ -30,4 +30,4 @@ impl fmt::Display for Error { impl error::Error for Error {} /// A `Result` of `T` or an error of `bindgen::codegen::error::Error`. -pub type Result<T> = ::std::result::Result<T, Error>; +pub(crate) type Result<T> = ::std::result::Result<T, Error>; diff --git a/codegen/helpers.rs b/codegen/helpers.rs index 088c7f9..726fe75 100644 --- a/codegen/helpers.rs +++ b/codegen/helpers.rs @@ -5,18 +5,18 @@ use crate::ir::layout::Layout; use proc_macro2::{Ident, Span, TokenStream}; use quote::TokenStreamExt; -pub mod attributes { +pub(crate) mod attributes { use proc_macro2::{Ident, Span, TokenStream}; - use std::str::FromStr; + use std::{borrow::Cow, str::FromStr}; - pub fn repr(which: &str) -> TokenStream { + pub(crate) fn repr(which: &str) -> TokenStream { let which = Ident::new(which, Span::call_site()); quote! { #[repr( #which )] } } - pub fn repr_list(which_ones: &[&str]) -> TokenStream { + pub(crate) fn repr_list(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() .cloned() @@ -26,7 +26,7 @@ pub mod attributes { } } - pub fn derives(which_ones: &[&str]) -> TokenStream { + pub(crate) fn derives(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() .cloned() @@ -36,25 +36,25 @@ pub mod attributes { } } - pub fn inline() -> TokenStream { + pub(crate) fn inline() -> TokenStream { quote! { #[inline] } } - pub fn must_use() -> TokenStream { + pub(crate) fn must_use() -> TokenStream { quote! { #[must_use] } } - pub fn non_exhaustive() -> TokenStream { + pub(crate) fn non_exhaustive() -> TokenStream { quote! { #[non_exhaustive] } } - pub fn doc(comment: String) -> TokenStream { + pub(crate) fn doc(comment: String) -> TokenStream { if comment.is_empty() { quote!() } else { @@ -62,10 +62,15 @@ pub mod attributes { } } - pub fn link_name(name: &str) -> TokenStream { + pub(crate) fn link_name<const MANGLE: bool>(name: &str) -> TokenStream { // LLVM mangles the name by default but it's already mangled. // Prefixing the name with \u{1} should tell LLVM to not mangle it. - let name = format!("\u{1}{}", name); + let name: Cow<'_, str> = if MANGLE { + name.into() + } else { + format!("\u{1}{}", name).into() + }; + quote! { #[link_name = #name] } @@ -74,7 +79,7 @@ pub mod attributes { /// Generates a proper type for a field or type with a given `Layout`, that is, /// a type with the correct size and alignment restrictions. -pub fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream { +pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream { let opaque = layout.opaque(); // FIXME(emilio, #412): We fall back to byte alignment, but there are @@ -105,7 +110,7 @@ pub fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream { } /// Integer type of the same size as the given `Layout`. -pub fn integer_type( +pub(crate) fn integer_type( ctx: &BindgenContext, layout: Layout, ) -> Option<TokenStream> { @@ -115,7 +120,10 @@ pub fn integer_type( } /// Generates a bitfield allocation unit type for a type with the given `Layout`. -pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream { +pub(crate) fn bitfield_unit( + ctx: &BindgenContext, + layout: Layout, +) -> TokenStream { let mut tokens = quote! {}; if ctx.options().enable_cxx_namespaces { @@ -130,7 +138,7 @@ pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream { tokens } -pub mod ast_ty { +pub(crate) mod ast_ty { use crate::ir::context::BindgenContext; use crate::ir::function::FunctionSig; use crate::ir::layout::Layout; @@ -138,7 +146,7 @@ pub mod ast_ty { use proc_macro2::{self, TokenStream}; use std::str::FromStr; - pub fn c_void(ctx: &BindgenContext) -> TokenStream { + pub(crate) fn c_void(ctx: &BindgenContext) -> TokenStream { // ctypes_prefix takes precedence match ctx.options().ctypes_prefix { Some(ref prefix) => { @@ -159,7 +167,7 @@ pub mod ast_ty { } } - pub fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream { + pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream { let ident = ctx.rust_ident_raw(name); match ctx.options().ctypes_prefix { Some(ref prefix) => { @@ -184,7 +192,7 @@ pub mod ast_ty { } } - pub fn float_kind_rust_type( + pub(crate) fn float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, layout: Option<Layout>, @@ -229,25 +237,25 @@ pub mod ast_ty { } } - pub fn int_expr(val: i64) -> TokenStream { + pub(crate) fn int_expr(val: i64) -> TokenStream { // Don't use quote! { #val } because that adds the type suffix. let val = proc_macro2::Literal::i64_unsuffixed(val); quote!(#val) } - pub fn uint_expr(val: u64) -> TokenStream { + pub(crate) fn uint_expr(val: u64) -> TokenStream { // Don't use quote! { #val } because that adds the type suffix. let val = proc_macro2::Literal::u64_unsuffixed(val); quote!(#val) } - pub fn byte_array_expr(bytes: &[u8]) -> TokenStream { + pub(crate) fn byte_array_expr(bytes: &[u8]) -> TokenStream { let mut bytes: Vec<_> = bytes.to_vec(); bytes.push(0); quote! { [ #(#bytes),* ] } } - pub fn cstr_expr(mut string: String) -> TokenStream { + pub(crate) fn cstr_expr(mut string: String) -> TokenStream { string.push('\0'); let b = proc_macro2::Literal::byte_string(string.as_bytes()); quote! { @@ -255,7 +263,10 @@ pub mod ast_ty { } } - pub fn float_expr(ctx: &BindgenContext, f: f64) -> Result<TokenStream, ()> { + pub(crate) fn float_expr( + ctx: &BindgenContext, + f: f64, + ) -> Result<TokenStream, ()> { if f.is_finite() { let val = proc_macro2::Literal::f64_unsuffixed(f); @@ -286,7 +297,7 @@ pub mod ast_ty { Err(()) } - pub fn arguments_from_signature( + pub(crate) fn arguments_from_signature( signature: &FunctionSig, ctx: &BindgenContext, ) -> Vec<TokenStream> { diff --git a/codegen/impl_debug.rs b/codegen/impl_debug.rs index 0e2cd33..67ec214 100644 --- a/codegen/impl_debug.rs +++ b/codegen/impl_debug.rs @@ -3,7 +3,7 @@ use crate::ir::context::BindgenContext; use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName}; use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; -pub fn gen_debug_impl( +pub(crate) fn gen_debug_impl( ctx: &BindgenContext, fields: &[Field], item: &Item, @@ -51,7 +51,7 @@ pub fn gen_debug_impl( /// A trait for the things which we can codegen tokens that contribute towards a /// generated `impl Debug`. -pub trait ImplDebug<'a> { +pub(crate) trait ImplDebug<'a> { /// Any extra parameter required by this a particular `ImplDebug` implementation. type Extra; diff --git a/codegen/impl_partialeq.rs b/codegen/impl_partialeq.rs index 960306f..42fabf6 100644 --- a/codegen/impl_partialeq.rs +++ b/codegen/impl_partialeq.rs @@ -5,7 +5,7 @@ use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; /// Generate a manual implementation of `PartialEq` trait for the /// specified compound type. -pub fn gen_partialeq_impl( +pub(crate) fn gen_partialeq_impl( ctx: &BindgenContext, comp_info: &CompInfo, item: &Item, @@ -18,7 +18,7 @@ pub fn gen_partialeq_impl( &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..] }); } else if comp_info.kind() == CompKind::Union { - assert!(!ctx.options().rust_features().untagged_union); + assert!(!ctx.options().untagged_union); tokens.push(quote! { &self.bindgen_union_field[..] == &other.bindgen_union_field[..] }); diff --git a/codegen/mod.rs b/codegen/mod.rs index b6fb70e..0dd3228 100644 --- a/codegen/mod.rs +++ b/codegen/mod.rs @@ -5,7 +5,7 @@ mod impl_debug; mod impl_partialeq; mod postprocessing; mod serialize; -pub mod struct_layout; +pub(crate) mod struct_layout; #[cfg(test)] #[allow(warnings)] @@ -21,7 +21,9 @@ use super::BindgenOptions; use crate::callbacks::{DeriveInfo, TypeKind as DeriveTypeKind}; use crate::ir::analysis::{HasVtable, Sizedness}; -use crate::ir::annotations::FieldAccessorKind; +use crate::ir::annotations::{ + Annotations, FieldAccessorKind, FieldVisibilityKind, +}; use crate::ir::comp::{ Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods, Method, MethodKind, @@ -55,8 +57,7 @@ use crate::{Entry, HashMap, HashSet}; use std::borrow::Cow; use std::cell::Cell; use std::collections::VecDeque; -use std::fmt::Write; -use std::iter; +use std::fmt::{self, Write}; use std::ops; use std::str::FromStr; @@ -72,19 +73,19 @@ impl From<std::io::Error> for CodegenError { } } -impl std::fmt::Display for CodegenError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for CodegenError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - CodegenError::Serialize { msg, loc } => { + Self::Serialize { msg, loc } => { write!(f, "serialization error at {}: {}", loc, msg) } - CodegenError::Io(err) => err.fmt(f), + Self::Io(err) => err.fmt(f), } } } // Name of type defined in constified enum module -pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type"; +pub(crate) static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type"; fn top_level_path( ctx: &BindgenContext, @@ -124,6 +125,7 @@ fn root_import( } bitflags! { + #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] struct DerivableTraits: u16 { const DEBUG = 1 << 0; const DEFAULT = 1 << 1; @@ -222,7 +224,7 @@ struct CodegenResult<'a> { items: Vec<proc_macro2::TokenStream>, dynamic_items: DynamicItems, - /// A monotonic counter used to add stable unique id's to stuff that doesn't + /// A monotonic counter used to add stable unique ID's to stuff that doesn't /// need to be referenced by anything. codegen_id: &'a Cell<usize>, @@ -694,7 +696,7 @@ impl CodeGenerator for Var { // Account the trailing zero. // // TODO: Here we ignore the type we just made up, probably - // we should refactor how the variable type and ty id work. + // we should refactor how the variable type and ty ID work. let len = bytes.len() + 1; let ty = quote! { [u8; #len] @@ -745,13 +747,18 @@ impl CodeGenerator for Var { } } else { // If necessary, apply a `#[link_name]` attribute - let link_name = self.mangled_name().unwrap_or_else(|| self.name()); - if !utils::names_will_be_identical_after_mangling( - &canonical_name, - link_name, - None, - ) { - attrs.push(attributes::link_name(link_name)); + if let Some(link_name) = self.link_name() { + attrs.push(attributes::link_name::<false>(link_name)); + } else { + let link_name = + self.mangled_name().unwrap_or_else(|| self.name()); + if !utils::names_will_be_identical_after_mangling( + &canonical_name, + link_name, + None, + ) { + attrs.push(attributes::link_name::<false>(link_name)); + } } let maybe_mut = if self.is_const() { @@ -1034,13 +1041,15 @@ impl CodeGenerator for Type { }); } + let access_spec = + access_specifier(ctx.options().default_visibility); tokens.append_all(match alias_style { AliasVariation::TypeAlias => quote! { = #inner_rust_type ; }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { quote! { - (pub #inner_rust_type) ; + (#access_spec #inner_rust_type) ; } } }); @@ -1271,7 +1280,7 @@ trait FieldCodegen<'a> { fn codegen<F, M>( &self, ctx: &BindgenContext, - fields_should_be_private: bool, + visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, @@ -1290,7 +1299,7 @@ impl<'a> FieldCodegen<'a> for Field { fn codegen<F, M>( &self, ctx: &BindgenContext, - fields_should_be_private: bool, + visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, @@ -1306,7 +1315,7 @@ impl<'a> FieldCodegen<'a> for Field { Field::DataMember(ref data) => { data.codegen( ctx, - fields_should_be_private, + visibility_kind, accessor_kind, parent, result, @@ -1319,7 +1328,7 @@ impl<'a> FieldCodegen<'a> for Field { Field::Bitfields(ref unit) => { unit.codegen( ctx, - fields_should_be_private, + visibility_kind, accessor_kind, parent, result, @@ -1368,7 +1377,7 @@ impl<'a> FieldCodegen<'a> for FieldData { fn codegen<F, M>( &self, ctx: &BindgenContext, - fields_should_be_private: bool, + parent_visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, @@ -1431,23 +1440,31 @@ impl<'a> FieldCodegen<'a> for FieldData { fields.extend(Some(padding_field)); } - let is_private = (!self.is_public() && - ctx.options().respect_cxx_access_specs) || - self.annotations() - .private_fields() - .unwrap_or(fields_should_be_private); - + let visibility = compute_visibility( + ctx, + self.is_public(), + Some(self.annotations()), + parent_visibility_kind, + ); let accessor_kind = self.annotations().accessor_kind().unwrap_or(accessor_kind); - if is_private { - field.append_all(quote! { - #field_ident : #ty , - }); - } else { - field.append_all(quote! { - pub #field_ident : #ty , - }); + match visibility { + FieldVisibilityKind::Private => { + field.append_all(quote! { + #field_ident : #ty , + }); + } + FieldVisibilityKind::PublicCrate => { + field.append_all(quote! { + pub(crate) #field_ident : #ty , + }); + } + FieldVisibilityKind::Public => { + field.append_all(quote! { + pub #field_ident : #ty , + }); + } } fields.extend(Some(field)); @@ -1557,13 +1574,48 @@ impl Bitfield { } fn access_specifier( - ctx: &BindgenContext, - is_pub: bool, + visibility: FieldVisibilityKind, ) -> proc_macro2::TokenStream { - if is_pub || !ctx.options().respect_cxx_access_specs { - quote! { pub } - } else { - quote! {} + match visibility { + FieldVisibilityKind::Private => quote! {}, + FieldVisibilityKind::PublicCrate => quote! { pub(crate) }, + FieldVisibilityKind::Public => quote! { pub }, + } +} + +/// Compute a fields or structs visibility based on multiple conditions. +/// 1. If the element was declared public, and we respect such CXX accesses specs +/// (context option) => By default Public, but this can be overruled by an `annotation`. +/// +/// 2. If the element was declared private, and we respect such CXX accesses specs +/// (context option) => By default Private, but this can be overruled by an `annotation`. +/// +/// 3. If we do not respect visibility modifiers, the result depends on the `annotation`, +/// if any, or the passed `default_kind`. +/// +fn compute_visibility( + ctx: &BindgenContext, + is_declared_public: bool, + annotations: Option<&Annotations>, + default_kind: FieldVisibilityKind, +) -> FieldVisibilityKind { + match ( + is_declared_public, + ctx.options().respect_cxx_access_specs, + annotations.and_then(|e| e.visibility_kind()), + ) { + (true, true, annotated_visibility) => { + // declared as public, cxx specs are respected + annotated_visibility.unwrap_or(FieldVisibilityKind::Public) + } + (false, true, annotated_visibility) => { + // declared as private, cxx specs are respected + annotated_visibility.unwrap_or(FieldVisibilityKind::Private) + } + (_, false, annotated_visibility) => { + // cxx specs are not respected, declaration does not matter. + annotated_visibility.unwrap_or(default_kind) + } } } @@ -1573,7 +1625,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { fn codegen<F, M>( &self, ctx: &BindgenContext, - fields_should_be_private: bool, + visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, @@ -1591,15 +1643,18 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { let layout = self.layout(); let unit_field_ty = helpers::bitfield_unit(ctx, layout); - let field_ty = if parent.is_union() { - wrap_union_field_if_needed( - ctx, - struct_layout, - unit_field_ty.clone(), - result, - ) - } else { - unit_field_ty.clone() + let field_ty = { + let unit_field_ty = unit_field_ty.clone(); + if parent.is_union() { + wrap_union_field_if_needed( + ctx, + struct_layout, + unit_field_ty, + result, + ) + } else { + unit_field_ty + } }; { @@ -1611,8 +1666,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { 2 => quote! { u16 }, _ => quote! { u8 }, }; + let access_spec = access_specifier(visibility_kind); let align_field = quote! { - pub #align_field_ident: [#align_ty; 0], + #access_spec #align_field_ident: [#align_ty; 0], }; fields.extend(Some(align_field)); } @@ -1631,7 +1687,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { // the 32 items limitation. let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT; - let mut access_spec = !fields_should_be_private; + let mut all_fields_declared_as_public = true; for bf in self.bitfields() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { @@ -1644,12 +1700,11 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { continue; } - access_spec &= bf.is_public(); + all_fields_declared_as_public &= bf.is_public(); let mut bitfield_representable_as_int = true; - bf.codegen( ctx, - fields_should_be_private, + visibility_kind, accessor_kind, parent, result, @@ -1677,7 +1732,13 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl); } - let access_spec = access_specifier(ctx, access_spec); + let visibility_kind = compute_visibility( + ctx, + all_fields_declared_as_public, + None, + visibility_kind, + ); + let access_spec = access_specifier(visibility_kind); let field = quote! { #access_spec #unit_field_ident : #field_ty , @@ -1723,7 +1784,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { fn codegen<F, M>( &self, ctx: &BindgenContext, - fields_should_be_private: bool, + visibility_kind: FieldVisibilityKind, _accessor_kind: FieldAccessorKind, parent: &CompInfo, _result: &mut CodegenResult, @@ -1763,10 +1824,14 @@ impl<'a> FieldCodegen<'a> for Bitfield { let offset = self.offset_into_unit(); let width = self.width() as u8; - let access_spec = access_specifier( + + let visibility_kind = compute_visibility( ctx, - self.is_public() && !fields_should_be_private, + self.is_public(), + Some(self.annotations()), + visibility_kind, ); + let access_spec = access_specifier(visibility_kind); if parent.is_union() && !struct_layout.is_rust_union() { methods.extend(Some(quote! { @@ -1892,7 +1957,16 @@ impl CodeGenerator for CompInfo { struct_layout.saw_base(inner_item.expect_type()); - let access_spec = access_specifier(ctx, base.is_public()); + let visibility = match ( + base.is_public(), + ctx.options().respect_cxx_access_specs, + ) { + (true, true) => FieldVisibilityKind::Public, + (false, true) => FieldVisibilityKind::Private, + _ => ctx.options().default_visibility, + }; + + let access_spec = access_specifier(visibility); fields.push(quote! { #access_spec #field_name: #inner, }); @@ -1901,8 +1975,10 @@ impl CodeGenerator for CompInfo { let mut methods = vec![]; if !is_opaque { - let fields_should_be_private = - item.annotations().private_fields().unwrap_or(false); + let visibility = item + .annotations() + .visibility_kind() + .unwrap_or(ctx.options().default_visibility); let struct_accessor_kind = item .annotations() .accessor_kind() @@ -1910,7 +1986,7 @@ impl CodeGenerator for CompInfo { for field in self.fields() { field.codegen( ctx, - fields_should_be_private, + visibility, struct_accessor_kind, self, result, @@ -2491,6 +2567,9 @@ impl Method { ClangAbi::Known(Abi::CUnwind) => { ctx.options().rust_features().c_unwind_abi } + ClangAbi::Known(Abi::EfiApi) => { + ctx.options().rust_features().abi_efiapi + } _ => true, }; @@ -2661,6 +2740,35 @@ impl Default for EnumVariation { } } +impl fmt::Display for EnumVariation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::Rust { + non_exhaustive: false, + } => "rust", + Self::Rust { + non_exhaustive: true, + } => "rust_non_exhaustive", + Self::NewType { + is_bitfield: true, .. + } => "bitfield", + Self::NewType { + is_bitfield: false, + is_global, + } => { + if *is_global { + "newtype_global" + } else { + "newtype" + } + } + Self::Consts => "consts", + Self::ModuleConsts => "moduleconsts", + }; + s.fmt(f) + } +} + impl std::str::FromStr for EnumVariation { type Err = std::io::Error; @@ -3347,13 +3455,13 @@ pub enum MacroTypeVariation { Unsigned, } -impl MacroTypeVariation { - /// Convert a `MacroTypeVariation` to its str representation. - pub fn as_str(&self) -> &str { - match self { - MacroTypeVariation::Signed => "signed", - MacroTypeVariation::Unsigned => "unsigned", - } +impl fmt::Display for MacroTypeVariation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::Signed => "signed", + Self::Unsigned => "unsigned", + }; + s.fmt(f) } } @@ -3393,14 +3501,15 @@ pub enum AliasVariation { NewTypeDeref, } -impl AliasVariation { - /// Convert an `AliasVariation` to its str representation. - pub fn as_str(&self) -> &str { - match self { - AliasVariation::TypeAlias => "type_alias", - AliasVariation::NewType => "new_type", - AliasVariation::NewTypeDeref => "new_type_deref", - } +impl fmt::Display for AliasVariation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::TypeAlias => "type_alias", + Self::NewType => "new_type", + Self::NewTypeDeref => "new_type_deref", + }; + + s.fmt(f) } } @@ -3430,10 +3539,10 @@ impl std::str::FromStr for AliasVariation { } } -/// Enum for how non-Copy unions should be translated. +/// Enum for how non-`Copy` `union`s should be translated. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum NonCopyUnionStyle { - /// Wrap members in a type generated by bindgen. + /// Wrap members in a type generated by `bindgen`. BindgenWrapper, /// Wrap members in [`::core::mem::ManuallyDrop`]. /// @@ -3442,13 +3551,14 @@ pub enum NonCopyUnionStyle { ManuallyDrop, } -impl NonCopyUnionStyle { - /// Convert an `NonCopyUnionStyle` to its str representation. - pub fn as_str(&self) -> &'static str { - match self { +impl fmt::Display for NonCopyUnionStyle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { Self::BindgenWrapper => "bindgen_wrapper", Self::ManuallyDrop => "manually_drop", - } + }; + + s.fmt(f) } } @@ -3983,9 +4093,8 @@ impl TryToRustTy for FunctionSig { // TODO: we might want to consider ignoring the reference return value. let ret = utils::fnsig_return_ty(ctx, self); let arguments = utils::fnsig_arguments(ctx, self); - let abi = self.abi(ctx, None); - match abi { + match self.abi(ctx, None) { ClangAbi::Known(Abi::ThisCall) if !ctx.options().rust_features().thiscall_abi => { @@ -4004,7 +4113,13 @@ impl TryToRustTy for FunctionSig { warn!("Skipping function with C-unwind ABI that isn't supported by the configured Rust target"); Ok(proc_macro2::TokenStream::new()) } - _ => Ok(quote! { + ClangAbi::Known(Abi::EfiApi) + if !ctx.options().rust_features().abi_efiapi => + { + warn!("Skipping function with efiapi ABI that isn't supported by the configured Rust target"); + Ok(proc_macro2::TokenStream::new()) + } + abi => Ok(quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret }), } @@ -4029,14 +4144,10 @@ impl CodeGenerator for Function { let is_internal = matches!(self.linkage(), Linkage::Internal); - if is_internal { - if ctx.options().wrap_static_fns { - result.items_to_serialize.push(item.id()); - } else { - // We can't do anything with Internal functions if we are not wrapping them so just - // avoid generating anything for them. - return None; - } + if is_internal && !ctx.options().wrap_static_fns { + // We can't do anything with Internal functions if we are not wrapping them so just + // avoid generating anything for them. + return None; } // Pure virtual methods have no actual symbol, so we can't generate @@ -4111,23 +4222,54 @@ impl CodeGenerator for Function { ClangAbi::Known(Abi::ThisCall) if !ctx.options().rust_features().thiscall_abi => { - warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); + unsupported_abi_diagnostic::<false>( + name, + item.location(), + "thiscall", + ctx, + ); return None; } ClangAbi::Known(Abi::Vectorcall) if !ctx.options().rust_features().vectorcall_abi => { - warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target"); + unsupported_abi_diagnostic::<false>( + name, + item.location(), + "vectorcall", + ctx, + ); return None; } ClangAbi::Known(Abi::CUnwind) if !ctx.options().rust_features().c_unwind_abi => { - warn!("Skipping function with C-unwind ABI that isn't supported by the configured Rust target"); + unsupported_abi_diagnostic::<false>( + name, + item.location(), + "C-unwind", + ctx, + ); + return None; + } + ClangAbi::Known(Abi::EfiApi) + if !ctx.options().rust_features().abi_efiapi => + { + unsupported_abi_diagnostic::<true>( + name, + item.location(), + "efiapi", + ctx, + ); return None; } ClangAbi::Known(Abi::Win64) if signature.is_variadic() => { - warn!("Skipping variadic function with Win64 ABI that isn't supported"); + unsupported_abi_diagnostic::<true>( + name, + item.location(), + "Win64", + ctx, + ); return None; } ClangAbi::Unknown(unknown_abi) => { @@ -4139,6 +4281,10 @@ impl CodeGenerator for Function { abi => abi, }; + if is_internal && ctx.options().wrap_static_fns { + result.items_to_serialize.push(item.id()); + } + // Handle overloaded functions by giving each overload its own unique // suffix. let times_seen = result.overload_number(&canonical_name); @@ -4147,16 +4293,21 @@ impl CodeGenerator for Function { } let mut has_link_name_attr = false; - let link_name = mangled_name.unwrap_or(name); - if !is_dynamic_function && - !utils::names_will_be_identical_after_mangling( - &canonical_name, - link_name, - Some(abi), - ) - { - attributes.push(attributes::link_name(link_name)); + if let Some(link_name) = self.link_name() { + attributes.push(attributes::link_name::<false>(link_name)); has_link_name_attr = true; + } else { + let link_name = mangled_name.unwrap_or(name); + if !is_dynamic_function && + !utils::names_will_be_identical_after_mangling( + &canonical_name, + link_name, + Some(abi), + ) + { + attributes.push(attributes::link_name::<false>(link_name)); + has_link_name_attr = true; + } } // Unfortunately this can't piggyback on the `attributes` list because @@ -4169,7 +4320,7 @@ impl CodeGenerator for Function { if is_internal && ctx.options().wrap_static_fns && !has_link_name_attr { let name = canonical_name.clone() + ctx.wrap_static_fns_suffix(); - attributes.push(attributes::link_name(&name)); + attributes.push(attributes::link_name::<true>(&name)); } let ident = ctx.rust_ident(canonical_name); @@ -4205,6 +4356,51 @@ impl CodeGenerator for Function { } } +fn unsupported_abi_diagnostic<const VARIADIC: bool>( + fn_name: &str, + _location: Option<&crate::clang::SourceLocation>, + abi: &str, + _ctx: &BindgenContext, +) { + warn!( + "Skipping {}function `{}` with the {} ABI that isn't supported by the configured Rust target", + if VARIADIC { "variadic " } else { "" }, + fn_name, + abi + ); + + #[cfg(feature = "experimental")] + if _ctx.options().emit_diagnostics { + use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; + + let mut diag = Diagnostic::default(); + diag + .with_title(format!( + "The `{}` {}function uses the {} ABI which is not supported by the configured Rust target.", + fn_name, + if VARIADIC { "variadic " } else { "" }, + abi), Level::Warn) + .add_annotation("No code will be generated for this function.", Level::Warn) + .add_annotation(format!("The configured Rust version is {}.", String::from(_ctx.options().rust_target)), Level::Note); + + if let Some(loc) = _location { + let (file, line, col, _) = loc.location(); + + if let Some(filename) = file.name() { + if let Ok(Some(source)) = get_line(&filename, line) { + let mut slice = Slice::default(); + slice + .with_source(source) + .with_location(filename, line, col); + diag.add_slice(slice); + } + } + } + + diag.display() + } +} + fn objc_method_codegen( ctx: &BindgenContext, method: &ObjCMethod, @@ -4226,13 +4422,12 @@ fn objc_method_codegen( let fn_ret = utils::fnsig_return_ty(ctx, signature); let sig = if method.is_class_method() { - let fn_args = fn_args.clone(); quote! { ( #( #fn_args ),* ) #fn_ret } } else { - let fn_args = fn_args.clone(); - let args = iter::once(quote! { &self }).chain(fn_args.into_iter()); + let self_arr = [quote! { &self }]; + let args = self_arr.iter().chain(fn_args.iter()); quote! { ( #( #args ),* ) #fn_ret } @@ -4476,8 +4671,7 @@ impl CodeGenerator for ObjCInterface { pub(crate) fn codegen( context: BindgenContext, -) -> Result<(proc_macro2::TokenStream, BindgenOptions, Vec<String>), CodegenError> -{ +) -> Result<(proc_macro2::TokenStream, BindgenOptions), CodegenError> { context.gen(|context| { let _t = context.timer("codegen"); let counter = Cell::new(0); @@ -4536,7 +4730,7 @@ pub(crate) fn codegen( }) } -pub mod utils { +pub(crate) mod utils { use super::serialize::CSerialize; use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; use crate::ir::context::BindgenContext; @@ -4544,8 +4738,8 @@ pub mod utils { use crate::ir::item::{Item, ItemCanonicalPath}; use crate::ir::ty::TypeKind; use crate::{args_are_cpp, file_is_cpp}; - use proc_macro2; use std::borrow::Cow; + use std::io::Write; use std::mem; use std::path::PathBuf; use std::str::FromStr; @@ -4570,7 +4764,7 @@ pub mod utils { let dir = path.parent().unwrap(); if !dir.exists() { - std::fs::create_dir_all(&dir)?; + std::fs::create_dir_all(dir)?; } let is_cpp = args_are_cpp(&context.options().clang_args) || @@ -4584,6 +4778,24 @@ pub mod utils { let mut code = Vec::new(); + if !context.options().input_headers.is_empty() { + for header in &context.options().input_headers { + writeln!(code, "#include \"{}\"", header)?; + } + + writeln!(code)?; + } + + if !context.options().input_header_contents.is_empty() { + for (name, contents) in &context.options().input_header_contents { + writeln!(code, "// {}\n{}", name, contents)?; + } + + writeln!(code)?; + } + + writeln!(code, "// Static wrappers\n")?; + for &id in &result.items_to_serialize { let item = context.resolve_item(id); item.serialize(context, (), &mut vec![], &mut code)?; @@ -4594,7 +4806,7 @@ pub mod utils { Ok(()) } - pub fn prepend_bitfield_unit_type( + pub(crate) fn prepend_bitfield_unit_type( ctx: &BindgenContext, result: &mut Vec<proc_macro2::TokenStream>, ) { @@ -4613,7 +4825,7 @@ pub mod utils { result.extend(old_items); } - pub fn prepend_objc_header( + pub(crate) fn prepend_objc_header( ctx: &BindgenContext, result: &mut Vec<proc_macro2::TokenStream>, ) { @@ -4638,7 +4850,7 @@ pub mod utils { result.extend(old_items.into_iter()); } - pub fn prepend_block_header( + pub(crate) fn prepend_block_header( ctx: &BindgenContext, result: &mut Vec<proc_macro2::TokenStream>, ) { @@ -4657,7 +4869,7 @@ pub mod utils { result.extend(old_items.into_iter()); } - pub fn prepend_union_types( + pub(crate) fn prepend_union_types( ctx: &BindgenContext, result: &mut Vec<proc_macro2::TokenStream>, ) { @@ -4769,7 +4981,7 @@ pub mod utils { result.extend(old_items.into_iter()); } - pub fn prepend_incomplete_array_types( + pub(crate) fn prepend_incomplete_array_types( ctx: &BindgenContext, result: &mut Vec<proc_macro2::TokenStream>, ) { @@ -4845,7 +5057,9 @@ pub mod utils { result.extend(old_items.into_iter()); } - pub fn prepend_complex_type(result: &mut Vec<proc_macro2::TokenStream>) { + pub(crate) fn prepend_complex_type( + result: &mut Vec<proc_macro2::TokenStream>, + ) { let complex_type = quote! { #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(C)] @@ -4860,7 +5074,7 @@ pub mod utils { result.extend(old_items.into_iter()); } - pub fn build_path( + pub(crate) fn build_path( item: &Item, ctx: &BindgenContext, ) -> error::Result<proc_macro2::TokenStream> { @@ -4881,7 +5095,7 @@ pub mod utils { } } - pub fn type_from_named( + pub(crate) fn type_from_named( ctx: &BindgenContext, name: &str, ) -> Option<proc_macro2::TokenStream> { @@ -4949,14 +5163,14 @@ pub mod utils { } } - pub fn fnsig_return_ty( + pub(crate) fn fnsig_return_ty( ctx: &BindgenContext, sig: &FunctionSig, ) -> proc_macro2::TokenStream { fnsig_return_ty_internal(ctx, sig, /* include_arrow = */ true) } - pub fn fnsig_arguments( + pub(crate) fn fnsig_arguments( ctx: &BindgenContext, sig: &FunctionSig, ) -> Vec<proc_macro2::TokenStream> { @@ -5029,7 +5243,7 @@ pub mod utils { args } - pub fn fnsig_argument_identifiers( + pub(crate) fn fnsig_argument_identifiers( ctx: &BindgenContext, sig: &FunctionSig, ) -> Vec<proc_macro2::TokenStream> { @@ -5058,7 +5272,7 @@ pub mod utils { args } - pub fn fnsig_block( + pub(crate) fn fnsig_block( ctx: &BindgenContext, sig: &FunctionSig, ) -> proc_macro2::TokenStream { diff --git a/codegen/postprocessing/merge_extern_blocks.rs b/codegen/postprocessing/merge_extern_blocks.rs index 8dacedf..10fa0ec 100644 --- a/codegen/postprocessing/merge_extern_blocks.rs +++ b/codegen/postprocessing/merge_extern_blocks.rs @@ -1,68 +1,72 @@ use syn::{ - visit_mut::{visit_item_mod_mut, VisitMut}, - Item, ItemForeignMod, ItemMod, + visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut}, + File, Item, ItemForeignMod, ItemMod, }; -pub(super) fn merge_extern_blocks(item_mod: &mut ItemMod) { - Visitor.visit_item_mod_mut(item_mod) +pub(super) fn merge_extern_blocks(file: &mut File) { + Visitor.visit_file_mut(file) } struct Visitor; impl VisitMut for Visitor { + fn visit_file_mut(&mut self, file: &mut File) { + visit_items(&mut file.items); + visit_file_mut(self, file) + } + fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { if let Some((_, ref mut items)) = item_mod.content { - // Keep all the extern blocks in a different `Vec` for faster search. - let mut extern_blocks = Vec::<ItemForeignMod>::new(); + visit_items(items); + } + visit_item_mod_mut(self, item_mod) + } +} - for item in std::mem::take(items) { - if let Item::ForeignMod(ItemForeignMod { +fn visit_items(items: &mut Vec<Item>) { + // Keep all the extern blocks in a different `Vec` for faster search. + let mut extern_blocks = Vec::<ItemForeignMod>::new(); + + for item in std::mem::take(items) { + if let Item::ForeignMod(ItemForeignMod { + attrs, + abi, + brace_token, + unsafety, + items: extern_block_items, + }) = item + { + let mut exists = false; + for extern_block in &mut extern_blocks { + // Check if there is a extern block with the same ABI and + // attributes. + if extern_block.attrs == attrs && extern_block.abi == abi { + // Merge the items of the two blocks. + extern_block.items.extend_from_slice(&extern_block_items); + exists = true; + break; + } + } + // If no existing extern block had the same ABI and attributes, store + // it. + if !exists { + extern_blocks.push(ItemForeignMod { attrs, abi, brace_token, - items: extern_block_items, unsafety, - }) = item - { - let mut exists = false; - for extern_block in &mut extern_blocks { - // Check if there is a extern block with the same ABI and - // attributes. - if extern_block.attrs == attrs && - extern_block.abi == abi - { - // Merge the items of the two blocks. - extern_block - .items - .extend_from_slice(&extern_block_items); - exists = true; - break; - } - } - // If no existing extern block had the same ABI and attributes, store - // it. - if !exists { - extern_blocks.push(ItemForeignMod { - attrs, - abi, - brace_token, - items: extern_block_items, - unsafety, - }); - } - } else { - // If the item is not an extern block, we don't have to do anything and just - // push it back. - items.push(item); - } - } - - // Move all the extern blocks alongside the rest of the items. - for extern_block in extern_blocks { - items.push(Item::ForeignMod(extern_block)); + items: extern_block_items, + }); } + } else { + // If the item is not an extern block, we don't have to do anything and just + // push it back. + items.push(item); } + } - visit_item_mod_mut(self, item_mod) + // Move all the extern blocks alongside the rest of the items. + for extern_block in extern_blocks { + items.push(Item::ForeignMod(extern_block)); } } diff --git a/codegen/postprocessing/mod.rs b/codegen/postprocessing/mod.rs index 1d5a498..9641698 100644 --- a/codegen/postprocessing/mod.rs +++ b/codegen/postprocessing/mod.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::ToTokens; -use syn::{parse2, ItemMod}; +use syn::{parse2, File}; use crate::BindgenOptions; @@ -12,7 +12,7 @@ use sort_semantically::sort_semantically; struct PostProcessingPass { should_run: fn(&BindgenOptions) -> bool, - run: fn(&mut ItemMod), + run: fn(&mut File), } // TODO: This can be a const fn when mutable references are allowed in const @@ -21,7 +21,7 @@ macro_rules! pass { ($pass:ident) => { PostProcessingPass { should_run: |options| options.$pass, - run: |item_mod| $pass(item_mod), + run: |file| $pass(file), } }; } @@ -33,34 +33,25 @@ pub(crate) fn postprocessing( items: Vec<TokenStream>, options: &BindgenOptions, ) -> TokenStream { + let items = items.into_iter().collect(); let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options)); + if !require_syn { - return items.into_iter().collect(); + return items; } - let module_wrapped_tokens = - quote!(mod wrapper_for_postprocessing_hack { #( #items )* }); // This syn business is a hack, for now. This means that we are re-parsing already // generated code using `syn` (as opposed to `quote`) because `syn` provides us more // control over the elements. - // One caveat is that some of the items coming from `quote`d output might have - // multiple items within them. Hence, we have to wrap the incoming in a `mod`. // The `unwrap` here is deliberate because bindgen should generate valid rust items at all // times. - let mut item_mod = parse2::<ItemMod>(module_wrapped_tokens).unwrap(); + let mut file = parse2::<File>(items).unwrap(); for pass in PASSES { if (pass.should_run)(options) { - (pass.run)(&mut item_mod); + (pass.run)(&mut file); } } - let synful_items = item_mod - .content - .map(|(_, items)| items) - .unwrap_or_default() - .into_iter() - .map(|item| item.into_token_stream()); - - quote! { #( #synful_items )* } + file.into_token_stream() } diff --git a/codegen/postprocessing/sort_semantically.rs b/codegen/postprocessing/sort_semantically.rs index 71fb75c..be94ce6 100644 --- a/codegen/postprocessing/sort_semantically.rs +++ b/codegen/postprocessing/sort_semantically.rs @@ -1,37 +1,46 @@ use syn::{ - visit_mut::{visit_item_mod_mut, VisitMut}, - Item, ItemMod, + visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut}, + File, Item, ItemMod, }; -pub(super) fn sort_semantically(item_mod: &mut ItemMod) { - Visitor.visit_item_mod_mut(item_mod) +pub(super) fn sort_semantically(file: &mut File) { + Visitor.visit_file_mut(file) } struct Visitor; impl VisitMut for Visitor { + fn visit_file_mut(&mut self, file: &mut File) { + visit_items(&mut file.items); + visit_file_mut(self, file) + } + fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { if let Some((_, ref mut items)) = item_mod.content { - items.sort_by_key(|item| match item { - Item::Type(_) => 0, - Item::Struct(_) => 1, - Item::Const(_) => 2, - Item::Fn(_) => 3, - Item::Enum(_) => 4, - Item::Union(_) => 5, - Item::Static(_) => 6, - Item::Trait(_) => 7, - Item::TraitAlias(_) => 8, - Item::Impl(_) => 9, - Item::Mod(_) => 10, - Item::Use(_) => 11, - Item::Verbatim(_) => 12, - Item::ExternCrate(_) => 13, - Item::ForeignMod(_) => 14, - Item::Macro(_) => 15, - _ => 18, - }); + visit_items(items); } visit_item_mod_mut(self, item_mod) } } + +fn visit_items(items: &mut [Item]) { + items.sort_by_key(|item| match item { + Item::Type(_) => 0, + Item::Struct(_) => 1, + Item::Const(_) => 2, + Item::Fn(_) => 3, + Item::Enum(_) => 4, + Item::Union(_) => 5, + Item::Static(_) => 6, + Item::Trait(_) => 7, + Item::TraitAlias(_) => 8, + Item::Impl(_) => 9, + Item::Mod(_) => 10, + Item::Use(_) => 11, + Item::Verbatim(_) => 12, + Item::ExternCrate(_) => 13, + Item::ForeignMod(_) => 14, + Item::Macro(_) => 15, + _ => 18, + }); +} diff --git a/codegen/serialize.rs b/codegen/serialize.rs index 217098e..ac62023 100644 --- a/codegen/serialize.rs +++ b/codegen/serialize.rs @@ -44,12 +44,10 @@ impl<'a> CSerialize<'a> for Item { ItemKind::Function(func) => { func.serialize(ctx, self, stack, writer) } - kind => { - return Err(CodegenError::Serialize { - msg: format!("Cannot serialize item kind {:?}", kind), - loc: get_loc(self), - }); - } + kind => Err(CodegenError::Serialize { + msg: format!("Cannot serialize item kind {:?}", kind), + loc: get_loc(self), + }), } } } @@ -107,36 +105,10 @@ impl<'a> CSerialize<'a> for Function { // The function's return type let ret_ty = signature.return_type(); - // Write `ret_ty wrap_name(args) asm("wrap_name");` - ret_ty.serialize(ctx, (), stack, writer)?; - write!(writer, " {}(", wrap_name)?; - if args.is_empty() { - write!(writer, "void")?; - } else { - serialize_sep( - ", ", - args.iter(), - ctx, - writer, - |(name, type_id), ctx, buf| { - type_id.serialize(ctx, (), &mut vec![name.clone()], buf) - }, - )?; - } - writeln!(writer, ") asm(\"{}\");", wrap_name)?; - // Write `ret_ty wrap_name(args) { return name(arg_names)' }` ret_ty.serialize(ctx, (), stack, writer)?; write!(writer, " {}(", wrap_name)?; - serialize_sep( - ", ", - args.iter(), - ctx, - writer, - |(name, type_id), _, buf| { - type_id.serialize(ctx, (), &mut vec![name.clone()], buf) - }, - )?; + serialize_args(&args, ctx, writer)?; write!(writer, ") {{ return {}(", name)?; serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| { write!(buf, "{}", name).map_err(From::from) @@ -313,6 +285,14 @@ impl<'a> CSerialize<'a> for Type { CompKind::Union => write!(writer, "union {}", name)?, }; } + TypeKind::Enum(_enum_ty) => { + if self.is_const() { + write!(writer, "const ")?; + } + + let name = item.canonical_name(ctx); + write!(writer, "enum {}", name)?; + } ty => { return Err(CodegenError::Serialize { msg: format!("Cannot serialize type kind {:?}", ty), @@ -332,6 +312,28 @@ impl<'a> CSerialize<'a> for Type { } } +fn serialize_args<W: Write>( + args: &[(String, TypeId)], + ctx: &BindgenContext, + writer: &mut W, +) -> Result<(), CodegenError> { + if args.is_empty() { + write!(writer, "void")?; + } else { + serialize_sep( + ", ", + args.iter(), + ctx, + writer, + |(name, type_id), ctx, buf| { + type_id.serialize(ctx, (), &mut vec![name.clone()], buf) + }, + )?; + } + + Ok(()) +} + fn serialize_sep< W: Write, F: FnMut(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>, diff --git a/codegen/struct_layout.rs b/codegen/struct_layout.rs index ddac1b0..cca4a59 100644 --- a/codegen/struct_layout.rs +++ b/codegen/struct_layout.rs @@ -13,7 +13,7 @@ const MAX_GUARANTEED_ALIGN: usize = 8; /// Trace the layout of struct. #[derive(Debug)] -pub struct StructLayoutTracker<'a> { +pub(crate) struct StructLayoutTracker<'a> { name: &'a str, ctx: &'a BindgenContext, comp: &'a CompInfo, @@ -29,7 +29,7 @@ pub struct StructLayoutTracker<'a> { } /// Returns a size aligned to a given value. -pub fn align_to(size: usize, align: usize) -> usize { +pub(crate) fn align_to(size: usize, align: usize) -> usize { if align == 0 { return size; } @@ -43,7 +43,7 @@ pub fn align_to(size: usize, align: usize) -> usize { } /// Returns the lower power of two byte count that can hold at most n bits. -pub fn bytes_from_bits_pow2(mut n: usize) -> usize { +pub(crate) fn bytes_from_bits_pow2(mut n: usize) -> usize { if n == 0 { return 0; } @@ -83,7 +83,7 @@ fn test_bytes_from_bits_pow2() { } impl<'a> StructLayoutTracker<'a> { - pub fn new( + pub(crate) fn new( ctx: &'a BindgenContext, comp: &'a CompInfo, ty: &'a Type, @@ -109,15 +109,15 @@ impl<'a> StructLayoutTracker<'a> { } } - pub fn can_copy_union_fields(&self) -> bool { + pub(crate) fn can_copy_union_fields(&self) -> bool { self.can_copy_union_fields } - pub fn is_rust_union(&self) -> bool { + pub(crate) fn is_rust_union(&self) -> bool { self.is_rust_union } - pub fn saw_vtable(&mut self) { + pub(crate) fn saw_vtable(&mut self) { debug!("saw vtable for {}", self.name); let ptr_size = self.ctx.target_pointer_size(); @@ -126,7 +126,7 @@ impl<'a> StructLayoutTracker<'a> { self.max_field_align = ptr_size; } - pub fn saw_base(&mut self, base_ty: &Type) { + pub(crate) fn saw_base(&mut self, base_ty: &Type) { debug!("saw base for {}", self.name); if let Some(layout) = base_ty.layout(self.ctx) { self.align_to_latest_field(layout); @@ -137,7 +137,7 @@ impl<'a> StructLayoutTracker<'a> { } } - pub fn saw_bitfield_unit(&mut self, layout: Layout) { + pub(crate) fn saw_bitfield_unit(&mut self, layout: Layout) { debug!("saw bitfield unit for {}: {:?}", self.name, layout); self.align_to_latest_field(layout); @@ -159,7 +159,7 @@ impl<'a> StructLayoutTracker<'a> { /// Returns a padding field if necessary for a given new field _before_ /// adding that field. - pub fn saw_field( + pub(crate) fn saw_field( &mut self, field_name: &str, field_ty: &Type, @@ -189,7 +189,7 @@ impl<'a> StructLayoutTracker<'a> { self.saw_field_with_layout(field_name, field_layout, field_offset) } - pub fn saw_field_with_layout( + pub(crate) fn saw_field_with_layout( &mut self, field_name: &str, field_layout: Layout, @@ -274,7 +274,7 @@ impl<'a> StructLayoutTracker<'a> { padding_layout.map(|layout| self.padding_field(layout)) } - pub fn add_tail_padding( + pub(crate) fn add_tail_padding( &mut self, comp_name: &str, comp_layout: Layout, @@ -305,7 +305,7 @@ impl<'a> StructLayoutTracker<'a> { Some(self.padding_field(Layout::new(size, 0))) } - pub fn pad_struct( + pub(crate) fn pad_struct( &mut self, layout: Layout, ) -> Option<proc_macro2::TokenStream> { @@ -360,7 +360,7 @@ impl<'a> StructLayoutTracker<'a> { } } - pub fn requires_explicit_align(&self, layout: Layout) -> bool { + pub(crate) fn requires_explicit_align(&self, layout: Layout) -> bool { let repr_align = self.ctx.options().rust_features().repr_align; // Always force explicit repr(align) for stuff more than 16-byte aligned diff --git a/diagnostics.rs b/diagnostics.rs new file mode 100644 index 0000000..f765afe --- /dev/null +++ b/diagnostics.rs @@ -0,0 +1,189 @@ +//! Types and function used to emit pretty diagnostics for `bindgen`. +//! +//! The entry point of this module is the [`Diagnostic`] type. + +use std::fmt::Write; +use std::io::{self, BufRead, BufReader}; +use std::{borrow::Cow, fs::File}; + +use annotate_snippets::{ + display_list::{DisplayList, FormatOptions}, + snippet::{Annotation, Slice as ExtSlice, Snippet}, +}; + +use annotate_snippets::snippet::AnnotationType; + +#[derive(Clone, Copy, Debug)] +pub(crate) enum Level { + Error, + Warn, + Info, + Note, + Help, +} + +impl From<Level> for AnnotationType { + fn from(level: Level) -> Self { + match level { + Level::Error => Self::Error, + Level::Warn => Self::Warning, + Level::Info => Self::Info, + Level::Note => Self::Note, + Level::Help => Self::Help, + } + } +} + +/// A `bindgen` diagnostic. +#[derive(Default)] +pub(crate) struct Diagnostic<'a> { + title: Option<(Cow<'a, str>, Level)>, + slices: Vec<Slice<'a>>, + footer: Vec<(Cow<'a, str>, Level)>, +} + +impl<'a> Diagnostic<'a> { + /// Add a title to the diagnostic and set its type. + pub(crate) fn with_title( + &mut self, + title: impl Into<Cow<'a, str>>, + level: Level, + ) -> &mut Self { + self.title = Some((title.into(), level)); + self + } + + /// Add a slice of source code to the diagnostic. + pub(crate) fn add_slice(&mut self, slice: Slice<'a>) -> &mut Self { + self.slices.push(slice); + self + } + + /// Add a footer annotation to the diagnostic. This annotation will have its own type. + pub(crate) fn add_annotation( + &mut self, + msg: impl Into<Cow<'a, str>>, + level: Level, + ) -> &mut Self { + self.footer.push((msg.into(), level)); + self + } + + /// Print this diagnostic. + /// + /// The diagnostic is printed using `cargo:warning` if `bindgen` is being invoked by a build + /// script or using `eprintln` otherwise. + pub(crate) fn display(&self) { + std::thread_local! { + static INVOKED_BY_BUILD_SCRIPT: bool = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_some(); + } + + let mut title = None; + let mut footer = vec![]; + let mut slices = vec![]; + if let Some((msg, level)) = &self.title { + title = Some(Annotation { + id: Some("bindgen"), + label: Some(msg.as_ref()), + annotation_type: (*level).into(), + }) + } + + for (msg, level) in &self.footer { + footer.push(Annotation { + id: None, + label: Some(msg.as_ref()), + annotation_type: (*level).into(), + }); + } + + // add additional info that this is generated by bindgen + // so as to not confuse with rustc warnings + footer.push(Annotation { + id: None, + label: Some("This diagnostic was generated by bindgen."), + annotation_type: AnnotationType::Info, + }); + + for slice in &self.slices { + if let Some(source) = &slice.source { + slices.push(ExtSlice { + source: source.as_ref(), + line_start: slice.line.unwrap_or_default(), + origin: slice.filename.as_deref(), + annotations: vec![], + fold: false, + }) + } + } + + let snippet = Snippet { + title, + footer, + slices, + opt: FormatOptions { + color: true, + ..Default::default() + }, + }; + let dl = DisplayList::from(snippet); + + if INVOKED_BY_BUILD_SCRIPT.with(Clone::clone) { + // This is just a hack which hides the `warning:` added by cargo at the beginning of + // every line. This should be fine as our diagnostics already have a colorful title. + // FIXME (pvdrz): Could it be that this doesn't work in other languages? + let hide_warning = "\r \r"; + let string = dl.to_string(); + for line in string.lines() { + println!("cargo:warning={}{}", hide_warning, line); + } + } else { + eprintln!("{}\n", dl); + } + } +} + +/// A slice of source code. +#[derive(Default)] +pub(crate) struct Slice<'a> { + source: Option<Cow<'a, str>>, + filename: Option<String>, + line: Option<usize>, +} + +impl<'a> Slice<'a> { + /// Set the source code. + pub(crate) fn with_source( + &mut self, + source: impl Into<Cow<'a, str>>, + ) -> &mut Self { + self.source = Some(source.into()); + self + } + + /// Set the file, line and column. + pub(crate) fn with_location( + &mut self, + mut name: String, + line: usize, + col: usize, + ) -> &mut Self { + write!(name, ":{}:{}", line, col) + .expect("Writing to a string cannot fail"); + self.filename = Some(name); + self.line = Some(line); + self + } +} + +pub(crate) fn get_line( + filename: &str, + line: usize, +) -> io::Result<Option<String>> { + let file = BufReader::new(File::open(filename)?); + if let Some(line) = file.lines().nth(line.wrapping_sub(1)) { + return line.map(Some); + } + + Ok(None) +} diff --git a/features.rs b/features.rs index 4fee5d6..fe6f415 100644 --- a/features.rs +++ b/features.rs @@ -1,7 +1,7 @@ //! Contains code for selecting features -#![deny(missing_docs)] #![deny(unused_extern_crates)] +#![deny(clippy::missing_docs_in_private_items)] #![allow(deprecated)] use std::io; @@ -131,6 +131,9 @@ macro_rules! rust_target_base { /// Rust stable 1.64 /// * `core_ffi_c` ([Tracking issue](https://github.com/rust-lang/rust/issues/94501)) => Stable_1_64 => 1.64; + /// Rust stable 1.68 + /// * `abi_efiapi` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/65815)) + => Stable_1_68 => 1.68; /// Nightly rust /// * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202)) /// * `vectorcall` calling convention (no tracking issue) @@ -144,7 +147,7 @@ rust_target_base!(rust_target_def); rust_target_base!(rust_target_values_def); /// Latest stable release of Rust -pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_64; +pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_68; /// Create RustFeatures struct definition, new(), and a getter for each field macro_rules! rust_feature_def { @@ -241,6 +244,9 @@ rust_feature_def!( Stable_1_64 { => core_ffi_c; } + Stable_1_68 { + => abi_efiapi; + } Nightly { => thiscall_abi; => vectorcall_abi; diff --git a/ir/analysis/derive.rs b/ir/analysis/derive.rs index d888cd5..d8d29ed 100644 --- a/ir/analysis/derive.rs +++ b/ir/analysis/derive.rs @@ -61,7 +61,7 @@ pub enum DeriveTrait { /// * For all other (simple) types, compiler and standard library limitations /// dictate whether the trait is implemented. #[derive(Debug, Clone)] -pub struct CannotDerive<'ctx> { +pub(crate) struct CannotDerive<'ctx> { ctx: &'ctx BindgenContext, derive_trait: DeriveTrait, @@ -172,7 +172,7 @@ impl<'ctx> CannotDerive<'ctx> { if item.is_opaque(self.ctx, &()) { if !self.derive_trait.can_derive_union() && ty.is_union() && - self.ctx.options().rust_features().untagged_union + self.ctx.options().untagged_union { trace!( " cannot derive {} for Rust unions", @@ -322,7 +322,7 @@ impl<'ctx> CannotDerive<'ctx> { if info.kind() == CompKind::Union { if self.derive_trait.can_derive_union() { - if self.ctx.options().rust_features().untagged_union && + if self.ctx.options().untagged_union && // https://github.com/rust-lang/rust/issues/36640 (!info.self_template_params(self.ctx).is_empty() || !item.all_template_params(self.ctx).is_empty()) @@ -334,7 +334,7 @@ impl<'ctx> CannotDerive<'ctx> { } // fall through to be same as non-union handling } else { - if self.ctx.options().rust_features().untagged_union { + if self.ctx.options().untagged_union { trace!( " cannot derive {} for Rust unions", self.derive_trait @@ -722,7 +722,7 @@ impl<'ctx> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> { /// /// Elements that are not `CanDerive::Yes` are kept in the set, so that it /// represents all items that cannot derive. -pub fn as_cannot_derive_set( +pub(crate) fn as_cannot_derive_set( can_derive: HashMap<ItemId, CanDerive>, ) -> HashSet<ItemId> { can_derive diff --git a/ir/analysis/has_destructor.rs b/ir/analysis/has_destructor.rs index 74fd73d..cbcbe55 100644 --- a/ir/analysis/has_destructor.rs +++ b/ir/analysis/has_destructor.rs @@ -22,7 +22,7 @@ use crate::{HashMap, HashSet}; /// * If T is the type of a field, that field has a destructor if it's not a bitfield, /// and if T has a destructor. #[derive(Debug, Clone)] -pub struct HasDestructorAnalysis<'ctx> { +pub(crate) struct HasDestructorAnalysis<'ctx> { ctx: &'ctx BindgenContext, // The incremental result of this analysis's computation. Everything in this diff --git a/ir/analysis/has_float.rs b/ir/analysis/has_float.rs index bbf2126..219c5a5 100644 --- a/ir/analysis/has_float.rs +++ b/ir/analysis/has_float.rs @@ -22,7 +22,7 @@ use crate::{HashMap, HashSet}; /// float if any of the template arguments or template definition /// has. #[derive(Debug, Clone)] -pub struct HasFloat<'ctx> { +pub(crate) struct HasFloat<'ctx> { ctx: &'ctx BindgenContext, // The incremental result of this analysis's computation. Everything in this diff --git a/ir/analysis/has_type_param_in_array.rs b/ir/analysis/has_type_param_in_array.rs index aa52304..088c08f 100644 --- a/ir/analysis/has_type_param_in_array.rs +++ b/ir/analysis/has_type_param_in_array.rs @@ -22,7 +22,7 @@ use crate::{HashMap, HashSet}; /// type parameter in array if any of the template arguments or template definition /// has. #[derive(Debug, Clone)] -pub struct HasTypeParameterInArray<'ctx> { +pub(crate) struct HasTypeParameterInArray<'ctx> { ctx: &'ctx BindgenContext, // The incremental result of this analysis's computation. Everything in this diff --git a/ir/analysis/has_vtable.rs b/ir/analysis/has_vtable.rs index 8ac47a6..980a551 100644 --- a/ir/analysis/has_vtable.rs +++ b/ir/analysis/has_vtable.rs @@ -10,7 +10,7 @@ use std::ops; /// The result of the `HasVtableAnalysis` for an individual item. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum HasVtableResult { +pub(crate) enum HasVtableResult { /// The item does not have a vtable pointer. No, @@ -30,7 +30,7 @@ impl Default for HasVtableResult { impl HasVtableResult { /// Take the least upper bound of `self` and `rhs`. - pub fn join(self, rhs: Self) -> Self { + pub(crate) fn join(self, rhs: Self) -> Self { cmp::max(self, rhs) } } @@ -60,7 +60,7 @@ impl ops::BitOrAssign for HasVtableResult { /// * If T is an instantiation of an abstract template definition, T has /// vtable if template definition has vtable #[derive(Debug, Clone)] -pub struct HasVtableAnalysis<'ctx> { +pub(crate) struct HasVtableAnalysis<'ctx> { ctx: &'ctx BindgenContext, // The incremental result of this analysis's computation. Everything in this @@ -230,7 +230,7 @@ impl<'ctx> From<HasVtableAnalysis<'ctx>> for HashMap<ItemId, HasVtableResult> { /// This is not for _computing_ whether the thing has a vtable, it is for /// looking up the results of the HasVtableAnalysis's computations for a /// specific thing. -pub trait HasVtable { +pub(crate) trait HasVtable { /// Return `true` if this thing has vtable, `false` otherwise. fn has_vtable(&self, ctx: &BindgenContext) -> bool; diff --git a/ir/analysis/mod.rs b/ir/analysis/mod.rs index 40dfc6d..0263088 100644 --- a/ir/analysis/mod.rs +++ b/ir/analysis/mod.rs @@ -39,19 +39,24 @@ // Re-export individual analyses. mod template_params; -pub use self::template_params::UsedTemplateParameters; +pub(crate) use self::template_params::UsedTemplateParameters; mod derive; -pub use self::derive::{as_cannot_derive_set, CannotDerive, DeriveTrait}; +pub use self::derive::DeriveTrait; +pub(crate) use self::derive::{as_cannot_derive_set, CannotDerive}; mod has_vtable; -pub use self::has_vtable::{HasVtable, HasVtableAnalysis, HasVtableResult}; +pub(crate) use self::has_vtable::{ + HasVtable, HasVtableAnalysis, HasVtableResult, +}; mod has_destructor; -pub use self::has_destructor::HasDestructorAnalysis; +pub(crate) use self::has_destructor::HasDestructorAnalysis; mod has_type_param_in_array; -pub use self::has_type_param_in_array::HasTypeParameterInArray; +pub(crate) use self::has_type_param_in_array::HasTypeParameterInArray; mod has_float; -pub use self::has_float::HasFloat; +pub(crate) use self::has_float::HasFloat; mod sizedness; -pub use self::sizedness::{Sizedness, SizednessAnalysis, SizednessResult}; +pub(crate) use self::sizedness::{ + Sizedness, SizednessAnalysis, SizednessResult, +}; use crate::ir::context::{BindgenContext, ItemId}; @@ -73,7 +78,7 @@ use std::ops; /// /// For a simple example analysis, see the `ReachableFrom` type in the `tests` /// module below. -pub trait MonotoneFramework: Sized + fmt::Debug { +pub(crate) trait MonotoneFramework: Sized + fmt::Debug { /// The type of node in our dependency graph. /// /// This is just generic (and not `ItemId`) so that we can easily unit test @@ -121,7 +126,7 @@ pub trait MonotoneFramework: Sized + fmt::Debug { /// Whether an analysis's `constrain` function modified the incremental results /// or not. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ConstrainResult { +pub(crate) enum ConstrainResult { /// The incremental results were updated, and the fix-point computation /// should continue. Changed, @@ -155,7 +160,7 @@ impl ops::BitOrAssign for ConstrainResult { } /// Run an analysis in the monotone framework. -pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output +pub(crate) fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output where Analysis: MonotoneFramework, { @@ -174,7 +179,7 @@ where } /// Generate the dependency map for analysis -pub fn generate_dependencies<F>( +pub(crate) fn generate_dependencies<F>( ctx: &BindgenContext, consider_edge: F, ) -> HashMap<ItemId, Vec<ItemId>> diff --git a/ir/analysis/sizedness.rs b/ir/analysis/sizedness.rs index 251c374..995d700 100644 --- a/ir/analysis/sizedness.rs +++ b/ir/analysis/sizedness.rs @@ -25,7 +25,7 @@ use std::{cmp, ops}; /// We initially assume that all types are `ZeroSized` and then update our /// understanding as we learn more about each type. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum SizednessResult { +pub(crate) enum SizednessResult { /// The type is zero-sized. /// /// This means that if it is a C++ type, and is not being used as a base @@ -52,7 +52,7 @@ pub enum SizednessResult { /// have an `_address` byte inserted. /// /// We don't properly handle this situation correctly right now: - /// https://github.com/rust-lang/rust-bindgen/issues/586 + /// <https://github.com/rust-lang/rust-bindgen/issues/586> DependsOnTypeParam, /// Has some size that is known to be greater than zero. That doesn't mean @@ -70,7 +70,7 @@ impl Default for SizednessResult { impl SizednessResult { /// Take the least upper bound of `self` and `rhs`. - pub fn join(self, rhs: Self) -> Self { + pub(crate) fn join(self, rhs: Self) -> Self { cmp::max(self, rhs) } } @@ -102,7 +102,7 @@ impl ops::BitOrAssign for SizednessResult { /// /// * For type parameters, `DependsOnTypeParam` is assigned. #[derive(Debug)] -pub struct SizednessAnalysis<'ctx> { +pub(crate) struct SizednessAnalysis<'ctx> { ctx: &'ctx BindgenContext, dependencies: HashMap<TypeId, Vec<TypeId>>, // Incremental results of the analysis. Missing entries are implicitly @@ -346,11 +346,11 @@ impl<'ctx> From<SizednessAnalysis<'ctx>> for HashMap<TypeId, SizednessResult> { } } -/// A convenience trait for querying whether some type or id is sized. +/// A convenience trait for querying whether some type or ID is sized. /// /// This is not for _computing_ whether the thing is sized, it is for looking up /// the results of the `Sizedness` analysis's computations for a specific thing. -pub trait Sizedness { +pub(crate) trait Sizedness { /// Get the sizedness of this type. fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult; diff --git a/ir/analysis/template_params.rs b/ir/analysis/template_params.rs index f4f0c59..3e6cd5e 100644 --- a/ir/analysis/template_params.rs +++ b/ir/analysis/template_params.rs @@ -14,7 +14,7 @@ //! If we generate the naive Rust code for this alias, we get: //! //! ```ignore -//! pub type Fml<T> = ::std::os::raw::int; +//! pub(crate) type Fml<T> = ::std::os::raw::int; //! ``` //! //! And this is rejected by `rustc` due to the unused type parameter. @@ -146,7 +146,7 @@ use crate::{HashMap, HashSet}; /// specially; see `constrain_instantiation_of_blocklisted_template` and its /// documentation for details. #[derive(Debug, Clone)] -pub struct UsedTemplateParameters<'ctx> { +pub(crate) struct UsedTemplateParameters<'ctx> { ctx: &'ctx BindgenContext, // The Option is only there for temporary moves out of the hash map. See the @@ -329,7 +329,7 @@ impl<'ctx> UsedTemplateParameters<'ctx> { } } - /// The join operation on our lattice: the set union of all of this id's + /// The join operation on our lattice: the set union of all of this ID's /// successors. fn constrain_join(&self, used_by_this_id: &mut ItemSet, item: &Item) { trace!(" other item: join with successors' usage"); @@ -518,7 +518,7 @@ impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> { // exiting this method. extra_assert!(self.used.values().all(|v| v.is_some())); - // Take the set for this id out of the hash map while we mutate it based + // Take the set for this ID out of the hash map while we mutate it based // on other hash map entries. We *must* put it back into the hash map at // the end of this method. This allows us to side-step HashMap's lack of // an analog to slice::split_at_mut. diff --git a/ir/annotations.rs b/ir/annotations.rs index 288c11e..423f6c4 100644 --- a/ir/annotations.rs +++ b/ir/annotations.rs @@ -4,11 +4,55 @@ //! replace other types with, mark as opaque, etc. This module deals with all of //! that stuff. +use std::str::FromStr; + use crate::clang; +/// What kind of visibility modifer should be used for a struct or field? +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +pub enum FieldVisibilityKind { + /// Fields are marked as private, i.e., struct Foo {bar: bool} + Private, + /// Fields are marked as crate public, i.e., struct Foo {pub(crate) bar: bool} + PublicCrate, + /// Fields are marked as public, i.e., struct Foo {pub bar: bool} + Public, +} + +impl FromStr for FieldVisibilityKind { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "private" => Ok(Self::Private), + "crate" => Ok(Self::PublicCrate), + "public" => Ok(Self::Public), + _ => Err(format!("Invalid visibility kind: `{}`", s)), + } + } +} + +impl std::fmt::Display for FieldVisibilityKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let s = match self { + FieldVisibilityKind::Private => "private", + FieldVisibilityKind::PublicCrate => "crate", + FieldVisibilityKind::Public => "public", + }; + + s.fmt(f) + } +} + +impl Default for FieldVisibilityKind { + fn default() -> Self { + FieldVisibilityKind::Public + } +} + /// What kind of accessor should we provide for a field? #[derive(Copy, PartialEq, Eq, Clone, Debug)] -pub enum FieldAccessorKind { +pub(crate) enum FieldAccessorKind { /// No accessor. None, /// Plain accessor. @@ -21,12 +65,9 @@ pub enum FieldAccessorKind { /// Annotations for a given item, or a field. /// -/// You can see the kind of comments that are accepted in the Doxygen -/// documentation: -/// -/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html +/// You can see the kind of comments that are accepted in the [Doxygen documentation](https://www.doxygen.nl/manual/docblocks.html). #[derive(Default, Clone, PartialEq, Eq, Debug)] -pub struct Annotations { +pub(crate) struct Annotations { /// Whether this item is marked as opaque. Only applies to types. opaque: bool, /// Whether this item should be hidden from the output. Only applies to @@ -42,11 +83,11 @@ pub struct Annotations { disallow_debug: bool, /// Manually disable deriving/implement default on this type. disallow_default: bool, - /// Whether to add a #[must_use] annotation to this type. + /// Whether to add a `#[must_use]` annotation to this type. must_use_type: bool, - /// Whether fields should be marked as private or not. You can set this on + /// Visibility of struct fields. You can set this on /// structs (it will apply to all the fields), or individual fields. - private_fields: Option<bool>, + visibility_kind: Option<FieldVisibilityKind>, /// The kind of accessor this field will have. Also can be applied to /// structs so all the fields inside share it by default. accessor_kind: Option<FieldAccessorKind>, @@ -80,7 +121,7 @@ fn parse_accessor(s: &str) -> FieldAccessorKind { impl Annotations { /// Construct new annotations for the given cursor and its bindgen comments /// (if any). - pub fn new(cursor: &clang::Cursor) -> Option<Annotations> { + pub(crate) fn new(cursor: &clang::Cursor) -> Option<Annotations> { let mut anno = Annotations::default(); let mut matched_one = false; anno.parse(&cursor.comment(), &mut matched_one); @@ -93,12 +134,12 @@ impl Annotations { } /// Should this type be hidden? - pub fn hide(&self) -> bool { + pub(crate) fn hide(&self) -> bool { self.hide } /// Should this type be opaque? - pub fn opaque(&self) -> bool { + pub(crate) fn opaque(&self) -> bool { self.opaque } @@ -124,42 +165,42 @@ impl Annotations { /// ``` /// /// That is, code for `Foo` is used to generate `Bar`. - pub fn use_instead_of(&self) -> Option<&[String]> { + pub(crate) fn use_instead_of(&self) -> Option<&[String]> { self.use_instead_of.as_deref() } /// The list of derives that have been specified in this annotation. - pub fn derives(&self) -> &[String] { + pub(crate) fn derives(&self) -> &[String] { &self.derives } /// Should we avoid implementing the `Copy` trait? - pub fn disallow_copy(&self) -> bool { + pub(crate) fn disallow_copy(&self) -> bool { self.disallow_copy } /// Should we avoid implementing the `Debug` trait? - pub fn disallow_debug(&self) -> bool { + pub(crate) fn disallow_debug(&self) -> bool { self.disallow_debug } /// Should we avoid implementing the `Default` trait? - pub fn disallow_default(&self) -> bool { + pub(crate) fn disallow_default(&self) -> bool { self.disallow_default } /// Should this type get a `#[must_use]` annotation? - pub fn must_use_type(&self) -> bool { + pub(crate) fn must_use_type(&self) -> bool { self.must_use_type } - /// Should the fields be private? - pub fn private_fields(&self) -> Option<bool> { - self.private_fields + /// What kind of accessors should we provide for this type's fields? + pub(crate) fn visibility_kind(&self) -> Option<FieldVisibilityKind> { + self.visibility_kind } /// What kind of accessors should we provide for this type's fields? - pub fn accessor_kind(&self) -> Option<FieldAccessorKind> { + pub(crate) fn accessor_kind(&self) -> Option<FieldAccessorKind> { self.accessor_kind } @@ -188,7 +229,11 @@ impl Annotations { } "derive" => self.derives.push(attr.value), "private" => { - self.private_fields = Some(attr.value != "false") + self.visibility_kind = if attr.value != "false" { + Some(FieldVisibilityKind::Private) + } else { + Some(FieldVisibilityKind::Public) + }; } "accessor" => { self.accessor_kind = Some(parse_accessor(&attr.value)) @@ -205,7 +250,7 @@ impl Annotations { } /// Returns whether we've parsed a "constant" attribute. - pub fn constify_enum_variant(&self) -> bool { + pub(crate) fn constify_enum_variant(&self) -> bool { self.constify_enum_variant } } diff --git a/ir/comment.rs b/ir/comment.rs index 3eb17aa..7b6f105 100644 --- a/ir/comment.rs +++ b/ir/comment.rs @@ -12,7 +12,7 @@ enum Kind { } /// Preprocesses a C/C++ comment so that it is a valid Rust comment. -pub fn preprocess(comment: &str) -> String { +pub(crate) fn preprocess(comment: &str) -> String { match self::kind(comment) { Some(Kind::SingleLines) => preprocess_single_lines(comment), Some(Kind::MultiLine) => preprocess_multi_line(comment), @@ -22,7 +22,7 @@ use std::mem; /// The kind of compound type. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum CompKind { +pub(crate) enum CompKind { /// A struct. Struct, /// A union. @@ -31,7 +31,7 @@ pub enum CompKind { /// The kind of C++ method. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum MethodKind { +pub(crate) enum MethodKind { /// A constructor. We represent it as method for convenience, to avoid code /// duplication. Constructor, @@ -55,7 +55,7 @@ pub enum MethodKind { impl MethodKind { /// Is this a destructor method? - pub fn is_destructor(&self) -> bool { + pub(crate) fn is_destructor(&self) -> bool { matches!( *self, MethodKind::Destructor | MethodKind::VirtualDestructor { .. } @@ -63,7 +63,7 @@ impl MethodKind { } /// Is this a pure virtual method? - pub fn is_pure_virtual(&self) -> bool { + pub(crate) fn is_pure_virtual(&self) -> bool { match *self { MethodKind::Virtual { pure_virtual } | MethodKind::VirtualDestructor { pure_virtual } => pure_virtual, @@ -74,7 +74,7 @@ impl MethodKind { /// A struct representing a C++ method, either static, normal, or virtual. #[derive(Debug)] -pub struct Method { +pub(crate) struct Method { kind: MethodKind, /// The signature of the method. Take into account this is not a `Type` /// item, but a `Function` one. @@ -86,7 +86,7 @@ pub struct Method { impl Method { /// Construct a new `Method`. - pub fn new( + pub(crate) fn new( kind: MethodKind, signature: FunctionId, is_const: bool, @@ -99,17 +99,17 @@ impl Method { } /// What kind of method is this? - pub fn kind(&self) -> MethodKind { + pub(crate) fn kind(&self) -> MethodKind { self.kind } /// Is this a constructor? - pub fn is_constructor(&self) -> bool { + pub(crate) fn is_constructor(&self) -> bool { self.kind == MethodKind::Constructor } /// Is this a virtual method? - pub fn is_virtual(&self) -> bool { + pub(crate) fn is_virtual(&self) -> bool { matches!( self.kind, MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. } @@ -117,23 +117,23 @@ impl Method { } /// Is this a static method? - pub fn is_static(&self) -> bool { + pub(crate) fn is_static(&self) -> bool { self.kind == MethodKind::Static } - /// Get the id for the `Function` signature for this method. - pub fn signature(&self) -> FunctionId { + /// Get the ID for the `Function` signature for this method. + pub(crate) fn signature(&self) -> FunctionId { self.signature } /// Is this a const qualified method? - pub fn is_const(&self) -> bool { + pub(crate) fn is_const(&self) -> bool { self.is_const } } /// Methods common to the various field types. -pub trait FieldMethods { +pub(crate) trait FieldMethods { /// Get the name of this field. fn name(&self) -> Option<&str>; @@ -161,7 +161,7 @@ pub trait FieldMethods { /// 2.4.II.1 in the Itanium C++ /// ABI](http://itanium-cxx-abi.github.io/cxx-abi/abi.html#class-types). #[derive(Debug)] -pub struct BitfieldUnit { +pub(crate) struct BitfieldUnit { nth: usize, layout: Layout, bitfields: Vec<Bitfield>, @@ -171,24 +171,24 @@ impl BitfieldUnit { /// Get the 1-based index of this bitfield unit within its containing /// struct. Useful for generating a Rust struct's field name for this unit /// of bitfields. - pub fn nth(&self) -> usize { + pub(crate) fn nth(&self) -> usize { self.nth } /// Get the layout within which these bitfields reside. - pub fn layout(&self) -> Layout { + pub(crate) fn layout(&self) -> Layout { self.layout } /// Get the bitfields within this unit. - pub fn bitfields(&self) -> &[Bitfield] { + pub(crate) fn bitfields(&self) -> &[Bitfield] { &self.bitfields } } /// A struct representing a C++ field. #[derive(Debug)] -pub enum Field { +pub(crate) enum Field { /// A normal data member. DataMember(FieldData), @@ -198,7 +198,7 @@ pub enum Field { impl Field { /// Get this field's layout. - pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { + pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { match *self { Field::Bitfields(BitfieldUnit { layout, .. }) => Some(layout), Field::DataMember(ref data) => { @@ -307,7 +307,7 @@ impl DotAttributes for Bitfield { /// A logical bitfield within some physical bitfield allocation unit. #[derive(Debug)] -pub struct Bitfield { +pub(crate) struct Bitfield { /// Index of the bit within this bitfield's allocation unit where this /// bitfield's bits begin. offset_into_unit: usize, @@ -341,27 +341,12 @@ impl Bitfield { /// Get the index of the bit within this bitfield's allocation unit where /// this bitfield begins. - pub fn offset_into_unit(&self) -> usize { + pub(crate) fn offset_into_unit(&self) -> usize { self.offset_into_unit } - /// Get the mask value that when &'ed with this bitfield's allocation unit - /// produces this bitfield's value. - pub fn mask(&self) -> u64 { - use std::u64; - - let unoffseted_mask = - if self.width() as u64 == mem::size_of::<u64>() as u64 * 8 { - u64::MAX - } else { - (1u64 << self.width()) - 1u64 - }; - - unoffseted_mask << self.offset_into_unit() - } - /// Get the bit width of this bitfield. - pub fn width(&self) -> u32 { + pub(crate) fn width(&self) -> u32 { self.data.bitfield_width().unwrap() } @@ -369,7 +354,7 @@ impl Bitfield { /// /// Panics if called before assigning bitfield accessor names or if /// this bitfield have no name. - pub fn getter_name(&self) -> &str { + pub(crate) fn getter_name(&self) -> &str { assert!( self.name().is_some(), "`Bitfield::getter_name` called on anonymous field" @@ -384,7 +369,7 @@ impl Bitfield { /// /// Panics if called before assigning bitfield accessor names or if /// this bitfield have no name. - pub fn setter_name(&self) -> &str { + pub(crate) fn setter_name(&self) -> &str { assert!( self.name().is_some(), "`Bitfield::setter_name` called on anonymous field" @@ -866,7 +851,7 @@ impl Trace for CompFields { /// Common data shared across different field types. #[derive(Clone, Debug)] -pub struct FieldData { +pub(crate) struct FieldData { /// The name of the field, empty if it's an unnamed bitfield width. name: Option<String>, @@ -921,7 +906,7 @@ impl FieldMethods for FieldData { /// The kind of inheritance a base class is using. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum BaseKind { +pub(crate) enum BaseKind { /// Normal inheritance, like: /// /// ```cpp @@ -938,25 +923,25 @@ pub enum BaseKind { /// A base class. #[derive(Clone, Debug)] -pub struct Base { +pub(crate) struct Base { /// The type of this base class. - pub ty: TypeId, + pub(crate) ty: TypeId, /// The kind of inheritance we're doing. - pub kind: BaseKind, + pub(crate) kind: BaseKind, /// Name of the field in which this base should be stored. - pub field_name: String, + pub(crate) field_name: String, /// Whether this base is inherited from publically. - pub is_pub: bool, + pub(crate) is_pub: bool, } impl Base { /// Whether this base class is inheriting virtually. - pub fn is_virtual(&self) -> bool { + pub(crate) fn is_virtual(&self) -> bool { self.kind == BaseKind::Virtual } /// Whether this base class should have it's own field for storage. - pub fn requires_storage(&self, ctx: &BindgenContext) -> bool { + pub(crate) fn requires_storage(&self, ctx: &BindgenContext) -> bool { // Virtual bases are already taken into account by the vtable // pointer. // @@ -976,7 +961,7 @@ impl Base { } /// Whether this base is inherited from publically. - pub fn is_public(&self) -> bool { + pub(crate) fn is_public(&self) -> bool { self.is_pub } } @@ -987,7 +972,7 @@ impl Base { /// of fields which also are associated with their own (potentially compound) /// type. #[derive(Debug)] -pub struct CompInfo { +pub(crate) struct CompInfo { /// Whether this is a struct or a union. kind: CompKind, @@ -1067,7 +1052,7 @@ pub struct CompInfo { impl CompInfo { /// Construct a new compound type. - pub fn new(kind: CompKind) -> Self { + pub(crate) fn new(kind: CompKind) -> Self { CompInfo { kind, fields: CompFields::default(), @@ -1097,7 +1082,7 @@ impl CompInfo { /// If we're a union without known layout, we try to compute it from our /// members. This is not ideal, but clang fails to report the size for these /// kind of unions, see test/headers/template_union.hpp - pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { + pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { // We can't do better than clang here, sorry. if self.kind == CompKind::Struct { return None; @@ -1126,7 +1111,7 @@ impl CompInfo { } /// Get this type's set of fields. - pub fn fields(&self) -> &[Field] { + pub(crate) fn fields(&self) -> &[Field] { match self.fields { CompFields::Error => &[], CompFields::After { ref fields, .. } => fields, @@ -1184,7 +1169,7 @@ impl CompInfo { /// Returns whether we have a too large bitfield unit, in which case we may /// not be able to derive some of the things we should be able to normally /// derive. - pub fn has_too_large_bitfield_unit(&self) -> bool { + pub(crate) fn has_too_large_bitfield_unit(&self) -> bool { if !self.has_bitfields() { return false; } @@ -1198,53 +1183,53 @@ impl CompInfo { /// Does this type have any template parameters that aren't types /// (e.g. int)? - pub fn has_non_type_template_params(&self) -> bool { + pub(crate) fn has_non_type_template_params(&self) -> bool { self.has_non_type_template_params } /// Do we see a virtual function during parsing? /// Get the has_own_virtual_method boolean. - pub fn has_own_virtual_method(&self) -> bool { + pub(crate) fn has_own_virtual_method(&self) -> bool { self.has_own_virtual_method } /// Did we see a destructor when parsing this type? - pub fn has_own_destructor(&self) -> bool { + pub(crate) fn has_own_destructor(&self) -> bool { self.has_destructor } /// Get this type's set of methods. - pub fn methods(&self) -> &[Method] { + pub(crate) fn methods(&self) -> &[Method] { &self.methods } /// Get this type's set of constructors. - pub fn constructors(&self) -> &[FunctionId] { + pub(crate) fn constructors(&self) -> &[FunctionId] { &self.constructors } /// Get this type's destructor. - pub fn destructor(&self) -> Option<(MethodKind, FunctionId)> { + pub(crate) fn destructor(&self) -> Option<(MethodKind, FunctionId)> { self.destructor } /// What kind of compound type is this? - pub fn kind(&self) -> CompKind { + pub(crate) fn kind(&self) -> CompKind { self.kind } /// Is this a union? - pub fn is_union(&self) -> bool { + pub(crate) fn is_union(&self) -> bool { self.kind() == CompKind::Union } /// The set of types that this one inherits from. - pub fn base_members(&self) -> &[Base] { + pub(crate) fn base_members(&self) -> &[Base] { &self.base_members } /// Construct a new compound type from a Clang type. - pub fn from_ty( + pub(crate) fn from_ty( potential_id: ItemId, ty: &clang::Type, location: Option<clang::Cursor>, @@ -1611,23 +1596,23 @@ impl CompInfo { /// Get the set of types that were declared within this compound type /// (e.g. nested class definitions). - pub fn inner_types(&self) -> &[TypeId] { + pub(crate) fn inner_types(&self) -> &[TypeId] { &self.inner_types } /// Get the set of static variables declared within this compound type. - pub fn inner_vars(&self) -> &[VarId] { + pub(crate) fn inner_vars(&self) -> &[VarId] { &self.inner_vars } /// Have we found a field with an opaque type that could potentially mess up /// the layout of this compound type? - pub fn found_unknown_attr(&self) -> bool { + pub(crate) fn found_unknown_attr(&self) -> bool { self.found_unknown_attr } /// Is this compound type packed? - pub fn is_packed( + pub(crate) fn is_packed( &self, ctx: &BindgenContext, layout: Option<&Layout>, @@ -1657,12 +1642,12 @@ impl CompInfo { } /// Returns true if compound type has been forward declared - pub fn is_forward_declaration(&self) -> bool { + pub(crate) fn is_forward_declaration(&self) -> bool { self.is_forward_declaration } /// Compute this compound structure's bitfield allocation units. - pub fn compute_bitfield_units( + pub(crate) fn compute_bitfield_units( &mut self, ctx: &BindgenContext, layout: Option<&Layout>, @@ -1672,7 +1657,7 @@ impl CompInfo { } /// Assign for each anonymous field a generated name. - pub fn deanonymize_fields(&mut self, ctx: &BindgenContext) { + pub(crate) fn deanonymize_fields(&mut self, ctx: &BindgenContext) { self.fields.deanonymize_fields(ctx, &self.methods); } @@ -1685,7 +1670,7 @@ impl CompInfo { /// /// Second boolean returns whether all fields can be copied (and thus /// ManuallyDrop is not needed). - pub fn is_rust_union( + pub(crate) fn is_rust_union( &self, ctx: &BindgenContext, layout: Option<&Layout>, @@ -1695,7 +1680,7 @@ impl CompInfo { return (false, false); } - if !ctx.options().rust_features().untagged_union { + if !ctx.options().untagged_union { return (false, false); } diff --git a/ir/context.rs b/ir/context.rs index b693a70..a5c14a8 100644 --- a/ir/context.rs +++ b/ir/context.rs @@ -23,8 +23,7 @@ use crate::clang::{self, Cursor}; use crate::codegen::CodegenError; use crate::BindgenOptions; use crate::{Entry, HashMap, HashSet}; -use cexpr; -use clang_sys; + use proc_macro2::{Ident, Span, TokenStream}; use quote::ToTokens; use std::borrow::Cow; @@ -35,12 +34,13 @@ use std::mem; /// An identifier for some kind of IR item. #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] -pub struct ItemId(usize); +pub(crate) struct ItemId(usize); +/// Declare a newtype around `ItemId` with convesion methods. macro_rules! item_id_newtype { ( $( #[$attr:meta] )* - pub struct $name:ident(ItemId) + pub(crate) struct $name:ident(ItemId) where $( #[$checked_attr:meta] )* checked = $checked:ident with $check_method:ident, @@ -51,11 +51,12 @@ macro_rules! item_id_newtype { ) => { $( #[$attr] )* #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] - pub struct $name(ItemId); + pub(crate) struct $name(ItemId); impl $name { - /// Create an `ItemResolver` from this id. - pub fn into_resolver(self) -> ItemResolver { + /// Create an `ItemResolver` from this ID. + #[allow(dead_code)] + pub(crate) fn into_resolver(self) -> ItemResolver { let id: ItemId = self.into(); id.into() } @@ -83,9 +84,10 @@ macro_rules! item_id_newtype { } } + #[allow(dead_code)] impl ItemId { $( #[$checked_attr] )* - pub fn $checked(&self, ctx: &BindgenContext) -> Option<$name> { + pub(crate) fn $checked(&self, ctx: &BindgenContext) -> Option<$name> { if ctx.resolve_item(*self).kind().$check_method() { Some($name(*self)) } else { @@ -94,7 +96,7 @@ macro_rules! item_id_newtype { } $( #[$expected_attr] )* - pub fn $expected(&self, ctx: &BindgenContext) -> $name { + pub(crate) fn $expected(&self, ctx: &BindgenContext) -> $name { self.$checked(ctx) .expect(concat!( stringify!($expected), @@ -103,7 +105,7 @@ macro_rules! item_id_newtype { } $( #[$unchecked_attr] )* - pub fn $unchecked(&self) -> $name { + pub(crate) fn $unchecked(&self) -> $name { $name(*self) } } @@ -113,7 +115,7 @@ macro_rules! item_id_newtype { item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Type`. - pub struct TypeId(ItemId) + pub(crate) struct TypeId(ItemId) where /// Convert this `ItemId` into a `TypeId` if its associated item is a type, /// otherwise return `None`. @@ -125,14 +127,14 @@ item_id_newtype! { expected = expect_type_id, /// Convert this `ItemId` into a `TypeId` without actually checking whether - /// this id actually points to a `Type`. + /// this ID actually points to a `Type`. unchecked = as_type_id_unchecked; } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Module`. - pub struct ModuleId(ItemId) + pub(crate) struct ModuleId(ItemId) where /// Convert this `ItemId` into a `ModuleId` if its associated item is a /// module, otherwise return `None`. @@ -144,14 +146,14 @@ item_id_newtype! { expected = expect_module_id, /// Convert this `ItemId` into a `ModuleId` without actually checking - /// whether this id actually points to a `Module`. + /// whether this ID actually points to a `Module`. unchecked = as_module_id_unchecked; } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Var`. - pub struct VarId(ItemId) + pub(crate) struct VarId(ItemId) where /// Convert this `ItemId` into a `VarId` if its associated item is a var, /// otherwise return `None`. @@ -163,14 +165,14 @@ item_id_newtype! { expected = expect_var_id, /// Convert this `ItemId` into a `VarId` without actually checking whether - /// this id actually points to a `Var`. + /// this ID actually points to a `Var`. unchecked = as_var_id_unchecked; } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Function`. - pub struct FunctionId(ItemId) + pub(crate) struct FunctionId(ItemId) where /// Convert this `ItemId` into a `FunctionId` if its associated item is a function, /// otherwise return `None`. @@ -182,7 +184,7 @@ item_id_newtype! { expected = expect_function_id, /// Convert this `ItemId` into a `FunctionId` without actually checking whether - /// this id actually points to a `Function`. + /// this ID actually points to a `Function`. unchecked = as_function_id_unchecked; } @@ -193,8 +195,8 @@ impl From<ItemId> for usize { } impl ItemId { - /// Get a numeric representation of this id. - pub fn as_usize(&self) -> usize { + /// Get a numeric representation of this ID. + pub(crate) fn as_usize(&self) -> usize { (*self).into() } } @@ -305,7 +307,7 @@ enum TypeKey { /// A context used during parsing and generation of structs. #[derive(Debug)] -pub struct BindgenContext { +pub(crate) struct BindgenContext { /// The map of all the items parsed so far, keyed off ItemId. items: Vec<Option<Item>>, @@ -313,7 +315,7 @@ pub struct BindgenContext { /// item ids during parsing. types: HashMap<TypeKey, TypeId>, - /// Maps from a cursor to the item id of the named template type parameter + /// Maps from a cursor to the item ID of the named template type parameter /// for that cursor. type_params: HashMap<clang::Cursor, TypeId>, @@ -326,7 +328,7 @@ pub struct BindgenContext { /// Current module being traversed. current_module: ModuleId, - /// A HashMap keyed on a type definition, and whose value is the parent id + /// A HashMap keyed on a type definition, and whose value is the parent ID /// of the declaration. /// /// This is used to handle the cases where the semantic and the lexical @@ -390,7 +392,7 @@ pub struct BindgenContext { /// It's computed right after computing the allowlisted items. codegen_items: Option<ItemSet>, - /// Map from an item's id to the set of template parameter items that it + /// Map from an item's ID to the set of template parameter items that it /// uses. See `ir::named` for more details. Always `Some` during the codegen /// phase. used_template_parameters: Option<HashMap<ItemId, ItemSet>>, @@ -475,9 +477,6 @@ pub struct BindgenContext { /// Populated when we enter codegen by `compute_has_float`; always `None` /// before that and `Some` after. has_float: Option<HashSet<ItemId>>, - - /// The set of warnings raised during binding generation. - warnings: Vec<String>, } /// A traversal of allowlisted items. @@ -504,7 +503,7 @@ impl<'ctx> Iterator for AllowlistedItemsTraversal<'ctx> { impl<'ctx> AllowlistedItemsTraversal<'ctx> { /// Construct a new allowlisted items traversal. - pub fn new<R>( + pub(crate) fn new<R>( ctx: &'ctx BindgenContext, roots: R, predicate: for<'a> fn(&'a BindgenContext, Edge) -> bool, @@ -593,51 +592,50 @@ If you encounter an error missing from this list, please file an issue or a PR!" have_destructor: None, has_type_param_in_array: None, has_float: None, - warnings: Vec::new(), } } /// Returns `true` if the target architecture is wasm32 - pub fn is_target_wasm32(&self) -> bool { + pub(crate) fn is_target_wasm32(&self) -> bool { self.target_info.triple.starts_with("wasm32-") } /// Creates a timer for the current bindgen phase. If time_phases is `true`, /// the timer will print to stderr when it is dropped, otherwise it will do /// nothing. - pub fn timer<'a>(&self, name: &'a str) -> Timer<'a> { + pub(crate) fn timer<'a>(&self, name: &'a str) -> Timer<'a> { Timer::new(name).with_output(self.options.time_phases) } /// Returns the pointer width to use for the target for the current /// translation. - pub fn target_pointer_size(&self) -> usize { + pub(crate) fn target_pointer_size(&self) -> usize { self.target_info.pointer_width / 8 } /// Get the stack of partially parsed types that we are in the middle of /// parsing. - pub fn currently_parsed_types(&self) -> &[PartialType] { + pub(crate) fn currently_parsed_types(&self) -> &[PartialType] { &self.currently_parsed_types[..] } /// Begin parsing the given partial type, and push it onto the /// `currently_parsed_types` stack so that we won't infinite recurse if we /// run into a reference to it while parsing it. - pub fn begin_parsing(&mut self, partial_ty: PartialType) { + pub(crate) fn begin_parsing(&mut self, partial_ty: PartialType) { self.currently_parsed_types.push(partial_ty); } /// Finish parsing the current partial type, pop it off the /// `currently_parsed_types` stack, and return it. - pub fn finish_parsing(&mut self) -> PartialType { + pub(crate) fn finish_parsing(&mut self) -> PartialType { self.currently_parsed_types.pop().expect( "should have been parsing a type, if we finished parsing a type", ) } /// Add another path to the set of included files. - pub fn include_file(&mut self, filename: String) { + pub(crate) fn include_file(&mut self, filename: String) { for cb in &self.options().parse_callbacks { cb.include_file(&filename); } @@ -645,7 +643,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Get any included files. - pub fn deps(&self) -> &BTreeSet<String> { + pub(crate) fn deps(&self) -> &BTreeSet<String> { &self.deps } @@ -653,7 +651,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// /// This inserts it into the internal items set, and its type into the /// internal types set. - pub fn add_item( + pub(crate) fn add_item( &mut self, item: Item, declaration: Option<Cursor>, @@ -778,7 +776,11 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Add a new named template type parameter to this context's item set. - pub fn add_type_param(&mut self, item: Item, definition: clang::Cursor) { + pub(crate) fn add_type_param( + &mut self, + item: Item, + definition: clang::Cursor, + ) { debug!( "BindgenContext::add_type_param: item = {:?}; definition = {:?}", item, definition @@ -813,7 +815,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Get the named type defined at the given cursor location, if we've /// already added one. - pub fn get_type_param(&self, definition: &clang::Cursor) -> Option<TypeId> { + pub(crate) fn get_type_param( + &self, + definition: &clang::Cursor, + ) -> Option<TypeId> { assert_eq!( definition.kind(), clang_sys::CXCursor_TemplateTypeParameter @@ -825,7 +830,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Mangles a name so it doesn't conflict with any keyword. #[rustfmt::skip] - pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> { + pub(crate) fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> { if name.contains('@') || name.contains('?') || name.contains('$') || @@ -856,7 +861,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Returns a mangled name as a rust identifier. - pub fn rust_ident<S>(&self, name: S) -> Ident + pub(crate) fn rust_ident<S>(&self, name: S) -> Ident where S: AsRef<str>, { @@ -864,7 +869,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Returns a mangled name as a rust identifier. - pub fn rust_ident_raw<T>(&self, name: T) -> Ident + pub(crate) fn rust_ident_raw<T>(&self, name: T) -> Ident where T: AsRef<str>, { @@ -872,7 +877,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Iterate over all items that have been defined. - pub fn items(&self) -> impl Iterator<Item = (ItemId, &Item)> { + pub(crate) fn items(&self) -> impl Iterator<Item = (ItemId, &Item)> { self.items.iter().enumerate().filter_map(|(index, item)| { let item = item.as_ref()?; Some((ItemId(index), item)) @@ -880,7 +885,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Have we collected all unresolved type references yet? - pub fn collected_typerefs(&self) -> bool { + pub(crate) fn collected_typerefs(&self) -> bool { self.collected_typerefs } @@ -1077,7 +1082,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" // Relocate the replacement item from where it was declared, to // where the thing it is replacing was declared. // - // First, we'll make sure that its parent id is correct. + // First, we'll make sure that its parent ID is correct. let old_parent = self.resolve_item(replacement_id).parent_id(); if new_parent == old_parent { @@ -1147,7 +1152,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" pub(crate) fn gen<F, Out>( mut self, cb: F, - ) -> Result<(Out, BindgenOptions, Vec<String>), CodegenError> + ) -> Result<(Out, BindgenOptions), CodegenError> where F: FnOnce(&Self) -> Result<Out, CodegenError>, { @@ -1185,7 +1190,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.compute_cannot_derive_partialord_partialeq_or_eq(); let ret = cb(&self)?; - Ok((ret, self.options, self.warnings)) + Ok((ret, self.options)) } /// When the `testing_only_extra_assertions` feature is enabled, this @@ -1263,8 +1268,8 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.sizedness = Some(analyze::<SizednessAnalysis>(self)); } - /// Look up whether the type with the given id is sized or not. - pub fn lookup_sizedness(&self, id: TypeId) -> SizednessResult { + /// Look up whether the type with the given ID is sized or not. + pub(crate) fn lookup_sizedness(&self, id: TypeId) -> SizednessResult { assert!( self.in_codegen_phase(), "We only compute sizedness after we've entered codegen" @@ -1286,7 +1291,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Look up whether the item with `id` has vtable or not. - pub fn lookup_has_vtable(&self, id: TypeId) -> HasVtableResult { + pub(crate) fn lookup_has_vtable(&self, id: TypeId) -> HasVtableResult { assert!( self.in_codegen_phase(), "We only compute vtables when we enter codegen" @@ -1310,7 +1315,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Look up whether the item with `id` has a destructor. - pub fn lookup_has_destructor(&self, id: TypeId) -> bool { + pub(crate) fn lookup_has_destructor(&self, id: TypeId) -> bool { assert!( self.in_codegen_phase(), "We only compute destructors when we enter codegen" @@ -1354,7 +1359,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// manually provide a definition for them. To give them the most /// flexibility when doing that, we assume that they use every template /// parameter and always pass template arguments through in instantiations. - pub fn uses_template_parameter( + pub(crate) fn uses_template_parameter( &self, item: ItemId, template_param: TypeId, @@ -1386,7 +1391,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// `false` otherwise. /// /// Has the same restrictions that `uses_template_parameter` has. - pub fn uses_any_template_parameters(&self, item: ItemId) -> bool { + pub(crate) fn uses_any_template_parameters(&self, item: ItemId) -> bool { assert!( self.in_codegen_phase(), "We only compute template parameter usage as we enter codegen" @@ -1424,38 +1429,38 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Get the root module. - pub fn root_module(&self) -> ModuleId { + pub(crate) fn root_module(&self) -> ModuleId { self.root_module } - /// Resolve a type with the given id. + /// Resolve a type with the given ID. /// /// Panics if there is no item for the given `TypeId` or if the resolved /// item is not a `Type`. - pub fn resolve_type(&self, type_id: TypeId) -> &Type { + pub(crate) fn resolve_type(&self, type_id: TypeId) -> &Type { self.resolve_item(type_id).kind().expect_type() } - /// Resolve a function with the given id. + /// Resolve a function with the given ID. /// /// Panics if there is no item for the given `FunctionId` or if the resolved /// item is not a `Function`. - pub fn resolve_func(&self, func_id: FunctionId) -> &Function { + pub(crate) fn resolve_func(&self, func_id: FunctionId) -> &Function { self.resolve_item(func_id).kind().expect_function() } /// Resolve the given `ItemId` as a type, or `None` if there is no item with - /// the given id. + /// the given ID. /// - /// Panics if the id resolves to an item that is not a type. - pub fn safe_resolve_type(&self, type_id: TypeId) -> Option<&Type> { + /// Panics if the ID resolves to an item that is not a type. + pub(crate) fn safe_resolve_type(&self, type_id: TypeId) -> Option<&Type> { self.resolve_item_fallible(type_id) .map(|t| t.kind().expect_type()) } /// Resolve the given `ItemId` into an `Item`, or `None` if no such item /// exists. - pub fn resolve_item_fallible<Id: Into<ItemId>>( + pub(crate) fn resolve_item_fallible<Id: Into<ItemId>>( &self, id: Id, ) -> Option<&Item> { @@ -1464,8 +1469,8 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Resolve the given `ItemId` into an `Item`. /// - /// Panics if the given id does not resolve to any item. - pub fn resolve_item<Id: Into<ItemId>>(&self, item_id: Id) -> &Item { + /// Panics if the given ID does not resolve to any item. + pub(crate) fn resolve_item<Id: Into<ItemId>>(&self, item_id: Id) -> &Item { let item_id = item_id.into(); match self.resolve_item_fallible(item_id) { Some(item) => item, @@ -1474,7 +1479,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Get the current module. - pub fn current_module(&self) -> ModuleId { + pub(crate) fn current_module(&self) -> ModuleId { self.current_module } @@ -1486,7 +1491,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// TODO(emilio): We could consider doing this only when /// declaration.lexical_parent() != definition.lexical_parent(), but it's /// not sure it's worth it. - pub fn add_semantic_parent( + pub(crate) fn add_semantic_parent( &mut self, definition: clang::Cursor, parent_id: ItemId, @@ -1495,7 +1500,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Returns a known semantic parent for a given definition. - pub fn known_semantic_parent( + pub(crate) fn known_semantic_parent( &self, definition: clang::Cursor, ) -> Option<ItemId> { @@ -1649,7 +1654,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" clang_sys::CXCursor_TypeRef | clang_sys::CXCursor_TypedefDecl | clang_sys::CXCursor_TypeAliasDecl => { - // The `with_id` id will potentially end up unused if we give up + // The `with_id` ID will potentially end up unused if we give up // on this type (for example, because it has const value // template args), so if we pass `with_id` as the parent, it is // potentially a dangling reference. Instead, use the canonical @@ -1808,7 +1813,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// If we have already resolved the type for the given type declaration, /// return its `ItemId`. Otherwise, return `None`. - pub fn get_resolved_type( + pub(crate) fn get_resolved_type( &self, decl: &clang::CanonicalTypeDeclaration, ) -> Option<TypeId> { @@ -1824,7 +1829,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Looks up for an already resolved type, either because it's builtin, or /// because we already have it in the map. - pub fn builtin_or_resolved_ty( + pub(crate) fn builtin_or_resolved_ty( &mut self, with_id: ItemId, parent_id: Option<ItemId>, @@ -1894,7 +1899,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// We should probably make the constness tracking separate, so it doesn't /// bloat that much, but hey, we already bloat the heck out of builtin /// types. - pub fn build_ty_wrapper( + pub(crate) fn build_ty_wrapper( &mut self, with_id: ItemId, wrapped_id: TypeId, @@ -1907,7 +1912,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// A wrapper over a type that adds a const qualifier explicitly. /// /// Needed to handle const methods in C++, wrapping the type . - pub fn build_const_wrapper( + pub(crate) fn build_const_wrapper( &mut self, with_id: ItemId, wrapped_id: TypeId, @@ -1944,8 +1949,8 @@ If you encounter an error missing from this list, please file an issue or a PR!" with_id.as_type_id_unchecked() } - /// Returns the next item id to be used for an item. - pub fn next_item_id(&mut self) -> ItemId { + /// Returns the next item ID to be used for an item. + pub(crate) fn next_item_id(&mut self) -> ItemId { let ret = ItemId(self.items.len()); self.items.push(None); ret @@ -2015,17 +2020,17 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Get the current Clang translation unit that is being processed. - pub fn translation_unit(&self) -> &clang::TranslationUnit { + pub(crate) fn translation_unit(&self) -> &clang::TranslationUnit { &self.translation_unit } /// Have we parsed the macro named `macro_name` already? - pub fn parsed_macro(&self, macro_name: &[u8]) -> bool { + pub(crate) fn parsed_macro(&self, macro_name: &[u8]) -> bool { self.parsed_macros.contains_key(macro_name) } /// Get the currently parsed macros. - pub fn parsed_macros( + pub(crate) fn parsed_macros( &self, ) -> &StdHashMap<Vec<u8>, cexpr::expr::EvalResult> { debug_assert!(!self.in_codegen_phase()); @@ -2033,7 +2038,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Mark the macro named `macro_name` as parsed. - pub fn note_parsed_macro( + pub(crate) fn note_parsed_macro( &mut self, id: Vec<u8>, value: cexpr::expr::EvalResult, @@ -2042,16 +2047,16 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Are we in the codegen phase? - pub fn in_codegen_phase(&self) -> bool { + pub(crate) fn in_codegen_phase(&self) -> bool { self.in_codegen } - /// Mark the type with the given `name` as replaced by the type with id + /// Mark the type with the given `name` as replaced by the type with ID /// `potential_ty`. /// /// Replacement types are declared using the `replaces="xxx"` annotation, /// and implies that the original type is hidden. - pub fn replace(&mut self, name: &[String], potential_ty: ItemId) { + pub(crate) fn replace(&mut self, name: &[String], potential_ty: ItemId) { match self.replacements.entry(name.into()) { Entry::Vacant(entry) => { debug!( @@ -2074,7 +2079,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Has the item with the given `name` and `id` been replaced by another /// type? - pub fn is_replaced_type<Id: Into<ItemId>>( + pub(crate) fn is_replaced_type<Id: Into<ItemId>>( &self, path: &[String], id: Id, @@ -2084,7 +2089,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Is the type with the given `name` marked as opaque? - pub fn opaque_by_name(&self, path: &[String]) -> bool { + pub(crate) fn opaque_by_name(&self, path: &[String]) -> bool { debug_assert!( self.in_codegen_phase(), "You're not supposed to call this yet" @@ -2176,9 +2181,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" (module_name, kind) } - /// Given a CXCursor_Namespace cursor, return the item id of the + /// Given a CXCursor_Namespace cursor, return the item ID of the /// corresponding module, or create one on the fly. - pub fn module(&mut self, cursor: clang::Cursor) -> ModuleId { + pub(crate) fn module(&mut self, cursor: clang::Cursor) -> ModuleId { use clang_sys::*; assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person"); let cursor = cursor.canonical(); @@ -2209,7 +2214,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Start traversing the module with the given `module_id`, invoke the /// callback `cb`, and then return to traversing the original module. - pub fn with_module<F>(&mut self, module_id: ModuleId, cb: F) + pub(crate) fn with_module<F>(&mut self, module_id: ModuleId, cb: F) where F: FnOnce(&mut Self), { @@ -2227,7 +2232,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// /// If no items are explicitly allowlisted, then all items are considered /// allowlisted. - pub fn allowlisted_items(&self) -> &ItemSet { + pub(crate) fn allowlisted_items(&self) -> &ItemSet { assert!(self.in_codegen_phase()); assert!(self.current_module == self.root_module); @@ -2236,7 +2241,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Check whether a particular blocklisted type implements a trait or not. /// Results may be cached. - pub fn blocklisted_type_implements_trait( + pub(crate) fn blocklisted_type_implements_trait( &self, item: &Item, derive_trait: DeriveTrait, @@ -2277,7 +2282,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Is the given type a type from <stdint.h> that corresponds to a Rust primitive type? - pub fn is_stdint_type(&self, name: &str) -> bool { + pub(crate) fn is_stdint_type(&self, name: &str) -> bool { match name { "int8_t" | "uint8_t" | "int16_t" | "uint16_t" | "int32_t" | "uint32_t" | "int64_t" | "uint64_t" | "uintptr_t" | @@ -2288,7 +2293,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Get a reference to the set of items we should generate. - pub fn codegen_items(&self) -> &ItemSet { + pub(crate) fn codegen_items(&self) -> &ItemSet { assert!(self.in_codegen_phase()); assert!(self.current_module == self.root_module); self.codegen_items.as_ref().unwrap() @@ -2454,30 +2459,22 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.allowlisted = Some(allowlisted); self.codegen_items = Some(codegen_items); - let mut warnings = Vec::new(); - for item in self.options().allowlisted_functions.unmatched_items() { - warnings - .push(format!("unused option: --allowlist-function {}", item)); + unused_regex_diagnostic(item, "--allowlist-function", self); } for item in self.options().allowlisted_vars.unmatched_items() { - warnings.push(format!("unused option: --allowlist-var {}", item)); + unused_regex_diagnostic(item, "--allowlist-var", self); } for item in self.options().allowlisted_types.unmatched_items() { - warnings.push(format!("unused option: --allowlist-type {}", item)); - } - - for msg in warnings { - warn!("{}", msg); - self.warnings.push(msg); + unused_regex_diagnostic(item, "--allowlist-type", self); } } /// Convenient method for getting the prefix to use for most traits in /// codegen depending on the `use_core` option. - pub fn trait_prefix(&self) -> Ident { + pub(crate) fn trait_prefix(&self) -> Ident { if self.options().use_core { self.rust_ident_raw("core") } else { @@ -2486,12 +2483,12 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Call if a bindgen complex is generated - pub fn generated_bindgen_complex(&self) { + pub(crate) fn generated_bindgen_complex(&self) { self.generated_bindgen_complex.set(true) } /// Whether we need to generate the bindgen complex type - pub fn need_bindgen_complex_type(&self) -> bool { + pub(crate) fn need_bindgen_complex_type(&self) -> bool { self.generated_bindgen_complex.get() } @@ -2530,7 +2527,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } } - // Find enums in this module, and record the id of each one that + // Find enums in this module, and record the ID of each one that // has a typedef. for child_id in module.children() { if let Some(ItemKind::Type(ty)) = @@ -2551,7 +2548,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Look up whether `id` refers to an `enum` whose underlying type is /// defined by a `typedef`. - pub fn is_enum_typedef_combo(&self, id: ItemId) -> bool { + pub(crate) fn is_enum_typedef_combo(&self, id: ItemId) -> bool { assert!( self.in_codegen_phase(), "We only compute enum_typedef_combos when we enter codegen", @@ -2574,7 +2571,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Look up whether the item with `id` can /// derive debug or not. - pub fn lookup_can_derive_debug<Id: Into<ItemId>>(&self, id: Id) -> bool { + pub(crate) fn lookup_can_derive_debug<Id: Into<ItemId>>( + &self, + id: Id, + ) -> bool { let id = id.into(); assert!( self.in_codegen_phase(), @@ -2601,7 +2601,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Look up whether the item with `id` can /// derive default or not. - pub fn lookup_can_derive_default<Id: Into<ItemId>>(&self, id: Id) -> bool { + pub(crate) fn lookup_can_derive_default<Id: Into<ItemId>>( + &self, + id: Id, + ) -> bool { let id = id.into(); assert!( self.in_codegen_phase(), @@ -2639,7 +2642,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Look up whether the item with `id` can /// derive hash or not. - pub fn lookup_can_derive_hash<Id: Into<ItemId>>(&self, id: Id) -> bool { + pub(crate) fn lookup_can_derive_hash<Id: Into<ItemId>>( + &self, + id: Id, + ) -> bool { let id = id.into(); assert!( self.in_codegen_phase(), @@ -2668,7 +2674,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Look up whether the item with `id` can derive `Partial{Eq,Ord}`. - pub fn lookup_can_derive_partialeq_or_partialord<Id: Into<ItemId>>( + pub(crate) fn lookup_can_derive_partialeq_or_partialord< + Id: Into<ItemId>, + >( &self, id: Id, ) -> CanDerive { @@ -2689,7 +2697,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Look up whether the item with `id` can derive `Copy` or not. - pub fn lookup_can_derive_copy<Id: Into<ItemId>>(&self, id: Id) -> bool { + pub(crate) fn lookup_can_derive_copy<Id: Into<ItemId>>( + &self, + id: Id, + ) -> bool { assert!( self.in_codegen_phase(), "We only compute can_derive_debug when we enter codegen" @@ -2712,7 +2723,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Look up whether the item with `id` has type parameter in array or not. - pub fn lookup_has_type_param_in_array<Id: Into<ItemId>>( + pub(crate) fn lookup_has_type_param_in_array<Id: Into<ItemId>>( &self, id: Id, ) -> bool { @@ -2739,7 +2750,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Look up whether the item with `id` has array or not. - pub fn lookup_has_float<Id: Into<ItemId>>(&self, id: Id) -> bool { + pub(crate) fn lookup_has_float<Id: Into<ItemId>>(&self, id: Id) -> bool { assert!( self.in_codegen_phase(), "We only compute has float when we enter codegen" @@ -2751,41 +2762,42 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Check if `--no-partialeq` flag is enabled for this item. - pub fn no_partialeq_by_name(&self, item: &Item) -> bool { + pub(crate) fn no_partialeq_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_partialeq_types.matches(name) } /// Check if `--no-copy` flag is enabled for this item. - pub fn no_copy_by_name(&self, item: &Item) -> bool { + pub(crate) fn no_copy_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_copy_types.matches(name) } /// Check if `--no-debug` flag is enabled for this item. - pub fn no_debug_by_name(&self, item: &Item) -> bool { + pub(crate) fn no_debug_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_debug_types.matches(name) } /// Check if `--no-default` flag is enabled for this item. - pub fn no_default_by_name(&self, item: &Item) -> bool { + pub(crate) fn no_default_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_default_types.matches(name) } /// Check if `--no-hash` flag is enabled for this item. - pub fn no_hash_by_name(&self, item: &Item) -> bool { + pub(crate) fn no_hash_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_hash_types.matches(name) } /// Check if `--must-use-type` flag is enabled for this item. - pub fn must_use_type_by_name(&self, item: &Item) -> bool { + pub(crate) fn must_use_type_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().must_use_types.matches(name) } + /// Wrap some tokens in an `unsafe` block if the `--wrap-unsafe-ops` option is enabled. pub(crate) fn wrap_unsafe_ops(&self, tokens: impl ToTokens) -> TokenStream { if self.options.wrap_unsafe_ops { quote!(unsafe { #tokens }) @@ -2794,6 +2806,8 @@ If you encounter an error missing from this list, please file an issue or a PR!" } } + /// Get the suffix to be added to `static` functions if the `--wrap-static-fns` option is + /// enabled. pub(crate) fn wrap_static_fns_suffix(&self) -> &str { self.options() .wrap_static_fns_suffix @@ -2804,15 +2818,15 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// A builder struct for configuring item resolution options. #[derive(Debug, Copy, Clone)] -pub struct ItemResolver { +pub(crate) struct ItemResolver { id: ItemId, through_type_refs: bool, through_type_aliases: bool, } impl ItemId { - /// Create an `ItemResolver` from this item id. - pub fn into_resolver(self) -> ItemResolver { + /// Create an `ItemResolver` from this item ID. + pub(crate) fn into_resolver(self) -> ItemResolver { self.into() } } @@ -2827,8 +2841,8 @@ where } impl ItemResolver { - /// Construct a new `ItemResolver` from the given id. - pub fn new<Id: Into<ItemId>>(id: Id) -> ItemResolver { + /// Construct a new `ItemResolver` from the given ID. + pub(crate) fn new<Id: Into<ItemId>>(id: Id) -> ItemResolver { let id = id.into(); ItemResolver { id, @@ -2838,19 +2852,19 @@ impl ItemResolver { } /// Keep resolving through `Type::TypeRef` items. - pub fn through_type_refs(mut self) -> ItemResolver { + pub(crate) fn through_type_refs(mut self) -> ItemResolver { self.through_type_refs = true; self } /// Keep resolving through `Type::Alias` items. - pub fn through_type_aliases(mut self) -> ItemResolver { + pub(crate) fn through_type_aliases(mut self) -> ItemResolver { self.through_type_aliases = true; self } /// Finish configuring and perform the actual item resolution. - pub fn resolve(self, ctx: &BindgenContext) -> &Item { + pub(crate) fn resolve(self, ctx: &BindgenContext) -> &Item { assert!(ctx.collected_typerefs()); let mut id = self.id; @@ -2887,7 +2901,7 @@ impl ItemResolver { /// A type that we are in the middle of parsing. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct PartialType { +pub(crate) struct PartialType { decl: Cursor, // Just an ItemId, and not a TypeId, because we haven't finished this type // yet, so there's still time for things to go wrong. @@ -2896,19 +2910,19 @@ pub struct PartialType { impl PartialType { /// Construct a new `PartialType`. - pub fn new(decl: Cursor, id: ItemId) -> PartialType { + pub(crate) fn new(decl: Cursor, id: ItemId) -> PartialType { // assert!(decl == decl.canonical()); PartialType { decl, id } } /// The cursor pointing to this partial type's declaration location. - pub fn decl(&self) -> &Cursor { + pub(crate) fn decl(&self) -> &Cursor { &self.decl } /// The item ID allocated for this type. This is *NOT* a key for an entry in /// the context's item set yet! - pub fn id(&self) -> ItemId { + pub(crate) fn id(&self) -> ItemId { self.id } } @@ -2945,3 +2959,23 @@ impl TemplateParameters for PartialType { } } } + +fn unused_regex_diagnostic(item: &str, name: &str, _ctx: &BindgenContext) { + warn!("unused option: {} {}", name, item); + + #[cfg(feature = "experimental")] + if _ctx.options().emit_diagnostics { + use crate::diagnostics::{Diagnostic, Level}; + + Diagnostic::default() + .with_title( + format!("Unused regular expression: `{}`.", item), + Level::Warn, + ) + .add_annotation( + format!("This regular expression was passed to `{}`.", name), + Level::Note, + ) + .display(); + } +} diff --git a/ir/derive.rs b/ir/derive.rs index 594ce2a..3877b42 100644 --- a/ir/derive.rs +++ b/ir/derive.rs @@ -18,7 +18,7 @@ use std::ops; /// A trait that encapsulates the logic for whether or not we can derive `Debug` /// for a given thing. -pub trait CanDeriveDebug { +pub(crate) trait CanDeriveDebug { /// Return `true` if `Debug` can be derived for this thing, `false` /// otherwise. fn can_derive_debug(&self, ctx: &BindgenContext) -> bool; @@ -26,7 +26,7 @@ pub trait CanDeriveDebug { /// A trait that encapsulates the logic for whether or not we can derive `Copy` /// for a given thing. -pub trait CanDeriveCopy { +pub(crate) trait CanDeriveCopy { /// Return `true` if `Copy` can be derived for this thing, `false` /// otherwise. fn can_derive_copy(&self, ctx: &BindgenContext) -> bool; @@ -34,7 +34,7 @@ pub trait CanDeriveCopy { /// A trait that encapsulates the logic for whether or not we can derive /// `Default` for a given thing. -pub trait CanDeriveDefault { +pub(crate) trait CanDeriveDefault { /// Return `true` if `Default` can be derived for this thing, `false` /// otherwise. fn can_derive_default(&self, ctx: &BindgenContext) -> bool; @@ -42,7 +42,7 @@ pub trait CanDeriveDefault { /// A trait that encapsulates the logic for whether or not we can derive `Hash` /// for a given thing. -pub trait CanDeriveHash { +pub(crate) trait CanDeriveHash { /// Return `true` if `Hash` can be derived for this thing, `false` /// otherwise. fn can_derive_hash(&self, ctx: &BindgenContext) -> bool; @@ -50,7 +50,7 @@ pub trait CanDeriveHash { /// A trait that encapsulates the logic for whether or not we can derive /// `PartialEq` for a given thing. -pub trait CanDerivePartialEq { +pub(crate) trait CanDerivePartialEq { /// Return `true` if `PartialEq` can be derived for this thing, `false` /// otherwise. fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool; @@ -58,7 +58,7 @@ pub trait CanDerivePartialEq { /// A trait that encapsulates the logic for whether or not we can derive /// `PartialOrd` for a given thing. -pub trait CanDerivePartialOrd { +pub(crate) trait CanDerivePartialOrd { /// Return `true` if `PartialOrd` can be derived for this thing, `false` /// otherwise. fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool; @@ -66,14 +66,14 @@ pub trait CanDerivePartialOrd { /// A trait that encapsulates the logic for whether or not we can derive `Eq` /// for a given thing. -pub trait CanDeriveEq { +pub(crate) trait CanDeriveEq { /// Return `true` if `Eq` can be derived for this thing, `false` otherwise. fn can_derive_eq(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive `Ord` /// for a given thing. -pub trait CanDeriveOrd { +pub(crate) trait CanDeriveOrd { /// Return `true` if `Ord` can be derived for this thing, `false` otherwise. fn can_derive_ord(&self, ctx: &BindgenContext) -> bool; } @@ -115,7 +115,7 @@ impl Default for CanDerive { impl CanDerive { /// Take the least upper bound of `self` and `rhs`. - pub fn join(self, rhs: Self) -> Self { + pub(crate) fn join(self, rhs: Self) -> Self { cmp::max(self, rhs) } } @@ -8,7 +8,7 @@ use std::path::Path; /// A trait for anything that can write attributes as `<table>` rows to a dot /// file. -pub trait DotAttributes { +pub(crate) trait DotAttributes { /// Write this thing's attributes to the given output. Each attribute must /// be its own `<tr>...</tr>`. fn dot_attributes<W>( @@ -21,7 +21,7 @@ pub trait DotAttributes { } /// Write a graphviz dot file containing our IR. -pub fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()> +pub(crate) fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()> where P: AsRef<Path>, { diff --git a/ir/enum_ty.rs b/ir/enum_ty.rs index 63871fd..70cf0ea 100644 --- a/ir/enum_ty.rs +++ b/ir/enum_ty.rs @@ -22,7 +22,7 @@ pub enum EnumVariantCustomBehavior { /// A C/C++ enumeration. #[derive(Debug)] -pub struct Enum { +pub(crate) struct Enum { /// The representation used for this enum; it should be an `IntKind` type or /// an alias to one. /// @@ -36,22 +36,25 @@ pub struct Enum { impl Enum { /// Construct a new `Enum` with the given representation and variants. - pub fn new(repr: Option<TypeId>, variants: Vec<EnumVariant>) -> Self { + pub(crate) fn new( + repr: Option<TypeId>, + variants: Vec<EnumVariant>, + ) -> Self { Enum { repr, variants } } /// Get this enumeration's representation. - pub fn repr(&self) -> Option<TypeId> { + pub(crate) fn repr(&self) -> Option<TypeId> { self.repr } /// Get this enumeration's variants. - pub fn variants(&self) -> &[EnumVariant] { + pub(crate) fn variants(&self) -> &[EnumVariant] { &self.variants } /// Construct an enumeration from the given Clang type. - pub fn from_ty( + pub(crate) fn from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Result<Self, ParseError> { @@ -169,7 +172,7 @@ impl Enum { } /// Returns the final representation of the enum. - pub fn computed_enum_variation( + pub(crate) fn computed_enum_variation( &self, ctx: &BindgenContext, item: &Item, @@ -236,7 +239,7 @@ impl Enum { /// A single enum variant, to be contained only in an enum. #[derive(Debug)] -pub struct EnumVariant { +pub(crate) struct EnumVariant { /// The name of the variant. name: String, @@ -268,7 +271,7 @@ pub enum EnumVariantValue { impl EnumVariant { /// Construct a new enumeration variant from the given parts. - pub fn new( + pub(crate) fn new( name: String, name_for_allowlisting: String, comment: Option<String>, @@ -285,35 +288,35 @@ impl EnumVariant { } /// Get this variant's name. - pub fn name(&self) -> &str { + pub(crate) fn name(&self) -> &str { &self.name } /// Get this variant's name. - pub fn name_for_allowlisting(&self) -> &str { + pub(crate) fn name_for_allowlisting(&self) -> &str { &self.name_for_allowlisting } /// Get this variant's value. - pub fn val(&self) -> EnumVariantValue { + pub(crate) fn val(&self) -> EnumVariantValue { self.val } /// Get this variant's documentation. - pub fn comment(&self) -> Option<&str> { + pub(crate) fn comment(&self) -> Option<&str> { self.comment.as_deref() } /// Returns whether this variant should be enforced to be a constant by code /// generation. - pub fn force_constification(&self) -> bool { + pub(crate) fn force_constification(&self) -> bool { self.custom_behavior .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) } /// Returns whether the current variant should be hidden completely from the /// resulting rust enum. - pub fn hidden(&self) -> bool { + pub(crate) fn hidden(&self) -> bool { self.custom_behavior .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) } diff --git a/ir/function.rs b/ir/function.rs index baa2c36..fab380e 100644 --- a/ir/function.rs +++ b/ir/function.rs @@ -10,8 +10,7 @@ use crate::callbacks::{ItemInfo, ItemKind}; use crate::clang::{self, Attribute}; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; use clang_sys::{self, CXCallingConv}; -use proc_macro2; -use quote; + use quote::TokenStreamExt; use std::io; use std::str::FromStr; @@ -20,7 +19,7 @@ const RUST_DERIVE_FUNPTR_LIMIT: usize = 12; /// What kind of a function are we looking at? #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum FunctionKind { +pub(crate) enum FunctionKind { /// A plain, free function. Function, /// A method of some kind. @@ -30,7 +29,7 @@ pub enum FunctionKind { impl FunctionKind { /// Given a clang cursor, return the kind of function it represents, or /// `None` otherwise. - pub fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> { + pub(crate) fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> { // FIXME(emilio): Deduplicate logic with `ir::comp`. Some(match cursor.kind() { clang_sys::CXCursor_FunctionDecl => FunctionKind::Function, @@ -64,7 +63,7 @@ impl FunctionKind { /// The style of linkage #[derive(Debug, Clone, Copy)] -pub enum Linkage { +pub(crate) enum Linkage { /// Externally visible and can be linked against External, /// Not exposed externally. 'static inline' functions will have this kind of linkage @@ -76,18 +75,18 @@ pub enum Linkage { /// The argument names vector must be the same length as the ones in the /// signature. #[derive(Debug)] -pub struct Function { +pub(crate) struct Function { /// The name of this function. name: String, /// The mangled name, that is, the symbol. mangled_name: Option<String>, - /// The id pointing to the current function signature. - signature: TypeId, + /// The link name. If specified, overwrite mangled_name. + link_name: Option<String>, - /// The doc comment on the function, if any. - comment: Option<String>, + /// The ID pointing to the current function signature. + signature: TypeId, /// The kind of function this is. kind: FunctionKind, @@ -98,51 +97,51 @@ pub struct Function { impl Function { /// Construct a new function. - pub fn new( + pub(crate) fn new( name: String, mangled_name: Option<String>, + link_name: Option<String>, signature: TypeId, - comment: Option<String>, kind: FunctionKind, linkage: Linkage, ) -> Self { Function { name, mangled_name, + link_name, signature, - comment, kind, linkage, } } /// Get this function's name. - pub fn name(&self) -> &str { + pub(crate) fn name(&self) -> &str { &self.name } /// Get this function's name. - pub fn mangled_name(&self) -> Option<&str> { + pub(crate) fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_deref() } - /// Get this function's signature type. - pub fn signature(&self) -> TypeId { - self.signature + /// Get this function's link name. + pub fn link_name(&self) -> Option<&str> { + self.link_name.as_deref() } - /// Get this function's comment. - pub fn comment(&self) -> Option<&str> { - self.comment.as_deref() + /// Get this function's signature type. + pub(crate) fn signature(&self) -> TypeId { + self.signature } /// Get this function's kind. - pub fn kind(&self) -> FunctionKind { + pub(crate) fn kind(&self) -> FunctionKind { self.kind } /// Get this function's linkage. - pub fn linkage(&self) -> Linkage { + pub(crate) fn linkage(&self) -> Linkage { self.linkage } } @@ -177,6 +176,8 @@ pub enum Abi { C, /// The "stdcall" ABI. Stdcall, + /// The "efiapi" ABI. + EfiApi, /// The "fastcall" ABI. Fastcall, /// The "thiscall" ABI. @@ -198,6 +199,7 @@ impl FromStr for Abi { match s { "C" => Ok(Self::C), "stdcall" => Ok(Self::Stdcall), + "efiapi" => Ok(Self::EfiApi), "fastcall" => Ok(Self::Fastcall), "thiscall" => Ok(Self::ThisCall), "vectorcall" => Ok(Self::Vectorcall), @@ -214,6 +216,7 @@ impl std::fmt::Display for Abi { let s = match *self { Self::C => "C", Self::Stdcall => "stdcall", + Self::EfiApi => "efiapi", Self::Fastcall => "fastcall", Self::ThisCall => "thiscall", Self::Vectorcall => "vectorcall", @@ -236,6 +239,7 @@ impl quote::ToTokens for Abi { /// An ABI extracted from a clang cursor. #[derive(Debug, Copy, Clone)] pub(crate) enum ClangAbi { + /// An ABI known by Rust. Known(Abi), /// An unknown or invalid ABI. Unknown(CXCallingConv), @@ -262,7 +266,10 @@ impl quote::ToTokens for ClangAbi { /// A function signature. #[derive(Debug)] -pub struct FunctionSig { +pub(crate) struct FunctionSig { + /// The name of this function signature. + name: String, + /// The return type of the function. return_type: TypeId, @@ -297,7 +304,7 @@ fn get_abi(cc: CXCallingConv) -> ClangAbi { } /// Get the mangled name for the cursor's referent. -pub fn cursor_mangling( +pub(crate) fn cursor_mangling( ctx: &BindgenContext, cursor: &clang::Cursor, ) -> Option<String> { @@ -399,7 +406,7 @@ fn args_from_ty_and_cursor( impl FunctionSig { /// Construct a new function signature from the given Clang type. - pub fn from_ty( + pub(crate) fn from_ty( ty: &clang::Type, cursor: &clang::Cursor, ctx: &mut BindgenContext, @@ -572,7 +579,8 @@ impl FunctionSig { warn!("Unknown calling convention: {:?}", call_conv); } - Ok(FunctionSig { + Ok(Self { + name: spelling, return_type: ret, argument_types: args, is_variadic: ty.is_variadic(), @@ -583,12 +591,12 @@ impl FunctionSig { } /// Get this function signature's return type. - pub fn return_type(&self) -> TypeId { + pub(crate) fn return_type(&self) -> TypeId { self.return_type } /// Get this function signature's argument (name, type) pairs. - pub fn argument_types(&self) -> &[(Option<String>, TypeId)] { + pub(crate) fn argument_types(&self) -> &[(Option<String>, TypeId)] { &self.argument_types } @@ -611,13 +619,20 @@ impl FunctionSig { } else { self.abi } + } else if let Some((abi, _)) = ctx + .options() + .abi_overrides + .iter() + .find(|(_, regex_set)| regex_set.matches(&self.name)) + { + ClangAbi::Known(*abi) } else { self.abi } } /// Is this function signature variadic? - pub fn is_variadic(&self) -> bool { + pub(crate) fn is_variadic(&self) -> bool { // Clang reports some functions as variadic when they *might* be // variadic. We do the argument check because rust doesn't codegen well // variadic functions without an initial argument. @@ -625,7 +640,7 @@ impl FunctionSig { } /// Must this function's return value be used? - pub fn must_use(&self) -> bool { + pub(crate) fn must_use(&self) -> bool { self.must_use } @@ -635,10 +650,10 @@ impl FunctionSig { /// /// For more details, see: /// - /// * https://github.com/rust-lang/rust-bindgen/issues/547, - /// * https://github.com/rust-lang/rust/issues/38848, - /// * and https://github.com/rust-lang/rust/issues/40158 - pub fn function_pointers_can_derive(&self) -> bool { + /// * <https://github.com/rust-lang/rust-bindgen/issues/547>, + /// * <https://github.com/rust-lang/rust/issues/38848>, + /// * and <https://github.com/rust-lang/rust/issues/40158> + pub(crate) fn function_pointers_can_derive(&self) -> bool { if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT { return false; } @@ -646,6 +661,7 @@ impl FunctionSig { matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..)) } + /// Whether this function has attributes marking it as divergent. pub(crate) fn is_divergent(&self) -> bool { self.is_divergent } @@ -734,10 +750,22 @@ impl ClangSubItemParser for Function { assert!(!name.is_empty(), "Empty function name."); let mangled_name = cursor_mangling(context, &cursor); - let comment = cursor.raw_comment(); - let function = - Self::new(name.clone(), mangled_name, sig, comment, kind, linkage); + let link_name = context.options().last_callback(|callbacks| { + callbacks.generated_link_name_override(ItemInfo { + name: name.as_str(), + kind: ItemKind::Function, + }) + }); + + let function = Self::new( + name.clone(), + mangled_name, + link_name, + sig, + kind, + linkage, + ); Ok(ParseResult::New(function, Some(cursor))) } @@ -12,7 +12,7 @@ pub enum IntKind { /// An `unsigned char`. UChar, - /// An `wchar_t`. + /// A `wchar_t`. WChar, /// A platform-dependent `char` type, with the signedness support. @@ -87,7 +87,7 @@ pub enum IntKind { impl IntKind { /// Is this integral type signed? - pub fn is_signed(&self) -> bool { + pub(crate) fn is_signed(&self) -> bool { use self::IntKind::*; match *self { // TODO(emilio): wchar_t can in theory be signed, but we have no way @@ -108,7 +108,7 @@ impl IntKind { /// If this type has a known size, return it (in bytes). This is to /// alleviate libclang sometimes not giving us a layout (like in the case /// when an enum is defined inside a class with template parameters). - pub fn known_size(&self) -> Option<usize> { + pub(crate) fn known_size(&self) -> Option<usize> { use self::IntKind::*; Some(match *self { Bool | UChar | SChar | U8 | I8 | Char { .. } => 1, @@ -121,7 +121,7 @@ impl IntKind { } /// Whether this type's signedness matches the value. - pub fn signedness_matches(&self, val: i64) -> bool { + pub(crate) fn signedness_matches(&self, val: i64) -> bool { val >= 0 || self.is_signed() } } @@ -19,9 +19,9 @@ use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::{Type, TypeKind}; use crate::clang; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; -use clang_sys; + use lazycell::LazyCell; -use regex; + use std::cell::Cell; use std::collections::BTreeSet; use std::fmt::Write; @@ -38,7 +38,7 @@ use std::iter; /// /// This name is required to be safe for Rust, that is, is not expected to /// return any rust keyword from here. -pub trait ItemCanonicalName { +pub(crate) trait ItemCanonicalName { /// Get the canonical name for this item. fn canonical_name(&self, ctx: &BindgenContext) -> String; } @@ -55,7 +55,7 @@ pub trait ItemCanonicalName { /// /// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical /// name is just `"BAR"`. -pub trait ItemCanonicalPath { +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. @@ -69,7 +69,7 @@ pub trait ItemCanonicalPath { } /// A trait for determining if some IR thing is opaque or not. -pub trait IsOpaque { +pub(crate) trait IsOpaque { /// Extra context the IR thing needs to determine if it is opaque or not. type Extra; @@ -80,20 +80,20 @@ pub trait IsOpaque { } /// A trait for determining if some IR thing has type parameter in array or not. -pub trait HasTypeParamInArray { +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 trait HasFloat { +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 trait ItemAncestors { +pub(crate) trait ItemAncestors { /// Get an iterable over this item's ancestors. fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>; } @@ -118,7 +118,7 @@ impl DebugOnlyItemSet { } /// An iterator over an item and its ancestors. -pub struct ItemAncestorsIter<'a> { +pub(crate) struct ItemAncestorsIter<'a> { item: ItemId, ctx: &'a BindgenContext, seen: DebugOnlyItemSet, @@ -362,7 +362,7 @@ impl CanDeriveOrd for Item { /// 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, +/// 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. /// @@ -375,20 +375,20 @@ impl CanDeriveOrd for Item { /// all of them apply to every item. Those rules are described in the /// `annotations` module. #[derive(Debug)] -pub struct Item { - /// This item's id. +pub(crate) struct Item { + /// This item's ID. id: ItemId, - /// The item's local id, unique only amongst its siblings. Only used for + /// 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 + /// 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. + /// 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`. @@ -406,11 +406,11 @@ pub struct Item { /// 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 + /// 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 is its own ID. parent_id: ItemId, /// The item kind. kind: ItemKind, @@ -426,7 +426,7 @@ impl AsRef<ItemId> for Item { impl Item { /// Construct a new `Item`. - pub fn new( + pub(crate) fn new( id: ItemId, comment: Option<String>, annotations: Option<Annotations>, @@ -450,7 +450,7 @@ impl Item { } /// Construct a new opaque item type. - pub fn new_opaque_type( + pub(crate) fn new_opaque_type( with_id: ItemId, ty: &clang::Type, ctx: &mut BindgenContext, @@ -468,28 +468,31 @@ impl Item { } /// Get this `Item`'s identifier. - pub fn id(&self) -> ItemId { + 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 fn parent_id(&self) -> ItemId { + pub(crate) fn parent_id(&self) -> ItemId { self.parent_id } - /// Set this item's parent id. + /// Set this item's parent ID. /// /// This is only used so replacements get generated in the proper module. - pub fn set_parent_for_replacement<Id: Into<ItemId>>(&mut self, id: Id) { + 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 fn codegen_depth(&self, ctx: &BindgenContext) -> usize { + pub(crate) fn codegen_depth(&self, ctx: &BindgenContext) -> usize { if !ctx.options().enable_cxx_namespaces { return 0; } @@ -507,7 +510,7 @@ impl Item { /// Get this `Item`'s comment, if it has any, already preprocessed and with /// the right indentation. - pub fn comment(&self, ctx: &BindgenContext) -> Option<String> { + pub(crate) fn comment(&self, ctx: &BindgenContext) -> Option<String> { if !ctx.options().generate_comments { return None; } @@ -518,17 +521,17 @@ impl Item { } /// What kind of item is this? - pub fn kind(&self) -> &ItemKind { + pub(crate) fn kind(&self) -> &ItemKind { &self.kind } /// Get a mutable reference to this item's kind. - pub fn kind_mut(&mut self) -> &mut ItemKind { + pub(crate) fn kind_mut(&mut self) -> &mut ItemKind { &mut self.kind } /// Where in the source is this item located? - pub fn location(&self) -> Option<&clang::SourceLocation> { + pub(crate) fn location(&self) -> Option<&clang::SourceLocation> { self.location.as_ref() } @@ -537,7 +540,7 @@ impl Item { /// 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 fn local_id(&self, ctx: &BindgenContext) -> usize { + 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() @@ -550,7 +553,7 @@ impl Item { /// 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 fn next_child_local_id(&self) -> usize { + 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 @@ -574,7 +577,7 @@ impl Item { /// 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 fn is_toplevel(&self, ctx: &BindgenContext) -> bool { + 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 && @@ -605,36 +608,36 @@ impl Item { /// Get a reference to this item's underlying `Type`. Panic if this is some /// other kind of item. - pub fn expect_type(&self) -> &Type { + 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 fn as_type(&self) -> Option<&Type> { + 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 fn expect_function(&self) -> &Function { + pub(crate) fn expect_function(&self) -> &Function { self.kind().expect_function() } /// Is this item a module? - pub fn is_module(&self) -> bool { + pub(crate) fn is_module(&self) -> bool { matches!(self.kind, ItemKind::Module(..)) } /// Get this item's annotations. - pub fn annotations(&self) -> &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 fn is_blocklisted(&self, ctx: &BindgenContext) -> bool { + pub(crate) fn is_blocklisted(&self, ctx: &BindgenContext) -> bool { debug_assert!( ctx.in_codegen_phase(), "You're not supposed to call this yet" @@ -670,22 +673,15 @@ impl Item { } } - /// Is this a reference to another type? - pub fn is_type_ref(&self) -> bool { - self.as_type().map_or(false, |ty| ty.is_type_ref()) - } - - /// Is this item a var type? - pub fn is_var(&self) -> bool { - matches!(*self.kind(), ItemKind::Var(..)) - } - /// Take out item NameOptions - pub fn name<'a>(&'a self, ctx: &'a BindgenContext) -> NameOptions<'a> { + pub(crate) fn name<'a>( + &'a self, + ctx: &'a BindgenContext, + ) -> NameOptions<'a> { NameOptions::new(self, ctx) } - /// Get the target item id for name generation. + /// 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; @@ -715,7 +711,10 @@ impl Item { /// Create a fully disambiguated name for an item, including template /// parameters if it is a type - pub fn full_disambiguated_name(&self, ctx: &BindgenContext) -> String { + 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); @@ -839,7 +838,7 @@ impl Item { /// 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 fn real_canonical_name( + pub(crate) fn real_canonical_name( &self, ctx: &BindgenContext, opt: &NameOptions, @@ -862,7 +861,7 @@ impl Item { return base_name; } - // Ancestors' id iter + // Ancestors' ID iter let mut ids_iter = target .parent_id() .ancestors(ctx) @@ -939,11 +938,11 @@ impl Item { ctx.rust_mangle(&name).into_owned() } - /// The exposed id that represents an unique id among the siblings of a + /// The exposed ID that represents an unique ID among the siblings of a /// given item. - pub fn exposed_id(&self, ctx: &BindgenContext) -> String { + 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. + // 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 { @@ -955,14 +954,14 @@ impl Item { } // Note that this `id_` prefix prevents (really unlikely) collisions - // between the global id and the local id of an item with the same + // 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 fn as_module(&self) -> Option<&Module> { + pub(crate) fn as_module(&self) -> Option<&Module> { match self.kind { ItemKind::Module(ref module) => Some(module), _ => None, @@ -971,7 +970,7 @@ impl Item { /// Get a mutable reference to this item's `Module`, or `None` if this is /// not a `Module` item. - pub fn as_module_mut(&mut self) -> Option<&mut Module> { + pub(crate) fn as_module_mut(&mut self) -> Option<&mut Module> { match self.kind { ItemKind::Module(ref mut module) => Some(module), _ => None, @@ -1010,7 +1009,7 @@ impl Item { } /// Is this item of a kind that is enabled for code generation? - pub fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool { + pub(crate) fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool { let cc = &ctx.options().codegen_config; match *self.kind() { ItemKind::Module(..) => true, @@ -1036,7 +1035,10 @@ impl Item { /// Returns the path we should use for allowlisting / blocklisting, which /// doesn't include user-mangling. - pub fn path_for_allowlisting(&self, ctx: &BindgenContext) -> &Vec<String> { + pub(crate) fn path_for_allowlisting( + &self, + ctx: &BindgenContext, + ) -> &Vec<String> { self.path_for_allowlisting .borrow_with(|| self.compute_path(ctx, UserMangled::No)) } @@ -1094,8 +1096,8 @@ impl Item { }) } - /// Whether this is a #[must_use] type. - pub fn must_use(&self, ctx: &BindgenContext) -> bool { + /// 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) } } @@ -1222,7 +1224,7 @@ impl HasFloat for Item { } /// A set of items. -pub type ItemSet = BTreeSet<ItemId>; +pub(crate) type ItemSet = BTreeSet<ItemId>; impl DotAttributes for Item { fn dot_attributes<W>( @@ -1306,6 +1308,7 @@ fn visit_child( } impl Item { + /// Create a builtin type. pub(crate) fn builtin_type( kind: TypeKind, is_const: bool, @@ -1331,6 +1334,7 @@ impl Item { id.as_type_id_unchecked() } + /// Parse this item from the given Clang cursor. pub(crate) fn parse( cursor: clang::Cursor, parent_id: Option<ItemId>, @@ -1349,6 +1353,7 @@ impl Item { 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) { @@ -1477,6 +1482,8 @@ impl Item { } } + /// 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, @@ -1552,6 +1559,7 @@ impl Item { 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, @@ -1565,10 +1573,10 @@ impl Item { /// 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 + /// 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 + /// 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, @@ -1617,7 +1625,11 @@ impl Item { canonical_def.unwrap_or_else(|| ty.declaration()) }; - let comment = decl.raw_comment().or_else(|| location.raw_comment()); + 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)); @@ -1737,9 +1749,8 @@ impl Item { 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. + /// 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, @@ -1978,7 +1989,7 @@ enum UserMangled { /// Builder struct for naming variations, which hold inside different /// flags for naming options. #[derive(Debug)] -pub struct NameOptions<'a> { +pub(crate) struct NameOptions<'a> { item: &'a Item, ctx: &'a BindgenContext, within_namespaces: bool, @@ -1987,7 +1998,7 @@ pub struct NameOptions<'a> { impl<'a> NameOptions<'a> { /// Construct a new `NameOptions` - pub fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self { + pub(crate) fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self { NameOptions { item, ctx, @@ -1998,7 +2009,7 @@ impl<'a> NameOptions<'a> { /// 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 fn within_namespaces(&mut self) -> &mut Self { + pub(crate) fn within_namespaces(&mut self) -> &mut Self { self.within_namespaces = true; self } @@ -2009,7 +2020,7 @@ impl<'a> NameOptions<'a> { } /// Construct a name `String` - pub fn get(&self) -> String { + pub(crate) fn get(&self) -> String { self.item.real_canonical_name(self.ctx, self) } } diff --git a/ir/item_kind.rs b/ir/item_kind.rs index 4a12fef..e861849 100644 --- a/ir/item_kind.rs +++ b/ir/item_kind.rs @@ -10,7 +10,7 @@ use std::io; /// A item we parse and translate. #[derive(Debug)] -pub enum ItemKind { +pub(crate) enum ItemKind { /// A module, created implicitly once (the root module), or via C++ /// namespaces. Module(Module), @@ -28,7 +28,7 @@ pub enum ItemKind { impl ItemKind { /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it /// is some other kind. - pub fn as_module(&self) -> Option<&Module> { + pub(crate) fn as_module(&self) -> Option<&Module> { match *self { ItemKind::Module(ref module) => Some(module), _ => None, @@ -36,7 +36,7 @@ impl ItemKind { } /// Transform our `ItemKind` into a string. - pub fn kind_name(&self) -> &'static str { + pub(crate) fn kind_name(&self) -> &'static str { match *self { ItemKind::Module(..) => "Module", ItemKind::Type(..) => "Type", @@ -46,19 +46,13 @@ impl ItemKind { } /// Is this a module? - pub fn is_module(&self) -> bool { + pub(crate) fn is_module(&self) -> bool { self.as_module().is_some() } - /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it - /// is some other kind. - pub fn expect_module(&self) -> &Module { - self.as_module().expect("Not a module") - } - /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if /// it is some other kind. - pub fn as_function(&self) -> Option<&Function> { + pub(crate) fn as_function(&self) -> Option<&Function> { match *self { ItemKind::Function(ref func) => Some(func), _ => None, @@ -66,19 +60,19 @@ impl ItemKind { } /// Is this a function? - pub fn is_function(&self) -> bool { + pub(crate) fn is_function(&self) -> bool { self.as_function().is_some() } /// Get a reference to this `ItemKind`'s underying `Function`, or panic if /// it is some other kind. - pub fn expect_function(&self) -> &Function { + pub(crate) fn expect_function(&self) -> &Function { self.as_function().expect("Not a function") } /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if /// it is some other kind. - pub fn as_type(&self) -> Option<&Type> { + pub(crate) fn as_type(&self) -> Option<&Type> { match *self { ItemKind::Type(ref ty) => Some(ty), _ => None, @@ -87,7 +81,7 @@ impl ItemKind { /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` /// if it is some other kind. - pub fn as_type_mut(&mut self) -> Option<&mut Type> { + pub(crate) fn as_type_mut(&mut self) -> Option<&mut Type> { match *self { ItemKind::Type(ref mut ty) => Some(ty), _ => None, @@ -95,19 +89,19 @@ impl ItemKind { } /// Is this a type? - pub fn is_type(&self) -> bool { + pub(crate) fn is_type(&self) -> bool { self.as_type().is_some() } /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is /// some other kind. - pub fn expect_type(&self) -> &Type { + pub(crate) fn expect_type(&self) -> &Type { self.as_type().expect("Not a type") } /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is /// some other kind. - pub fn as_var(&self) -> Option<&Var> { + pub(crate) fn as_var(&self) -> Option<&Var> { match *self { ItemKind::Var(ref v) => Some(v), _ => None, @@ -115,15 +109,9 @@ impl ItemKind { } /// Is this a variable? - pub fn is_var(&self) -> bool { + pub(crate) fn is_var(&self) -> bool { self.as_var().is_some() } - - /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is - /// some other kind. - pub fn expect_var(&self) -> &Var { - self.as_var().expect("Not a var") - } } impl DotAttributes for ItemKind { diff --git a/ir/layout.rs b/ir/layout.rs index 6f45030..ba944b0 100644 --- a/ir/layout.rs +++ b/ir/layout.rs @@ -8,13 +8,13 @@ use std::cmp; /// A type that represents the struct layout of a type. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Layout { +pub(crate) struct Layout { /// The size (in bytes) of this layout. - pub size: usize, + pub(crate) size: usize, /// The alignment (in bytes) of this layout. - pub align: usize, + pub(crate) align: usize, /// Whether this layout's members are packed or not. - pub packed: bool, + pub(crate) packed: bool, } #[test] @@ -34,7 +34,7 @@ fn test_layout_for_size() { impl Layout { /// Gets the integer type name for a given known size. - pub fn known_type_for_size( + pub(crate) fn known_type_for_size( ctx: &BindgenContext, size: usize, ) -> Option<&'static str> { @@ -50,7 +50,7 @@ impl Layout { /// Construct a new `Layout` with the given `size` and `align`. It is not /// packed. - pub fn new(size: usize, align: usize) -> Self { + pub(crate) fn new(size: usize, align: usize) -> Self { Layout { size, align, @@ -72,33 +72,26 @@ impl Layout { /// Creates a non-packed layout for a given size, trying to use the maximum /// alignment possible. - pub fn for_size(ctx: &BindgenContext, size: usize) -> Self { + pub(crate) fn for_size(ctx: &BindgenContext, size: usize) -> Self { Self::for_size_internal(ctx.target_pointer_size(), size) } - /// Is this a zero-sized layout? - pub fn is_zero(&self) -> bool { - self.size == 0 && self.align == 0 - } - - /// Construct a zero-sized layout. - pub fn zero() -> Self { - Self::new(0, 0) - } - /// Get this layout as an opaque type. - pub fn opaque(&self) -> Opaque { + pub(crate) fn opaque(&self) -> Opaque { Opaque(*self) } } /// When we are treating a type as opaque, it is just a blob with a `Layout`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Opaque(pub Layout); +pub(crate) struct Opaque(pub(crate) Layout); impl Opaque { /// Construct a new opaque type from the given clang type. - pub fn from_clang_ty(ty: &clang::Type, ctx: &BindgenContext) -> Type { + pub(crate) fn from_clang_ty( + ty: &clang::Type, + ctx: &BindgenContext, + ) -> Type { let layout = Layout::new(ty.size(ctx), ty.align(ctx)); let ty_kind = TypeKind::Opaque; let is_const = ty.is_const(); @@ -107,7 +100,7 @@ impl Opaque { /// Return the known rust type we should use to create a correctly-aligned /// field with this layout. - pub fn known_rust_type_for_array( + pub(crate) fn known_rust_type_for_array( &self, ctx: &BindgenContext, ) -> Option<&'static str> { @@ -116,7 +109,7 @@ impl Opaque { /// Return the array size that an opaque type for this layout should have if /// we know the correct type for it, or `None` otherwise. - pub fn array_size(&self, ctx: &BindgenContext) -> Option<usize> { + pub(crate) fn array_size(&self, ctx: &BindgenContext) -> Option<usize> { if self.known_rust_type_for_array(ctx).is_some() { Some(self.0.size / cmp::max(self.0.align, 1)) } else { @@ -127,7 +120,7 @@ impl Opaque { /// Return `true` if this opaque layout's array size will fit within the /// maximum number of array elements that Rust allows deriving traits /// with. Return `false` otherwise. - pub fn array_size_within_derive_limit( + pub(crate) fn array_size_within_derive_limit( &self, ctx: &BindgenContext, ) -> CanDerive { @@ -2,23 +2,24 @@ //! //! Parsing C/C++ generates the IR, while code generation outputs Rust code from //! the IR. +#![deny(clippy::missing_docs_in_private_items)] -pub mod analysis; -pub mod annotations; -pub mod comment; -pub mod comp; -pub mod context; -pub mod derive; -pub mod dot; -pub mod enum_ty; -pub mod function; -pub mod int; -pub mod item; -pub mod item_kind; -pub mod layout; -pub mod module; -pub mod objc; -pub mod template; -pub mod traversal; -pub mod ty; -pub mod var; +pub(crate) mod analysis; +pub(crate) mod annotations; +pub(crate) mod comment; +pub(crate) mod comp; +pub(crate) mod context; +pub(crate) mod derive; +pub(crate) mod dot; +pub(crate) mod enum_ty; +pub(crate) mod function; +pub(crate) mod int; +pub(crate) mod item; +pub(crate) mod item_kind; +pub(crate) mod layout; +pub(crate) mod module; +pub(crate) mod objc; +pub(crate) mod template; +pub(crate) mod traversal; +pub(crate) mod ty; +pub(crate) mod var; diff --git a/ir/module.rs b/ir/module.rs index d5aca94..f25ef40 100644 --- a/ir/module.rs +++ b/ir/module.rs @@ -10,7 +10,7 @@ use std::io; /// Whether this module is inline or not. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ModuleKind { +pub(crate) enum ModuleKind { /// This module is not inline. Normal, /// This module is inline, as in `inline namespace foo {}`. @@ -19,7 +19,7 @@ pub enum ModuleKind { /// A module, as in, a C++ namespace. #[derive(Clone, Debug)] -pub struct Module { +pub(crate) struct Module { /// The name of the module, or none if it's anonymous. name: Option<String>, /// The kind of module this is. @@ -30,7 +30,7 @@ pub struct Module { impl Module { /// Construct a new `Module`. - pub fn new(name: Option<String>, kind: ModuleKind) -> Self { + pub(crate) fn new(name: Option<String>, kind: ModuleKind) -> Self { Module { name, kind, @@ -39,22 +39,22 @@ impl Module { } /// Get this module's name. - pub fn name(&self) -> Option<&str> { + pub(crate) fn name(&self) -> Option<&str> { self.name.as_deref() } /// Get a mutable reference to this module's children. - pub fn children_mut(&mut self) -> &mut ItemSet { + pub(crate) fn children_mut(&mut self) -> &mut ItemSet { &mut self.children } /// Get this module's children. - pub fn children(&self) -> &ItemSet { + pub(crate) fn children(&self) -> &ItemSet { &self.children } /// Whether this namespace is inline. - pub fn is_inline(&self) -> bool { + pub(crate) fn is_inline(&self) -> bool { self.kind == ModuleKind::Inline } } @@ -21,7 +21,7 @@ use proc_macro2::{Ident, Span, TokenStream}; /// /// Also protocols and categories are parsed as this type #[derive(Debug)] -pub struct ObjCInterface { +pub(crate) struct ObjCInterface { /// The name /// like, NSObject name: String, @@ -31,13 +31,13 @@ pub struct ObjCInterface { is_protocol: bool, /// The list of template names almost always, ObjectType or KeyType - pub template_names: Vec<String>, + pub(crate) template_names: Vec<String>, /// The list of protocols that this interface conforms to. - pub conforms_to: Vec<ItemId>, + pub(crate) conforms_to: Vec<ItemId>, /// The direct parent for this interface. - pub parent_class: Option<ItemId>, + pub(crate) parent_class: Option<ItemId>, /// List of the methods defined in this interfae methods: Vec<ObjCMethod>, @@ -47,7 +47,7 @@ pub struct ObjCInterface { /// The objective c methods #[derive(Debug)] -pub struct ObjCMethod { +pub(crate) struct ObjCMethod { /// The original method selector name /// like, dataWithBytes:length: name: String, @@ -78,14 +78,14 @@ impl ObjCInterface { /// The name /// like, NSObject - pub fn name(&self) -> &str { + pub(crate) fn name(&self) -> &str { self.name.as_ref() } /// Formats the name for rust /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods /// and protocols are like PNSObject - pub fn rust_name(&self) -> String { + pub(crate) fn rust_name(&self) -> String { if let Some(ref cat) = self.category { format!("{}_{}", self.name(), cat) } else if self.is_protocol { @@ -96,32 +96,32 @@ impl ObjCInterface { } /// Is this a template interface? - pub fn is_template(&self) -> bool { + pub(crate) fn is_template(&self) -> bool { !self.template_names.is_empty() } /// List of the methods defined in this interface - pub fn methods(&self) -> &Vec<ObjCMethod> { + pub(crate) fn methods(&self) -> &Vec<ObjCMethod> { &self.methods } /// Is this a protocol? - pub fn is_protocol(&self) -> bool { + pub(crate) fn is_protocol(&self) -> bool { self.is_protocol } /// Is this a category? - pub fn is_category(&self) -> bool { + pub(crate) fn is_category(&self) -> bool { self.category.is_some() } /// List of the class methods defined in this interface - pub fn class_methods(&self) -> &Vec<ObjCMethod> { + pub(crate) fn class_methods(&self) -> &Vec<ObjCMethod> { &self.class_methods } /// Parses the Objective C interface from the cursor - pub fn from_ty( + pub(crate) fn from_ty( cursor: &clang::Cursor, ctx: &mut BindgenContext, ) -> Option<Self> { @@ -229,30 +229,27 @@ impl ObjCMethod { } } - /// The original method selector name - /// like, dataWithBytes:length: - pub fn name(&self) -> &str { - self.name.as_ref() - } - /// Method name as converted to rust /// like, dataWithBytes_length_ - pub fn rust_name(&self) -> &str { + pub(crate) fn rust_name(&self) -> &str { self.rust_name.as_ref() } /// Returns the methods signature as FunctionSig - pub fn signature(&self) -> &FunctionSig { + pub(crate) fn signature(&self) -> &FunctionSig { &self.signature } /// Is this a class method? - pub fn is_class_method(&self) -> bool { + pub(crate) fn is_class_method(&self) -> bool { self.is_class_method } /// Formats the method call - pub fn format_method_call(&self, args: &[TokenStream]) -> TokenStream { + pub(crate) fn format_method_call( + &self, + args: &[TokenStream], + ) -> TokenStream { let split_name: Vec<Option<Ident>> = self .name .split(':') diff --git a/ir/template.rs b/ir/template.rs index e3ef6a9..4dd8442 100644 --- a/ir/template.rs +++ b/ir/template.rs @@ -77,28 +77,28 @@ use crate::clang; /// The following table depicts the results of each trait method when invoked on /// each of the declarations above: /// -/// +------+----------------------+--------------------------+------------------------+---- -/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ... -/// +------+----------------------+--------------------------+------------------------+---- -/// |Foo | [T, U] | 2 | [T, U] | ... -/// |Bar | [V] | 1 | [T, U, V] | ... -/// |Inner | [] | 0 | [T, U] | ... -/// |Lol | [W] | 1 | [T, U, W] | ... -/// |Wtf | [X] | 1 | [T, U, X] | ... -/// |Qux | [] | 0 | [] | ... +/// +------+----------------------+--------------------------+-------------------------+---- +/// |Decl. | self_template_params | num_self_template_params | all_template_parameters | ... +/// +------+----------------------+--------------------------+-------------------------+---- +/// |Foo | T, U | 2 | T, U | ... +/// |Bar | V | 1 | T, U, V | ... +/// |Inner | | 0 | T, U | ... +/// |Lol | W | 1 | T, U, W | ... +/// |Wtf | X | 1 | T, U, X | ... +/// |Qux | | 0 | | ... /// +------+----------------------+--------------------------+------------------------+---- /// /// ----+------+-----+----------------------+ /// ... |Decl. | ... | used_template_params | /// ----+------+-----+----------------------+ -/// ... |Foo | ... | [T, U] | -/// ... |Bar | ... | [V] | -/// ... |Inner | ... | [] | -/// ... |Lol | ... | [T] | -/// ... |Wtf | ... | [T] | -/// ... |Qux | ... | [] | +/// ... |Foo | ... | T, U | +/// ... |Bar | ... | V | +/// ... |Inner | ... | | +/// ... |Lol | ... | T | +/// ... |Wtf | ... | T | +/// ... |Qux | ... | | /// ----+------+-----+----------------------+ -pub trait TemplateParameters: Sized { +pub(crate) trait TemplateParameters: Sized { /// Get the set of `ItemId`s that make up this template declaration's free /// template parameters. /// @@ -163,11 +163,11 @@ pub trait TemplateParameters: Sized { } /// A trait for things which may or may not be a named template type parameter. -pub trait AsTemplateParam { +pub(crate) trait AsTemplateParam { /// Any extra information the implementor might need to make this decision. type Extra; - /// Convert this thing to the item id of a named template type parameter. + /// Convert this thing to the item ID of a named template type parameter. fn as_template_param( &self, ctx: &BindgenContext, @@ -186,7 +186,7 @@ pub trait AsTemplateParam { /// A concrete instantiation of a generic template. #[derive(Clone, Debug)] -pub struct TemplateInstantiation { +pub(crate) struct TemplateInstantiation { /// The template definition which this is instantiating. definition: TypeId, /// The concrete template arguments, which will be substituted in the @@ -196,7 +196,7 @@ pub struct TemplateInstantiation { impl TemplateInstantiation { /// Construct a new template instantiation from the given parts. - pub fn new<I>(definition: TypeId, args: I) -> TemplateInstantiation + pub(crate) fn new<I>(definition: TypeId, args: I) -> TemplateInstantiation where I: IntoIterator<Item = TypeId>, { @@ -207,17 +207,17 @@ impl TemplateInstantiation { } /// Get the template definition for this instantiation. - pub fn template_definition(&self) -> TypeId { + pub(crate) fn template_definition(&self) -> TypeId { self.definition } /// Get the concrete template arguments used in this instantiation. - pub fn template_arguments(&self) -> &[TypeId] { + pub(crate) fn template_arguments(&self) -> &[TypeId] { &self.args[..] } /// Parse a `TemplateInstantiation` from a clang `Type`. - pub fn from_ty( + pub(crate) fn from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Option<TemplateInstantiation> { diff --git a/ir/traversal.rs b/ir/traversal.rs index f14483f..17e24f7 100644 --- a/ir/traversal.rs +++ b/ir/traversal.rs @@ -12,14 +12,14 @@ use std::collections::{BTreeMap, VecDeque}; /// The `from` is left implicit: it is the concrete `Trace` implementer which /// yielded this outgoing edge. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Edge { +pub(crate) struct Edge { to: ItemId, kind: EdgeKind, } impl Edge { /// Construct a new edge whose referent is `to` and is of the given `kind`. - pub fn new(to: ItemId, kind: EdgeKind) -> Edge { + pub(crate) fn new(to: ItemId, kind: EdgeKind) -> Edge { Edge { to, kind } } } @@ -33,7 +33,7 @@ impl From<Edge> for ItemId { /// The kind of edge reference. This is useful when we wish to only consider /// certain kinds of edges for a particular traversal or analysis. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum EdgeKind { +pub(crate) enum EdgeKind { /// A generic, catch-all edge. Generic, @@ -182,12 +182,13 @@ pub enum EdgeKind { /// /// The predicate must return true if the traversal should follow this edge /// and visit everything that is reachable through it. -pub type TraversalPredicate = for<'a> fn(&'a BindgenContext, Edge) -> bool; +pub(crate) type TraversalPredicate = + for<'a> fn(&'a BindgenContext, Edge) -> bool; /// A `TraversalPredicate` implementation that follows all edges, and therefore /// traversals using this predicate will see the whole IR graph reachable from /// the traversal's roots. -pub fn all_edges(_: &BindgenContext, _: Edge) -> bool { +pub(crate) fn all_edges(_: &BindgenContext, _: Edge) -> bool { true } @@ -196,14 +197,14 @@ pub fn all_edges(_: &BindgenContext, _: Edge) -> bool { /// will only visit the traversal's roots and their inner types. This is used /// in no-recursive-allowlist mode, where inner types such as anonymous /// structs/unions still need to be processed. -pub fn only_inner_type_edges(_: &BindgenContext, edge: Edge) -> bool { +pub(crate) fn only_inner_type_edges(_: &BindgenContext, edge: Edge) -> bool { edge.kind == EdgeKind::InnerType } /// A `TraversalPredicate` implementation that only follows edges to items that /// are enabled for code generation. This lets us skip considering items for /// which are not reachable from code generation. -pub fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool { +pub(crate) fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool { let cc = &ctx.options().codegen_config; match edge.kind { EdgeKind::Generic => { @@ -233,7 +234,7 @@ pub fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool { /// The storage for the set of items that have been seen (although their /// outgoing edges might not have been fully traversed yet) in an active /// traversal. -pub trait TraversalStorage<'ctx> { +pub(crate) trait TraversalStorage<'ctx> { /// Construct a new instance of this TraversalStorage, for a new traversal. fn new(ctx: &'ctx BindgenContext) -> Self; @@ -259,7 +260,7 @@ impl<'ctx> TraversalStorage<'ctx> for ItemSet { /// each item. This is useful for providing debug assertions with meaningful /// diagnostic messages about dangling items. #[derive(Debug)] -pub struct Paths<'ctx>(BTreeMap<ItemId, ItemId>, &'ctx BindgenContext); +pub(crate) struct Paths<'ctx>(BTreeMap<ItemId, ItemId>, &'ctx BindgenContext); impl<'ctx> TraversalStorage<'ctx> for Paths<'ctx> { fn new(ctx: &'ctx BindgenContext) -> Self { @@ -300,7 +301,7 @@ impl<'ctx> TraversalStorage<'ctx> for Paths<'ctx> { /// Using a FIFO queue with a traversal will yield a breadth-first traversal, /// while using a LIFO queue will result in a depth-first traversal of the IR /// graph. -pub trait TraversalQueue: Default { +pub(crate) trait TraversalQueue: Default { /// Add a newly discovered item to the queue. fn push(&mut self, item: ItemId); @@ -329,7 +330,7 @@ impl TraversalQueue for VecDeque<ItemId> { } /// Something that can receive edges from a `Trace` implementation. -pub trait Tracer { +pub(crate) trait Tracer { /// Note an edge between items. Called from within a `Trace` implementation. fn visit_kind(&mut self, item: ItemId, kind: EdgeKind); @@ -351,7 +352,7 @@ where /// Trace all of the outgoing edges to other items. Implementations should call /// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)` /// for each of their outgoing edges. -pub trait Trace { +pub(crate) trait Trace { /// If a particular type needs extra information beyond what it has in /// `self` and `context` to find its referenced items, its implementation /// can define this associated type, forcing callers to pass the needed @@ -371,7 +372,7 @@ pub trait Trace { /// An graph traversal of the transitive closure of references between items. /// /// See `BindgenContext::allowlisted_items` for more information. -pub struct ItemTraversal<'ctx, Storage, Queue> +pub(crate) struct ItemTraversal<'ctx, Storage, Queue> where Storage: TraversalStorage<'ctx>, Queue: TraversalQueue, @@ -397,7 +398,7 @@ where Queue: TraversalQueue, { /// Begin a new traversal, starting from the given roots. - pub fn new<R>( + pub(crate) fn new<R>( ctx: &'ctx BindgenContext, roots: R, predicate: TraversalPredicate, @@ -474,5 +475,5 @@ where /// /// See `BindgenContext::assert_no_dangling_item_traversal` for more /// information. -pub type AssertNoDanglingItemsTraversal<'ctx> = +pub(crate) type AssertNoDanglingItemsTraversal<'ctx> = ItemTraversal<'ctx, Paths<'ctx>, VecDeque<ItemId>>; @@ -24,7 +24,7 @@ use std::io; /// (size, alignment and packedness) if known, a `Kind`, which determines which /// kind of type it is, and whether the type is const. #[derive(Debug)] -pub struct Type { +pub(crate) struct Type { /// The name of the type, or None if it was an unnamed struct or union. name: Option<String>, /// The layout of the type, if known. @@ -39,21 +39,12 @@ pub struct Type { /// traits, and so if we have a type containing an array with more than this /// many items, we won't be able to derive common traits on that type. /// -pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32; +pub(crate) const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32; impl Type { - /// Get the underlying `CompInfo` for this type, or `None` if this is some - /// other kind of type. - pub fn as_comp(&self) -> Option<&CompInfo> { - match self.kind { - TypeKind::Comp(ref ci) => Some(ci), - _ => None, - } - } - /// Get the underlying `CompInfo` for this type as a mutable reference, or /// `None` if this is some other kind of type. - pub fn as_comp_mut(&mut self) -> Option<&mut CompInfo> { + pub(crate) fn as_comp_mut(&mut self) -> Option<&mut CompInfo> { match self.kind { TypeKind::Comp(ref mut ci) => Some(ci), _ => None, @@ -61,7 +52,7 @@ impl Type { } /// Construct a new `Type`. - pub fn new( + pub(crate) fn new( name: Option<String>, layout: Option<Layout>, kind: TypeKind, @@ -76,37 +67,37 @@ impl Type { } /// Which kind of type is this? - pub fn kind(&self) -> &TypeKind { + pub(crate) fn kind(&self) -> &TypeKind { &self.kind } /// Get a mutable reference to this type's kind. - pub fn kind_mut(&mut self) -> &mut TypeKind { + pub(crate) fn kind_mut(&mut self) -> &mut TypeKind { &mut self.kind } /// Get this type's name. - pub fn name(&self) -> Option<&str> { + pub(crate) fn name(&self) -> Option<&str> { self.name.as_deref() } /// Whether this is a block pointer type. - pub fn is_block_pointer(&self) -> bool { + pub(crate) fn is_block_pointer(&self) -> bool { matches!(self.kind, TypeKind::BlockPointer(..)) } /// Is this an integer type, including `bool` or `char`? - pub fn is_int(&self) -> bool { + pub(crate) fn is_int(&self) -> bool { matches!(self.kind, TypeKind::Int(_)) } /// Is this a compound type? - pub fn is_comp(&self) -> bool { + pub(crate) fn is_comp(&self) -> bool { matches!(self.kind, TypeKind::Comp(..)) } /// Is this a union? - pub fn is_union(&self) -> bool { + pub(crate) fn is_union(&self) -> bool { match self.kind { TypeKind::Comp(ref comp) => comp.is_union(), _ => false, @@ -114,32 +105,27 @@ impl Type { } /// Is this type of kind `TypeKind::TypeParam`? - pub fn is_type_param(&self) -> bool { + pub(crate) fn is_type_param(&self) -> bool { matches!(self.kind, TypeKind::TypeParam) } /// Is this a template instantiation type? - pub fn is_template_instantiation(&self) -> bool { + pub(crate) fn is_template_instantiation(&self) -> bool { matches!(self.kind, TypeKind::TemplateInstantiation(..)) } - /// Is this a template alias type? - pub fn is_template_alias(&self) -> bool { - matches!(self.kind, TypeKind::TemplateAlias(..)) - } - /// Is this a function type? - pub fn is_function(&self) -> bool { + pub(crate) fn is_function(&self) -> bool { matches!(self.kind, TypeKind::Function(..)) } /// Is this an enum type? - pub fn is_enum(&self) -> bool { + pub(crate) fn is_enum(&self) -> bool { matches!(self.kind, TypeKind::Enum(..)) } /// Is this either a builtin or named type? - pub fn is_builtin_or_type_param(&self) -> bool { + pub(crate) fn is_builtin_or_type_param(&self) -> bool { matches!( self.kind, TypeKind::Void | @@ -155,29 +141,29 @@ impl Type { } /// Creates a new named type, with name `name`. - pub fn named(name: String) -> Self { + pub(crate) fn named(name: String) -> Self { let name = if name.is_empty() { None } else { Some(name) }; Self::new(name, None, TypeKind::TypeParam, false) } /// Is this a floating point type? - pub fn is_float(&self) -> bool { + pub(crate) fn is_float(&self) -> bool { matches!(self.kind, TypeKind::Float(..)) } /// Is this a boolean type? - pub fn is_bool(&self) -> bool { + pub(crate) fn is_bool(&self) -> bool { matches!(self.kind, TypeKind::Int(IntKind::Bool)) } /// Is this an integer type? - pub fn is_integer(&self) -> bool { + pub(crate) fn is_integer(&self) -> bool { matches!(self.kind, TypeKind::Int(..)) } /// Cast this type to an integer kind, or `None` if it is not an integer /// type. - pub fn as_integer(&self) -> Option<IntKind> { + pub(crate) fn as_integer(&self) -> Option<IntKind> { match self.kind { TypeKind::Int(int_kind) => Some(int_kind), _ => None, @@ -185,25 +171,20 @@ impl Type { } /// Is this a `const` qualified type? - pub fn is_const(&self) -> bool { + pub(crate) fn is_const(&self) -> bool { self.is_const } - /// Is this a reference to another type? - pub fn is_type_ref(&self) -> bool { - matches!( - self.kind, - TypeKind::ResolvedTypeRef(_) | TypeKind::UnresolvedTypeRef(_, _, _) - ) - } - /// Is this an unresolved reference? - pub fn is_unresolved_ref(&self) -> bool { + pub(crate) fn is_unresolved_ref(&self) -> bool { matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _)) } /// Is this a incomplete array type? - pub fn is_incomplete_array(&self, ctx: &BindgenContext) -> Option<ItemId> { + pub(crate) fn is_incomplete_array( + &self, + ctx: &BindgenContext, + ) -> Option<ItemId> { match self.kind { TypeKind::Array(item, len) => { if len == 0 { @@ -220,7 +201,7 @@ impl Type { } /// What is the layout of this type? - pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { + pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { self.layout.or_else(|| { match self.kind { TypeKind::Comp(ref ci) => ci.layout(ctx), @@ -245,7 +226,7 @@ impl Type { /// avoid generating invalid code with some cases we can't handle, see: /// /// tests/headers/381-decltype-alias.hpp - pub fn is_invalid_type_param(&self) -> bool { + pub(crate) fn is_invalid_type_param(&self) -> bool { match self.kind { TypeKind::TypeParam => { let name = self.name().expect("Unnamed named type?"); @@ -266,7 +247,7 @@ impl Type { } /// Get this type's santizied name. - pub fn sanitized_name<'a>( + pub(crate) fn sanitized_name<'a>( &'a self, ctx: &BindgenContext, ) -> Option<Cow<'a, str>> { @@ -289,7 +270,7 @@ impl Type { } /// See safe_canonical_type. - pub fn canonical_type<'tr>( + pub(crate) fn canonical_type<'tr>( &'tr self, ctx: &'tr BindgenContext, ) -> &'tr Type { @@ -302,7 +283,7 @@ impl Type { /// For example, for a `typedef`, the canonical type would be the /// `typedef`ed type, for a template instantiation, would be the template /// its specializing, and so on. Return None if the type is unresolved. - pub fn safe_canonical_type<'tr>( + pub(crate) fn safe_canonical_type<'tr>( &'tr self, ctx: &'tr BindgenContext, ) -> Option<&'tr Type> { @@ -341,7 +322,7 @@ impl Type { /// There are some types we don't want to stop at when finding an opaque /// item, so we can arrive to the proper item that needs to be generated. - pub fn should_be_traced_unconditionally(&self) -> bool { + pub(crate) fn should_be_traced_unconditionally(&self) -> bool { matches!( self.kind, TypeKind::Comp(..) | @@ -570,7 +551,7 @@ impl TemplateParameters for TypeKind { /// The kind of float this type represents. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum FloatKind { +pub(crate) enum FloatKind { /// A `float`. Float, /// A `double`. @@ -583,7 +564,7 @@ pub enum FloatKind { /// The different kinds of types that we can parse. #[derive(Debug)] -pub enum TypeKind { +pub(crate) enum TypeKind { /// The void type. Void, @@ -680,7 +661,7 @@ impl Type { /// /// It's sort of nasty and full of special-casing, but hopefully the /// comments in every special case justify why they're there. - pub fn from_clang_ty( + pub(crate) fn from_clang_ty( potential_id: ItemId, ty: &clang::Type, location: Cursor, @@ -730,7 +711,7 @@ impl Type { // Objective C template type parameter // FIXME: This is probably wrong, we are attempting to find the // objc template params, which seem to manifest as a typedef. - // We are rewriting them as id to suppress multiple conflicting + // We are rewriting them as ID to suppress multiple conflicting // typedefs at root level if ty_kind == CXType_Typedef { let is_template_type_param = @@ -11,13 +11,13 @@ use crate::callbacks::{ItemInfo, ItemKind, MacroParsingBehavior}; use crate::clang; use crate::clang::ClangToken; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; -use cexpr; + use std::io; use std::num::Wrapping; /// The type for a constant variable. #[derive(Debug)] -pub enum VarType { +pub(crate) enum VarType { /// A boolean. Bool(bool), /// An integer. @@ -32,11 +32,13 @@ pub enum VarType { /// A `Var` is our intermediate representation of a variable. #[derive(Debug)] -pub struct Var { +pub(crate) struct Var { /// The name of the variable. name: String, /// The mangled name of the variable. mangled_name: Option<String>, + /// The link name of the variable. + link_name: Option<String>, /// The type of the variable. ty: TypeId, /// The value of the variable, that needs to be suitable for `ty`. @@ -47,9 +49,10 @@ pub struct Var { impl Var { /// Construct a new `Var`. - pub fn new( + pub(crate) fn new( name: String, mangled_name: Option<String>, + link_name: Option<String>, ty: TypeId, val: Option<VarType>, is_const: bool, @@ -58,6 +61,7 @@ impl Var { Var { name, mangled_name, + link_name, ty, val, is_const, @@ -65,29 +69,34 @@ impl Var { } /// Is this variable `const` qualified? - pub fn is_const(&self) -> bool { + pub(crate) fn is_const(&self) -> bool { self.is_const } /// The value of this constant variable, if any. - pub fn val(&self) -> Option<&VarType> { + pub(crate) fn val(&self) -> Option<&VarType> { self.val.as_ref() } /// Get this variable's type. - pub fn ty(&self) -> TypeId { + pub(crate) fn ty(&self) -> TypeId { self.ty } /// Get this variable's name. - pub fn name(&self) -> &str { + pub(crate) fn name(&self) -> &str { &self.name } /// Get this variable's mangled name. - pub fn mangled_name(&self) -> Option<&str> { + pub(crate) fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_deref() } + + /// Get this variable's link name. + pub fn link_name(&self) -> Option<&str> { + self.link_name.as_deref() + } } impl DotAttributes for Var { @@ -213,7 +222,7 @@ impl ClangSubItemParser for Var { if previously_defined { let name = String::from_utf8(id).unwrap(); - warn!("Duplicated macro definition: {}", name); + duplicated_macro_diagnostic(&name, cursor.location(), ctx); return Err(ParseError::Continue); } @@ -267,7 +276,7 @@ impl ClangSubItemParser for Var { let ty = Item::builtin_type(type_kind, true, ctx); Ok(ParseResult::New( - Var::new(name, None, ty, Some(val), true), + Var::new(name, None, None, ty, Some(val), true), Some(cursor), )) } @@ -291,6 +300,13 @@ impl ClangSubItemParser for Var { return Err(ParseError::Continue); } + let link_name = ctx.options().last_callback(|callbacks| { + callbacks.generated_link_name_override(ItemInfo { + name: name.as_str(), + kind: ItemKind::Var, + }) + }); + let ty = cursor.cur_type(); // TODO(emilio): do we have to special-case constant arrays in @@ -360,7 +376,8 @@ impl ClangSubItemParser for Var { }; let mangling = cursor_mangling(ctx, &cursor); - let var = Var::new(name, mangling, ty, value, is_const); + let var = + Var::new(name, mangling, link_name, ty, value, is_const); Ok(ParseResult::New(var, Some(cursor))) } @@ -423,3 +440,49 @@ fn get_integer_literal_from_cursor(cursor: &clang::Cursor) -> Option<i64> { }); value } + +fn duplicated_macro_diagnostic( + macro_name: &str, + _location: crate::clang::SourceLocation, + _ctx: &BindgenContext, +) { + warn!("Duplicated macro definition: {}", macro_name); + + #[cfg(feature = "experimental")] + // FIXME (pvdrz & amanjeev): This diagnostic message shows way too often to be actually + // useful. We have to change the logic where this function is called to be able to emit this + // message only when the duplication is an actuall issue. + // + // If I understood correctly, `bindgen` ignores all `#undef` directives. Meaning that this: + // ```c + // #define FOO 1 + // #undef FOO + // #define FOO 2 + // ``` + // + // Will trigger this message even though there's nothing wrong with it. + #[allow(clippy::overly_complex_bool_expr)] + if false && _ctx.options().emit_diagnostics { + use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; + use std::borrow::Cow; + + let mut slice = Slice::default(); + let mut source = Cow::from(macro_name); + + let (file, line, col, _) = _location.location(); + if let Some(filename) = file.name() { + if let Ok(Some(code)) = get_line(&filename, line) { + source = code.into(); + } + slice.with_location(filename, line, col); + } + + slice.with_source(source); + + Diagnostic::default() + .with_title("Duplicated macro definition.", Level::Warn) + .add_slice(slice) + .add_annotation("This macro had a duplicate.", Level::Note) + .display(); + } +} @@ -9,6 +9,7 @@ //! additional documentation. #![deny(missing_docs)] #![deny(unused_extern_crates)] +#![deny(clippy::disallowed_methods)] // To avoid rather annoying warnings when matching with CXCursor_xxx as a // constant. #![allow(non_upper_case_globals)] @@ -33,82 +34,55 @@ mod log_stubs; #[macro_use] mod extra_assertions; -// A macro to declare an internal module for which we *must* provide -// documentation for. If we are building with the "testing_only_docs" feature, -// then the module is declared public, and our `#![deny(missing_docs)]` pragma -// applies to it. This feature is used in CI, so we won't let anything slip by -// undocumented. Normal builds, however, will leave the module private, so that -// we don't expose internals to library consumers. -macro_rules! doc_mod { - ($m:ident, $doc_mod_name:ident) => { - #[cfg(feature = "testing_only_docs")] - pub mod $doc_mod_name { - //! Autogenerated documentation module. - pub use super::$m::*; - } - }; -} +mod codegen; +mod deps; +mod options; +mod time; -macro_rules! fn_with_regex_arg { - ($(#[$attrs:meta])* pub fn $($tokens:tt)*) => { - $(#[$attrs])* - /// Check the [regular expression arguments] section and the [regex] crate - /// documentation for further information. - /// - /// [regular expression arguments]: ./struct.Builder.html#regular-expression-arguments - /// [regex]: <https://docs.rs/regex> - pub fn $($tokens)* - }; -} +pub mod callbacks; mod clang; -mod codegen; -mod deps; +#[cfg(feature = "experimental")] +mod diagnostics; mod features; -pub mod ir; +mod ir; mod parse; mod regex_set; -mod time; - -pub mod callbacks; -doc_mod!(clang, clang_docs); -doc_mod!(features, features_docs); -doc_mod!(ir, ir_docs); -doc_mod!(parse, parse_docs); -doc_mod!(regex_set, regex_set_docs); +pub use codegen::{ + AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, +}; +pub use features::{RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS}; +pub use ir::annotations::FieldVisibilityKind; +pub use ir::function::Abi; +pub use regex_set::RegexSet; use codegen::CodegenError; +use features::RustFeatures; use ir::comment; - -pub use crate::codegen::{ - AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, -}; -use crate::features::RustFeatures; -pub use crate::features::{ - RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS, -}; -use crate::ir::context::{BindgenContext, ItemId}; -pub use crate::ir::function::Abi; -use crate::ir::item::Item; -use crate::parse::ParseError; -pub use crate::regex_set::RegexSet; +use ir::context::{BindgenContext, ItemId}; +use ir::item::Item; +use options::BindgenOptions; +use parse::ParseError; use std::borrow::Cow; +use std::collections::hash_map::Entry; use std::env; +use std::ffi::OsStr; use std::fs::{File, OpenOptions}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::rc::Rc; +use std::str::FromStr; // Some convenient typedefs for a fast hash map and hash set. -type HashMap<K, V> = ::rustc_hash::FxHashMap<K, V>; -type HashSet<K> = ::rustc_hash::FxHashSet<K>; -pub(crate) use std::collections::hash_map::Entry; +type HashMap<K, V> = rustc_hash::FxHashMap<K, V>; +type HashSet<K> = rustc_hash::FxHashSet<K>; /// Default prefix for the anon fields. pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_"; + const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern"; fn file_is_cpp(name_file: &str) -> bool { @@ -134,6 +108,7 @@ fn args_are_cpp(clang_args: &[String]) -> bool { } bitflags! { + #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// A type used to indicate which kind of items we have to generate. pub struct CodegenConfig: u32 { /// Whether to generate functions. @@ -189,6 +164,52 @@ impl Default for CodegenConfig { } } +/// Formatting tools that can be used to format the bindings +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub enum Formatter { + /// Do not format the bindings. + None, + /// Use `rustfmt` to format the bindings. + Rustfmt, + #[cfg(feature = "prettyplease")] + /// Use `prettyplease` to format the bindings. + Prettyplease, +} + +impl Default for Formatter { + fn default() -> Self { + Self::Rustfmt + } +} + +impl FromStr for Formatter { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "none" => Ok(Self::None), + "rustfmt" => Ok(Self::Rustfmt), + #[cfg(feature = "prettyplease")] + "prettyplease" => Ok(Self::Prettyplease), + _ => Err(format!("`{}` is not a valid formatter", s)), + } + } +} + +impl std::fmt::Display for Formatter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let s = match self { + Self::None => "none", + Self::Rustfmt => "rustfmt", + #[cfg(feature = "prettyplease")] + Self::Prettyplease => "prettyplease", + }; + + s.fmt(f) + } +} + /// Configure and generate Rust bindings for a C/C++ header. /// /// This is the main entry point to the library. @@ -242,14 +263,27 @@ impl Default for CodegenConfig { /// /// # Regular expression arguments /// -/// Some [`Builder`] methods like the `allowlist_*` and `blocklist_*` family of methods allow -/// regular expressions as arguments. These regular expressions will be parenthesized and wrapped -/// in `^` and `$`. So if `<regex>` is passed as argument, the regular expression to be stored will -/// be `^(<regex>)$`. +/// Some [`Builder`] methods such as the `allowlist_*` and `blocklist_*` methods allow regular +/// expressions as arguments. These regular expressions will be enclosed in parentheses and +/// anchored with `^` and `$`. So if the argument passed is `<regex>`, the regular expression to be +/// stored will be `^(<regex>)$`. +/// +/// As a consequence, regular expressions passed to `bindgen` will try to match the whole name of +/// an item instead of a section of it, which means that to match any items with the prefix +/// `prefix`, the `prefix.*` regular expression must be used. +/// +/// Certain methods, like [`Builder::allowlist_function`], use regular expressions over function +/// names. To match C++ methods, prefix the name of the type where they belong followed by an +/// underscore. So if the type `Foo` has a method `bar`, it can be matched with the `Foo_bar` +/// regular expression. +/// +/// Additionally, Objective-C interfaces can be matched by prefixing the regular expression with +/// `I`. For example, the `IFoo` regular expression matches the `Foo` interface and the `IFoo_foo` +/// regular expression matches the `foo` method of the `Foo` interface. /// /// Releases of `bindgen` with a version lesser or equal to `0.62.0` used to accept the wildcard /// pattern `*` as a valid regular expression. This behavior has been deprecated and the `.*` -/// pattern must be used instead. +/// regular expression must be used instead. #[derive(Debug, Default, Clone)] pub struct Builder { options: BindgenOptions, @@ -260,13 +294,18 @@ pub fn builder() -> Builder { Default::default() } -fn get_extra_clang_args() -> Vec<String> { +fn get_extra_clang_args( + parse_callbacks: &[Rc<dyn callbacks::ParseCallbacks>], +) -> Vec<String> { // Add any extra arguments from the environment to the clang command line. - let extra_clang_args = - match get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS") { - None => return vec![], - Some(s) => s, - }; + let extra_clang_args = match get_target_dependent_env_var( + parse_callbacks, + "BINDGEN_EXTRA_CLANG_ARGS", + ) { + None => return vec![], + Some(s) => s, + }; + // Try to parse it with shell quoting. If we fail, make it one single big argument. if let Some(strings) = shlex::split(&extra_clang_args) { return strings; @@ -275,1306 +314,12 @@ fn get_extra_clang_args() -> Vec<String> { } impl Builder { - /// Generates the command line flags use for creating `Builder`. - pub fn command_line_flags(&self) -> Vec<String> { - let mut output_vector: Vec<String> = Vec::new(); - - if let Some(header) = self.options.input_headers.last().cloned() { - // Positional argument 'header' - output_vector.push(header); - } - - output_vector.push("--rust-target".into()); - output_vector.push(self.options.rust_target.into()); - - // FIXME(emilio): This is a bit hacky, maybe we should stop re-using the - // RustFeatures to store the "disable_untagged_union" call, and make it - // a different flag that we check elsewhere / in generate(). - if !self.options.rust_features.untagged_union && - RustFeatures::from(self.options.rust_target).untagged_union - { - output_vector.push("--disable-untagged-union".into()); - } - - if self.options.default_enum_style != Default::default() { - output_vector.push("--default-enum-style".into()); - output_vector.push( - match self.options.default_enum_style { - codegen::EnumVariation::Rust { - non_exhaustive: false, - } => "rust", - codegen::EnumVariation::Rust { - non_exhaustive: true, - } => "rust_non_exhaustive", - codegen::EnumVariation::NewType { - is_bitfield: true, - .. - } => "bitfield", - codegen::EnumVariation::NewType { - is_bitfield: false, - is_global, - } => { - if is_global { - "newtype_global" - } else { - "newtype" - } - } - codegen::EnumVariation::Consts => "consts", - codegen::EnumVariation::ModuleConsts => "moduleconsts", - } - .into(), - ) - } - - if self.options.default_macro_constant_type != Default::default() { - output_vector.push("--default-macro-constant-type".into()); - output_vector - .push(self.options.default_macro_constant_type.as_str().into()); - } - - if self.options.default_alias_style != Default::default() { - output_vector.push("--default-alias-style".into()); - output_vector - .push(self.options.default_alias_style.as_str().into()); - } - - if self.options.default_non_copy_union_style != Default::default() { - output_vector.push("--default-non-copy-union-style".into()); - output_vector.push( - self.options.default_non_copy_union_style.as_str().into(), - ); - } - - let regex_sets = &[ - (&self.options.bitfield_enums, "--bitfield-enum"), - (&self.options.newtype_enums, "--newtype-enum"), - (&self.options.newtype_global_enums, "--newtype-global-enum"), - (&self.options.rustified_enums, "--rustified-enum"), - ( - &self.options.rustified_non_exhaustive_enums, - "--rustified-enum-non-exhaustive", - ), - ( - &self.options.constified_enum_modules, - "--constified-enum-module", - ), - (&self.options.constified_enums, "--constified-enum"), - (&self.options.type_alias, "--type-alias"), - (&self.options.new_type_alias, "--new-type-alias"), - (&self.options.new_type_alias_deref, "--new-type-alias-deref"), - ( - &self.options.bindgen_wrapper_union, - "--bindgen-wrapper-union", - ), - (&self.options.manually_drop_union, "--manually-drop-union"), - (&self.options.blocklisted_types, "--blocklist-type"), - (&self.options.blocklisted_functions, "--blocklist-function"), - (&self.options.blocklisted_items, "--blocklist-item"), - (&self.options.blocklisted_files, "--blocklist-file"), - (&self.options.opaque_types, "--opaque-type"), - (&self.options.allowlisted_functions, "--allowlist-function"), - (&self.options.allowlisted_types, "--allowlist-type"), - (&self.options.allowlisted_vars, "--allowlist-var"), - (&self.options.allowlisted_files, "--allowlist-file"), - (&self.options.no_partialeq_types, "--no-partialeq"), - (&self.options.no_copy_types, "--no-copy"), - (&self.options.no_debug_types, "--no-debug"), - (&self.options.no_default_types, "--no-default"), - (&self.options.no_hash_types, "--no-hash"), - (&self.options.must_use_types, "--must-use-type"), - ]; - - for (set, flag) in regex_sets { - for item in set.get_items() { - output_vector.push((*flag).to_owned()); - output_vector.push(item.to_owned()); - } - } - - for (abi, set) in &self.options.abi_overrides { - for item in set.get_items() { - output_vector.push("--override-abi".to_owned()); - output_vector.push(format!("{}={}", item, abi)); - } - } - - if !self.options.layout_tests { - output_vector.push("--no-layout-tests".into()); - } - - if self.options.impl_debug { - output_vector.push("--impl-debug".into()); - } - - if self.options.impl_partialeq { - output_vector.push("--impl-partialeq".into()); - } - - if !self.options.derive_copy { - output_vector.push("--no-derive-copy".into()); - } - - if !self.options.derive_debug { - output_vector.push("--no-derive-debug".into()); - } - - if !self.options.derive_default { - output_vector.push("--no-derive-default".into()); - } else { - output_vector.push("--with-derive-default".into()); - } - - if self.options.derive_hash { - output_vector.push("--with-derive-hash".into()); - } - - if self.options.derive_partialord { - output_vector.push("--with-derive-partialord".into()); - } - - if self.options.derive_ord { - output_vector.push("--with-derive-ord".into()); - } - - if self.options.derive_partialeq { - output_vector.push("--with-derive-partialeq".into()); - } - - if self.options.derive_eq { - output_vector.push("--with-derive-eq".into()); - } - - if self.options.time_phases { - output_vector.push("--time-phases".into()); - } - - if !self.options.generate_comments { - output_vector.push("--no-doc-comments".into()); - } - - if !self.options.allowlist_recursively { - output_vector.push("--no-recursive-allowlist".into()); - } - - if self.options.objc_extern_crate { - output_vector.push("--objc-extern-crate".into()); - } - - if self.options.generate_block { - output_vector.push("--generate-block".into()); - } - - if self.options.block_extern_crate { - output_vector.push("--block-extern-crate".into()); - } - - if self.options.builtins { - output_vector.push("--builtins".into()); - } - - if let Some(ref prefix) = self.options.ctypes_prefix { - output_vector.push("--ctypes-prefix".into()); - output_vector.push(prefix.clone()); - } - - if self.options.anon_fields_prefix != DEFAULT_ANON_FIELDS_PREFIX { - output_vector.push("--anon-fields-prefix".into()); - output_vector.push(self.options.anon_fields_prefix.clone()); - } - - if self.options.emit_ast { - output_vector.push("--emit-clang-ast".into()); - } - - if self.options.emit_ir { - output_vector.push("--emit-ir".into()); - } - if let Some(ref graph) = self.options.emit_ir_graphviz { - output_vector.push("--emit-ir-graphviz".into()); - output_vector.push(graph.clone()) - } - if self.options.enable_cxx_namespaces { - output_vector.push("--enable-cxx-namespaces".into()); - } - if self.options.enable_function_attribute_detection { - output_vector.push("--enable-function-attribute-detection".into()); - } - if self.options.disable_name_namespacing { - output_vector.push("--disable-name-namespacing".into()); - } - if self.options.disable_nested_struct_naming { - output_vector.push("--disable-nested-struct-naming".into()); - } - - if self.options.disable_header_comment { - output_vector.push("--disable-header-comment".into()); - } - - if !self.options.codegen_config.functions() { - output_vector.push("--ignore-functions".into()); - } - - output_vector.push("--generate".into()); - - //Temporary placeholder for below 4 options - let mut options: Vec<String> = Vec::new(); - if self.options.codegen_config.functions() { - options.push("functions".into()); - } - if self.options.codegen_config.types() { - options.push("types".into()); - } - if self.options.codegen_config.vars() { - options.push("vars".into()); - } - if self.options.codegen_config.methods() { - options.push("methods".into()); - } - if self.options.codegen_config.constructors() { - options.push("constructors".into()); - } - if self.options.codegen_config.destructors() { - options.push("destructors".into()); - } - - output_vector.push(options.join(",")); - - if !self.options.codegen_config.methods() { - output_vector.push("--ignore-methods".into()); - } - - if !self.options.convert_floats { - output_vector.push("--no-convert-floats".into()); - } - - if !self.options.prepend_enum_name { - output_vector.push("--no-prepend-enum-name".into()); - } - - if self.options.fit_macro_constants { - output_vector.push("--fit-macro-constant-types".into()); - } - - if self.options.array_pointers_in_arguments { - output_vector.push("--use-array-pointers-in-arguments".into()); - } - - if let Some(ref wasm_import_module_name) = - self.options.wasm_import_module_name - { - output_vector.push("--wasm-import-module-name".into()); - output_vector.push(wasm_import_module_name.clone()); - } - - for line in &self.options.raw_lines { - output_vector.push("--raw-line".into()); - output_vector.push(line.clone()); - } - - for (module, lines) in &self.options.module_lines { - for line in lines.iter() { - output_vector.push("--module-raw-line".into()); - output_vector.push(module.clone()); - output_vector.push(line.clone()); - } - } - - if self.options.use_core { - output_vector.push("--use-core".into()); - } - - if self.options.conservative_inline_namespaces { - output_vector.push("--conservative-inline-namespaces".into()); - } - - if self.options.generate_inline_functions { - output_vector.push("--generate-inline-functions".into()); - } - - if !self.options.record_matches { - output_vector.push("--no-record-matches".into()); - } - - if !self.options.size_t_is_usize { - output_vector.push("--no-size_t-is-usize".into()); - } - - if !self.options.rustfmt_bindings { - output_vector.push("--no-rustfmt-bindings".into()); - } - - if let Some(path) = self - .options - .rustfmt_configuration_file - .as_ref() - .and_then(|f| f.to_str()) - { - output_vector.push("--rustfmt-configuration-file".into()); - output_vector.push(path.into()); - } - - if let Some(ref name) = self.options.dynamic_library_name { - output_vector.push("--dynamic-loading".into()); - output_vector.push(name.clone()); - } - - if self.options.dynamic_link_require_all { - output_vector.push("--dynamic-link-require-all".into()); - } - - if self.options.respect_cxx_access_specs { - output_vector.push("--respect-cxx-access-specs".into()); - } - - if self.options.translate_enum_integer_types { - output_vector.push("--translate-enum-integer-types".into()); - } - - if self.options.c_naming { - output_vector.push("--c-naming".into()); - } - - if self.options.force_explicit_padding { - output_vector.push("--explicit-padding".into()); - } - - if self.options.vtable_generation { - output_vector.push("--vtable-generation".into()); - } - - if self.options.sort_semantically { - output_vector.push("--sort-semantically".into()); - } - - if self.options.merge_extern_blocks { - output_vector.push("--merge-extern-blocks".into()); - } - - if self.options.wrap_unsafe_ops { - output_vector.push("--wrap-unsafe-ops".into()); - } - - #[cfg(feature = "cli")] - for callbacks in &self.options.parse_callbacks { - output_vector.extend(callbacks.cli_args()); - } - if self.options.wrap_static_fns { - output_vector.push("--wrap-static-fns".into()) - } - - if let Some(ref path) = self.options.wrap_static_fns_path { - output_vector.push("--wrap-static-fns-path".into()); - output_vector.push(path.display().to_string()); - } - - if let Some(ref suffix) = self.options.wrap_static_fns_suffix { - output_vector.push("--wrap-static-fns-suffix".into()); - output_vector.push(suffix.clone()); - } - - if cfg!(feature = "experimental") { - output_vector.push("--experimental".into()); - } - - // Add clang arguments - - output_vector.push("--".into()); - - if !self.options.clang_args.is_empty() { - output_vector.extend(self.options.clang_args.iter().cloned()); - } - - // To pass more than one header, we need to pass all but the last - // header via the `-include` clang arg - for header in &self.options.input_headers - [..self.options.input_headers.len().saturating_sub(1)] - { - output_vector.push("-include".to_string()); - output_vector.push(header.clone()); - } - - output_vector - } - - /// Add an input C/C++ header to generate bindings for. - /// - /// This can be used to generate bindings to a single header: - /// - /// ```ignore - /// let bindings = bindgen::Builder::default() - /// .header("input.h") - /// .generate() - /// .unwrap(); - /// ``` - /// - /// Or you can invoke it multiple times to generate bindings to multiple - /// headers: - /// - /// ```ignore - /// let bindings = bindgen::Builder::default() - /// .header("first.h") - /// .header("second.h") - /// .header("third.h") - /// .generate() - /// .unwrap(); - /// ``` - pub fn header<T: Into<String>>(mut self, header: T) -> Builder { - self.options.input_headers.push(header.into()); - self - } - - /// Add a depfile output which will be written alongside the generated bindings. - pub fn depfile<H: Into<String>, D: Into<PathBuf>>( - mut self, - output_module: H, - depfile: D, - ) -> Builder { - self.options.depfile = Some(deps::DepfileSpec { - output_module: output_module.into(), - depfile_path: depfile.into(), - }); - self - } - - /// Add `contents` as an input C/C++ header named `name`. - /// - /// The file `name` will be added to the clang arguments. - pub fn header_contents(mut self, name: &str, contents: &str) -> Builder { - // Apparently clang relies on having virtual FS correspondent to - // the real one, so we need absolute paths here - let absolute_path = env::current_dir() - .expect("Cannot retrieve current directory") - .join(name) - .to_str() - .expect("Cannot convert current directory name to string") - .to_owned(); - self.options - .input_header_contents - .push((absolute_path, contents.into())); - self - } - - /// Specify the rust target - /// - /// The default is the latest stable Rust version - pub fn rust_target(mut self, rust_target: RustTarget) -> Self { - #[allow(deprecated)] - if rust_target <= RustTarget::Stable_1_30 { - warn!( - "The {} rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", - String::from(rust_target) - ); - } - self.options.set_rust_target(rust_target); - self - } - - /// Disable support for native Rust unions, if supported. - pub fn disable_untagged_union(mut self) -> Self { - self.options.rust_features.untagged_union = false; - self - } - - /// Disable insertion of bindgen's version identifier into generated - /// bindings. - pub fn disable_header_comment(mut self) -> Self { - self.options.disable_header_comment = true; - self - } - - /// Set the output graphviz file. - pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder { - let path = path.into(); - self.options.emit_ir_graphviz = Some(path); - self - } - - /// Whether the generated bindings should contain documentation comments - /// (docstrings) or not. This is set to true by default. - /// - /// Note that clang by default excludes comments from system headers, pass - /// `-fretain-comments-from-system-headers` as - /// [`clang_arg`][Builder::clang_arg] to include them. It can also be told - /// to process all comments (not just documentation ones) using the - /// `-fparse-all-comments` flag. See [slides on clang comment parsing]( - /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for - /// background and examples. - pub fn generate_comments(mut self, doit: bool) -> Self { - self.options.generate_comments = doit; - self - } - - /// Whether to allowlist recursively or not. Defaults to true. - /// - /// Given that we have explicitly allowlisted the "initiate_dance_party" - /// function in this C header: - /// - /// ```c - /// typedef struct MoonBoots { - /// int bouncy_level; - /// } MoonBoots; - /// - /// void initiate_dance_party(MoonBoots* boots); - /// ``` - /// - /// We would normally generate bindings to both the `initiate_dance_party` - /// function and the `MoonBoots` struct that it transitively references. By - /// configuring with `allowlist_recursively(false)`, `bindgen` will not emit - /// bindings for anything except the explicitly allowlisted items, and there - /// would be no emitted struct definition for `MoonBoots`. However, the - /// `initiate_dance_party` function would still reference `MoonBoots`! - /// - /// **Disabling this feature will almost certainly cause `bindgen` to emit - /// bindings that will not compile!** If you disable this feature, then it - /// is *your* responsibility to provide definitions for every type that is - /// referenced from an explicitly allowlisted item. One way to provide the - /// definitions is by using the [`Builder::raw_line`](#method.raw_line) - /// method, another would be to define them in Rust and then `include!(...)` - /// the bindings immediately afterwards. - pub fn allowlist_recursively(mut self, doit: bool) -> Self { - self.options.allowlist_recursively = doit; - self - } - - /// Generate `#[macro_use] extern crate objc;` instead of `use objc;` - /// in the prologue of the files generated from objective-c files - pub fn objc_extern_crate(mut self, doit: bool) -> Self { - self.options.objc_extern_crate = doit; - self - } - - /// Generate proper block signatures instead of void pointers. - pub fn generate_block(mut self, doit: bool) -> Self { - self.options.generate_block = doit; - self - } - - /// Generate `#[macro_use] extern crate block;` instead of `use block;` - /// in the prologue of the files generated from apple block files - pub fn block_extern_crate(mut self, doit: bool) -> Self { - self.options.block_extern_crate = doit; - self - } - - /// Whether to use the clang-provided name mangling. This is true by default - /// and probably needed for C++ features. - /// - /// However, some old libclang versions seem to return incorrect results in - /// some cases for non-mangled functions, see [1], so we allow disabling it. - /// - /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 - pub fn trust_clang_mangling(mut self, doit: bool) -> Self { - self.options.enable_mangling = doit; - self - } - - fn_with_regex_arg! { - /// Hide the given type from the generated bindings. Regular expressions are - /// supported. - /// - /// To blocklist types prefixed with "mylib" use `"mylib_.*"`. - pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.blocklisted_types.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Hide the given function from the generated bindings. Regular expressions - /// are supported. - /// - /// Methods can be blocklisted by prefixing the name of the type implementing - /// them followed by an underscore. So if `Foo` has a method `bar`, it can - /// be blocklisted as `Foo_bar`. - /// - /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`. - pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.blocklisted_functions.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Hide the given item from the generated bindings, regardless of - /// whether it's a type, function, module, etc. Regular - /// expressions are supported. - /// - /// To blocklist items prefixed with "mylib" use `"mylib_.*"`. - pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.blocklisted_items.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Hide any contents of the given file from the generated bindings, - /// regardless of whether it's a type, function, module etc. - pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.blocklisted_files.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Treat the given type as opaque in the generated bindings. Regular - /// expressions are supported. - /// - /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`. - pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.opaque_types.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Allowlist the given type so that it (and all types that it transitively - /// refers to) appears in the generated bindings. Regular expressions are - /// supported. - /// - /// To allowlist types prefixed with "mylib" use `"mylib_.*"`. - pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.allowlisted_types.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Allowlist the given function so that it (and all types that it - /// transitively refers to) appears in the generated bindings. Regular - /// expressions are supported. - /// - /// Methods can be allowlisted by prefixing the name of the type - /// implementing them followed by an underscore. So if `Foo` has a method - /// `bar`, it can be allowlisted as `Foo_bar`. - /// - /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`. - pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.allowlisted_functions.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Allowlist the given variable so that it (and all types that it - /// transitively refers to) appears in the generated bindings. Regular - /// expressions are supported. - /// - /// To allowlist variables prefixed with "mylib" use `"mylib_.*"`. - pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.allowlisted_vars.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Allowlist the given file so that its contents appear in the generated bindings. - pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.allowlisted_files.insert(arg); - self - } - } - - /// Set the default style of code to generate for enums - pub fn default_enum_style( - mut self, - arg: codegen::EnumVariation, - ) -> Builder { - self.options.default_enum_style = arg; - self - } - - fn_with_regex_arg! { - /// Mark the given enum (or set of enums, if using a pattern) as being - /// bitfield-like. Regular expressions are supported. - /// - /// This makes bindgen generate a type that isn't a rust `enum`. Regular - /// expressions are supported. - /// - /// This is similar to the newtype enum style, but with the bitwise - /// operators implemented. - pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.bitfield_enums.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given enum (or set of enums, if using a pattern) as a newtype. - /// Regular expressions are supported. - /// - /// This makes bindgen generate a type that isn't a Rust `enum`. Regular - /// expressions are supported. - pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.newtype_enums.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given enum (or set of enums, if using a pattern) as a newtype - /// whose variants are exposed as global constants. - /// - /// Regular expressions are supported. - /// - /// This makes bindgen generate a type that isn't a Rust `enum`. Regular - /// expressions are supported. - pub fn newtype_global_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.newtype_global_enums.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given enum (or set of enums, if using a pattern) as a Rust - /// enum. - /// - /// This makes bindgen generate enums instead of constants. Regular - /// expressions are supported. - /// - /// **Use this with caution**, creating this in unsafe code - /// (including FFI) with an invalid value will invoke undefined behaviour. - /// You may want to use the newtype enum style instead. - pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.rustified_enums.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given enum (or set of enums, if using a pattern) as a Rust - /// enum with the `#[non_exhaustive]` attribute. - /// - /// This makes bindgen generate enums instead of constants. Regular - /// expressions are supported. - /// - /// **Use this with caution**, creating this in unsafe code - /// (including FFI) with an invalid value will invoke undefined behaviour. - /// You may want to use the newtype enum style instead. - pub fn rustified_non_exhaustive_enum<T: AsRef<str>>( - mut self, - arg: T, - ) -> Builder { - self.options.rustified_non_exhaustive_enums.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given enum (or set of enums, if using a pattern) as a set of - /// constants that are not to be put into a module. - pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.constified_enums.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given enum (or set of enums, if using a pattern) as a set of - /// constants that should be put into a module. - /// - /// This makes bindgen generate modules containing constants instead of - /// just constants. Regular expressions are supported. - pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.constified_enum_modules.insert(arg); - self - } - } - - /// Set the default type for macro constants - pub fn default_macro_constant_type( - mut self, - arg: codegen::MacroTypeVariation, - ) -> Builder { - self.options.default_macro_constant_type = arg; - self - } - - /// Set the default style of code to generate for typedefs - pub fn default_alias_style( - mut self, - arg: codegen::AliasVariation, - ) -> Builder { - self.options.default_alias_style = arg; - self - } - - fn_with_regex_arg! { - /// Mark the given typedef alias (or set of aliases, if using a pattern) to - /// use regular Rust type aliasing. - /// - /// This is the default behavior and should be used if `default_alias_style` - /// was set to NewType or NewTypeDeref and you want to override it for a - /// set of typedefs. - pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.type_alias.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given typedef alias (or set of aliases, if using a pattern) to - /// be generated as a new type by having the aliased type be wrapped in a - /// #[repr(transparent)] struct. - /// - /// Used to enforce stricter type checking. - pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.new_type_alias.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given typedef alias (or set of aliases, if using a pattern) to - /// be generated as a new type by having the aliased type be wrapped in a - /// #[repr(transparent)] struct and also have an automatically generated - /// impl's of `Deref` and `DerefMut` to their aliased type. - pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.new_type_alias_deref.insert(arg); - self - } - } - - /// Set the default style of code to generate for unions with a non-Copy member. - pub fn default_non_copy_union_style( - mut self, - arg: codegen::NonCopyUnionStyle, - ) -> Self { - self.options.default_non_copy_union_style = arg; - self - } - - fn_with_regex_arg! { - /// Mark the given union (or set of union, if using a pattern) to use - /// a bindgen-generated wrapper for its members if at least one is non-Copy. - pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self { - self.options.bindgen_wrapper_union.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Mark the given union (or set of union, if using a pattern) to use - /// [`::core::mem::ManuallyDrop`] for its members if at least one is non-Copy. - /// - /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your - /// MSRV is lower. - pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self { - self.options.manually_drop_union.insert(arg); - self - } - } - - fn_with_regex_arg! { - /// Add a string to prepend to the generated bindings. The string is passed - /// through without any modification. - pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self { - self.options.raw_lines.push(arg.into()); - self - } - } - - /// Add a given line to the beginning of module `mod`. - pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self - where - T: Into<String>, - U: Into<String>, - { - self.options - .module_lines - .entry(mod_.into()) - .or_insert_with(Vec::new) - .push(line.into()); - self - } - - /// Add a given set of lines to the beginning of module `mod`. - pub fn module_raw_lines<T, I>(mut self, mod_: T, lines: I) -> Self - where - T: Into<String>, - I: IntoIterator, - I::Item: Into<String>, - { - self.options - .module_lines - .entry(mod_.into()) - .or_insert_with(Vec::new) - .extend(lines.into_iter().map(Into::into)); - self - } - - /// Add an argument to be passed straight through to clang. - pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder { - self.options.clang_args.push(arg.into()); - self - } - - /// Add arguments to be passed straight through to clang. - pub fn clang_args<I>(mut self, iter: I) -> Builder - where - I: IntoIterator, - I::Item: AsRef<str>, - { - for arg in iter { - self = self.clang_arg(arg.as_ref()) - } - self - } - - /// Emit bindings for builtin definitions (for example `__builtin_va_list`) - /// in the generated Rust. - pub fn emit_builtins(mut self) -> Builder { - self.options.builtins = true; - self - } - - /// Avoid converting floats to `f32`/`f64` by default. - pub fn no_convert_floats(mut self) -> Self { - self.options.convert_floats = false; - self - } - - /// Set whether layout tests should be generated. - pub fn layout_tests(mut self, doit: bool) -> Self { - self.options.layout_tests = doit; - self - } - - /// Set whether `Debug` should be implemented, if it can not be derived automatically. - pub fn impl_debug(mut self, doit: bool) -> Self { - self.options.impl_debug = doit; - self - } - - /// Set whether `PartialEq` should be implemented, if it can not be derived automatically. - pub fn impl_partialeq(mut self, doit: bool) -> Self { - self.options.impl_partialeq = doit; - self - } - - /// Set whether `Copy` should be derived by default. - pub fn derive_copy(mut self, doit: bool) -> Self { - self.options.derive_copy = doit; - self - } - - /// Set whether `Debug` should be derived by default. - pub fn derive_debug(mut self, doit: bool) -> Self { - self.options.derive_debug = doit; - self - } - - /// Set whether `Default` should be derived by default. - pub fn derive_default(mut self, doit: bool) -> Self { - self.options.derive_default = doit; - self - } - - /// Set whether `Hash` should be derived by default. - pub fn derive_hash(mut self, doit: bool) -> Self { - self.options.derive_hash = doit; - self - } - - /// Set whether `PartialOrd` should be derived by default. - /// If we don't compute partialord, we also cannot compute - /// ord. Set the derive_ord to `false` when doit is `false`. - pub fn derive_partialord(mut self, doit: bool) -> Self { - self.options.derive_partialord = doit; - if !doit { - self.options.derive_ord = false; - } - self - } - - /// Set whether `Ord` should be derived by default. - /// We can't compute `Ord` without computing `PartialOrd`, - /// so we set the same option to derive_partialord. - pub fn derive_ord(mut self, doit: bool) -> Self { - self.options.derive_ord = doit; - self.options.derive_partialord = doit; - self - } - - /// Set whether `PartialEq` should be derived by default. - /// - /// If we don't derive `PartialEq`, we also cannot derive `Eq`, so deriving - /// `Eq` is also disabled when `doit` is `false`. - pub fn derive_partialeq(mut self, doit: bool) -> Self { - self.options.derive_partialeq = doit; - if !doit { - self.options.derive_eq = false; - } - self - } - - /// Set whether `Eq` should be derived by default. - /// - /// We can't derive `Eq` without also deriving `PartialEq`, so we also - /// enable deriving `PartialEq` when `doit` is `true`. - pub fn derive_eq(mut self, doit: bool) -> Self { - self.options.derive_eq = doit; - if doit { - self.options.derive_partialeq = doit; - } - self - } - - /// Set whether or not to time bindgen phases, and print information to - /// stderr. - pub fn time_phases(mut self, doit: bool) -> Self { - self.options.time_phases = doit; - self - } - - /// Emit Clang AST. - pub fn emit_clang_ast(mut self) -> Builder { - self.options.emit_ast = true; - self - } - - /// Emit IR. - pub fn emit_ir(mut self) -> Builder { - self.options.emit_ir = true; - self - } - - /// Enable C++ namespaces. - pub fn enable_cxx_namespaces(mut self) -> Builder { - self.options.enable_cxx_namespaces = true; - self - } - - /// Enable detecting must_use attributes on C functions. - /// - /// This is quite slow in some cases (see #1465), so it's disabled by - /// default. - /// - /// Note that for this to do something meaningful for now at least, the rust - /// target version has to have support for `#[must_use]`. - pub fn enable_function_attribute_detection(mut self) -> Self { - self.options.enable_function_attribute_detection = true; - self - } - - /// Disable name auto-namespacing. - /// - /// By default, bindgen mangles names like `foo::bar::Baz` to look like - /// `foo_bar_Baz` instead of just `Baz`. - /// - /// This method disables that behavior. - /// - /// Note that this intentionally does not change the names used for - /// allowlisting and blocklisting, which should still be mangled with the - /// namespaces. - /// - /// Note, also, that this option may cause bindgen to generate duplicate - /// names. - pub fn disable_name_namespacing(mut self) -> Builder { - self.options.disable_name_namespacing = true; - self - } - - /// Disable nested struct naming. - /// - /// The following structs have different names for C and C++. In case of C - /// they are visible as `foo` and `bar`. In case of C++ they are visible as - /// `foo` and `foo::bar`. - /// - /// ```c - /// struct foo { - /// struct bar { - /// } b; - /// }; - /// ``` - /// - /// Bindgen wants to avoid duplicate names by default so it follows C++ naming - /// and it generates `foo`/`foo_bar` instead of just `foo`/`bar`. - /// - /// This method disables this behavior and it is indented to be used only - /// for headers that were written for C. - pub fn disable_nested_struct_naming(mut self) -> Builder { - self.options.disable_nested_struct_naming = true; - self - } - - /// Treat inline namespaces conservatively. - /// - /// This is tricky, because in C++ is technically legal to override an item - /// defined in an inline namespace: - /// - /// ```cpp - /// inline namespace foo { - /// using Bar = int; - /// } - /// using Bar = long; - /// ``` - /// - /// Even though referencing `Bar` is a compiler error. - /// - /// We want to support this (arguably esoteric) use case, but we don't want - /// to make the rest of bindgen users pay an usability penalty for that. - /// - /// To support this, we need to keep all the inline namespaces around, but - /// then bindgen usage is a bit more difficult, because you cannot - /// reference, e.g., `std::string` (you'd need to use the proper inline - /// namespace). - /// - /// We could complicate a lot of the logic to detect name collisions, and if - /// not detected generate a `pub use inline_ns::*` or something like that. - /// - /// That's probably something we can do if we see this option is needed in a - /// lot of cases, to improve it's usability, but my guess is that this is - /// not going to be too useful. - pub fn conservative_inline_namespaces(mut self) -> Builder { - self.options.conservative_inline_namespaces = true; - self - } - - /// Whether inline functions should be generated or not. - /// - /// Note that they will usually not work. However you can use - /// `-fkeep-inline-functions` or `-fno-inline-functions` if you are - /// responsible of compiling the library to make them callable. - pub fn generate_inline_functions(mut self, doit: bool) -> Self { - self.options.generate_inline_functions = doit; - self - } - - /// Ignore functions. - pub fn ignore_functions(mut self) -> Builder { - self.options.codegen_config.remove(CodegenConfig::FUNCTIONS); - self - } - - /// Ignore methods. - pub fn ignore_methods(mut self) -> Builder { - self.options.codegen_config.remove(CodegenConfig::METHODS); - self - } - - /// Use core instead of libstd in the generated bindings. - pub fn use_core(mut self) -> Builder { - self.options.use_core = true; - self - } - - /// Use the given prefix for the raw types instead of `::std::os::raw`. - pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { - self.options.ctypes_prefix = Some(prefix.into()); - self - } - - /// Use the given prefix for the anon fields. - pub fn anon_fields_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { - self.options.anon_fields_prefix = prefix.into(); - self - } - - /// Allows configuring types in different situations, see the - /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation. - pub fn parse_callbacks( - mut self, - cb: Box<dyn callbacks::ParseCallbacks>, - ) -> Self { - self.options.parse_callbacks.push(Rc::from(cb)); - self - } - - /// Choose what to generate using a - /// [`CodegenConfig`](./struct.CodegenConfig.html). - pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { - self.options.codegen_config = config; - self - } - - /// Whether to detect include paths using clang_sys. - pub fn detect_include_paths(mut self, doit: bool) -> Self { - self.options.detect_include_paths = doit; - self - } - - /// Whether to try to fit macro constants to types smaller than u32/i32 - pub fn fit_macro_constants(mut self, doit: bool) -> Self { - self.options.fit_macro_constants = doit; - self - } - - /// Prepend the enum name to constant or newtype variants. - pub fn prepend_enum_name(mut self, doit: bool) -> Self { - self.options.prepend_enum_name = doit; - self - } - - /// Set whether `size_t` should be translated to `usize` automatically. - pub fn size_t_is_usize(mut self, is: bool) -> Self { - self.options.size_t_is_usize = is; - self - } - - /// Set whether rustfmt should format the generated bindings. - pub fn rustfmt_bindings(mut self, doit: bool) -> Self { - self.options.rustfmt_bindings = doit; - self - } - - /// Set whether we should record matched items in our regex sets. - pub fn record_matches(mut self, doit: bool) -> Self { - self.options.record_matches = doit; - self - } - - /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt - /// options are used. - pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self { - self = self.rustfmt_bindings(true); - self.options.rustfmt_configuration_file = path; - self - } - - /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled. - pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self { - self.options.rustfmt_path = Some(path.into()); - self - } - - /// If true, always emit explicit padding fields. - /// - /// If a struct needs to be serialized in its native format (padding bytes - /// and all), for example writing it to a file or sending it on the network, - /// then this should be enabled, as anything reading the padding bytes of - /// a struct may lead to Undefined Behavior. - pub fn explicit_padding(mut self, doit: bool) -> Self { - self.options.force_explicit_padding = doit; - self - } - - /// If true, enables experimental support to generate vtable functions. - /// - /// Should mostly work, though some edge cases are likely to be broken. - pub fn vtable_generation(mut self, doit: bool) -> Self { - self.options.vtable_generation = doit; - self - } - - /// If true, enables the sorting of the output in a predefined manner. - /// - /// TODO: Perhaps move the sorting order out into a config - pub fn sort_semantically(mut self, doit: bool) -> Self { - self.options.sort_semantically = doit; - self - } - - /// If true, merges extern blocks. - pub fn merge_extern_blocks(mut self, doit: bool) -> Self { - self.options.merge_extern_blocks = doit; - self - } - /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result<Bindings, BindgenError> { // Add any extra arguments from the environment to the clang command line. - self.options.clang_args.extend(get_extra_clang_args()); + self.options + .clang_args + .extend(get_extra_clang_args(&self.options.parse_callbacks)); // Transform input headers to arguments on the clang command line. self.options.clang_args.extend( @@ -1657,7 +402,7 @@ impl Builder { cmd.arg(a); } - for a in get_extra_clang_args() { + for a in get_extra_clang_args(&self.options.parse_callbacks) { cmd.arg(a); } @@ -1680,510 +425,13 @@ impl Builder { )) } } - - fn_with_regex_arg! { - /// Don't derive `PartialEq` for a given type. Regular - /// expressions are supported. - pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder { - self.options.no_partialeq_types.insert(arg.into()); - self - } - } - - fn_with_regex_arg! { - /// Don't derive `Copy` for a given type. Regular - /// expressions are supported. - pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self { - self.options.no_copy_types.insert(arg.into()); - self - } - } - - fn_with_regex_arg! { - /// Don't derive `Debug` for a given type. Regular - /// expressions are supported. - pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self { - self.options.no_debug_types.insert(arg.into()); - self - } - } - - fn_with_regex_arg! { - /// Don't derive/impl `Default` for a given type. Regular - /// expressions are supported. - pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self { - self.options.no_default_types.insert(arg.into()); - self - } - } - - fn_with_regex_arg! { - /// Don't derive `Hash` for a given type. Regular - /// expressions are supported. - pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder { - self.options.no_hash_types.insert(arg.into()); - self - } - } - - fn_with_regex_arg! { - /// Add `#[must_use]` for the given type. Regular - /// expressions are supported. - pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder { - self.options.must_use_types.insert(arg.into()); - self - } - } - - /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut) - pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self { - self.options.array_pointers_in_arguments = doit; - self - } - - /// Set the wasm import module name - pub fn wasm_import_module_name<T: Into<String>>( - mut self, - import_name: T, - ) -> Self { - self.options.wasm_import_module_name = Some(import_name.into()); - self - } - - /// Specify the dynamic library name if we are generating bindings for a shared library. - pub fn dynamic_library_name<T: Into<String>>( - mut self, - dynamic_library_name: T, - ) -> Self { - self.options.dynamic_library_name = Some(dynamic_library_name.into()); - self - } - - /// Require successful linkage for all routines in a shared library. - /// This allows us to optimize function calls by being able to safely assume function pointers - /// are valid. - pub fn dynamic_link_require_all(mut self, req: bool) -> Self { - self.options.dynamic_link_require_all = req; - self - } - - /// Generate bindings as `pub` only if the bound item is publically accessible by C++. - pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self { - self.options.respect_cxx_access_specs = doit; - self - } - - /// Always translate enum integer types to native Rust integer types. - /// - /// This will result in enums having types such as `u32` and `i16` instead - /// of `c_uint` and `c_short`. Types for Rustified enums are always - /// translated. - pub fn translate_enum_integer_types(mut self, doit: bool) -> Self { - self.options.translate_enum_integer_types = doit; - self - } - - /// Generate types with C style naming. - /// - /// This will add prefixes to the generated type names. For example instead of a struct `A` we - /// will generate struct `struct_A`. Currently applies to structs, unions, and enums. - pub fn c_naming(mut self, doit: bool) -> Self { - self.options.c_naming = doit; - self - } - - /// Override the ABI of a given function. Regular expressions are supported. - pub fn override_abi<T: Into<String>>(mut self, abi: Abi, arg: T) -> Self { - self.options - .abi_overrides - .entry(abi) - .or_default() - .insert(arg.into()); - self - } - - /// If true, wraps unsafe operations in unsafe blocks. - pub fn wrap_unsafe_ops(mut self, doit: bool) -> Self { - self.options.wrap_unsafe_ops = doit; - self - } - - #[cfg(feature = "experimental")] - /// Whether to generate extern wrappers for `static` and `static inline` functions. Defaults to - /// false. - pub fn wrap_static_fns(mut self, doit: bool) -> Self { - self.options.wrap_static_fns = doit; - self - } - - #[cfg(feature = "experimental")] - /// Set the path for the source code file that would be created if any wrapper functions must - /// be generated due to the presence of static functions. - /// - /// Bindgen will automatically add the right extension to the header and source code files. - pub fn wrap_static_fns_path<T: AsRef<Path>>(mut self, path: T) -> Self { - self.options.wrap_static_fns_path = Some(path.as_ref().to_owned()); - self - } - - #[cfg(feature = "experimental")] - /// Set the suffix added to the extern wrapper functions generated for `static` and `static - /// inline` functions. - pub fn wrap_static_fns_suffix<T: AsRef<str>>(mut self, suffix: T) -> Self { - self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned()); - self - } -} - -/// Configuration options for generated bindings. -#[derive(Clone, Debug)] -struct BindgenOptions { - /// The set of types that have been blocklisted and should not appear - /// anywhere in the generated code. - blocklisted_types: RegexSet, - - /// The set of functions that have been blocklisted and should not appear - /// in the generated code. - blocklisted_functions: RegexSet, - - /// The set of items, regardless of item-type, that have been - /// blocklisted and should not appear in the generated code. - blocklisted_items: RegexSet, - - /// The set of files whose contents should be blocklisted and should not - /// appear in the generated code. - blocklisted_files: RegexSet, - - /// The set of types that should be treated as opaque structures in the - /// generated code. - opaque_types: RegexSet, - - /// The explicit rustfmt path. - rustfmt_path: Option<PathBuf>, - - /// The path to which we should write a Makefile-syntax depfile (if any). - depfile: Option<deps::DepfileSpec>, - - /// The set of types that we should have bindings for in the generated - /// code. - /// - /// This includes all types transitively reachable from any type in this - /// set. One might think of allowlisted types/vars/functions as GC roots, - /// and the generated Rust code as including everything that gets marked. - allowlisted_types: RegexSet, - - /// Allowlisted functions. See docs for `allowlisted_types` for more. - allowlisted_functions: RegexSet, - - /// Allowlisted variables. See docs for `allowlisted_types` for more. - allowlisted_vars: RegexSet, - - /// The set of files whose contents should be allowlisted. - allowlisted_files: RegexSet, - - /// The default style of code to generate for enums - default_enum_style: codegen::EnumVariation, - - /// The enum patterns to mark an enum as a bitfield - /// (newtype with bitwise operations). - bitfield_enums: RegexSet, - - /// The enum patterns to mark an enum as a newtype. - newtype_enums: RegexSet, - - /// The enum patterns to mark an enum as a global newtype. - newtype_global_enums: RegexSet, - - /// The enum patterns to mark an enum as a Rust enum. - rustified_enums: RegexSet, - - /// The enum patterns to mark an enum as a non-exhaustive Rust enum. - rustified_non_exhaustive_enums: RegexSet, - - /// The enum patterns to mark an enum as a module of constants. - constified_enum_modules: RegexSet, - - /// The enum patterns to mark an enum as a set of constants. - constified_enums: RegexSet, - - /// The default type for C macro constants. - default_macro_constant_type: codegen::MacroTypeVariation, - - /// The default style of code to generate for typedefs. - default_alias_style: codegen::AliasVariation, - - /// Typedef patterns that will use regular type aliasing. - type_alias: RegexSet, - - /// Typedef patterns that will be aliased by creating a new struct. - new_type_alias: RegexSet, - - /// Typedef patterns that will be wrapped in a new struct and have - /// Deref and Deref to their aliased type. - new_type_alias_deref: RegexSet, - - /// The default style of code to generate for union containing non-Copy - /// members. - default_non_copy_union_style: codegen::NonCopyUnionStyle, - - /// The union patterns to mark an non-Copy union as using the bindgen - /// generated wrapper. - bindgen_wrapper_union: RegexSet, - - /// The union patterns to mark an non-Copy union as using the - /// `::core::mem::ManuallyDrop` wrapper. - manually_drop_union: RegexSet, - - /// Whether we should generate builtins or not. - builtins: bool, - - /// True if we should dump the Clang AST for debugging purposes. - emit_ast: bool, - - /// True if we should dump our internal IR for debugging purposes. - emit_ir: bool, - - /// Output graphviz dot file. - emit_ir_graphviz: Option<String>, - - /// True if we should emulate C++ namespaces with Rust modules in the - /// generated bindings. - enable_cxx_namespaces: bool, - - /// True if we should try to find unexposed attributes in functions, in - /// order to be able to generate #[must_use] attributes in Rust. - enable_function_attribute_detection: bool, - - /// True if we should avoid mangling names with namespaces. - disable_name_namespacing: bool, - - /// True if we should avoid generating nested struct names. - disable_nested_struct_naming: bool, - - /// True if we should avoid embedding version identifiers into source code. - disable_header_comment: bool, - - /// True if we should generate layout tests for generated structures. - layout_tests: bool, - - /// True if we should implement the Debug trait for C/C++ structures and types - /// that do not support automatically deriving Debug. - impl_debug: bool, - - /// True if we should implement the PartialEq trait for C/C++ structures and types - /// that do not support automatically deriving PartialEq. - impl_partialeq: bool, - - /// True if we should derive Copy trait implementations for C/C++ structures - /// and types. - derive_copy: bool, - - /// True if we should derive Debug trait implementations for C/C++ structures - /// and types. - derive_debug: bool, - - /// True if we should derive Default trait implementations for C/C++ structures - /// and types. - derive_default: bool, - - /// True if we should derive Hash trait implementations for C/C++ structures - /// and types. - derive_hash: bool, - - /// True if we should derive PartialOrd trait implementations for C/C++ structures - /// and types. - derive_partialord: bool, - - /// True if we should derive Ord trait implementations for C/C++ structures - /// and types. - derive_ord: bool, - - /// True if we should derive PartialEq trait implementations for C/C++ structures - /// and types. - derive_partialeq: bool, - - /// True if we should derive Eq trait implementations for C/C++ structures - /// and types. - derive_eq: bool, - - /// True if we should avoid using libstd to use libcore instead. - use_core: bool, - - /// An optional prefix for the "raw" types, like `c_int`, `c_void`... - ctypes_prefix: Option<String>, - - /// The prefix for the anon fields. - anon_fields_prefix: String, - - /// Whether to time the bindgen phases. - time_phases: bool, - - /// Whether we should convert float types to f32/f64 types. - convert_floats: bool, - - /// The set of raw lines to prepend to the top-level module of generated - /// Rust code. - raw_lines: Vec<String>, - - /// The set of raw lines to prepend to each of the modules. - /// - /// This only makes sense if the `enable_cxx_namespaces` option is set. - module_lines: HashMap<String, Vec<String>>, - - /// The set of arguments to pass straight through to Clang. - clang_args: Vec<String>, - - /// The input header files. - input_headers: Vec<String>, - - /// Tuples of unsaved file contents of the form (name, contents). - input_header_contents: Vec<(String, String)>, - - /// A user-provided visitor to allow customizing different kinds of - /// situations. - parse_callbacks: Vec<Rc<dyn callbacks::ParseCallbacks>>, - - /// Which kind of items should we generate? By default, we'll generate all - /// of them. - codegen_config: CodegenConfig, - - /// Whether to treat inline namespaces conservatively. - /// - /// See the builder method description for more details. - conservative_inline_namespaces: bool, - - /// Whether to keep documentation comments in the generated output. See the - /// documentation for more details. Defaults to true. - generate_comments: bool, - - /// Whether to generate inline functions. Defaults to false. - generate_inline_functions: bool, - - /// Whether to allowlist types recursively. Defaults to true. - allowlist_recursively: bool, - - /// Instead of emitting 'use objc;' to files generated from objective c files, - /// generate '#[macro_use] extern crate objc;' - objc_extern_crate: bool, - - /// Instead of emitting 'use block;' to files generated from objective c files, - /// generate '#[macro_use] extern crate block;' - generate_block: bool, - - /// Instead of emitting 'use block;' to files generated from objective c files, - /// generate '#[macro_use] extern crate block;' - block_extern_crate: bool, - - /// Whether to use the clang-provided name mangling. This is true and - /// probably needed for C++ features. - /// - /// However, some old libclang versions seem to return incorrect results in - /// some cases for non-mangled functions, see [1], so we allow disabling it. - /// - /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 - enable_mangling: bool, - - /// Whether to detect include paths using clang_sys. - detect_include_paths: bool, - - /// Whether to try to fit macro constants into types smaller than u32/i32 - fit_macro_constants: bool, - - /// Whether to prepend the enum name to constant or newtype variants. - prepend_enum_name: bool, - - /// Version of the Rust compiler to target - rust_target: RustTarget, - - /// Features to enable, derived from `rust_target` - rust_features: RustFeatures, - - /// Whether we should record which items in the regex sets ever matched. - /// - /// This may be a bit slower, but will enable reporting of unused allowlist - /// items via the `error!` log. - record_matches: bool, - - /// Whether `size_t` should be translated to `usize` automatically. - size_t_is_usize: bool, - - /// Whether rustfmt should format the generated bindings. - rustfmt_bindings: bool, - - /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt - /// options are used. - rustfmt_configuration_file: Option<PathBuf>, - - /// The set of types that we should not derive `PartialEq` for. - no_partialeq_types: RegexSet, - - /// The set of types that we should not derive `Copy` for. - no_copy_types: RegexSet, - - /// The set of types that we should not derive `Debug` for. - no_debug_types: RegexSet, - - /// The set of types that we should not derive/impl `Default` for. - no_default_types: RegexSet, - - /// The set of types that we should not derive `Hash` for. - no_hash_types: RegexSet, - - /// The set of types that we should be annotated with `#[must_use]`. - must_use_types: RegexSet, - - /// Decide if C arrays should be regular pointers in rust or array pointers - array_pointers_in_arguments: bool, - - /// Wasm import module name. - wasm_import_module_name: Option<String>, - - /// The name of the dynamic library (if we are generating bindings for a shared library). If - /// this is None, no dynamic bindings are created. - dynamic_library_name: Option<String>, - - /// Require successful linkage for all routines in a shared library. - /// This allows us to optimize function calls by being able to safely assume function pointers - /// are valid. No effect if `dynamic_library_name` is None. - dynamic_link_require_all: bool, - - /// Only make generated bindings `pub` if the items would be publically accessible - /// by C++. - respect_cxx_access_specs: bool, - - /// Always translate enum integer types to native Rust integer types. - translate_enum_integer_types: bool, - - /// Generate types with C style naming. - c_naming: bool, - - /// Always output explicit padding fields - force_explicit_padding: bool, - - /// Emit vtable functions. - vtable_generation: bool, - - /// Sort the code generation. - sort_semantically: bool, - - /// Deduplicate `extern` blocks. - merge_extern_blocks: bool, - - abi_overrides: HashMap<Abi, RegexSet>, - - /// Whether to wrap unsafe operations in unsafe blocks or not. - wrap_unsafe_ops: bool, - - wrap_static_fns: bool, - - wrap_static_fns_suffix: Option<String>, - - wrap_static_fns_path: Option<PathBuf>, } impl BindgenOptions { fn build(&mut self) { - let regex_sets = [ + const REGEX_SETS_LEN: usize = 27; + + let regex_sets: [_; REGEX_SETS_LEN] = [ &mut self.allowlisted_vars, &mut self.allowlisted_types, &mut self.allowlisted_functions, @@ -2212,10 +460,69 @@ impl BindgenOptions { &mut self.no_hash_types, &mut self.must_use_types, ]; + let record_matches = self.record_matches; + #[cfg(feature = "experimental")] + { + let sets_len = REGEX_SETS_LEN + self.abi_overrides.len(); + let names = if self.emit_diagnostics { + <[&str; REGEX_SETS_LEN]>::into_iter([ + "--blocklist-type", + "--blocklist-function", + "--blocklist-item", + "--blocklist-file", + "--opaque-type", + "--allowlist-type", + "--allowlist-function", + "--allowlist-var", + "--allowlist-file", + "--bitfield-enum", + "--newtype-enum", + "--newtype-global-enum", + "--rustified-enum", + "--rustified-enum-non-exhaustive", + "--constified-enum-module", + "--constified-enum", + "--type-alias", + "--new-type-alias", + "--new-type-alias-deref", + "--bindgen-wrapper-union", + "--manually-drop-union", + "--no-partialeq", + "--no-copy", + "--no-debug", + "--no-default", + "--no-hash", + "--must-use", + ]) + .chain((0..self.abi_overrides.len()).map(|_| "--override-abi")) + .map(Some) + .collect() + } else { + vec![None; sets_len] + }; + + for (regex_set, name) in + self.abi_overrides.values_mut().chain(regex_sets).zip(names) + { + regex_set.build_with_diagnostics(record_matches, name); + } + } + #[cfg(not(feature = "experimental"))] for regex_set in self.abi_overrides.values_mut().chain(regex_sets) { regex_set.build(record_matches); } + + let rust_target = self.rust_target; + #[allow(deprecated)] + if rust_target <= RustTarget::Stable_1_30 { + deprecated_target_diagnostic(rust_target, self); + } + + // Disable `untagged_union` if the target does not support it. + if !self.rust_features.untagged_union { + self.untagged_union = false; + } } /// Update rust target version @@ -2260,121 +567,25 @@ impl BindgenOptions { } } -impl Default for BindgenOptions { - fn default() -> BindgenOptions { - macro_rules! options { - ($($field:ident $(: $value:expr)?,)* --default-fields-- $($default_field:ident,)*) => { - BindgenOptions { - $($field $(: $value)*,)* - $($default_field: Default::default(),)* - } - }; - } +fn deprecated_target_diagnostic(target: RustTarget, _options: &BindgenOptions) { + let target = String::from(target); + warn!("The {} Rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", target,); - let rust_target = RustTarget::default(); - - options! { - rust_target, - rust_features: rust_target.into(), - layout_tests: true, - derive_copy: true, - derive_debug: true, - anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(), - convert_floats: true, - codegen_config: CodegenConfig::all(), - generate_comments: true, - allowlist_recursively: true, - enable_mangling: true, - detect_include_paths: true, - prepend_enum_name: true, - record_matches: true, - rustfmt_bindings: true, - size_t_is_usize: true, - - --default-fields-- - blocklisted_types, - blocklisted_functions, - blocklisted_items, - blocklisted_files, - opaque_types, - rustfmt_path, - depfile, - allowlisted_types, - allowlisted_functions, - allowlisted_vars, - allowlisted_files, - default_enum_style, - bitfield_enums, - newtype_enums, - newtype_global_enums, - rustified_enums, - rustified_non_exhaustive_enums, - constified_enums, - constified_enum_modules, - default_macro_constant_type, - default_alias_style, - type_alias, - new_type_alias, - new_type_alias_deref, - default_non_copy_union_style, - bindgen_wrapper_union, - manually_drop_union, - builtins, - emit_ast, - emit_ir, - emit_ir_graphviz, - impl_debug, - impl_partialeq, - derive_default, - derive_hash, - derive_partialord, - derive_ord, - derive_partialeq, - derive_eq, - enable_cxx_namespaces, - enable_function_attribute_detection, - disable_name_namespacing, - disable_nested_struct_naming, - disable_header_comment, - use_core, - ctypes_prefix, - raw_lines, - module_lines, - clang_args, - input_headers, - input_header_contents, - parse_callbacks, - conservative_inline_namespaces, - generate_inline_functions, - generate_block, - objc_extern_crate, - block_extern_crate, - fit_macro_constants, - time_phases, - rustfmt_configuration_file, - no_partialeq_types, - no_copy_types, - no_debug_types, - no_default_types, - no_hash_types, - must_use_types, - array_pointers_in_arguments, - wasm_import_module_name, - dynamic_library_name, - dynamic_link_require_all, - respect_cxx_access_specs, - translate_enum_integer_types, - c_naming, - force_explicit_padding, - vtable_generation, - sort_semantically, - merge_extern_blocks, - abi_overrides, - wrap_unsafe_ops, - wrap_static_fns, - wrap_static_fns_suffix, - wrap_static_fns_path, - } + #[cfg(feature = "experimental")] + if _options.emit_diagnostics { + use crate::diagnostics::{Diagnostic, Level}; + + let mut diagnostic = Diagnostic::default(); + diagnostic.with_title( + format!("The {} Rust target is deprecated.", target), + Level::Warn, + ); + diagnostic.add_annotation( + "This Rust target was passed to `--rust-target`", + Level::Info, + ); + diagnostic.add_annotation("If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", Level::Help); + diagnostic.display(); } } @@ -2448,7 +659,6 @@ impl std::error::Error for BindgenError {} #[derive(Debug)] pub struct Bindings { options: BindgenOptions, - warnings: Vec<String>, module: proc_macro2::TokenStream, } @@ -2673,14 +883,10 @@ impl Bindings { parse(&mut context)?; } - let (module, options, warnings) = + let (module, options) = codegen::codegen(context).map_err(BindgenError::Codegen)?; - Ok(Bindings { - options, - warnings, - module, - }) + Ok(Bindings { options, module }) } /// Write these bindings as source text to a file. @@ -2697,7 +903,7 @@ impl Bindings { /// Write these bindings as source text to the given `Write`able. pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> { if !self.options.disable_header_comment { - let version = Some("0.64.0"); + let version = Some("0.65.1"); let header = format!( "/* automatically generated by rust-bindgen {} */\n\n", version.unwrap_or("(unknown version)") @@ -2714,18 +920,16 @@ impl Bindings { writer.write_all("\n".as_bytes())?; } - let bindings = self.module.to_string(); - - match self.rustfmt_generated_string(&bindings) { - Ok(rustfmt_bindings) => { - writer.write_all(rustfmt_bindings.as_bytes())?; + match self.format_tokens(&self.module) { + Ok(formatted_bindings) => { + writer.write_all(formatted_bindings.as_bytes())?; } Err(err) => { eprintln!( "Failed to run rustfmt: {} (non-fatal, continuing)", err ); - writer.write_all(bindings.as_bytes())?; + writer.write_all(self.module.to_string().as_bytes())?; } } Ok(()) @@ -2733,7 +937,7 @@ impl Bindings { /// Gets the rustfmt path to rustfmt the generated bindings. fn rustfmt_path(&self) -> io::Result<Cow<PathBuf>> { - debug_assert!(self.options.rustfmt_bindings); + debug_assert!(matches!(self.options.formatter, Formatter::Rustfmt)); if let Some(ref p) = self.options.rustfmt_path { return Ok(Cow::Borrowed(p)); } @@ -2753,16 +957,22 @@ impl Bindings { Ok(Cow::Owned("rustfmt".into())) } - /// Checks if rustfmt_bindings is set and runs rustfmt on the string - fn rustfmt_generated_string<'a>( + /// Formats a token stream with the formatter set up in `BindgenOptions`. + fn format_tokens( &self, - source: &'a str, - ) -> io::Result<Cow<'a, str>> { + tokens: &proc_macro2::TokenStream, + ) -> io::Result<String> { let _t = time::Timer::new("rustfmt_generated_string") .with_output(self.options.time_phases); - if !self.options.rustfmt_bindings { - return Ok(Cow::Borrowed(source)); + match self.options.formatter { + Formatter::None => return Ok(tokens.to_string()), + + #[cfg(feature = "prettyplease")] + Formatter::Prettyplease => { + return Ok(prettyplease::unparse(&syn::parse_quote!(#tokens))); + } + Formatter::Rustfmt => (), } let rustfmt = self.rustfmt_path()?; @@ -2783,7 +993,7 @@ impl Bindings { let mut child_stdin = child.stdin.take().unwrap(); let mut child_stdout = child.stdout.take().unwrap(); - let source = source.to_owned(); + let source = tokens.to_string(); // Write to stdin in a new thread, so that we can read from stdout on this // thread. This keeps the child from blocking on writing to its stdout which @@ -2804,39 +1014,42 @@ impl Bindings { match String::from_utf8(output) { Ok(bindings) => match status.code() { - Some(0) => Ok(Cow::Owned(bindings)), + Some(0) => Ok(bindings), Some(2) => Err(io::Error::new( io::ErrorKind::Other, "Rustfmt parsing errors.".to_string(), )), Some(3) => { - warn!("Rustfmt could not format some lines."); - Ok(Cow::Owned(bindings)) + rustfmt_non_fatal_error_diagnostic( + "Rustfmt could not format some lines", + &self.options, + ); + Ok(bindings) } _ => Err(io::Error::new( io::ErrorKind::Other, "Internal rustfmt error".to_string(), )), }, - _ => Ok(Cow::Owned(source)), + _ => Ok(source), } } +} - /// Emit all the warning messages raised while generating the bindings in a build script. - /// - /// If you are using `bindgen` outside of a build script you should use [`Bindings::warnings`] - /// and handle the messages accordingly instead. - #[inline] - pub fn emit_warnings(&self) { - for message in &self.warnings { - println!("cargo:warning={}", message); - } - } +fn rustfmt_non_fatal_error_diagnostic(msg: &str, _options: &BindgenOptions) { + warn!("{}", msg); - /// Return all the warning messages raised while generating the bindings. - #[inline] - pub fn warnings(&self) -> &[String] { - &self.warnings + #[cfg(feature = "experimental")] + if _options.emit_diagnostics { + use crate::diagnostics::{Diagnostic, Level}; + + Diagnostic::default() + .with_title(msg, Level::Warn) + .add_annotation( + "The bindings will be generated but not formatted.", + Level::Note, + ) + .display(); } } @@ -2962,22 +1175,38 @@ pub fn clang_version() -> ClangVersion { } } +fn env_var<K: AsRef<str> + AsRef<OsStr>>( + parse_callbacks: &[Rc<dyn callbacks::ParseCallbacks>], + key: K, +) -> Result<String, std::env::VarError> { + for callback in parse_callbacks { + callback.read_env_var(key.as_ref()); + } + std::env::var(key) +} + /// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found. -fn get_target_dependent_env_var(var: &str) -> Option<String> { - if let Ok(target) = env::var("TARGET") { - if let Ok(v) = env::var(format!("{}_{}", var, target)) { +fn get_target_dependent_env_var( + parse_callbacks: &[Rc<dyn callbacks::ParseCallbacks>], + var: &str, +) -> Option<String> { + if let Ok(target) = env_var(parse_callbacks, "TARGET") { + if let Ok(v) = env_var(parse_callbacks, format!("{}_{}", var, target)) { return Some(v); } - if let Ok(v) = env::var(format!("{}_{}", var, target.replace('-', "_"))) - { + if let Ok(v) = env_var( + parse_callbacks, + format!("{}_{}", var, target.replace('-', "_")), + ) { return Some(v); } } - env::var(var).ok() + + env_var(parse_callbacks, var).ok() } /// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed -/// line +/// line and on env variable usage by echoing a rerun-if-env-changed line /// /// When running inside a `build.rs` script, this can be used to make cargo invalidate the /// generated bindings whenever any of the files included from the header change: @@ -2995,6 +1224,10 @@ impl callbacks::ParseCallbacks for CargoCallbacks { fn include_file(&self, filename: &str) { println!("cargo:rerun-if-changed={}", filename); } + + fn read_env_var(&self, key: &str) { + println!("cargo:rerun-if-env-changed={}", key); + } } /// Test command_line_flag function. diff --git a/options/as_args.rs b/options/as_args.rs new file mode 100644 index 0000000..13439c4 --- /dev/null +++ b/options/as_args.rs @@ -0,0 +1,52 @@ +use std::path::PathBuf; + +use crate::RegexSet; + +/// Trait used to turn [`crate::BindgenOptions`] fields into CLI args. +pub(super) trait AsArgs { + fn as_args(&self, args: &mut Vec<String>, flag: &str); +} + +/// If the `bool` is `true`, `flag` is pushed into `args`. +/// +/// be careful about the truth value of the field as some options, like `--no-layout-tests`, are +/// actually negations of the fields. +impl AsArgs for bool { + fn as_args(&self, args: &mut Vec<String>, flag: &str) { + if *self { + args.push(flag.to_string()); + } + } +} + +/// Iterate over all the items of the `RegexSet` and push `flag` followed by the item into `args` +/// for each item. +impl AsArgs for RegexSet { + fn as_args(&self, args: &mut Vec<String>, flag: &str) { + for item in self.get_items() { + args.extend_from_slice(&[flag.to_owned(), item.clone()]); + } + } +} + +/// If the `Option` is `Some(value)`, push `flag` followed by `value`. +impl AsArgs for Option<String> { + fn as_args(&self, args: &mut Vec<String>, flag: &str) { + if let Some(string) = self { + args.extend_from_slice(&[flag.to_owned(), string.clone()]); + } + } +} + +/// If the `Option` is `Some(path)`, push `flag` followed by the [`std::path::Path::display`] +/// representation of `path`. +impl AsArgs for Option<PathBuf> { + fn as_args(&self, args: &mut Vec<String>, flag: &str) { + if let Some(path) = self { + args.extend_from_slice(&[ + flag.to_owned(), + path.display().to_string(), + ]); + } + } +} diff --git a/options/helpers.rs b/options/helpers.rs new file mode 100644 index 0000000..1816c72 --- /dev/null +++ b/options/helpers.rs @@ -0,0 +1,43 @@ +/// Helper function that appends extra documentation to [`crate::Builder`] methods that support regular +/// expressions in their input. +macro_rules! regex_option { + ($(#[$attrs:meta])* pub fn $($tokens:tt)*) => { + $(#[$attrs])* + /// + /// Regular expressions are supported. Check the [regular expression + /// arguments](./struct.Builder.html#regular-expression-arguments) section and the + /// [regex](https://docs.rs/regex) crate documentation for further information. + pub fn $($tokens)* + }; +} + +/// Helper macro to set the default value of each option. +/// +/// This macro is an internal implementation detail of the `options` macro and should not be used +/// directly. +macro_rules! default { + () => { + Default::default() + }; + ($expr:expr) => { + $expr + }; +} + +/// Helper macro to set the conversion to CLI arguments for each option. +/// +/// This macro is an internal implementation detail of the `options` macro and should not be used +/// directly. +macro_rules! as_args { + ($flag:literal) => { + |field, args| AsArgs::as_args(field, args, $flag) + }; + ($expr:expr) => { + $expr + }; +} + +/// Helper function to ignore an option when converting it into CLI arguments. +/// +/// This function is only used inside `options` and should not be used in other contexts. +pub(super) fn ignore<T>(_: &T, _: &mut Vec<String>) {} diff --git a/options/mod.rs b/options/mod.rs new file mode 100644 index 0000000..c60da71 --- /dev/null +++ b/options/mod.rs @@ -0,0 +1,2008 @@ +//! Declarations and setter methods for `bindgen` options. +//! +//! The main entry point of this module is the `options` macro. +#[macro_use] +mod helpers; +mod as_args; + +use crate::callbacks::ParseCallbacks; +use crate::codegen::{ + AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, +}; +use crate::deps::DepfileSpec; +use crate::features::{RustFeatures, RustTarget}; +use crate::regex_set::RegexSet; +use crate::Abi; +use crate::Builder; +use crate::CodegenConfig; +use crate::FieldVisibilityKind; +use crate::Formatter; +use crate::HashMap; +use crate::DEFAULT_ANON_FIELDS_PREFIX; + +use std::env; +#[cfg(feature = "experimental")] +use std::path::Path; +use std::path::PathBuf; +use std::rc::Rc; + +use as_args::AsArgs; +use helpers::ignore; + +/// Macro used to generate the [`BindgenOptions`] type and the [`Builder`] setter methods for each +/// one of the fields of `BindgenOptions`. +/// +/// The input format of this macro resembles a `struct` pattern. Each field of the `BindgenOptions` +/// type is declared by adding the name of the field and its type using the `name: type` syntax and +/// a block of code with the following items: +/// +/// - `default`: The default value for the field. If this item is omitted, `Default::default()` is +/// used instead, meaning that the type of the field must implement `Default`. +/// - `methods`: A block of code containing methods for the `Builder` type. These methods should be +/// related to the field being declared. +/// - `as_args`: This item declares how the field should be converted into a valid CLI argument for +/// `bindgen` and is used in the [`Builder::command_line_flags`] method which is used to do a +/// roundtrip test of the CLI args in the `bindgen-test` crate. This item can take one of the +/// following: +/// - A string literal with the flag if the type of the field implements the [`AsArgs`] trait. +/// - A closure with the signature `|field, args: &mut Vec<String>| -> ()` that pushes arguments +/// into the `args` buffer based on the value of the field. This is used if the field does not +/// implement `AsArgs` or if the implementation of the trait is not logically correct for the +/// option and a custom behavior must be taken into account. +/// - The `ignore` literal, which does not emit any CLI arguments for this field. This is useful +/// if the field cannot be used from the `bindgen` CLI. +/// +/// As an example, this would be the declaration of a `bool` field called `be_fun` whose default +/// value is `false` (the `Default` value for `bool`): +/// ```rust,ignore +/// be_fun: bool { +/// methods: { +/// /// Ask `bindgen` to be fun. This option is disabled by default. +/// fn be_fun(mut self) -> Self { +/// self.options.be_fun = true; +/// self +/// } +/// }, +/// as_args: "--be-fun", +/// } +/// ``` +/// +/// However, we could also set the `be_fun` field to `true` by default and use a `--not-fun` flag +/// instead. This means that we have to add the `default` item and use a closure in the `as_args` +/// item: +/// ```rust,ignore +/// be_fun: bool { +/// default: true, +/// methods: { +/// /// Ask `bindgen` to not be fun. `bindgen` is fun by default. +/// fn not_fun(mut self) -> Self { +/// self.options.be_fun = false; +/// self +/// } +/// }, +/// as_args: |be_fun, args| (!be_fun).as_args(args, "--not-fun"), +/// } +/// ``` +/// More complex examples can be found in the sole invocation of this macro. +macro_rules! options { + ($( + $(#[doc = $docs:literal])+ + $field:ident: $ty:ty { + $(default: $default:expr,)? + methods: {$($methods_tokens:tt)*}$(,)? + as_args: $as_args:expr$(,)? + }$(,)? + )*) => { + #[derive(Debug, Clone)] + pub(crate) struct BindgenOptions { + $($(#[doc = $docs])* pub(crate) $field: $ty,)* + } + + impl Default for BindgenOptions { + fn default() -> Self { + Self { + $($field: default!($($default)*),)* + } + } + } + + impl Builder { + /// Generates the command line flags used to create this [`Builder`]. + pub fn command_line_flags(&self) -> Vec<String> { + let mut args = vec![]; + + let headers = match self.options.input_headers.split_last() { + Some((header, headers)) => { + // The last input header is passed as an argument in the first position. + args.push(header.clone()); + headers + }, + None => &[] + }; + + $({ + let func: fn(&$ty, &mut Vec<String>) = as_args!($as_args); + func(&self.options.$field, &mut args); + })* + + // Add the `--experimental` flag if `bindgen` is built with the `experimental` + // feature. + if cfg!(feature = "experimental") { + args.push("--experimental".to_owned()); + } + + // Add all the clang arguments. + args.push("--".to_owned()); + + if !self.options.clang_args.is_empty() { + args.extend_from_slice(&self.options.clang_args); + } + + // We need to pass all but the last header via the `-include` clang argument. + for header in headers { + args.push("-include".to_owned()); + args.push(header.clone()); + } + + args + } + + $($($methods_tokens)*)* + } + }; +} + +options! { + /// Types that have been blocklisted and should not appear anywhere in the generated code. + blocklisted_types: RegexSet { + methods: { + regex_option! { + /// Do not generate any bindings for the given type. + pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_types.insert(arg); + self + } + } + }, + as_args: "--blocklist-type", + }, + /// Functions that have been blocklisted and should not appear in the generated code. + blocklisted_functions: RegexSet { + methods: { + regex_option! { + /// Do not generate any bindings for the given function. + pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_functions.insert(arg); + self + } + } + }, + as_args: "--blocklist-function", + }, + /// Items that have been blocklisted and should not appear in the generated code. + blocklisted_items: RegexSet { + methods: { + regex_option! { + /// Do not generate any bindings for the given item, regardless of whether it is a + /// type, function, module, etc. + pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_items.insert(arg); + self + } + } + }, + as_args: "--blocklist-item", + }, + /// Files whose contents should be blocklisted and should not appear in the generated code. + blocklisted_files: RegexSet { + methods: { + regex_option! { + /// Do not generate any bindings for the contents of the given file, regardless of + /// whether the contents of the file are types, functions, modules, etc. + pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_files.insert(arg); + self + } + } + }, + as_args: "--blocklist-file", + }, + /// Types that should be treated as opaque structures in the generated code. + opaque_types: RegexSet { + methods: { + regex_option! { + /// Treat the given type as opaque in the generated bindings. + /// + /// Opaque in this context means that none of the generated bindings will contain + /// information about the inner representation of the type and the type itself will + /// be represented as a chunk of bytes with the alignment and size of the type. + pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.opaque_types.insert(arg); + self + } + } + }, + as_args: "--opaque-type", + }, + /// The explicit `rustfmt` path. + rustfmt_path: Option<PathBuf> { + methods: { + /// Set an explicit path to the `rustfmt` binary. + /// + /// This option only comes into effect if `rustfmt` is set to be the formatter used by + /// `bindgen`. Check the documentation of the [`Builder::formatter`] method for more + /// information. + pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self { + self.options.rustfmt_path = Some(path.into()); + self + } + }, + // This option cannot be set from the CLI. + as_args: ignore, + }, + /// The path to which we should write a Makefile-syntax depfile (if any). + depfile: Option<DepfileSpec> { + methods: { + /// Add a depfile output which will be written alongside the generated bindings. + pub fn depfile<H: Into<String>, D: Into<PathBuf>>( + mut self, + output_module: H, + depfile: D, + ) -> Builder { + self.options.depfile = Some(DepfileSpec { + output_module: output_module.into(), + depfile_path: depfile.into(), + }); + self + } + }, + as_args: |depfile, args| { + if let Some(depfile) = depfile { + args.push("--depfile".into()); + args.push(depfile.depfile_path.display().to_string()); + } + }, + }, + /// Types that have been allowlisted and should appear in the generated code. + allowlisted_types: RegexSet { + methods: { + regex_option! { + /// Generate bindings for the given type. + /// + /// This option is transitive by default. Check the documentation of the + /// [`Builder::allowlist_recursively`] method for further information. + pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_types.insert(arg); + self + } + } + }, + as_args: "--allowlist-type", + }, + /// Functions that have been allowlisted and should appear in the generated code. + allowlisted_functions: RegexSet { + methods: { + regex_option! { + /// Generate bindings for the given function. + /// + /// This option is transitive by default. Check the documentation of the + /// [`Builder::allowlist_recursively`] method for further information. + pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_functions.insert(arg); + self + } + } + }, + as_args: "--allowlist-function", + }, + /// Variables that have been allowlisted and should appear in the generated code. + allowlisted_vars: RegexSet { + methods: { + regex_option! { + /// Generate bindings for the given variable. + /// + /// This option is transitive by default. Check the documentation of the + /// [`Builder::allowlist_recursively`] method for further information. + pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_vars.insert(arg); + self + } + } + }, + as_args: "--allowlist-var", + }, + /// Files whose contents have been allowlisted and should appear in the generated code. + allowlisted_files: RegexSet { + methods: { + regex_option! { + /// Generate bindings for the content of the given file. + /// + /// This option is transitive by default. Check the documentation of the + /// [`Builder::allowlist_recursively`] method for further information. + pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_files.insert(arg); + self + } + } + }, + as_args: "--allowlist-file", + }, + /// The default style of for generated `enum`s. + default_enum_style: EnumVariation { + methods: { + /// Set the default style for generated `enum`s. + /// + /// If this method is not called, the [`EnumVariation::Consts`] style will be used by + /// default. + /// + /// To set the style for individual `enum`s, use [`Builder::bitfield_enum`], + /// [`Builder::newtype_enum`], [`Builder::newtype_global_enum`], + /// [`Builder::rustified_enum`], [`Builder::rustified_non_exhaustive_enum`], + /// [`Builder::constified_enum_module`] or [`Builder::constified_enum`]. + pub fn default_enum_style( + mut self, + arg: EnumVariation, + ) -> Builder { + self.options.default_enum_style = arg; + self + } + }, + as_args: |variation, args| { + if *variation != Default::default() { + args.push("--default-enum-style".to_owned()); + args.push(variation.to_string()); + } + }, + }, + /// `enum`s marked as bitfield-like. This is, newtypes with bitwise operations. + bitfield_enums: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as being bitfield-like. + /// + /// This is similar to the [`Builder::newtype_enum`] style, but with the bitwise + /// operators implemented. + pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.bitfield_enums.insert(arg); + self + } + } + }, + as_args: "--bitfield-enum", + }, + /// `enum`s marked as newtypes. + newtype_enums: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as a newtype. + /// + /// This means that an integer newtype will be declared to represent the `enum` + /// type and its variants will be represented as constants inside of this type's + /// `impl` block. + pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.newtype_enums.insert(arg); + self + } + } + }, + as_args: "--newtype-enum", + }, + /// `enum`s marked as global newtypes . + newtype_global_enums: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as a global newtype. + /// + /// This is similar to the [`Builder::newtype_enum`] style, but the constants for + /// each variant are free constants instead of being declared inside an `impl` + /// block for the newtype. + pub fn newtype_global_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.newtype_global_enums.insert(arg); + self + } + } + }, + as_args: "--newtype-global-enum", + }, + /// `enum`s marked as Rust `enum`s. + rustified_enums: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as a Rust `enum`. + /// + /// This means that each variant of the `enum` will be represented as a Rust `enum` + /// variant. + /// + /// **Use this with caution**, creating an instance of a Rust `enum` with an + /// invalid value will cause undefined behaviour. To avoid this, use the + /// [`Builder::newtype_enum`] style instead. + pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.rustified_enums.insert(arg); + self + } + } + }, + as_args: "--rustified-enum", + }, + /// `enum`s marked as non-exhaustive Rust `enum`s. + rustified_non_exhaustive_enums: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as a non-exhaustive Rust `enum`. + /// + /// This is similar to the [`Builder::rustified_enum`] style, but the `enum` is + /// tagged with the `#[non_exhaustive]` attribute. + pub fn rustified_non_exhaustive_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.rustified_non_exhaustive_enums.insert(arg); + self + } + } + }, + as_args: "--rustified-non-exhaustive-enums", + }, + /// `enum`s marked as modules of constants. + constified_enum_modules: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as a module with a set of integer constants. + pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.constified_enum_modules.insert(arg); + self + } + } + }, + as_args: "--constified-enum-module", + }, + /// `enum`s marked as a set of constants. + constified_enums: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as a set o integer constants. + /// + /// This is similar to the [`Builder::constified_enum_module`] style, but the + /// constants are generated in the current module instead of in a new module. + pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.constified_enums.insert(arg); + self + } + } + }, + as_args: "--constified-enum", + }, + /// The default type signedness for C macro constants. + default_macro_constant_type: MacroTypeVariation { + methods: { + /// Set the default type signedness to be used for macro constants. + /// + /// If this method is not called, [`MacroTypeVariation::Unsigned`] is used by default. + /// + /// To set the type for individual macro constants, use the + /// [`ParseCallbacks::int_macro`] method. + pub fn default_macro_constant_type(mut self, arg: MacroTypeVariation) -> Builder { + self.options.default_macro_constant_type = arg; + self + } + + }, + as_args: |variation, args| { + if *variation != Default::default() { + args.push("--default-macro-constant-type".to_owned()); + args.push(variation.to_string()); + } + }, + }, + /// The default style of code generation for `typedef`s. + default_alias_style: AliasVariation { + methods: { + /// Set the default style of code generation for `typedef`s. + /// + /// If this method is not called, the [`AliasVariation::TypeAlias`] style is used by + /// default. + /// + /// To set the style for individual `typedefs`s, use [`Builder::type_alias`], + /// [`Builder::new_type_alias`] or [`Builder::new_type_alias_deref`]. + pub fn default_alias_style( + mut self, + arg: AliasVariation, + ) -> Builder { + self.options.default_alias_style = arg; + self + } + }, + as_args: |variation, args| { + if *variation != Default::default() { + args.push("--default-alias-style".to_owned()); + args.push(variation.to_string()); + } + }, + }, + /// `typedef` patterns that will use regular type aliasing. + type_alias: RegexSet { + methods: { + regex_option! { + /// Mark the given `typedef` as a regular Rust `type` alias. + /// + /// This is the default behavior, meaning that this method only comes into effect + /// if a style different from [`AliasVariation::TypeAlias`] was passed to the + /// [`Builder::default_alias_style`] method. + pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.type_alias.insert(arg); + self + } + } + }, + as_args: "--type-alias", + }, + /// `typedef` patterns that will be aliased by creating a newtype. + new_type_alias: RegexSet { + methods: { + regex_option! { + /// Mark the given `typedef` as a Rust newtype by having the aliased + /// type be wrapped in a `struct` with `#[repr(transparent)]`. + /// + /// This method can be used to enforce stricter type checking. + pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.new_type_alias.insert(arg); + self + } + } + }, + as_args: "--new-type-alias", + }, + /// `typedef` patterns that will be wrapped in a newtype implementing `Deref` and `DerefMut`. + new_type_alias_deref: RegexSet { + methods: { + regex_option! { + /// Mark the given `typedef` to be generated as a newtype that can be dereferenced. + /// + /// This is similar to the [`Builder::new_type_alias`] style, but the newtype + /// implements `Deref` and `DerefMut` with the aliased type as a target. + pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.new_type_alias_deref.insert(arg); + self + } + } + }, + as_args: "--new-type-alias-deref", + }, + /// The default style of code to generate for `union`s containing non-`Copy` members. + default_non_copy_union_style: NonCopyUnionStyle { + methods: { + /// Set the default style of code to generate for `union`s with non-`Copy` members. + /// + /// If this method is not called, the [`NonCopyUnionStyle::BindgenWrapper`] style is + /// used by default. + /// + /// To set the style for individual `union`s, use [`Builder::bindgen_wrapper_union`] or + /// [`Builder::manually_drop_union`]. + pub fn default_non_copy_union_style(mut self, arg: NonCopyUnionStyle) -> Self { + self.options.default_non_copy_union_style = arg; + self + } + }, + as_args: |style, args| { + if *style != Default::default() { + args.push("--default-non-copy-union-style".to_owned()); + args.push(style.to_string()); + } + }, + }, + /// The patterns marking non-`Copy` `union`s as using the `bindgen` generated wrapper. + bindgen_wrapper_union: RegexSet { + methods: { + regex_option! { + /// Mark the given `union` to use a `bindgen`-generated wrapper for its members if at + /// least one them is not `Copy`. + /// + /// This is the default behavior, meaning that this method only comes into effect + /// if a style different from [`NonCopyUnionStyle::BindgenWrapper`] was passed to + /// the [`Builder::default_non_copy_union_style`] method. + pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self { + self.options.bindgen_wrapper_union.insert(arg); + self + } + } + }, + as_args: "--bindgen-wrapper-union", + }, + /// The patterns marking non-`Copy` `union`s as using the `ManuallyDrop` wrapper. + manually_drop_union: RegexSet { + methods: { + regex_option! { + /// Mark the given `union` to use [`::core::mem::ManuallyDrop`] for its members if + /// at least one of them is not `Copy`. + /// + /// The `ManuallyDrop` type was stabilized in Rust 1.20.0, do not use this option + /// if your target version is lower than this. + pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self { + self.options.manually_drop_union.insert(arg); + self + } + } + + }, + as_args: "--manually-drop-union", + }, + + + /// Whether we should generate built-in definitions. + builtins: bool { + methods: { + /// Generate Rust bindings for built-in definitions (for example `__builtin_va_list`). + /// + /// Bindings for built-in definitions are not emitted by default. + pub fn emit_builtins(mut self) -> Builder { + self.options.builtins = true; + self + } + }, + as_args: "--builtins", + }, + /// Whether we should dump the Clang AST for debugging purposes. + emit_ast: bool { + methods: { + /// Emit the Clang AST to `stdout` for debugging purposes. + /// + /// The Clang AST is not emitted by default. + pub fn emit_clang_ast(mut self) -> Builder { + self.options.emit_ast = true; + self + } + }, + as_args: "--emit-clang-ast", + }, + /// Whether we should dump our IR for debugging purposes. + emit_ir: bool { + methods: { + /// Emit the `bindgen` internal representation to `stdout` for debugging purposes. + /// + /// This internal representation is not emitted by default. + pub fn emit_ir(mut self) -> Builder { + self.options.emit_ir = true; + self + } + }, + as_args: "--emit-ir", + }, + /// Output path for the `graphviz` DOT file. + emit_ir_graphviz: Option<String> { + methods: { + /// Set the path for the file where the`bindgen` internal representation will be + /// emitted as a graph using the `graphviz` DOT language. + /// + /// This graph representation is not emitted by default. + pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder { + let path = path.into(); + self.options.emit_ir_graphviz = Some(path); + self + } + }, + as_args: "--emit-ir-graphviz", + }, + + /// Whether we should emulate C++ namespaces with Rust modules. + enable_cxx_namespaces: bool { + methods: { + /// Emulate C++ namespaces using Rust modules in the generated bindings. + /// + /// C++ namespaces are not emulated by default. + pub fn enable_cxx_namespaces(mut self) -> Builder { + self.options.enable_cxx_namespaces = true; + self + } + }, + as_args: "--enable-cxx-namespaces", + }, + /// Whether we should try to find unexposed attributes in functions. + enable_function_attribute_detection: bool { + methods: { + /// Enable detecting function attributes on C functions. + /// + /// This enables the following features: + /// - Add `#[must_use]` attributes to Rust items whose C counterparts are marked as so. + /// This feature also requires that the Rust target version supports the attribute. + /// - Set `!` as the return type for Rust functions whose C counterparts are marked as + /// diverging. + /// + /// This option can be quite slow in some cases (check [#1465]), so it is disabled by + /// default. + /// + /// [#1465]: https://github.com/rust-lang/rust-bindgen/issues/1465 + pub fn enable_function_attribute_detection(mut self) -> Self { + self.options.enable_function_attribute_detection = true; + self + } + + }, + as_args: "--enable-function-attribute-detection", + }, + /// Whether we should avoid mangling names with namespaces. + disable_name_namespacing: bool { + methods: { + /// Disable name auto-namespacing. + /// + /// By default, `bindgen` mangles names like `foo::bar::Baz` to look like `foo_bar_Baz` + /// instead of just `Baz`. This method disables that behavior. + /// + /// Note that this does not change the names used for allowlisting and blocklisting, + /// which should still be mangled with the namespaces. Additionally, this option may + /// cause `bindgen` to generate duplicate names. + pub fn disable_name_namespacing(mut self) -> Builder { + self.options.disable_name_namespacing = true; + self + } + }, + as_args: "--disable-name-namespacing", + }, + /// Whether we should avoid generating nested `struct` names. + disable_nested_struct_naming: bool { + methods: { + /// Disable nested `struct` naming. + /// + /// The following `struct`s have different names for C and C++. In C, they are visible + /// as `foo` and `bar`. In C++, they are visible as `foo` and `foo::bar`. + /// + /// ```c + /// struct foo { + /// struct bar { + /// } b; + /// }; + /// ``` + /// + /// `bindgen` tries to avoid duplicate names by default, so it follows the C++ naming + /// convention and it generates `foo` and `foo_bar` instead of just `foo` and `bar`. + /// + /// This method disables this behavior and it is indented to be used only for headers + /// that were written in C. + pub fn disable_nested_struct_naming(mut self) -> Builder { + self.options.disable_nested_struct_naming = true; + self + } + }, + as_args: "--disable-nested-struct-naming", + }, + /// Whether we should avoid embedding version identifiers into source code. + disable_header_comment: bool { + methods: { + /// Do not insert the `bindgen` version identifier into the generated bindings. + /// + /// This identifier is inserted by default. + pub fn disable_header_comment(mut self) -> Self { + self.options.disable_header_comment = true; + self + } + + }, + as_args: "--disable-header-comment", + }, + /// Whether we should generate layout tests for generated `struct`s. + layout_tests: bool { + default: true, + methods: { + /// Set whether layout tests should be generated. + /// + /// Layout tests are generated by default. + pub fn layout_tests(mut self, doit: bool) -> Self { + self.options.layout_tests = doit; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-layout-tests"), + }, + /// Whether we should implement `Debug` for types that cannot derive it. + impl_debug: bool { + methods: { + /// Set whether `Debug` should be implemented for types that cannot derive it. + /// + /// This option is disabled by default. + pub fn impl_debug(mut self, doit: bool) -> Self { + self.options.impl_debug = doit; + self + } + + }, + as_args: "--impl-debug", + }, + /// Whether we should implement `PartialEq` types that cannot derive it. + impl_partialeq: bool { + methods: { + /// Set whether `PartialEq` should be implemented for types that cannot derive it. + /// + /// This option is disabled by default. + pub fn impl_partialeq(mut self, doit: bool) -> Self { + self.options.impl_partialeq = doit; + self + } + }, + as_args: "--impl-partialeq", + }, + /// Whether we should derive `Copy` when possible. + derive_copy: bool { + default: true, + methods: { + /// Set whether the `Copy` trait should be derived when possible. + /// + /// `Copy` is derived by default. + pub fn derive_copy(mut self, doit: bool) -> Self { + self.options.derive_copy = doit; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-derive-copy"), + }, + + /// Whether we should derive `Debug` when possible. + derive_debug: bool { + default: true, + methods: { + /// Set whether the `Debug` trait should be derived when possible. + /// + /// The [`Builder::impl_debug`] method can be used to implement `Debug` for types that + /// cannot derive it. + /// + /// `Debug` is derived by default. + pub fn derive_debug(mut self, doit: bool) -> Self { + self.options.derive_debug = doit; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-derive-debug"), + }, + + /// Whether we should derive `Default` when possible. + derive_default: bool { + methods: { + /// Set whether the `Default` trait should be derived when possible. + /// + /// `Default` is not derived by default. + pub fn derive_default(mut self, doit: bool) -> Self { + self.options.derive_default = doit; + self + } + }, + as_args: |&value, args| { + let arg = if value { + "--with-derive-default" + } else { + "--no-derive-default" + }; + + args.push(arg.to_owned()); + }, + }, + /// Whether we should derive `Hash` when possible. + derive_hash: bool { + methods: { + /// Set whether the `Hash` trait should be derived when possible. + /// + /// `Hash` is not derived by default. + pub fn derive_hash(mut self, doit: bool) -> Self { + self.options.derive_hash = doit; + self + } + }, + as_args: "--with-derive-hash", + }, + /// Whether we should derive `PartialOrd` when possible. + derive_partialord: bool { + methods: { + /// Set whether the `PartialOrd` trait should be derived when possible. + /// + /// Take into account that `Ord` cannot be derived for a type that does not implement + /// `PartialOrd`. For this reason, setting this method to `false` also sets + /// automatically [`Builder::derive_ord`] to `false`. + /// + /// `PartialOrd` is not derived by default. + pub fn derive_partialord(mut self, doit: bool) -> Self { + self.options.derive_partialord = doit; + if !doit { + self.options.derive_ord = false; + } + self + } + }, + as_args: "--with-derive-partialord", + }, + /// Whether we should derive `Ord` when possible. + derive_ord: bool { + methods: { + /// Set whether the `Ord` trait should be derived when possible. + /// + /// Take into account that `Ord` cannot be derived for a type that does not implement + /// `PartialOrd`. For this reason, the value set with this method will also be set + /// automatically for [`Builder::derive_partialord`]. + /// + /// `Ord` is not derived by default. + pub fn derive_ord(mut self, doit: bool) -> Self { + self.options.derive_ord = doit; + self.options.derive_partialord = doit; + self + } + }, + as_args: "--with-derive-ord", + }, + /// Whether we should derive `PartialEq` when possible. + derive_partialeq: bool { + methods: { + /// Set whether the `PartialEq` trait should be derived when possible. + /// + /// Take into account that `Eq` cannot be derived for a type that does not implement + /// `PartialEq`. For this reason, setting this method to `false` also sets + /// automatically [`Builder::derive_eq`] to `false`. + /// + /// The [`Builder::impl_partialeq`] method can be used to implement `PartialEq` for + /// types that cannot derive it. + /// + /// `PartialEq` is not derived by default. + pub fn derive_partialeq(mut self, doit: bool) -> Self { + self.options.derive_partialeq = doit; + if !doit { + self.options.derive_eq = false; + } + self + } + }, + as_args: "--with-derive-partialeq", + }, + /// Whether we should derive `Eq` when possible. + derive_eq: bool { + methods: { + /// Set whether the `Eq` trait should be derived when possible. + /// + /// Take into account that `Eq` cannot be derived for a type that does not implement + /// `PartialEq`. For this reason, the value set with this method will also be set + /// automatically for [`Builder::derive_partialeq`]. + /// + /// `Eq` is not derived by default. + pub fn derive_eq(mut self, doit: bool) -> Self { + self.options.derive_eq = doit; + if doit { + self.options.derive_partialeq = doit; + } + self + } + }, + as_args: "--with-derive-eq", + }, + /// Whether we should use `core` instead of `std`. + /// + /// If this option is enabled and the Rust target version is greater than 1.64, the prefix for + /// C platform-specific types will be `::core::ffi` instead of `::core::os::raw`. + use_core: bool { + methods: { + /// Use `core` instead of `std` in the generated bindings. + /// + /// `std` is used by default. + pub fn use_core(mut self) -> Builder { + self.options.use_core = true; + self + } + + }, + as_args: "--use-core", + }, + /// An optional prefix for the C platform-specific types. + ctypes_prefix: Option<String> { + methods: { + /// Use the given prefix for the C platform-specific types instead of `::std::os::raw`. + /// + /// Alternatively, the [`Builder::use_core`] method can be used to set the prefix to + /// `::core::ffi` or `::core::os::raw`. + pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { + self.options.ctypes_prefix = Some(prefix.into()); + self + } + }, + as_args: "--ctypes-prefix", + }, + /// The prefix for anonymous fields. + anon_fields_prefix: String { + default: DEFAULT_ANON_FIELDS_PREFIX.into(), + methods: { + /// Use the given prefix for the anonymous fields. + /// + /// An anonymous field, is a field of a C/C++ type that does not have a name. For + /// example, in the following C code: + /// ```c + /// struct integer { + /// struct { + /// int inner; + /// }; + /// } + /// ``` + /// + /// The only field of the `integer` `struct` is an anonymous field and its Rust + /// representation will be named using this prefix followed by an integer identifier. + /// + /// The default prefix is `__bindgen_anon_`. + pub fn anon_fields_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { + self.options.anon_fields_prefix = prefix.into(); + self + } + }, + as_args: |prefix, args| { + if prefix != DEFAULT_ANON_FIELDS_PREFIX { + args.push("--anon-fields-prefix".to_owned()); + args.push(prefix.clone()); + } + }, + }, + /// Whether to measure the time for each one of the `bindgen` phases. + time_phases: bool { + methods: { + /// Set whether to measure the elapsed time for each one of the `bindgen` phases. This + /// information is printed to `stderr`. + /// + /// The elapsed time is not measured by default. + pub fn time_phases(mut self, doit: bool) -> Self { + self.options.time_phases = doit; + self + } + }, + as_args: "--time-phases", + }, + /// Whether to convert C float types to `f32` and `f64`. + convert_floats: bool { + default: true, + methods: { + /// Avoid converting C float types to `f32` and `f64`. + pub fn no_convert_floats(mut self) -> Self { + self.options.convert_floats = false; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-convert-floats"), + }, + /// The set of raw lines to be prepended to the top-level module of the generated Rust code. + raw_lines: Vec<String> { + methods: { + /// Add a line of Rust code at the beginning of the generated bindings. The string is + /// passed through without any modification. + pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self { + self.options.raw_lines.push(arg.into()); + self + } + }, + as_args: |raw_lines, args| { + for line in raw_lines { + args.push("--raw-line".to_owned()); + args.push(line.clone()); + } + }, + }, + /// The set of raw lines to prepend to different modules. + module_lines: HashMap<String, Vec<String>> { + methods: { + /// Add a given line to the beginning of a given module. + /// + /// This option only comes into effect if the [`Builder::enable_cxx_namespaces`] method + /// is also being called. + pub fn module_raw_line<T, U>(mut self, module: T, line: U) -> Self + where + T: Into<String>, + U: Into<String>, + { + self.options + .module_lines + .entry(module.into()) + .or_insert_with(Vec::new) + .push(line.into()); + self + } + }, + as_args: |module_lines, args| { + for (module, lines) in module_lines { + for line in lines.iter() { + args.push("--module-raw-line".to_owned()); + args.push(module.clone()); + args.push(line.clone()); + } + } + }, + }, + /// The input header files. + input_headers: Vec<String> { + methods: { + /// Add an input C/C++ header to generate bindings for. + /// + /// This can be used to generate bindings for a single header: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .header("input.h") + /// .generate() + /// .unwrap(); + /// ``` + /// + /// Or for multiple headers: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .header("first.h") + /// .header("second.h") + /// .header("third.h") + /// .generate() + /// .unwrap(); + /// ``` + pub fn header<T: Into<String>>(mut self, header: T) -> Builder { + self.options.input_headers.push(header.into()); + self + } + }, + // This field is handled specially inside the macro. + as_args: ignore, + }, + /// The set of arguments to be passed straight through to Clang. + clang_args: Vec<String> { + methods: { + /// Add an argument to be passed straight through to Clang. + pub fn clang_arg<T: Into<String>>(self, arg: T) -> Builder { + self.clang_args([arg.into()]) + } + + /// Add several arguments to be passed straight through to Clang. + pub fn clang_args<I: IntoIterator>(mut self, args: I) -> Builder + where + I::Item: AsRef<str>, + { + for arg in args { + self.options.clang_args.push(arg.as_ref().to_owned()); + } + self + } + }, + // This field is handled specially inside the macro. + as_args: ignore, + }, + /// Tuples of unsaved file contents of the form (name, contents). + input_header_contents: Vec<(String, String)> { + methods: { + /// Add `contents` as an input C/C++ header named `name`. + /// + /// This can be used to inject additional C/C++ code as an input without having to + /// create additional header files. + pub fn header_contents(mut self, name: &str, contents: &str) -> Builder { + // Apparently clang relies on having virtual FS correspondent to + // the real one, so we need absolute paths here + let absolute_path = env::current_dir() + .expect("Cannot retrieve current directory") + .join(name) + .to_str() + .expect("Cannot convert current directory name to string") + .to_owned(); + self.options + .input_header_contents + .push((absolute_path, contents.into())); + self + } + }, + // Header contents cannot be added from the CLI. + as_args: ignore, + }, + /// A user-provided visitor to allow customizing different kinds of situations. + parse_callbacks: Vec<Rc<dyn ParseCallbacks>> { + methods: { + /// Add a new [`ParseCallbacks`] instance to configure types in different situations. + pub fn parse_callbacks(mut self, cb: Box<dyn ParseCallbacks>) -> Self { + self.options.parse_callbacks.push(Rc::from(cb)); + self + } + }, + as_args: |_callbacks, _args| { + #[cfg(feature = "__cli")] + for cb in _callbacks { + _args.extend(cb.cli_args()); + } + }, + }, + /// Which kind of items should we generate. We generate all of them by default. + codegen_config: CodegenConfig { + default: CodegenConfig::all(), + methods: { + /// Do not generate any functions. + /// + /// Functions are generated by default. + pub fn ignore_functions(mut self) -> Builder { + self.options.codegen_config.remove(CodegenConfig::FUNCTIONS); + self + } + + /// Do not generate any methods. + /// + /// Methods are generated by default. + pub fn ignore_methods(mut self) -> Builder { + self.options.codegen_config.remove(CodegenConfig::METHODS); + self + } + + /// Choose what to generate using a [`CodegenConfig`]. + /// + /// This option overlaps with [`Builder::ignore_functions`] and + /// [`Builder::ignore_methods`]. + /// + /// All the items in `CodegenConfig` are generated by default. + pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { + self.options.codegen_config = config; + self + } + }, + as_args: |codegen_config, args| { + if !codegen_config.functions() { + args.push("--ignore-functions".to_owned()); + } + + args.push("--generate".to_owned()); + + //Temporary placeholder for the 4 options below. + let mut options: Vec<String> = Vec::new(); + if codegen_config.functions() { + options.push("functions".to_owned()); + } + + if codegen_config.types() { + options.push("types".to_owned()); + } + + if codegen_config.vars() { + options.push("vars".to_owned()); + } + + if codegen_config.methods() { + options.push("methods".to_owned()); + } + + if codegen_config.constructors() { + options.push("constructors".to_owned()); + } + + if codegen_config.destructors() { + options.push("destructors".to_owned()); + } + + args.push(options.join(",")); + + if !codegen_config.methods() { + args.push("--ignore-methods".to_owned()); + } + }, + }, + /// Whether to treat inline namespaces conservatively. + conservative_inline_namespaces: bool { + methods: { + /// Treat inline namespaces conservatively. + /// + /// This is tricky, because in C++ is technically legal to override an item + /// defined in an inline namespace: + /// + /// ```cpp + /// inline namespace foo { + /// using Bar = int; + /// } + /// using Bar = long; + /// ``` + /// + /// Even though referencing `Bar` is a compiler error. + /// + /// We want to support this (arguably esoteric) use case, but we do not want to make + /// the rest of `bindgen` users pay an usability penalty for that. + /// + /// To support this, we need to keep all the inline namespaces around, but then using + /// `bindgen` becomes a bit more difficult, because you cannot reference paths like + /// `std::string` (you'd need to use the proper inline namespace). + /// + /// We could complicate a lot of the logic to detect name collisions and, in the + /// absence of collisions, generate a `pub use inline_ns::*` or something like that. + /// + /// That is probably something we can do to improve the usability of this option if we + /// realize it is needed way more often. Our guess is that this extra logic is not + /// going to be very useful. + /// + /// This option is disabled by default. + pub fn conservative_inline_namespaces(mut self) -> Builder { + self.options.conservative_inline_namespaces = true; + self + } + }, + as_args: "--conservative-inline-namespaces", + }, + /// Whether to keep documentation comments in the generated output. + generate_comments: bool { + default: true, + methods: { + /// Set whether the generated bindings should contain documentation comments. + /// + /// Documentation comments are included by default. + /// + /// Note that clang excludes comments from system headers by default, pass + /// `"-fretain-comments-from-system-headers"` to the [`Builder::clang_arg`] method to + /// include them. + /// + /// It is also possible to process all comments and not just documentation using the + /// `"-fparse-all-comments"` flag. Check [these slides on clang comment parsing]( + /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for more information + /// and examples. + pub fn generate_comments(mut self, doit: bool) -> Self { + self.options.generate_comments = doit; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-doc-comments"), + }, + /// Whether to generate inline functions. + generate_inline_functions: bool { + methods: { + /// Set whether to generate inline functions. + /// + /// This option is disabled by default. + /// + /// Note that they will usually not work. However you can use `-fkeep-inline-functions` + /// or `-fno-inline-functions` if you are responsible of compiling the library to make + /// them callable. + #[cfg_attr( + features = "experimental", + doc = "\nCheck the [`Builder::wrap_static_fns`] method for an alternative." + )] + pub fn generate_inline_functions(mut self, doit: bool) -> Self { + self.options.generate_inline_functions = doit; + self + } + }, + as_args: "--generate-inline-functions", + }, + /// Whether to allowlist types recursively. + allowlist_recursively: bool { + default: true, + methods: { + /// Set whether to recursively allowlist items. + /// + /// Items are allowlisted recursively by default. + /// + /// Given that we have explicitly allowlisted the `initiate_dance_party` function in + /// this C header: + /// + /// ```c + /// typedef struct MoonBoots { + /// int bouncy_level; + /// } MoonBoots; + /// + /// void initiate_dance_party(MoonBoots* boots); + /// ``` + /// + /// We would normally generate bindings to both the `initiate_dance_party` function and + /// the `MoonBoots` type that it transitively references. If `false` is passed to this + /// method, `bindgen` will not emit bindings for anything except the explicitly + /// allowlisted items, meaning that the definition for `MoonBoots` would not be + /// generated. However, the `initiate_dance_party` function would still reference + /// `MoonBoots`! + /// + /// **Disabling this feature will almost certainly cause `bindgen` to emit bindings + /// that will not compile!** If you disable this feature, then it is *your* + /// responsibility to provide definitions for every type that is referenced from an + /// explicitly allowlisted item. One way to provide the missing definitions is by using + /// the [`Builder::raw_line`] method, another would be to define them in Rust and then + /// `include!(...)` the bindings immediately afterwards. + pub fn allowlist_recursively(mut self, doit: bool) -> Self { + self.options.allowlist_recursively = doit; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-recursive-allowlist"), + }, + /// Whether to emit `#[macro_use] extern crate objc;` instead of `use objc;` in the prologue of + /// the files generated from objective-c files. + objc_extern_crate: bool { + methods: { + /// Emit `#[macro_use] extern crate objc;` instead of `use objc;` in the prologue of + /// the files generated from objective-c files. + /// + /// `use objc;` is emitted by default. + pub fn objc_extern_crate(mut self, doit: bool) -> Self { + self.options.objc_extern_crate = doit; + self + } + }, + as_args: "--objc-extern-crate", + }, + /// Whether to generate proper block signatures instead of `void` pointers. + generate_block: bool { + methods: { + /// Generate proper block signatures instead of `void` pointers. + /// + /// `void` pointers are used by default. + pub fn generate_block(mut self, doit: bool) -> Self { + self.options.generate_block = doit; + self + } + }, + as_args: "--generate-block", + }, + /// Whether to emit `#[macro_use] extern crate block;` instead of `use block;` in the prologue + /// of the files generated from apple block files. + block_extern_crate: bool { + methods: { + /// Emit `#[macro_use] extern crate block;` instead of `use block;` in the prologue of + /// the files generated from apple block files. + /// + /// `use block;` is emitted by default. + pub fn block_extern_crate(mut self, doit: bool) -> Self { + self.options.block_extern_crate = doit; + self + } + }, + as_args: "--block-extern-crate", + }, + /// Whether to use the clang-provided name mangling. + enable_mangling: bool { + default: true, + methods: { + /// Set whether to use the clang-provided name mangling. This is probably needed for + /// C++ features. + /// + /// The mangling provided by clang is used by default. + /// + /// We allow disabling this option because some old `libclang` versions seem to return + /// incorrect results in some cases for non-mangled functions, check [#528] for more + /// information. + /// + /// [#528]: https://github.com/rust-lang/rust-bindgen/issues/528 + pub fn trust_clang_mangling(mut self, doit: bool) -> Self { + self.options.enable_mangling = doit; + self + } + + }, + as_args: |value, args| (!value).as_args(args, "--distrust-clang-mangling"), + }, + /// Whether to detect include paths using `clang_sys`. + detect_include_paths: bool { + default: true, + methods: { + /// Set whether to detect include paths using `clang_sys`. + /// + /// `clang_sys` is used to detect include paths by default. + pub fn detect_include_paths(mut self, doit: bool) -> Self { + self.options.detect_include_paths = doit; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-include-path-detection"), + }, + /// Whether we should try to fit macro constants into types smaller than `u32` and `i32`. + fit_macro_constants: bool { + methods: { + /// Set whether `bindgen` should try to fit macro constants into types smaller than `u32` + /// and `i32`. + /// + /// This option is disabled by default. + pub fn fit_macro_constants(mut self, doit: bool) -> Self { + self.options.fit_macro_constants = doit; + self + } + }, + as_args: "--fit-macro-constant-types", + }, + /// Whether to prepend the `enum` name to constant or newtype variants. + prepend_enum_name: bool { + default: true, + methods: { + /// Set whether to prepend the `enum` name to constant or newtype variants. + /// + /// The `enum` name is prepended by default. + pub fn prepend_enum_name(mut self, doit: bool) -> Self { + self.options.prepend_enum_name = doit; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-prepend-enum-name"), + }, + /// Version of the Rust compiler to target. + rust_target: RustTarget { + methods: { + /// Specify the Rust target version. + /// + /// The default target is the latest stable Rust version. + pub fn rust_target(mut self, rust_target: RustTarget) -> Self { + self.options.set_rust_target(rust_target); + self + } + }, + as_args: |rust_target, args| { + args.push("--rust-target".to_owned()); + args.push((*rust_target).into()); + }, + }, + /// Features to be enabled. They are derived from `rust_target`. + rust_features: RustFeatures { + default: RustTarget::default().into(), + methods: {}, + // This field cannot be set from the CLI, + as_args: ignore, + }, + /// Enable support for native Rust unions if they are supported. + untagged_union: bool { + default: true, + methods: { + /// Disable support for native Rust unions, if supported. + /// + /// The default value of this option is set based on the value passed to + /// [`Builder::rust_target`]. + pub fn disable_untagged_union(mut self) -> Self { + self.options.untagged_union = false; + self + } + } + as_args: |value, args| (!value).as_args(args, "--disable-untagged-union"), + }, + /// Whether we should record which items in the regex sets did match any C items. + record_matches: bool { + default: true, + methods: { + /// Set whether we should record which items in our regex sets did match any C items. + /// + /// Matches are recorded by default. + pub fn record_matches(mut self, doit: bool) -> Self { + self.options.record_matches = doit; + self + } + + }, + as_args: |value, args| (!value).as_args(args, "--no-record-matches"), + }, + /// Whether `size_t` should be translated to `usize` automatically. + size_t_is_usize: bool { + default: true, + methods: { + /// Set whether `size_t` should be translated to `usize`. + /// + /// `size_t` is translated to `usize` by default. + pub fn size_t_is_usize(mut self, is: bool) -> Self { + self.options.size_t_is_usize = is; + self + } + }, + as_args: |value, args| (!value).as_args(args, "--no-size_t-is-usize"), + }, + /// The tool that should be used to format the generated bindings. + formatter: Formatter { + methods: { + /// Set whether `rustfmt` should be used to format the generated bindings. + /// + /// `rustfmt` is used by default. + /// + /// This method overlaps in functionality with the more general [`Builder::formatter`]. + /// Thus, the latter should be preferred. + #[deprecated] + pub fn rustfmt_bindings(mut self, doit: bool) -> Self { + self.options.formatter = if doit { + Formatter::Rustfmt + } else { + Formatter::None + }; + self + } + + /// Set which tool should be used to format the generated bindings. + /// + /// The default formatter is [`Formatter::Rustfmt`]. + /// + /// To be able to use `prettyplease` as a formatter, the `"prettyplease"` feature for + /// `bindgen` must be enabled in the Cargo manifest. + pub fn formatter(mut self, formatter: Formatter) -> Self { + self.options.formatter = formatter; + self + } + }, + as_args: |formatter, args| { + if *formatter != Default::default() { + args.push("--formatter".to_owned()); + args.push(formatter.to_string()); + } + }, + }, + /// The absolute path to the `rustfmt` configuration file. + rustfmt_configuration_file: Option<PathBuf> { + methods: { + /// Set the absolute path to the `rustfmt` configuration file. + /// + /// The default `rustfmt` options are used if `None` is passed to this method or if + /// this method is not called at all. + /// + /// Calling this method will set the [`Builder::rustfmt_bindings`] option to `true` + /// and the [`Builder::formatter`] option to [`Formatter::Rustfmt`]. + pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self { + self = self.formatter(Formatter::Rustfmt); + self.options.rustfmt_configuration_file = path; + self + } + }, + as_args: "--rustfmt-configuration-file", + }, + /// Types that should not derive `PartialEq`. + no_partialeq_types: RegexSet { + methods: { + regex_option! { + /// Do not derive `PartialEq` for a given type. + pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.no_partialeq_types.insert(arg.into()); + self + } + } + }, + as_args: "--no-partialeq", + }, + /// Types that should not derive `Copy`. + no_copy_types: RegexSet { + methods: { + regex_option! { + /// Do not derive `Copy` and `Clone` for a given type. + pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self { + self.options.no_copy_types.insert(arg.into()); + self + } + } + }, + as_args: "--no-copy", + }, + /// Types that should not derive `Debug`. + no_debug_types: RegexSet { + methods: { + regex_option! { + /// Do not derive `Debug` for a given type. + pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self { + self.options.no_debug_types.insert(arg.into()); + self + } + } + }, + as_args: "--no-debug", + }, + /// Types that should not derive or implement `Default`. + no_default_types: RegexSet { + methods: { + regex_option! { + /// Do not derive or implement `Default` for a given type. + pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self { + self.options.no_default_types.insert(arg.into()); + self + } + } + }, + as_args: "--no-default", + }, + /// Types that should not derive `Hash`. + no_hash_types: RegexSet { + methods: { + regex_option! { + /// Do not derive `Hash` for a given type. + pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.no_hash_types.insert(arg.into()); + self + } + } + }, + as_args: "--no-hash", + }, + /// Types that should be annotated with `#[must_use]`. + must_use_types: RegexSet { + methods: { + regex_option! { + /// Annotate the given type with the `#[must_use]` attribute. + pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.must_use_types.insert(arg.into()); + self + } + } + }, + as_args: "--must-use-type", + }, + /// Whether C arrays should be regular pointers in rust or array pointers + array_pointers_in_arguments: bool { + methods: { + /// Translate arrays `T arr[size]` into array pointers `*mut [T; size]` instead of + /// translating them as `*mut T` which is the default. + /// + /// The same is done for `*const` pointers. + pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self { + self.options.array_pointers_in_arguments = doit; + self + } + + }, + as_args: "--use-array-pointers-in-arguments", + }, + /// The name of the `wasm_import_module`. + wasm_import_module_name: Option<String> { + methods: { + /// Adds the `#[link(wasm_import_module = import_name)]` attribute to all the `extern` + /// blocks generated by `bindgen`. + /// + /// This attribute is not added by default. + pub fn wasm_import_module_name<T: Into<String>>( + mut self, + import_name: T, + ) -> Self { + self.options.wasm_import_module_name = Some(import_name.into()); + self + } + }, + as_args: "--wasm-import-module-name", + }, + /// The name of the dynamic library (if we are generating bindings for a shared library). + dynamic_library_name: Option<String> { + methods: { + /// Generate bindings for a shared library with the given name. + /// + /// This option is disabled by default. + pub fn dynamic_library_name<T: Into<String>>( + mut self, + dynamic_library_name: T, + ) -> Self { + self.options.dynamic_library_name = Some(dynamic_library_name.into()); + self + } + }, + as_args: "--dynamic-loading", + }, + /// Whether to equire successful linkage for all routines in a shared library. + dynamic_link_require_all: bool { + methods: { + /// Set whether to require successful linkage for all routines in a shared library. + /// This allows us to optimize function calls by being able to safely assume function + /// pointers are valid. + /// + /// This option only comes into effect if the [`Builder::dynamic_library_name`] option + /// is set. + /// + /// This option is disabled by default. + pub fn dynamic_link_require_all(mut self, req: bool) -> Self { + self.options.dynamic_link_require_all = req; + self + } + }, + as_args: "--dynamic-link-require-all", + }, + /// Whether to only make generated bindings `pub` if the items would be publicly accessible by + /// C++. + respect_cxx_access_specs: bool { + methods: { + /// Set whether to respect the C++ access specifications. + /// + /// Passing `true` to this method will set the visibility of the generated Rust items + /// as `pub` only if the corresponding C++ items are publicly accessible instead of + /// marking all the items as public, which is the default. + pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self { + self.options.respect_cxx_access_specs = doit; + self + } + + }, + as_args: "--respect-cxx-access-specs", + }, + /// Whether to translate `enum` integer types to native Rust integer types. + translate_enum_integer_types: bool { + methods: { + /// Set whether to always translate `enum` integer types to native Rust integer types. + /// + /// Passing `true` to this method will result in `enum`s having types such as `u32` and + /// `i16` instead of `c_uint` and `c_short` which is the default. The `#[repr]` types + /// of Rust `enum`s are always translated to Rust integer types. + pub fn translate_enum_integer_types(mut self, doit: bool) -> Self { + self.options.translate_enum_integer_types = doit; + self + } + }, + as_args: "--translate-enum-integer-types", + }, + /// Whether to generate types with C style naming. + c_naming: bool { + methods: { + /// Set whether to generate types with C style naming. + /// + /// Passing `true` to this method will add prefixes to the generated type names. For + /// example, instead of a `struct` with name `A` we will generate a `struct` with + /// `struct_A`. Currently applies to `struct`s, `union`s, and `enum`s. + pub fn c_naming(mut self, doit: bool) -> Self { + self.options.c_naming = doit; + self + } + }, + as_args: "--c-naming", + }, + /// Wether to always emit explicit padding fields. + force_explicit_padding: bool { + methods: { + /// Set whether to always emit explicit padding fields. + /// + /// This option should be enabled if a `struct` needs to be serialized in its native + /// format (padding bytes and all). This could be required if such `struct` will be + /// written to a file or sent over the network, as anything reading the padding bytes + /// of a struct may cause undefined behavior. + /// + /// Padding fields are not emitted by default. + pub fn explicit_padding(mut self, doit: bool) -> Self { + self.options.force_explicit_padding = doit; + self + } + }, + as_args: "--explicit-padding", + }, + /// Whether to emit vtable functions. + vtable_generation: bool { + methods: { + /// Set whether to enable experimental support to generate virtual table functions. + /// + /// This option should mostly work, though some edge cases are likely to be broken. + /// + /// Virtual table generation is disabled by default. + pub fn vtable_generation(mut self, doit: bool) -> Self { + self.options.vtable_generation = doit; + self + } + }, + as_args: "--vtable-generation", + }, + /// Whether to sort the generated Rust items. + sort_semantically: bool { + methods: { + /// Set whether to sort the generated Rust items in a predefined manner. + /// + /// Items are not ordered by default. + pub fn sort_semantically(mut self, doit: bool) -> Self { + self.options.sort_semantically = doit; + self + } + }, + as_args: "--sort-semantically", + }, + /// Whether to deduplicate `extern` blocks. + merge_extern_blocks: bool { + methods: { + /// Merge all extern blocks under the same module into a single one. + /// + /// Extern blocks are not merged by default. + pub fn merge_extern_blocks(mut self, doit: bool) -> Self { + self.options.merge_extern_blocks = doit; + self + } + }, + as_args: "--merge-extern-blocks", + }, + /// Whether to wrap unsafe operations in unsafe blocks. + wrap_unsafe_ops: bool { + methods: { + /// Wrap all unsafe operations in unsafe blocks. + /// + /// Unsafe operations are not wrapped by default. + pub fn wrap_unsafe_ops(mut self, doit: bool) -> Self { + self.options.wrap_unsafe_ops = doit; + self + } + }, + as_args: "--wrap-unsafe-ops", + }, + /// Patterns for functions whose ABI should be overriden. + abi_overrides: HashMap<Abi, RegexSet> { + methods: { + regex_option! { + /// Override the ABI of a given function. + pub fn override_abi<T: Into<String>>(mut self, abi: Abi, arg: T) -> Self { + self.options + .abi_overrides + .entry(abi) + .or_default() + .insert(arg.into()); + self + } + } + }, + as_args: |overrides, args| { + for (abi, set) in overrides { + for item in set.get_items() { + args.push("--override-abi".to_owned()); + args.push(format!("{}={}", item, abi)); + } + } + }, + }, + /// Whether to generate wrappers for `static` functions. + wrap_static_fns: bool { + methods: { + #[cfg(feature = "experimental")] + /// Set whether to generate wrappers for `static`` functions. + /// + /// Passing `true` to this method will generate a C source file with non-`static` + /// functions that call the `static` functions found in the input headers and can be + /// called from Rust once the source file is compiled. + /// + /// The path of this source file can be set using the [`Builder::wrap_static_fns_path`] + /// method. + pub fn wrap_static_fns(mut self, doit: bool) -> Self { + self.options.wrap_static_fns = doit; + self + } + }, + as_args: "--wrap-static-fns", + }, + /// The suffix to be added to the function wrappers for `static` functions. + wrap_static_fns_suffix: Option<String> { + methods: { + #[cfg(feature = "experimental")] + /// Set the suffix added to the wrappers for `static` functions. + /// + /// This option only comes into effect if `true` is passed to the + /// [`Builder::wrap_static_fns`] method. + /// + /// The default suffix is `__extern`. + pub fn wrap_static_fns_suffix<T: AsRef<str>>(mut self, suffix: T) -> Self { + self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned()); + self + } + }, + as_args: "--wrap-static-fns-suffix", + }, + /// The path of the file where the wrappers for `static` functions will be emitted. + wrap_static_fns_path: Option<PathBuf> { + methods: { + #[cfg(feature = "experimental")] + /// Set the path for the source code file that would be created if any wrapper + /// functions must be generated due to the presence of `static` functions. + /// + /// `bindgen` will automatically add the right extension to the header and source code + /// files. + /// + /// This option only comes into effect if `true` is passed to the + /// [`Builder::wrap_static_fns`] method. + /// + /// The default path is `temp_dir/bindgen/extern`, where `temp_dir` is the path + /// returned by [`std::env::temp_dir`] . + pub fn wrap_static_fns_path<T: AsRef<Path>>(mut self, path: T) -> Self { + self.options.wrap_static_fns_path = Some(path.as_ref().to_owned()); + self + } + }, + as_args: "--wrap-static-fns-path", + }, + /// Default visibility of fields. + default_visibility: FieldVisibilityKind { + methods: { + /// Set the default visibility of fields, including bitfields and accessor methods for + /// bitfields. + /// + /// This option only comes into effect if the [`Builder::respect_cxx_access_specs`] + /// option is disabled. + pub fn default_visibility( + mut self, + visibility: FieldVisibilityKind, + ) -> Self { + self.options.default_visibility = visibility; + self + } + }, + as_args: |visibility, args| { + if *visibility != Default::default() { + args.push("--default-visibility".to_owned()); + args.push(visibility.to_string()); + } + }, + }, + /// Whether to emit diagnostics or not. + emit_diagnostics: bool { + methods: { + #[cfg(feature = "experimental")] + /// Emit diagnostics. + /// + /// These diagnostics are emitted to `stderr` if you are using `bindgen-cli` or printed + /// using `cargo:warning=` if you are using `bindgen` as a `build-dependency`. + /// + /// Diagnostics are not emitted by default. + /// + /// The layout and contents of these diagnostic messages are not covered by versioning + /// and can change without notice. + pub fn emit_diagnostics(mut self) -> Self { + self.options.emit_diagnostics = true; + self + } + }, + as_args: "--emit-diagnostics", + } +} @@ -1,4 +1,5 @@ //! Common traits and types related to parsing our IR from Clang cursors. +#![deny(clippy::missing_docs_in_private_items)] use crate::clang; use crate::ir::context::{BindgenContext, ItemId}; @@ -6,7 +7,7 @@ use crate::ir::context::{BindgenContext, ItemId}; /// Not so much an error in the traditional sense, but a control flow message /// when walking over Clang's AST with a cursor. #[derive(Debug)] -pub enum ParseError { +pub(crate) enum ParseError { /// Recurse down the current AST node's children. Recurse, /// Continue on to the next sibling AST node, or back up to the parent's @@ -16,7 +17,7 @@ pub enum ParseError { /// The result of parsing a Clang AST node. #[derive(Debug)] -pub enum ParseResult<T> { +pub(crate) enum ParseResult<T> { /// We've already resolved this item before, here is the extant `ItemId` for /// it. AlreadyResolved(ItemId), @@ -28,7 +29,7 @@ pub enum ParseResult<T> { /// An intermediate representation "sub-item" (i.e. one of the types contained /// inside an `ItemKind` variant) that can be parsed from a Clang cursor. -pub trait ClangSubItemParser: Sized { +pub(crate) trait ClangSubItemParser: Sized { /// Attempt to parse this type from the given cursor. /// /// The fact that is a reference guarantees it's held by the context, and diff --git a/regex_set.rs b/regex_set.rs index 6246dd2..1d5cad2 100644 --- a/regex_set.rs +++ b/regex_set.rs @@ -1,4 +1,5 @@ //! A type that represents the union of a set of regular expressions. +#![deny(clippy::missing_docs_in_private_items)] use regex::RegexSet as RxSet; use std::cell::Cell; @@ -18,9 +19,7 @@ pub struct RegexSet { impl RegexSet { /// Create a new RegexSet pub fn new() -> RegexSet { - RegexSet { - ..Default::default() - } + RegexSet::default() } /// Is this set empty? @@ -33,11 +32,7 @@ impl RegexSet { where S: AsRef<str>, { - let string = string.as_ref().to_owned(); - if string == "*" { - warn!("using wildcard patterns (`*`) is no longer considered valid. Use `.*` instead"); - } - self.items.push(string); + self.items.push(string.as_ref().to_owned()); self.matched.push(Cell::new(false)); self.set = None; } @@ -63,13 +58,56 @@ impl RegexSet { /// /// Must be called before calling `matches()`, or it will always return /// false. + #[inline] pub fn build(&mut self, record_matches: bool) { + self.build_inner(record_matches, None) + } + + #[cfg(all(feature = "__cli", feature = "experimental"))] + /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the + /// name of the regex set is passed to it. + /// + /// Must be called before calling `matches()`, or it will always return + /// false. + #[inline] + pub fn build_with_diagnostics( + &mut self, + record_matches: bool, + name: Option<&'static str>, + ) { + self.build_inner(record_matches, name) + } + + #[cfg(all(not(feature = "__cli"), feature = "experimental"))] + /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the + /// name of the regex set is passed to it. + /// + /// Must be called before calling `matches()`, or it will always return + /// false. + #[inline] + pub(crate) fn build_with_diagnostics( + &mut self, + record_matches: bool, + name: Option<&'static str>, + ) { + self.build_inner(record_matches, name) + } + + fn build_inner( + &mut self, + record_matches: bool, + _name: Option<&'static str>, + ) { let items = self.items.iter().map(|item| format!("^({})$", item)); self.record_matches = record_matches; self.set = match RxSet::new(items) { Ok(x) => Some(x), Err(e) => { warn!("Invalid regex in {:?}: {:?}", self.items, e); + #[cfg(feature = "experimental")] + if let Some(name) = _name { + invalid_regex_warning(self, e, name); + } None } } @@ -101,3 +139,66 @@ impl RegexSet { true } } + +#[cfg(feature = "experimental")] +fn invalid_regex_warning( + set: &RegexSet, + err: regex::Error, + name: &'static str, +) { + use crate::diagnostics::{Diagnostic, Level, Slice}; + + let mut diagnostic = Diagnostic::default(); + + match err { + regex::Error::Syntax(string) => { + if string.starts_with("regex parse error:\n") { + let mut source = String::new(); + + let mut parsing_source = true; + + for line in string.lines().skip(1) { + if parsing_source { + if line.starts_with(' ') { + source.push_str(line); + source.push('\n'); + continue; + } + parsing_source = false; + } + let error = "error: "; + if line.starts_with(error) { + let (_, msg) = line.split_at(error.len()); + diagnostic.add_annotation(msg.to_owned(), Level::Error); + } else { + diagnostic.add_annotation(line.to_owned(), Level::Info); + } + } + let mut slice = Slice::default(); + slice.with_source(source); + diagnostic.add_slice(slice); + + diagnostic.with_title( + "Error while parsing a regular expression.", + Level::Warn, + ); + } else { + diagnostic.with_title(string, Level::Warn); + } + } + err => { + let err = err.to_string(); + diagnostic.with_title(err, Level::Warn); + } + } + + diagnostic.add_annotation( + format!("This regular expression was passed via `{}`.", name), + Level::Note, + ); + + if set.items.iter().any(|item| item == "*") { + diagnostic.add_annotation("Wildcard patterns \"*\" are no longer considered valid. Use \".*\" instead.", Level::Help); + } + diagnostic.display(); +} |