diff --git a/bindgen-tests/tests/expectations/tests/field-rename-callback.rs b/bindgen-tests/tests/expectations/tests/field-rename-callback.rs new file mode 100644 index 0000000000..9739b79708 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/field-rename-callback.rs @@ -0,0 +1,623 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + fn extract_bit(byte: u8, index: usize) -> bool { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + Self::extract_bit(byte, index) + } + #[inline] + pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + *(core::ptr::addr_of!((*this).storage) as *const u8) + .offset(byte_index as isize) + }; + Self::extract_bit(byte, index) + } + #[inline] + fn change_bit(byte: u8, index: usize, val: bool) -> u8 { + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { byte | mask } else { byte & !mask } + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + *byte = Self::change_bit(*byte, index, val); + } + #[inline] + pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) { + debug_assert!(index / 8 < core::mem::size_of::()); + let byte_index = index / 8; + let byte = unsafe { + (core::ptr::addr_of_mut!((*this).storage) as *mut u8) + .offset(byte_index as isize) + }; + unsafe { *byte = Self::change_bit(*byte, index, val) }; + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len(), + ); + if bit_width == 0 { + return 0; + } + let mut val = 0u64; + let storage = self.storage.as_ref(); + let start_byte = bit_offset / 8; + let bit_shift = bit_offset % 8; + let bytes_needed = (bit_width as usize + bit_shift + 7) / 8; + if cfg!(target_endian = "big") { + for i in 0..bytes_needed { + val |= (storage[start_byte + i].reverse_bits() as u64) << (i * 8); + } + } else { + for i in 0..bytes_needed { + val |= (storage[start_byte + i] as u64) << (i * 8); + } + } + val >>= bit_shift; + if bit_width < 64 { + val &= (1u64 << bit_width) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - bit_width as usize); + } + val + } + #[inline] + pub unsafe fn raw_get(this: *const Self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + if bit_width == 0 { + return 0; + } + let mut val = 0u64; + let start_byte = bit_offset / 8; + let bit_shift = bit_offset % 8; + let bytes_needed = (bit_width as usize + bit_shift + 7) / 8; + let storage_ptr = unsafe { core::ptr::addr_of!((*this).storage) as *const u8 }; + if cfg!(target_endian = "big") { + for i in 0..bytes_needed { + let byte = unsafe { *storage_ptr.add(start_byte + i) }; + val |= (byte.reverse_bits() as u64) << (i * 8); + } + } else { + for i in 0..bytes_needed { + let byte = unsafe { *storage_ptr.add(start_byte + i) }; + val |= (byte as u64) << (i * 8); + } + } + val >>= bit_shift; + if bit_width < 64 { + val &= (1u64 << bit_width) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - bit_width as usize); + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len(), + ); + if bit_width == 0 { + return; + } + let mut val = val; + if bit_width < 64 { + val &= (1u64 << bit_width) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - bit_width as usize); + } + let storage = self.storage.as_mut(); + let start_byte = bit_offset / 8; + let bit_shift = bit_offset % 8; + let bytes_needed = (bit_width as usize + bit_shift + 7) / 8; + val <<= bit_shift; + let field_mask = if bit_width as usize + bit_shift >= 64 { + !0u64 << bit_shift + } else { + ((1u64 << bit_width) - 1) << bit_shift + }; + for i in 0..bytes_needed { + let byte_val = (val >> (i * 8)) as u8; + let byte_mask = (field_mask >> (i * 8)) as u8; + if cfg!(target_endian = "big") { + let byte = storage[start_byte + i].reverse_bits(); + let new_byte = (byte & !byte_mask) | (byte_val & byte_mask); + storage[start_byte + i] = new_byte.reverse_bits(); + } else { + storage[start_byte + i] = (storage[start_byte + i] & !byte_mask) + | (byte_val & byte_mask); + } + } + } + #[inline] + pub unsafe fn raw_set(this: *mut Self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::(), + ); + if bit_width == 0 { + return; + } + let mut val = val; + if bit_width < 64 { + val &= (1u64 << bit_width) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - bit_width as usize); + } + let start_byte = bit_offset / 8; + let bit_shift = bit_offset % 8; + let bytes_needed = (bit_width as usize + bit_shift + 7) / 8; + val <<= bit_shift; + let field_mask = if bit_width as usize + bit_shift >= 64 { + !0u64 << bit_shift + } else { + ((1u64 << bit_width) - 1) << bit_shift + }; + let storage_ptr = unsafe { core::ptr::addr_of_mut!((*this).storage) as *mut u8 }; + for i in 0..bytes_needed { + let byte_val = (val >> (i * 8)) as u8; + let byte_mask = (field_mask >> (i * 8)) as u8; + let byte_ptr = unsafe { storage_ptr.add(start_byte + i) }; + if cfg!(target_endian = "big") { + let byte = unsafe { (*byte_ptr).reverse_bits() }; + let new_byte = (byte & !byte_mask) | (byte_val & byte_mask); + unsafe { *byte_ptr = new_byte.reverse_bits() }; + } else { + unsafe { *byte_ptr = (*byte_ptr & !byte_mask) | (byte_val & byte_mask) }; + } + } + } +} +/// Const-generic methods for efficient bitfield access when offset and width +/// are known at compile time. +impl __BindgenBitfieldUnit<[u8; N]> { + /// Get a field using const generics for compile-time optimization. + /// Uses native word size operations when the field fits in usize. + #[inline] + pub const fn get_const(&self) -> u64 { + debug_assert!(BIT_WIDTH <= 64); + debug_assert!(BIT_OFFSET / 8 < N); + debug_assert!((BIT_OFFSET + (BIT_WIDTH as usize)) / 8 <= N); + if BIT_WIDTH == 0 { + return 0; + } + let start_byte = BIT_OFFSET / 8; + let bit_shift = BIT_OFFSET % 8; + let bytes_needed = (BIT_WIDTH as usize + bit_shift + 7) / 8; + if BIT_WIDTH as usize + bit_shift <= usize::BITS as usize { + let mut val = 0usize; + if cfg!(target_endian = "big") { + let mut i = 0; + while i < bytes_needed { + val + |= (self.storage[start_byte + i].reverse_bits() as usize) + << (i * 8); + i += 1; + } + } else { + let mut i = 0; + while i < bytes_needed { + val |= (self.storage[start_byte + i] as usize) << (i * 8); + i += 1; + } + } + val >>= bit_shift; + val &= (1usize << BIT_WIDTH) - 1; + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (usize::BITS as usize - BIT_WIDTH as usize); + } + val as u64 + } else { + let mut val = 0u64; + if cfg!(target_endian = "big") { + let mut i = 0; + while i < bytes_needed { + val + |= (self.storage[start_byte + i].reverse_bits() as u64) + << (i * 8); + i += 1; + } + } else { + let mut i = 0; + while i < bytes_needed { + val |= (self.storage[start_byte + i] as u64) << (i * 8); + i += 1; + } + } + val >>= bit_shift; + if BIT_WIDTH < 64 { + val &= (1u64 << BIT_WIDTH) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - BIT_WIDTH as usize); + } + val + } + } + /// Set a field using const generics for compile-time optimization. + /// Uses native word size operations when the field fits in usize. + #[inline] + pub fn set_const(&mut self, val: u64) { + debug_assert!(BIT_WIDTH <= 64); + debug_assert!(BIT_OFFSET / 8 < N); + debug_assert!((BIT_OFFSET + (BIT_WIDTH as usize)) / 8 <= N); + if BIT_WIDTH == 0 { + return; + } + let start_byte = BIT_OFFSET / 8; + let bit_shift = BIT_OFFSET % 8; + let bytes_needed = (BIT_WIDTH as usize + bit_shift + 7) / 8; + if BIT_WIDTH as usize + bit_shift <= usize::BITS as usize { + let mut val = val as usize; + val &= (1usize << BIT_WIDTH) - 1; + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (usize::BITS as usize - BIT_WIDTH as usize); + } + val <<= bit_shift; + let field_mask = ((1usize << BIT_WIDTH) - 1) << bit_shift; + let mut i = 0; + while i < bytes_needed { + let byte_val = (val >> (i * 8)) as u8; + let byte_mask = (field_mask >> (i * 8)) as u8; + if cfg!(target_endian = "big") { + let byte = self.storage[start_byte + i].reverse_bits(); + let new_byte = (byte & !byte_mask) | (byte_val & byte_mask); + self.storage[start_byte + i] = new_byte.reverse_bits(); + } else { + self.storage[start_byte + i] = (self.storage[start_byte + i] + & !byte_mask) | (byte_val & byte_mask); + } + i += 1; + } + } else { + let mut val = val; + if BIT_WIDTH < 64 { + val &= (1u64 << BIT_WIDTH) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - BIT_WIDTH as usize); + } + val <<= bit_shift; + let field_mask = if BIT_WIDTH as usize + bit_shift >= 64 { + !0u64 << bit_shift + } else { + ((1u64 << BIT_WIDTH) - 1) << bit_shift + }; + let mut i = 0; + while i < bytes_needed { + let byte_val = (val >> (i * 8)) as u8; + let byte_mask = (field_mask >> (i * 8)) as u8; + if cfg!(target_endian = "big") { + let byte = self.storage[start_byte + i].reverse_bits(); + let new_byte = (byte & !byte_mask) | (byte_val & byte_mask); + self.storage[start_byte + i] = new_byte.reverse_bits(); + } else { + self.storage[start_byte + i] = (self.storage[start_byte + i] + & !byte_mask) | (byte_val & byte_mask); + } + i += 1; + } + } + } + /// Raw pointer get using const generics for compile-time optimization. + /// Uses native word size operations when the field fits in usize. + #[inline] + pub const unsafe fn raw_get_const( + this: *const Self, + ) -> u64 { + debug_assert!(BIT_WIDTH <= 64); + debug_assert!(BIT_OFFSET / 8 < N); + debug_assert!((BIT_OFFSET + (BIT_WIDTH as usize)) / 8 <= N); + if BIT_WIDTH == 0 { + return 0; + } + let start_byte = BIT_OFFSET / 8; + let bit_shift = BIT_OFFSET % 8; + let bytes_needed = (BIT_WIDTH as usize + bit_shift + 7) / 8; + let storage_ptr = unsafe { core::ptr::addr_of!((*this).storage) as *const u8 }; + if BIT_WIDTH as usize + bit_shift <= usize::BITS as usize { + let mut val = 0usize; + if cfg!(target_endian = "big") { + let mut i = 0; + while i < bytes_needed { + let byte = unsafe { *storage_ptr.add(start_byte + i) }; + val |= (byte.reverse_bits() as usize) << (i * 8); + i += 1; + } + } else { + let mut i = 0; + while i < bytes_needed { + let byte = unsafe { *storage_ptr.add(start_byte + i) }; + val |= (byte as usize) << (i * 8); + i += 1; + } + } + val >>= bit_shift; + val &= (1usize << BIT_WIDTH) - 1; + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (usize::BITS as usize - BIT_WIDTH as usize); + } + val as u64 + } else { + let mut val = 0u64; + if cfg!(target_endian = "big") { + let mut i = 0; + while i < bytes_needed { + let byte = unsafe { *storage_ptr.add(start_byte + i) }; + val |= (byte.reverse_bits() as u64) << (i * 8); + i += 1; + } + } else { + let mut i = 0; + while i < bytes_needed { + let byte = unsafe { *storage_ptr.add(start_byte + i) }; + val |= (byte as u64) << (i * 8); + i += 1; + } + } + val >>= bit_shift; + if BIT_WIDTH < 64 { + val &= (1u64 << BIT_WIDTH) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - BIT_WIDTH as usize); + } + val + } + } + /// Raw pointer set using const generics for compile-time optimization. + /// Uses native word size operations when the field fits in usize. + #[inline] + pub unsafe fn raw_set_const( + this: *mut Self, + val: u64, + ) { + debug_assert!(BIT_WIDTH <= 64); + debug_assert!(BIT_OFFSET / 8 < N); + debug_assert!((BIT_OFFSET + (BIT_WIDTH as usize)) / 8 <= N); + if BIT_WIDTH == 0 { + return; + } + let start_byte = BIT_OFFSET / 8; + let bit_shift = BIT_OFFSET % 8; + let bytes_needed = (BIT_WIDTH as usize + bit_shift + 7) / 8; + let storage_ptr = this.cast::<[u8; N]>().cast::(); + if BIT_WIDTH as usize + bit_shift <= usize::BITS as usize { + let mut val = val as usize; + val &= (1usize << BIT_WIDTH) - 1; + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (usize::BITS as usize - BIT_WIDTH as usize); + } + val <<= bit_shift; + let field_mask = ((1usize << BIT_WIDTH) - 1) << bit_shift; + let mut i = 0; + while i < bytes_needed { + let byte_val = (val >> (i * 8)) as u8; + let byte_mask = (field_mask >> (i * 8)) as u8; + let byte_ptr = unsafe { storage_ptr.add(start_byte + i) }; + if cfg!(target_endian = "big") { + let byte = unsafe { (*byte_ptr).reverse_bits() }; + let new_byte = (byte & !byte_mask) | (byte_val & byte_mask); + unsafe { *byte_ptr = new_byte.reverse_bits() }; + } else { + unsafe { + *byte_ptr = (*byte_ptr & !byte_mask) | (byte_val & byte_mask) + }; + } + i += 1; + } + } else { + let mut val = val; + if BIT_WIDTH < 64 { + val &= (1u64 << BIT_WIDTH) - 1; + } + if cfg!(target_endian = "big") { + val = val.reverse_bits() >> (64 - BIT_WIDTH as usize); + } + val <<= bit_shift; + let field_mask = if BIT_WIDTH as usize + bit_shift >= 64 { + !0u64 << bit_shift + } else { + ((1u64 << BIT_WIDTH) - 1) << bit_shift + }; + let mut i = 0; + while i < bytes_needed { + let byte_val = (val >> (i * 8)) as u8; + let byte_mask = (field_mask >> (i * 8)) as u8; + let byte_ptr = unsafe { storage_ptr.add(start_byte + i) }; + if cfg!(target_endian = "big") { + let byte = unsafe { (*byte_ptr).reverse_bits() }; + let new_byte = (byte & !byte_mask) | (byte_val & byte_mask); + unsafe { *byte_ptr = new_byte.reverse_bits() }; + } else { + unsafe { + *byte_ptr = (*byte_ptr & !byte_mask) | (byte_val & byte_mask) + }; + } + i += 1; + } + } + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct RenameMe { + pub plain: ::std::os::raw::c_int, + pub rust_friendly: ::std::os::raw::c_int, + pub char_a: ::std::os::raw::c_char, + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub __bindgen_padding_0: u16, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of RenameMe"][::std::mem::size_of::() - 12usize]; + ["Alignment of RenameMe"][::std::mem::align_of::() - 4usize]; + [ + "Offset of field: RenameMe::plain", + ][::std::mem::offset_of!(RenameMe, plain) - 0usize]; + [ + "Offset of field: RenameMe::rust_friendly", + ][::std::mem::offset_of!(RenameMe, rust_friendly) - 4usize]; + [ + "Offset of field: RenameMe::char_a", + ][::std::mem::offset_of!(RenameMe, char_a) - 8usize]; +}; +impl RenameMe { + #[inline] + pub fn bitfield_less_ugly_name(&self) -> ::std::os::raw::c_int { + unsafe { + ::std::mem::transmute(self._bitfield_1.get_const::<0usize, 1u8>() as u32) + } + } + #[inline] + pub fn set_bitfield_less_ugly_name(&mut self, val: ::std::os::raw::c_int) { + unsafe { + let val: u32 = val as _; + self._bitfield_1.set_const::<0usize, 1u8>(val as u64) + } + } + #[inline] + pub unsafe fn bitfield_less_ugly_name_raw( + this: *const Self, + ) -> ::std::os::raw::c_int { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_get_const::< + 0usize, + 1u8, + >(::std::ptr::addr_of!((*this)._bitfield_1)) as u32, + ) + } + } + #[inline] + pub unsafe fn set_bitfield_less_ugly_name_raw( + this: *mut Self, + val: ::std::os::raw::c_int, + ) { + unsafe { + let val: u32 = val as _; + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_set_const::< + 0usize, + 1u8, + >(::std::ptr::addr_of_mut!((*this)._bitfield_1), val as u64) + } + } + #[inline] + pub fn bitfield_better_name(&self) -> ::std::os::raw::c_int { + unsafe { + ::std::mem::transmute(self._bitfield_1.get_const::<1usize, 1u8>() as u32) + } + } + #[inline] + pub fn set_bitfield_better_name(&mut self, val: ::std::os::raw::c_int) { + unsafe { + let val: u32 = val as _; + self._bitfield_1.set_const::<1usize, 1u8>(val as u64) + } + } + #[inline] + pub unsafe fn bitfield_better_name_raw(this: *const Self) -> ::std::os::raw::c_int { + unsafe { + ::std::mem::transmute( + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_get_const::< + 1usize, + 1u8, + >(::std::ptr::addr_of!((*this)._bitfield_1)) as u32, + ) + } + } + #[inline] + pub unsafe fn set_bitfield_better_name_raw( + this: *mut Self, + val: ::std::os::raw::c_int, + ) { + unsafe { + let val: u32 = val as _; + <__BindgenBitfieldUnit< + [u8; 1usize], + >>::raw_set_const::< + 1usize, + 1u8, + >(::std::ptr::addr_of_mut!((*this)._bitfield_1), val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + bitfield_less_ugly_name: ::std::os::raw::c_int, + bitfield_better_name: ::std::os::raw::c_int, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); + __bindgen_bitfield_unit + .set_const::< + 0usize, + 1u8, + >({ + let bitfield_less_ugly_name: u32 = bitfield_less_ugly_name as _; + bitfield_less_ugly_name as u64 + }); + __bindgen_bitfield_unit + .set_const::< + 1usize, + 1u8, + >({ + let bitfield_better_name: u32 = bitfield_better_name as _; + bitfield_better_name as u64 + }); + __bindgen_bitfield_unit + } +} diff --git a/bindgen-tests/tests/headers/field-rename-callback.h b/bindgen-tests/tests/headers/field-rename-callback.h new file mode 100644 index 0000000000..42800b7b7c --- /dev/null +++ b/bindgen-tests/tests/headers/field-rename-callback.h @@ -0,0 +1,9 @@ +// bindgen-parse-callbacks: struct-field-rename + +struct RenameMe { + int plain; + int renamed_member; + char a; + int bitfield_uGlyName: 1; + int bitfieldWorse_name: 1; +}; diff --git a/bindgen-tests/tests/parse_callbacks/mod.rs b/bindgen-tests/tests/parse_callbacks/mod.rs index 02d7fe8316..7e9f011812 100644 --- a/bindgen-tests/tests/parse_callbacks/mod.rs +++ b/bindgen-tests/tests/parse_callbacks/mod.rs @@ -73,6 +73,27 @@ impl ParseCallbacks for EnumVariantRename { } } +#[derive(Debug)] +struct StructFieldRename; + +impl ParseCallbacks for StructFieldRename { + fn field_name(&self, info: FieldInfo<'_>) -> Option { + if info.type_name == "RenameMe" { + if info.field_type_name == Some("char") { + return Some(format!("char_{}", info.field_name)); + } + match info.field_name { + "renamed_member" => Some("rust_friendly".into()), + "bitfield_uGlyName" => Some("bitfield_less_ugly_name".into()), + "bitfieldWorse_name" => Some("bitfield_better_name".into()), + _ => None, + } + } else { + None + } + } +} + #[derive(Debug)] struct BlocklistedTypeImplementsTrait; @@ -163,6 +184,7 @@ impl ParseCallbacks for OperatorRename { pub fn lookup(cb: &str) -> Box { match cb { "enum-variant-rename" => Box::new(EnumVariantRename), + "struct-field-rename" => Box::new(StructFieldRename), "blocklisted-type-implements-trait" => { Box::new(BlocklistedTypeImplementsTrait) } diff --git a/bindgen/callbacks.rs b/bindgen/callbacks.rs index 630a306aec..4df316b9d1 100644 --- a/bindgen/callbacks.rs +++ b/bindgen/callbacks.rs @@ -187,6 +187,11 @@ pub trait ParseCallbacks: fmt::Debug { None } + /// Allows to rename a struct or union field, replacing `_info.field_name`. + fn field_name(&self, _info: FieldInfo<'_>) -> Option { + None + } + /// Process a function name that as exactly one `va_list` argument /// to be wrapped as a variadic function with the wrapped static function /// feature. @@ -350,8 +355,8 @@ pub enum ItemKind { Var, } -/// Relevant information about a field for which visibility can be determined using -/// [`ParseCallbacks::field_visibility`]. +/// Relevant information about a field for which visibility and name can be overridden using +/// [`ParseCallbacks::field_visibility`] and [`ParseCallbacks::field_name`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[non_exhaustive] pub struct FieldInfo<'a> { diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index a41fa6f0b2..edf99374e5 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -11,6 +11,7 @@ use super::layout::Layout; use super::template::TemplateParameters; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; +use crate::callbacks::FieldInfo; use crate::clang; use crate::codegen::struct_layout::align_to; use crate::ir::derive::CanDeriveCopy; @@ -703,7 +704,12 @@ impl CompFields { } } - fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) { + fn assign_field_names( + &mut self, + ctx: &BindgenContext, + canonical_type_name: &str, + methods: &[Method], + ) { let fields = match *self { CompFields::After { ref mut fields, .. } => fields, // Nothing to do here. @@ -713,6 +719,46 @@ impl CompFields { } }; + for field in fields.iter_mut() { + match field { + Field::DataMember(FieldData { name, ty, .. }) => { + if let Some(original_name) = name.as_deref() { + let maybe_rename = ctx.options().last_callback(|cb| { + cb.field_name(FieldInfo { + type_name: canonical_type_name, + field_name: original_name, + field_type_name: ctx.resolve_type(*ty).name(), + }) + }); + + if let Some(new_name) = maybe_rename { + *name = Some(new_name); + } + } + } + Field::Bitfields(BitfieldUnit { bitfields, .. }) => { + for bitfield in bitfields.iter_mut() { + if let Some(original_name) = bitfield.name() { + let maybe_rename = + ctx.options().last_callback(|cb| { + cb.field_name(FieldInfo { + type_name: canonical_type_name, + field_name: original_name, + field_type_name: ctx + .resolve_type(bitfield.ty()) + .name(), + }) + }); + + if let Some(new_name) = maybe_rename { + bitfield.data.name = Some(new_name); + } + } + } + } + } + } + fn has_method( methods: &[Method], ctx: &BindgenContext, @@ -1700,8 +1746,13 @@ impl CompInfo { } /// Assign for each anonymous field a generated name. - pub(crate) fn deanonymize_fields(&mut self, ctx: &BindgenContext) { - self.fields.deanonymize_fields(ctx, &self.methods); + pub(crate) fn assign_field_names( + &mut self, + ctx: &BindgenContext, + canonical_type_name: &str, + ) { + self.fields + .assign_field_names(ctx, canonical_type_name, &self.methods); } /// Returns whether the current union can be represented as a Rust `union` diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index 8e4163df5e..b5b6b4a000 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -21,6 +21,7 @@ use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, Type, TypeKind}; use crate::clang::{self, ABIKind, Cursor}; use crate::codegen::CodegenError; +use crate::ir::item::ItemCanonicalName; use crate::BindgenOptions; use crate::{Entry, HashMap, HashSet}; @@ -1014,8 +1015,8 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Assign a new generated name for each anonymous field. - fn deanonymize_fields(&mut self) { - let _t = self.timer("deanonymize_fields"); + fn assign_field_names(&mut self) { + let _t = self.timer("assign_field_names"); let comp_item_ids: Vec = self .items() @@ -1028,13 +1029,15 @@ If you encounter an error missing from this list, please file an issue or a PR!" .collect(); for id in comp_item_ids { + let canonical_type_name = + self.resolve_item(id).canonical_name(self); self.with_loaned_item(id, |ctx, item| { item.kind_mut() .as_type_mut() .unwrap() .as_comp_mut() .unwrap() - .deanonymize_fields(ctx); + .assign_field_names(ctx, &canonical_type_name); }); } } @@ -1184,7 +1187,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.compute_bitfield_units(); self.process_replacements(); - self.deanonymize_fields(); + self.assign_field_names(); self.assert_no_dangling_references();