#![warn(missing_docs)] fires within the proc macro because of missing documentation on new
Closed this issue · 3 comments
chris-oo commented
When #![warn(missing_docs)]
is used, bitfield-struct's new implementation doesn't contain a doc comment which results in the lint firing. For example, the following code causes the lint to fire:
#![warn(missing_docs)]
//! My library.
use bitfield_struct::bitfield;
#[bitfield(u64)]
#[derive(Default)]
pub struct MyBitfield {
/// Look, a field.
#[bits(1)]
pub field_a: bool,
/// Some field.
#[bits(1)]
pub field_b: bool,
/// Another field.
#[bits(1)]
pub field_c: bool,
/// Currently reserved.
#[bits(61)]
pub reserved: u64,
}
Looking at rust-analyzer's recursive expansion, it seems like the new function needs a doc comment for the lint not to fire?
// Recursive expansion of bitfield macro
// ======================================
#[derive(Default, Copy, Clone)]
#[repr(transparent)]
pub struct MyBitfield(u64);
impl MyBitfield {
pub const fn new() -> Self {
Self(0)
}
const FIELD_A_BITS: usize = 1usize;
const FIELD_A_OFFSET: usize = 0usize;
#[doc = " Look, a field."]
#[doc = "\n\nBits: 0..1"]
pub fn set_field_a(&mut self, value: bool) {
*self = self.with_field_a(value);
}
#[doc = " Look, a field."]
#[doc = "\n\nBits: 0..1"]
pub const fn with_field_a(self, value: bool) -> Self {
Self(self.0 & !(1 << 0usize) | (value as u64) << 0usize)
}
#[doc = " Look, a field."]
#[doc = "\n\nBits: 0..1"]
pub const fn field_a(&self) -> bool {
((self.0 >> 0usize) & 1) != 0
}
const FIELD_B_BITS: usize = 1usize;
const FIELD_B_OFFSET: usize = 1usize;
#[doc = " Some field."]
#[doc = "\n\nBits: 1..2"]
pub fn set_field_b(&mut self, value: bool) {
*self = self.with_field_b(value);
}
#[doc = " Some field."]
#[doc = "\n\nBits: 1..2"]
pub const fn with_field_b(self, value: bool) -> Self {
Self(self.0 & !(1 << 1usize) | (value as u64) << 1usize)
}
#[doc = " Some field."]
#[doc = "\n\nBits: 1..2"]
pub const fn field_b(&self) -> bool {
((self.0 >> 1usize) & 1) != 0
}
const FIELD_C_BITS: usize = 1usize;
const FIELD_C_OFFSET: usize = 2usize;
#[doc = " Another field."]
#[doc = "\n\nBits: 2..3"]
pub fn set_field_c(&mut self, value: bool) {
*self = self.with_field_c(value);
}
#[doc = " Another field."]
#[doc = "\n\nBits: 2..3"]
pub const fn with_field_c(self, value: bool) -> Self {
Self(self.0 & !(1 << 2usize) | (value as u64) << 2usize)
}
#[doc = " Another field."]
#[doc = "\n\nBits: 2..3"]
pub const fn field_c(&self) -> bool {
((self.0 >> 2usize) & 1) != 0
}
const RESERVED_BITS: usize = 61usize;
const RESERVED_OFFSET: usize = 3usize;
#[doc = " Currently reserved."]
#[doc = "\n\nBits: 3..64"]
pub fn set_reserved(&mut self, value: u64) {
*self = self.with_reserved(value);
}
#[doc = " Currently reserved."]
#[doc = "\n\nBits: 3..64"]
pub const fn with_reserved(self, value: u64) -> Self {
#[allow(unused_comparisons)]
debug_assert!(if value> = 0 {
value& !0x1fffffffffffffff = = 0
}else {
!value& !0x1fffffffffffffff = = 0
},"value out of bounds");
Self(
self.0 & !(0x1fffffffffffffff << 3usize)
| (value as u64 & 0x1fffffffffffffff) << 3usize,
)
}
#[doc = " Currently reserved."]
#[doc = "\n\nBits: 3..64"]
pub const fn reserved(&self) -> u64 {
let shift = u64::BITS - 61u32;
(((self.0 >> 3usize) as u64) << shift) >> shift
}
}
impl From<u64> for MyBitfield {
fn from(v: u64) -> Self {
Self(v)
}
}
impl From<MyBitfield> for u64 {
fn from(v: MyBitfield) -> u64 {
v.0
}
}
impl core::fmt::Debug for MyBitfield {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("MyBitfield")
.field("field_a", &self.field_a())
.field("field_b", &self.field_b())
.field("field_c", &self.field_c())
.field("reserved", &self.reserved())
.finish()
}
}
I've worked around this by putting the structure inside it's own module where the lint is ignored, then pub re-exporting the bitfield, but it would be nice to not to have to do that workaround.
wrenger commented
Yes that looks like an oversight. I'll fix that.
chris-oo commented
Awesome thanks!