Skip to content

Commit 36c49d7

Browse files
authored
Merge pull request #2666 from topecongiro/issue-2634
Avoid flip-flopping impl items when reordering them
2 parents c3bdd3a + 43df7dc commit 36c49d7

File tree

7 files changed

+86
-45
lines changed

7 files changed

+86
-45
lines changed

src/comment.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,7 @@ impl<'a> CommentReducer<'a> {
11391139

11401140
impl<'a> Iterator for CommentReducer<'a> {
11411141
type Item = char;
1142+
11421143
fn next(&mut self) -> Option<Self::Item> {
11431144
loop {
11441145
let mut c = self.iter.next()?;

src/config/options.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ impl WidthHeuristics {
239239
single_line_if_else_max_width: 0,
240240
}
241241
}
242+
242243
// scale the default WidthHeuristics according to max_width
243244
pub fn scaled(max_width: usize) -> WidthHeuristics {
244245
let mut max_width_ratio: f32 = max_width as f32 / 100.0; // 100 is the default width -> default ratio is 1

src/imports.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,9 +799,11 @@ mod test {
799799
fn bump(&mut self) {
800800
self.input.next().unwrap();
801801
}
802+
802803
fn eat(&mut self, c: char) {
803804
assert!(self.input.next().unwrap() == c);
804805
}
806+
805807
fn push_segment(
806808
result: &mut Vec<UseSegment>,
807809
buf: &mut String,
@@ -825,6 +827,7 @@ mod test {
825827
}
826828
}
827829
}
830+
828831
fn parse_in_list(&mut self) -> UseTree {
829832
let mut result = vec![];
830833
let mut buf = String::new();

src/items.rs

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,55 @@ impl<'a> FmtVisitor<'a> {
578578

579579
combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
580580
}
581+
582+
fn visit_impl_items(&mut self, items: &[ast::ImplItem]) {
583+
if self.get_context().config.reorder_impl_items() {
584+
// Create visitor for each items, then reorder them.
585+
let mut buffer = vec![];
586+
for item in items {
587+
self.visit_impl_item(item);
588+
buffer.push((self.buffer.clone(), item.clone()));
589+
self.buffer.clear();
590+
}
591+
// type -> const -> macro -> method
592+
use ast::ImplItemKind::*;
593+
fn need_empty_line(a: &ast::ImplItemKind, b: &ast::ImplItemKind) -> bool {
594+
match (a, b) {
595+
(Type(..), Type(..)) | (Const(..), Const(..)) => false,
596+
_ => true,
597+
}
598+
}
599+
600+
buffer.sort_by(|(_, a), (_, b)| match (&a.node, &b.node) {
601+
(Type(..), _) => Ordering::Less,
602+
(_, Type(..)) => Ordering::Greater,
603+
(Const(..), _) => Ordering::Less,
604+
(_, Const(..)) => Ordering::Greater,
605+
(Macro(..), _) => Ordering::Less,
606+
(_, Macro(..)) => Ordering::Greater,
607+
_ => a.span.lo().cmp(&b.span.lo()),
608+
});
609+
let mut prev_kind = None;
610+
for (buf, item) in buffer {
611+
// Make sure that there are at least a single empty line between
612+
// different impl items.
613+
if prev_kind
614+
.as_ref()
615+
.map_or(false, |prev_kind| need_empty_line(prev_kind, &item.node))
616+
{
617+
self.push_str("\n");
618+
}
619+
let indent_str = self.block_indent.to_string_with_newline(self.config);
620+
self.push_str(&indent_str);
621+
self.push_str(buf.trim());
622+
prev_kind = Some(item.node.clone());
623+
}
624+
} else {
625+
for item in items {
626+
self.visit_impl_item(item);
627+
}
628+
}
629+
}
581630
}
582631

583632
pub fn format_impl(
@@ -672,51 +721,7 @@ pub fn format_impl(
672721
visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
673722

674723
visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
675-
if context.config.reorder_impl_items() {
676-
// Create visitor for each items, then reorder them.
677-
let mut buffer = vec![];
678-
for item in items {
679-
visitor.visit_impl_item(item);
680-
buffer.push((visitor.buffer.clone(), item.clone()));
681-
visitor.buffer.clear();
682-
}
683-
// type -> const -> macro -> method
684-
use ast::ImplItemKind::*;
685-
fn need_empty_line(a: &ast::ImplItemKind, b: &ast::ImplItemKind) -> bool {
686-
match (a, b) {
687-
(Type(..), Type(..)) | (Const(..), Const(..)) => false,
688-
_ => true,
689-
}
690-
}
691-
692-
buffer.sort_by(|(_, a), (_, b)| match (&a.node, &b.node) {
693-
(Type(..), _) => Ordering::Less,
694-
(_, Type(..)) => Ordering::Greater,
695-
(Const(..), _) => Ordering::Less,
696-
(_, Const(..)) => Ordering::Greater,
697-
(Macro(..), _) => Ordering::Less,
698-
(_, Macro(..)) => Ordering::Greater,
699-
_ => Ordering::Less,
700-
});
701-
let mut prev_kind = None;
702-
for (buf, item) in buffer {
703-
// Make sure that there are at least a single empty line between
704-
// different impl items.
705-
if prev_kind
706-
.as_ref()
707-
.map_or(false, |prev_kind| need_empty_line(prev_kind, &item.node))
708-
{
709-
visitor.push_str("\n");
710-
}
711-
visitor.push_str(&item_indent.to_string_with_newline(context.config));
712-
visitor.push_str(buf.trim());
713-
prev_kind = Some(item.node.clone());
714-
}
715-
} else {
716-
for item in items {
717-
visitor.visit_impl_item(item);
718-
}
719-
}
724+
visitor.visit_impl_items(items);
720725

721726
visitor.format_missing(item.span.hi() - BytePos(1));
722727

src/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ struct CharsIgnoreNewlineRepr<'a>(Peekable<Chars<'a>>);
568568

569569
impl<'a> Iterator for CharsIgnoreNewlineRepr<'a> {
570570
type Item = char;
571+
571572
fn next(&mut self) -> Option<char> {
572573
self.0.next().map(|c| {
573574
if c == '\r' {

tests/source/reorder-impl-items.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// rustfmt-reorder_impl_items: true
2+
3+
// The ordering of the folllowing impl items should be idempotent.
4+
impl<'a> Command<'a> {
5+
pub fn send_to(&self, w: &mut io::Write) -> io::Result<()> {
6+
match self {
7+
&Command::Data(ref c) => c.send_to(w),
8+
&Command::Vrfy(ref c) => c.send_to(w),
9+
}
10+
}
11+
12+
pub fn parse(arg: &[u8]) -> Result<Command, ParseError> {
13+
nom_to_result(command(arg))
14+
}
15+
}

tests/target/reorder-impl-items.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// rustfmt-reorder_impl_items: true
2+
3+
// The ordering of the folllowing impl items should be idempotent.
4+
impl<'a> Command<'a> {
5+
pub fn send_to(&self, w: &mut io::Write) -> io::Result<()> {
6+
match self {
7+
&Command::Data(ref c) => c.send_to(w),
8+
&Command::Vrfy(ref c) => c.send_to(w),
9+
}
10+
}
11+
12+
pub fn parse(arg: &[u8]) -> Result<Command, ParseError> {
13+
nom_to_result(command(arg))
14+
}
15+
}

0 commit comments

Comments
 (0)