Remove allow(pedantic) from formatter (#6549)

This commit is contained in:
Micha Reiser 2023-08-14 14:02:06 +02:00 committed by GitHub
parent c39bcbadff
commit 9584f613b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 348 additions and 316 deletions

View file

@ -20,10 +20,10 @@ pub(super) struct StackFrame {
/// Stores arguments passed to `print_element` call, holding the state specific to printing an element.
/// E.g. the `indent` depends on the token the Printer's currently processing. That's why
/// it must be stored outside of the [PrinterState] that stores the state common to all elements.
/// it must be stored outside of the [`PrinterState`] that stores the state common to all elements.
///
/// The state is passed by value, which is why it's important that it isn't storing any heavy
/// data structures. Such structures should be stored on the [PrinterState] instead.
/// data structures. Such structures should be stored on the [`PrinterState`] instead.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(super) struct PrintElementArgs {
indent: Indention,
@ -39,15 +39,15 @@ impl PrintElementArgs {
}
}
pub(super) fn mode(&self) -> PrintMode {
pub(super) fn mode(self) -> PrintMode {
self.mode
}
pub(super) fn measure_mode(&self) -> MeasureMode {
pub(super) fn measure_mode(self) -> MeasureMode {
self.measure_mode
}
pub(super) fn indention(&self) -> Indention {
pub(super) fn indention(self) -> Indention {
self.indent
}
@ -92,9 +92,9 @@ impl Default for PrintElementArgs {
}
}
/// Call stack that stores the [PrintElementCallArgs].
/// Call stack that stores the [`PrintElementCallArgs`].
///
/// New [PrintElementCallArgs] are pushed onto the stack for every [`start`](Tag::is_start) [`Tag`](FormatElement::Tag)
/// New [`PrintElementCallArgs`] are pushed onto the stack for every [`start`](Tag::is_start) [`Tag`](FormatElement::Tag)
/// and popped when reaching the corresponding [`end`](Tag::is_end) [`Tag`](FormatElement::Tag).
pub(super) trait CallStack {
type Stack: Stack<StackFrame> + Debug;
@ -158,7 +158,7 @@ pub(super) trait CallStack {
}
}
/// Returns the [PrintElementArgs] for the current stack frame.
/// Returns the [`PrintElementArgs`] for the current stack frame.
fn top(&self) -> PrintElementArgs {
self.stack()
.top()
@ -166,7 +166,7 @@ pub(super) trait CallStack {
.args
}
/// Returns the [TagKind] of the current stack frame or [None] if this is the root stack frame.
/// Returns the [`TagKind`] of the current stack frame or [None] if this is the root stack frame.
fn top_kind(&self) -> Option<TagKind> {
match self
.stack()
@ -179,16 +179,16 @@ pub(super) trait CallStack {
}
}
/// Creates a new stack frame for a [FormatElement::Tag] of `kind` with `args` as the call arguments.
/// Creates a new stack frame for a [`FormatElement::Tag`] of `kind` with `args` as the call arguments.
fn push(&mut self, kind: TagKind, args: PrintElementArgs) {
self.stack_mut().push(StackFrame {
kind: StackFrameKind::Tag(kind),
args,
})
});
}
}
/// Call stack used for printing the [FormatElement]s
/// Call stack used for printing the [`FormatElement`]s
#[derive(Debug, Clone)]
pub(super) struct PrintCallStack(Vec<StackFrame>);
@ -215,7 +215,7 @@ impl CallStack for PrintCallStack {
/// Call stack used for measuring if some content fits on the line.
///
/// The stack is a view on top of the [PrintCallStack] because the stack frames are still necessary for printing.
/// The stack is a view on top of the [`PrintCallStack`] because the stack frames are still necessary for printing.
#[must_use]
pub(super) struct FitsCallStack<'print> {
stack: StackedStack<'print, StackFrame>,

View file

@ -84,6 +84,7 @@ impl<'a> Printer<'a> {
queue: &mut PrintQueue<'a>,
element: &'a FormatElement,
) -> PrintResult<()> {
#[allow(clippy::enum_glob_use)]
use Tag::*;
let args = stack.top();
@ -94,7 +95,7 @@ impl<'a> Printer<'a> {
FormatElement::DynamicText { text } => self.print_text(text, None),
FormatElement::SourceCodeSlice { slice, .. } => {
let text = slice.text(self.source_code);
self.print_text(text, Some(slice.range()))
self.print_text(text, Some(slice.range()));
}
FormatElement::Line(line_mode) => {
if args.mode().is_flat()
@ -221,6 +222,8 @@ impl<'a> Printer<'a> {
FormatElement::Tag(StartVerbatim(kind)) => {
if let VerbatimKind::Verbatim { length } = kind {
// SAFETY: Ruff only supports formatting files <= 4GB
#[allow(clippy::cast_possible_truncation)]
self.state.verbatim_markers.push(TextRange::at(
TextSize::from(self.state.buffer.len() as u32),
*length,
@ -291,7 +294,7 @@ impl<'a> Printer<'a> {
kind: TagKind,
mode: GroupMode,
args: PrintElementArgs,
queue: &mut PrintQueue<'a>,
queue: &PrintQueue<'a>,
stack: &mut PrintCallStack,
) -> PrintResult<PrintMode> {
let group_mode = match mode {
@ -384,7 +387,7 @@ impl<'a> Printer<'a> {
if let Some(last) = self.state.source_markers.last() {
if last != &marker {
self.state.source_markers.push(marker)
self.state.source_markers.push(marker);
}
} else {
self.state.source_markers.push(marker);
@ -411,10 +414,11 @@ impl<'a> Printer<'a> {
queue.push(suffix);
}
LineSuffixEntry::Args(args) => {
stack.push(TagKind::LineSuffix, args);
const LINE_SUFFIX_END: &FormatElement =
&FormatElement::Tag(Tag::EndLineSuffix);
stack.push(TagKind::LineSuffix, args);
queue.push(LINE_SUFFIX_END);
}
}
@ -437,7 +441,7 @@ impl<'a> Printer<'a> {
self.state.measured_group_fits = true;
let normal_variants = &variants[..variants.len() - 1];
for variant in normal_variants.iter() {
for variant in normal_variants {
// Test if this variant fits and if so, use it. Otherwise try the next
// variant.
@ -614,7 +618,7 @@ impl<'a> Printer<'a> {
}
}
/// Semantic alias for [Self::print_entry] for fill items.
/// Semantic alias for [`Self::print_entry`] for fill items.
fn print_fill_item(
&mut self,
queue: &mut PrintQueue<'a>,
@ -624,7 +628,7 @@ impl<'a> Printer<'a> {
self.print_entry(queue, stack, args)
}
/// Semantic alias for [Self::print_entry] for fill separators.
/// Semantic alias for [`Self::print_entry`] for fill separators.
fn print_fill_separator(
&mut self,
queue: &mut PrintQueue<'a>,
@ -636,7 +640,7 @@ impl<'a> Printer<'a> {
/// Fully print an element (print the element itself and all its descendants)
///
/// Unlike [print_element], this function ensures the entire element has
/// Unlike [`print_element`], this function ensures the entire element has
/// been printed when it returns and the queue is back to its original state
fn print_entry(
&mut self,
@ -703,9 +707,11 @@ impl<'a> Printer<'a> {
} else {
self.state.buffer.push(char);
#[allow(clippy::cast_possible_truncation)]
let char_width = if char == '\t' {
self.options.tab_width as u32
u32::from(self.options.tab_width)
} else {
// SAFETY: A u32 is sufficient to represent the width of a file <= 4GB
char.width().unwrap_or(0) as u32
};
@ -791,7 +797,7 @@ enum Indention {
}
impl Indention {
const fn is_empty(&self) -> bool {
const fn is_empty(self) -> bool {
matches!(self, Indention::Level(0))
}
@ -801,27 +807,27 @@ impl Indention {
}
/// Returns the indention level
fn level(&self) -> u16 {
fn level(self) -> u16 {
match self {
Indention::Level(count) => *count,
Indention::Align { level: indent, .. } => *indent,
Indention::Level(count) => count,
Indention::Align { level: indent, .. } => indent,
}
}
/// Returns the number of trailing align spaces or 0 if none
fn align(&self) -> u8 {
fn align(self) -> u8 {
match self {
Indention::Level(_) => 0,
Indention::Align { align, .. } => (*align).into(),
Indention::Align { align, .. } => align.into(),
}
}
/// Increments the level by one.
///
/// The behaviour depends on the [`indent_style`][IndentStyle] if this is an [Indent::Align]:
/// The behaviour depends on the [`indent_style`][IndentStyle] if this is an [`Indent::Align`]:
/// - **Tabs**: `align` is converted into an indent. This results in `level` increasing by two: once for the align, once for the level increment
/// - **Spaces**: Increments the `level` by one and keeps the `align` unchanged.
/// Keeps any the current value is [Indent::Align] and increments the level by one.
/// Keeps any the current value is [`Indent::Align`] and increments the level by one.
fn increment_level(self, indent_style: IndentStyle) -> Self {
match self {
Indention::Level(count) => Indention::Level(count + 1),
@ -838,8 +844,8 @@ impl Indention {
}
/// Decrements the indent by one by:
/// - Reducing the level by one if this is [Indent::Level]
/// - Removing the `align` if this is [Indent::Align]
/// - Reducing the level by one if this is [`Indent::Level`]
/// - Removing the `align` if this is [`Indent::Align`]
///
/// No-op if the level is already zero.
fn decrement(self) -> Self {
@ -851,7 +857,7 @@ impl Indention {
/// Adds an `align` of `count` spaces to the current indention.
///
/// It increments the `level` value if the current value is [Indent::IndentAlign].
/// It increments the `level` value if the current value is [`Indent::IndentAlign`].
fn set_align(self, count: NonZeroU8) -> Self {
match self {
Indention::Level(indent_count) => Indention::Align {
@ -955,9 +961,9 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
Ok(true)
}
/// Tests if the content of a `Fill` item fits in [PrintMode::Flat].
/// Tests if the content of a `Fill` item fits in [`PrintMode::Flat`].
///
/// Returns `Err` if the top element of the queue is not a [Tag::StartEntry]
/// Returns `Err` if the top element of the queue is not a [`Tag::StartEntry`]
/// or if the document has any mismatching start/end tags.
fn fill_item_fits(&mut self) -> PrintResult<bool> {
self.fill_entry_fits(PrintMode::Flat)
@ -965,17 +971,17 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
/// Tests if the content of a `Fill` separator fits with `mode`.
///
/// Returns `Err` if the top element of the queue is not a [Tag::StartEntry]
/// Returns `Err` if the top element of the queue is not a [`Tag::StartEntry`]
/// or if the document has any mismatching start/end tags.
fn fill_separator_fits(&mut self, mode: PrintMode) -> PrintResult<bool> {
self.fill_entry_fits(mode)
}
/// Tests if the elements between the [Tag::StartEntry] and [Tag::EndEntry]
/// Tests if the elements between the [`Tag::StartEntry`] and [`Tag::EndEntry`]
/// of a fill item or separator fits with `mode`.
///
/// Returns `Err` if the queue isn't positioned at a [Tag::StartEntry] or if
/// the matching [Tag::EndEntry] is missing.
/// Returns `Err` if the queue isn't positioned at a [`Tag::StartEntry`] or if
/// the matching [`Tag::EndEntry`] is missing.
fn fill_entry_fits(&mut self, mode: PrintMode) -> PrintResult<bool> {
let start_entry = self.queue.top();
@ -997,6 +1003,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
/// Tests if the passed element fits on the current line or not.
fn fits_element(&mut self, element: &'a FormatElement) -> PrintResult<Fits> {
#[allow(clippy::enum_glob_use)]
use Tag::*;
let args = self.stack.top();
@ -1093,7 +1100,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
}
FormatElement::Tag(StartGroup(group)) => {
return self.fits_group(TagKind::Group, group.mode(), group.id(), args);
return Ok(self.fits_group(TagKind::Group, group.mode(), group.id(), args));
}
FormatElement::Tag(StartConditionalGroup(group)) => {
@ -1108,10 +1115,14 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
};
if condition.mode == print_mode {
return self.fits_group(TagKind::ConditionalGroup, group.mode(), None, args);
} else {
self.stack.push(TagKind::ConditionalGroup, args);
return Ok(self.fits_group(
TagKind::ConditionalGroup,
group.mode(),
None,
args,
));
}
self.stack.push(TagKind::ConditionalGroup, args);
}
FormatElement::Tag(StartConditionalContent(condition)) => {
@ -1183,14 +1194,14 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
TagKind::FitsExpanded,
args.with_print_mode(PrintMode::Expanded)
.with_measure_mode(MeasureMode::AllLines),
)
);
} else {
if propagate_expand.get() && args.mode().is_flat() {
return Ok(Fits::No);
}
// As usual
self.stack.push(TagKind::FitsExpanded, args)
self.stack.push(TagKind::FitsExpanded, args);
}
}
@ -1227,17 +1238,17 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
mode: GroupMode,
id: Option<GroupId>,
args: PrintElementArgs,
) -> PrintResult<Fits> {
) -> Fits {
if self.must_be_flat && !mode.is_flat() {
return Ok(Fits::No);
return Fits::No;
}
// Continue printing groups in expanded mode if measuring a `best_fitting` element where
// a group expands.
let print_mode = if !mode.is_flat() {
PrintMode::Expanded
} else {
let print_mode = if mode.is_flat() {
args.mode()
} else {
PrintMode::Expanded
};
self.stack.push(kind, args.with_print_mode(print_mode));
@ -1246,30 +1257,32 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
self.group_modes_mut().insert_print_mode(id, print_mode);
}
Ok(Fits::Maybe)
Fits::Maybe
}
fn fits_text(&mut self, text: &str, args: PrintElementArgs) -> Fits {
let indent = std::mem::take(&mut self.state.pending_indent);
self.state.line_width +=
indent.level() as u32 * self.options().indent_width() as u32 + indent.align() as u32;
self.state.line_width += u32::from(indent.level())
* u32::from(self.options().indent_width())
+ u32::from(indent.align());
for c in text.chars() {
let char_width = match c {
'\t' => self.options().tab_width as u32,
'\t' => u32::from(self.options().tab_width),
'\n' => {
if self.must_be_flat {
return Fits::No;
} else {
match args.measure_mode() {
MeasureMode::FirstLine => return Fits::Yes,
MeasureMode::AllLines => {
self.state.line_width = 0;
continue;
}
}
match args.measure_mode() {
MeasureMode::FirstLine => return Fits::Yes,
MeasureMode::AllLines => {
self.state.line_width = 0;
continue;
}
};
}
}
// SAFETY: A u32 is sufficient to format files <= 4GB
#[allow(clippy::cast_possible_truncation)]
c => c.width().unwrap_or(0) as u32,
};
self.state.line_width += char_width;
@ -1352,9 +1365,10 @@ enum Fits {
impl From<bool> for Fits {
fn from(value: bool) -> Self {
match value {
true => Fits::Yes,
false => Fits::No,
if value {
Fits::Yes
} else {
Fits::No
}
}
}
@ -1418,7 +1432,7 @@ mod tests {
],
});
assert_eq!(r#"["a", "b", "c", "d"]"#, result.as_code())
assert_eq!(r#"["a", "b", "c", "d"]"#, result.as_code());
}
#[test]
@ -1447,7 +1461,7 @@ mod tests {
b
a"#,
formatted.as_code()
)
);
}
#[test]
@ -1489,13 +1503,13 @@ two lines`,
"b",
]"#,
result.as_code()
)
);
}
#[test]
fn it_breaks_a_group_if_it_contains_a_hard_line_break() {
let result = format(&group(&format_args![text("a"), block_indent(&text("b"))]));
assert_eq!("a\n b\n", result.as_code())
assert_eq!("a\n b\n", result.as_code());
}
#[test]
@ -1559,7 +1573,7 @@ two lines`,
text("b"),
]);
assert_eq!("a\nb", result.as_code())
assert_eq!("a\nb", result.as_code());
}
#[test]
@ -1572,7 +1586,7 @@ two lines`,
text("b"),
]);
assert_eq!("a\n\n\n\nb", result.as_code())
assert_eq!("a\n\n\n\nb", result.as_code());
}
#[test]
@ -1586,7 +1600,7 @@ two lines`,
text("b"),
]);
assert_eq!("a\n\n\nb", result.as_code())
assert_eq!("a\n\n\nb", result.as_code());
}
#[test]
@ -1648,7 +1662,7 @@ two lines`,
assert_eq!(
printed.as_code(),
"1, 2, 3,\n723493294,\n[5],\n[\n\t123456789\n]"
)
);
}
#[test]
@ -1678,7 +1692,7 @@ two lines`,
&line_suffix(&format_args![space(), text("// trailing")])
]);
assert_eq!(printed.as_code(), "[1, 2, 3]; // trailing")
assert_eq!(printed.as_code(), "[1, 2, 3]; // trailing");
}
#[test]

View file

@ -1,6 +1,6 @@
use crate::{FormatOptions, IndentStyle, LineWidth};
/// Options that affect how the [crate::Printer] prints the format tokens
/// Options that affect how the [`crate::Printer`] prints the format tokens
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PrinterOptions {
/// Width of a single tab character (does it equal 2, 4, ... spaces?)
@ -33,7 +33,7 @@ impl Default for PrintWidth {
impl From<LineWidth> for PrintWidth {
fn from(width: LineWidth) -> Self {
Self(u16::from(width) as u32)
Self(u32::from(u16::from(width)))
}
}
@ -61,11 +61,13 @@ where
}
impl PrinterOptions {
#[must_use]
pub fn with_print_width(mut self, width: PrintWidth) -> Self {
self.print_width = width;
self
}
#[must_use]
pub fn with_indent(mut self, style: IndentStyle) -> Self {
self.indent_style = style;
@ -114,7 +116,7 @@ impl Default for PrinterOptions {
PrinterOptions {
tab_width: 2,
print_width: PrintWidth::default(),
indent_style: Default::default(),
indent_style: IndentStyle::default(),
line_ending: LineEnding::LineFeed,
}
}

View file

@ -7,7 +7,7 @@ use std::fmt::Debug;
use std::iter::FusedIterator;
use std::marker::PhantomData;
/// Queue of [FormatElement]s.
/// Queue of [`FormatElement`]s.
pub(super) trait Queue<'a> {
type Stack: Stack<&'a [FormatElement]>;
@ -40,19 +40,19 @@ pub(super) trait Queue<'a> {
}
}
/// Returns the next element, not traversing into [FormatElement::Interned].
/// Returns the next element, not traversing into [`FormatElement::Interned`].
fn top_with_interned(&self) -> Option<&'a FormatElement> {
self.stack()
.top()
.map(|top_slice| &top_slice[self.next_index()])
}
/// Returns the next element, recursively resolving the first element of [FormatElement::Interned].
/// Returns the next element, recursively resolving the first element of [`FormatElement::Interned`].
fn top(&self) -> Option<&'a FormatElement> {
let mut top = self.top_with_interned();
while let Some(FormatElement::Interned(interned)) = top {
top = interned.first()
top = interned.first();
}
top
@ -60,7 +60,7 @@ pub(super) trait Queue<'a> {
/// Queues a single element to process before the other elements in this queue.
fn push(&mut self, element: &'a FormatElement) {
self.extend_back(std::slice::from_ref(element))
self.extend_back(std::slice::from_ref(element));
}
/// Queues a slice of elements to process before the other elements in this queue.
@ -73,7 +73,7 @@ pub(super) trait Queue<'a> {
let next_index = self.next_index();
let stack = self.stack_mut();
if let Some(top) = stack.pop() {
stack.push(&top[next_index..])
stack.push(&top[next_index..]);
}
stack.push(slice);
@ -150,14 +150,14 @@ impl<'a> Queue<'a> for PrintQueue<'a> {
}
fn set_next_index(&mut self, index: usize) {
self.next_index = index
self.next_index = index;
}
}
/// Queue for measuring if an element fits on the line.
///
/// The queue is a view on top of the [PrintQueue] because no elements should be removed
/// from the [PrintQueue] while measuring.
/// The queue is a view on top of the [`PrintQueue`] because no elements should be removed
/// from the [`PrintQueue`] while measuring.
#[must_use]
#[derive(Debug)]
pub(super) struct FitsQueue<'a, 'print> {
@ -203,9 +203,9 @@ impl<'a, 'print> Queue<'a> for FitsQueue<'a, 'print> {
}
}
/// Iterator that calls [Queue::pop] until it reaches the end of the document.
/// Iterator that calls [`Queue::pop`] until it reaches the end of the document.
///
/// The iterator traverses into the content of any [FormatElement::Interned].
/// The iterator traverses into the content of any [`FormatElement::Interned`].
pub(super) struct QueueIterator<'a, 'q, Q: Queue<'a>> {
queue: &'q mut Q,
lifetime: PhantomData<&'a ()>,
@ -252,32 +252,31 @@ where
type Item = &'a FormatElement;
fn next(&mut self) -> Option<Self::Item> {
match self.depth {
0 => None,
_ => {
let mut top = self.queue.pop();
if self.depth == 0 {
None
} else {
let mut top = self.queue.pop();
while let Some(FormatElement::Interned(interned)) = top {
self.queue.extend_back(interned);
top = self.queue.pop();
}
while let Some(FormatElement::Interned(interned)) = top {
self.queue.extend_back(interned);
top = self.queue.pop();
}
match top.expect("Missing end signal.") {
element @ FormatElement::Tag(tag) if tag.kind() == self.kind => {
if tag.is_start() {
self.depth += 1;
} else {
self.depth -= 1;
match top.expect("Missing end signal.") {
element @ FormatElement::Tag(tag) if tag.kind() == self.kind => {
if tag.is_start() {
self.depth += 1;
} else {
self.depth -= 1;
if self.depth == 0 {
return None;
}
if self.depth == 0 {
return None;
}
Some(element)
}
element => Some(element),
Some(element)
}
element => Some(element),
}
}
}
@ -287,7 +286,7 @@ impl<'a, Q> FusedIterator for QueueContentIterator<'a, '_, Q> where Q: Queue<'a>
/// A predicate determining when to end measuring if some content fits on the line.
///
/// Called for every [`element`](FormatElement) in the [FitsQueue] when measuring if a content
/// Called for every [`element`](FormatElement) in the [`FitsQueue`] when measuring if a content
/// fits on the line. The measuring of the content ends after the first element [`element`](FormatElement) for which this
/// predicate returns `true` (similar to a take while iterator except that it takes while the predicate returns `false`).
pub(super) trait FitsEndPredicate {
@ -303,7 +302,7 @@ impl FitsEndPredicate for AllPredicate {
}
}
/// Filter that takes all elements between two matching [Tag::StartEntry] and [Tag::EndEntry] tags.
/// Filter that takes all elements between two matching [`Tag::StartEntry`] and [`Tag::EndEntry`] tags.
#[derive(Debug)]
pub(super) enum SingleEntryPredicate {
Entry { depth: usize },

View file

@ -19,7 +19,7 @@ impl<T> Stack<T> for Vec<T> {
}
fn push(&mut self, value: T) {
self.push(value)
self.push(value);
}
fn top(&self) -> Option<&T> {