diff --git a/bindgen-tests/tests/expectations/tests/merge-extern-blocks.rs b/bindgen-tests/tests/expectations/tests/merge-extern-blocks.rs index 66ceeff07..ae9799d27 100644 --- a/bindgen-tests/tests/expectations/tests/merge-extern-blocks.rs +++ b/bindgen-tests/tests/expectations/tests/merge-extern-blocks.rs @@ -5,33 +5,88 @@ non_upper_case_globals )] -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Point { - pub x: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_Point() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(Point)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(Point)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize }, - 0usize, - concat!("Offset of field: ", stringify!(Point), "::", stringify!(x)) - ); -} -extern "C" { - pub fn foo() -> ::std::os::raw::c_int; - pub fn bar() -> ::std::os::raw::c_int; +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Point { + pub x: ::std::os::raw::c_int, + } + #[test] + fn bindgen_test_layout_Point() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(Point)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Point)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(x) + ) + ); + } + pub mod ns { + #[allow(unused_imports)] + use self::super::super::root; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Point { + pub x: ::std::os::raw::c_int, + } + #[test] + fn bindgen_test_layout_Point() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(Point)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Point)) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(x) + ) + ); + } + extern "C" { + #[link_name = "\u{1}_ZN2ns3fooEv"] + pub fn foo() -> ::std::os::raw::c_int; + #[link_name = "\u{1}_ZN2ns3barEv"] + pub fn bar() -> ::std::os::raw::c_int; + } + } + extern "C" { + #[link_name = "\u{1}_Z3foov"] + pub fn foo() -> ::std::os::raw::c_int; + #[link_name = "\u{1}_Z3barv"] + pub fn bar() -> ::std::os::raw::c_int; + } } diff --git a/bindgen-tests/tests/expectations/tests/sort-items.rs b/bindgen-tests/tests/expectations/tests/sort-items.rs new file mode 100644 index 000000000..e04e3b609 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/sort-items.rs @@ -0,0 +1,220 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + pub type number = ::std::os::raw::c_int; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Point { + pub x: root::number, + pub y: root::number, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Angle { + pub a: root::number, + pub b: root::number, + } + pub const NUMBER: root::number = 42; + #[test] + fn bindgen_test_layout_Point() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Point)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Point)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(x) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(y) + ) + ); + } + #[test] + fn bindgen_test_layout_Angle() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Angle)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Angle)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).a) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).b) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(b) + ) + ); + } + pub mod ns { + pub type number = ::std::os::raw::c_int; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Point { + pub x: root::ns::number, + pub y: root::ns::number, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Angle { + pub a: root::ns::number, + pub b: root::ns::number, + } + pub const NUMBER: root::ns::number = 42; + #[test] + fn bindgen_test_layout_Point() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Point)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Point)) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(x) + ) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize + }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(y) + ) + ); + } + #[test] + fn bindgen_test_layout_Angle() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Angle)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Angle)) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).a) as usize - ptr as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).b) as usize - ptr as usize + }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(b) + ) + ); + } + #[allow(unused_imports)] + use self::super::super::root; + extern "C" { + #[link_name = "\u{1}_ZN2ns3fooEv"] + pub fn foo() -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_ZN2ns3barEi"] + pub fn bar(x: root::ns::number) -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_ZN2ns3bazENS_5PointE"] + pub fn baz(point: root::ns::Point) -> ::std::os::raw::c_int; + } + } + #[allow(unused_imports)] + use self::super::root; + extern "C" { + #[link_name = "\u{1}_Z3foov"] + pub fn foo() -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_Z3bari"] + pub fn bar(x: root::number) -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_Z3baz5Point"] + pub fn baz(point: root::Point) -> ::std::os::raw::c_int; + } +} diff --git a/bindgen-tests/tests/expectations/tests/sorted-items.rs b/bindgen-tests/tests/expectations/tests/sorted-items.rs deleted file mode 100644 index 7df7c3d71..000000000 --- a/bindgen-tests/tests/expectations/tests/sorted-items.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![allow( - dead_code, - non_snake_case, - non_camel_case_types, - non_upper_case_globals -)] - -pub type number = ::std::os::raw::c_int; -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Point { - pub x: number, - pub y: number, -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct Angle { - pub a: number, - pub b: number, -} -pub const NUMBER: number = 42; -#[test] -fn bindgen_test_layout_Point() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(Point)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(Point)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize }, - 0usize, - concat!("Offset of field: ", stringify!(Point), "::", stringify!(x)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize }, - 4usize, - concat!("Offset of field: ", stringify!(Point), "::", stringify!(y)) - ); -} -#[test] -fn bindgen_test_layout_Angle() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(Angle)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(Angle)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).a) as usize - ptr as usize }, - 0usize, - concat!("Offset of field: ", stringify!(Angle), "::", stringify!(a)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).b) as usize - ptr as usize }, - 4usize, - concat!("Offset of field: ", stringify!(Angle), "::", stringify!(b)) - ); -} -extern "C" { - pub fn foo() -> ::std::os::raw::c_int; -} -extern "C" { - pub fn bar(x: number) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn baz(point: Point) -> ::std::os::raw::c_int; -} diff --git a/bindgen-tests/tests/expectations/tests/sorted_items.rs b/bindgen-tests/tests/expectations/tests/sorted_items.rs new file mode 100644 index 000000000..e04e3b609 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/sorted_items.rs @@ -0,0 +1,220 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + pub type number = ::std::os::raw::c_int; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Point { + pub x: root::number, + pub y: root::number, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Angle { + pub a: root::number, + pub b: root::number, + } + pub const NUMBER: root::number = 42; + #[test] + fn bindgen_test_layout_Point() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Point)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Point)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(x) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(y) + ) + ); + } + #[test] + fn bindgen_test_layout_Angle() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Angle)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Angle)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).a) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).b) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(b) + ) + ); + } + pub mod ns { + pub type number = ::std::os::raw::c_int; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Point { + pub x: root::ns::number, + pub y: root::ns::number, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] + pub struct Angle { + pub a: root::ns::number, + pub b: root::ns::number, + } + pub const NUMBER: root::ns::number = 42; + #[test] + fn bindgen_test_layout_Point() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Point)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Point)) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(x) + ) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize + }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Point), + "::", + stringify!(y) + ) + ); + } + #[test] + fn bindgen_test_layout_Angle() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Angle)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Angle)) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).a) as usize - ptr as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).b) as usize - ptr as usize + }, + 4usize, + concat!( + "Offset of field: ", + stringify!(Angle), + "::", + stringify!(b) + ) + ); + } + #[allow(unused_imports)] + use self::super::super::root; + extern "C" { + #[link_name = "\u{1}_ZN2ns3fooEv"] + pub fn foo() -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_ZN2ns3barEi"] + pub fn bar(x: root::ns::number) -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_ZN2ns3bazENS_5PointE"] + pub fn baz(point: root::ns::Point) -> ::std::os::raw::c_int; + } + } + #[allow(unused_imports)] + use self::super::root; + extern "C" { + #[link_name = "\u{1}_Z3foov"] + pub fn foo() -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_Z3bari"] + pub fn bar(x: root::number) -> ::std::os::raw::c_int; + } + extern "C" { + #[link_name = "\u{1}_Z3baz5Point"] + pub fn baz(point: root::Point) -> ::std::os::raw::c_int; + } +} diff --git a/bindgen-tests/tests/headers/merge-extern-blocks.h b/bindgen-tests/tests/headers/merge-extern-blocks.h deleted file mode 100644 index 1d46b7d4a..000000000 --- a/bindgen-tests/tests/headers/merge-extern-blocks.h +++ /dev/null @@ -1,6 +0,0 @@ -// bindgen-flags: --merge-extern-blocks -- --target=x86_64-unknown-linux -int foo(); -typedef struct Point { - int x; -} Point; -int bar(); diff --git a/bindgen-tests/tests/headers/merge-extern-blocks.hpp b/bindgen-tests/tests/headers/merge-extern-blocks.hpp new file mode 100644 index 000000000..392e34a39 --- /dev/null +++ b/bindgen-tests/tests/headers/merge-extern-blocks.hpp @@ -0,0 +1,14 @@ +// bindgen-flags: --merge-extern-blocks --enable-cxx-namespaces -- --target=x86_64-unknown-linux +int foo(); +typedef struct Point { + int x; +} Point; +int bar(); + +namespace ns { + int foo(); + typedef struct Point { + int x; + } Point; + int bar(); +} diff --git a/bindgen-tests/tests/headers/sorted-items.h b/bindgen-tests/tests/headers/sorted-items.h deleted file mode 100644 index 11fc2ef40..000000000 --- a/bindgen-tests/tests/headers/sorted-items.h +++ /dev/null @@ -1,17 +0,0 @@ -// bindgen-flags: --sort-semantically -- --target=x86_64-unknown-linux - -int foo(); -typedef int number; -int bar(number x); -struct Point -{ - number x; - number y; -}; -struct Angle -{ - number a; - number b; -}; -int baz(struct Point point); -const number NUMBER = 42; diff --git a/bindgen-tests/tests/headers/sorted_items.hpp b/bindgen-tests/tests/headers/sorted_items.hpp new file mode 100644 index 000000000..9b5ced963 --- /dev/null +++ b/bindgen-tests/tests/headers/sorted_items.hpp @@ -0,0 +1,35 @@ +// bindgen-flags: --sort-semantically --enable-cxx-namespaces -- --target=x86_64-unknown-linux + +int foo(); +typedef int number; +int bar(number x); +struct Point +{ + number x; + number y; +}; +struct Angle +{ + number a; + number b; +}; +int baz(struct Point point); +const number NUMBER = 42; + +namespace ns { + int foo(); + typedef int number; + int bar(number x); + struct Point + { + number x; + number y; + }; + struct Angle + { + number a; + number b; + }; + int baz(struct Point point); + const number NUMBER = 42; +} diff --git a/bindgen/Cargo.toml b/bindgen/Cargo.toml index dca779bd0..3965ad4d4 100644 --- a/bindgen/Cargo.toml +++ b/bindgen/Cargo.toml @@ -45,7 +45,7 @@ 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"]} +syn = { version = "1.0.99", 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 } shlex = "1" diff --git a/bindgen/codegen/postprocessing/merge_extern_blocks.rs b/bindgen/codegen/postprocessing/merge_extern_blocks.rs index 2b7614941..05e7e9ef3 100644 --- a/bindgen/codegen/postprocessing/merge_extern_blocks.rs +++ b/bindgen/codegen/postprocessing/merge_extern_blocks.rs @@ -1,46 +1,66 @@ -use syn::{Item, ItemForeignMod}; +use syn::{ + visit_mut::{visit_item_mod_mut, VisitMut}, + Item, ItemForeignMod, ItemMod, +}; -pub(super) fn merge_extern_blocks(items: &mut Vec) { - // Keep all the extern blocks in a different `Vec` for faster search. - let mut foreign_mods = Vec::::new(); +pub(super) fn merge_extern_blocks(item_mod: &mut ItemMod) { + Visitor.visit_item_mod_mut(item_mod) +} + +struct Visitor; - for item in std::mem::take(items) { - match item { - Item::ForeignMod(ItemForeignMod { - attrs, - abi, - brace_token, - items: foreign_items, - }) => { - let mut exists = false; - for foreign_mod in &mut foreign_mods { - // Check if there is a extern block with the same ABI and - // attributes. - if foreign_mod.attrs == attrs && foreign_mod.abi == abi { - // Merge the items of the two blocks. - foreign_mod.items.extend_from_slice(&foreign_items); - exists = true; - break; +impl VisitMut for Visitor { + 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::::new(); + + for item in std::mem::take(items) { + if let Item::ForeignMod(ItemForeignMod { + attrs, + abi, + brace_token, + 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, + }); + } + } else { + // If the item is not an extern block, we don't have to do anything and just + // push it back. + items.push(item); } - // If no existing extern block had the same ABI and attributes, store - // it. - if !exists { - foreign_mods.push(ItemForeignMod { - attrs, - abi, - brace_token, - items: foreign_items, - }); - } } - // If the item is not an extern block, we don't have to do anything. - _ => 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)); + } } - } - // Move all the extern blocks alongside the rest of the items. - for foreign_mod in foreign_mods { - items.push(Item::ForeignMod(foreign_mod)); + visit_item_mod_mut(self, item_mod) } } diff --git a/bindgen/codegen/postprocessing/mod.rs b/bindgen/codegen/postprocessing/mod.rs index c6612f2b9..1d5a4983b 100644 --- a/bindgen/codegen/postprocessing/mod.rs +++ b/bindgen/codegen/postprocessing/mod.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::ToTokens; -use syn::Item; +use syn::{parse2, ItemMod}; use crate::BindgenOptions; @@ -12,7 +12,7 @@ use sort_semantically::sort_semantically; struct PostProcessingPass { should_run: fn(&BindgenOptions) -> bool, - run: fn(&mut Vec), + run: fn(&mut ItemMod), } // 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: |items| $pass(items), + run: |item_mod| $pass(item_mod), } }; } @@ -38,29 +38,29 @@ pub(crate) fn postprocessing( return items.into_iter().collect(); } let module_wrapped_tokens = - quote!(mod wrapper_for_sorting_hack { #( #items )* }); + 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 two `unwrap`s here are deliberate because - // The first one won't panic because we build the `mod` and know it is there - // The second one won't panic because we know original output has something in - // it already. - let (_, mut items) = syn::parse2::(module_wrapped_tokens) - .unwrap() - .content - .unwrap(); + // The `unwrap` here is deliberate because bindgen should generate valid rust items at all + // times. + let mut item_mod = parse2::(module_wrapped_tokens).unwrap(); for pass in PASSES { if (pass.should_run)(options) { - (pass.run)(&mut items); + (pass.run)(&mut item_mod); } } - let synful_items = items.into_iter().map(|item| item.into_token_stream()); + let synful_items = item_mod + .content + .map(|(_, items)| items) + .unwrap_or_default() + .into_iter() + .map(|item| item.into_token_stream()); quote! { #( #synful_items )* } } diff --git a/bindgen/codegen/postprocessing/sort_semantically.rs b/bindgen/codegen/postprocessing/sort_semantically.rs index 96596cb01..4f23ab73a 100644 --- a/bindgen/codegen/postprocessing/sort_semantically.rs +++ b/bindgen/codegen/postprocessing/sort_semantically.rs @@ -1,24 +1,38 @@ -use syn::Item; +use syn::{ + visit_mut::{visit_item_mod_mut, VisitMut}, + Item, ItemMod, +}; -pub(super) fn sort_semantically(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, - Item::Macro2(_) => 16, - _ => 18, - }); +pub(super) fn sort_semantically(item_mod: &mut ItemMod) { + Visitor.visit_item_mod_mut(item_mod) +} + +struct Visitor; + +impl VisitMut for Visitor { + 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, + Item::Macro2(_) => 16, + _ => 18, + }); + } + visit_item_mod_mut(self, item_mod) + } }