]> git.lizzy.rs Git - rust.git/blobdiff - src/lists.rs
Run rustfmt
[rust.git] / src / lists.rs
index 97dd093b4f9db75dcd996a00905ffbe435bec4c5..f57a78f9874e7e3a83ef2de088dcf702e981aad5 100644 (file)
@@ -1,46 +1,93 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 //! Format list-like expressions and items.
 
 use std::cmp;
 use std::iter::Peekable;
 
-use config::lists::*;
-use syntax::codemap::BytePos;
-
-use comment::{find_comment_end, rewrite_comment, FindUncommented};
-use config::{Config, IndentStyle};
-use rewrite::RewriteContext;
-use shape::{Indent, Shape};
-use utils::{count_newlines, first_line_width, last_line_width, mk_sp, starts_with_newline};
-use visitor::SnippetProvider;
-
-pub struct ListFormatting<'a> {
-    pub tactic: DefinitiveListTactic,
-    pub separator: &'a str,
-    pub trailing_separator: SeparatorTactic,
-    pub separator_place: SeparatorPlace,
-    pub shape: Shape,
-    // Non-expressions, e.g. items, will have a new line at the end of the list.
+use syntax::source_map::BytePos;
+
+use crate::comment::{find_comment_end, rewrite_comment, FindUncommented};
+use crate::config::lists::*;
+use crate::config::{Config, IndentStyle};
+use crate::rewrite::RewriteContext;
+use crate::shape::{Indent, Shape};
+use crate::utils::{count_newlines, first_line_width, last_line_width, mk_sp, starts_with_newline};
+use crate::visitor::SnippetProvider;
+
+pub(crate) struct ListFormatting<'a> {
+    tactic: DefinitiveListTactic,
+    separator: &'a str,
+    trailing_separator: SeparatorTactic,
+    separator_place: SeparatorPlace,
+    shape: Shape,
+    // Non-expressions, e.g., items, will have a new line at the end of the list.
     // Important for comment styles.
-    pub ends_with_newline: bool,
+    ends_with_newline: bool,
     // Remove newlines between list elements for expressions.
-    pub preserve_newline: bool,
+    preserve_newline: bool,
     // Nested import lists get some special handling for the "Mixed" list type
-    pub nested: bool,
-    pub config: &'a Config,
+    nested: bool,
+    // Whether comments should be visually aligned.
+    align_comments: bool,
+    config: &'a Config,
 }
 
 impl<'a> ListFormatting<'a> {
-    pub fn needs_trailing_separator(&self) -> bool {
+    pub(crate) fn new(shape: Shape, config: &'a Config) -> Self {
+        ListFormatting {
+            tactic: DefinitiveListTactic::Vertical,
+            separator: ",",
+            trailing_separator: SeparatorTactic::Never,
+            separator_place: SeparatorPlace::Back,
+            shape,
+            ends_with_newline: true,
+            preserve_newline: false,
+            nested: false,
+            align_comments: true,
+            config,
+        }
+    }
+
+    pub(crate) fn tactic(mut self, tactic: DefinitiveListTactic) -> Self {
+        self.tactic = tactic;
+        self
+    }
+
+    pub(crate) fn separator(mut self, separator: &'a str) -> Self {
+        self.separator = separator;
+        self
+    }
+
+    pub(crate) fn trailing_separator(mut self, trailing_separator: SeparatorTactic) -> Self {
+        self.trailing_separator = trailing_separator;
+        self
+    }
+
+    pub(crate) fn separator_place(mut self, separator_place: SeparatorPlace) -> Self {
+        self.separator_place = separator_place;
+        self
+    }
+
+    pub(crate) fn ends_with_newline(mut self, ends_with_newline: bool) -> Self {
+        self.ends_with_newline = ends_with_newline;
+        self
+    }
+
+    pub(crate) fn preserve_newline(mut self, preserve_newline: bool) -> Self {
+        self.preserve_newline = preserve_newline;
+        self
+    }
+
+    pub(crate) fn nested(mut self, nested: bool) -> Self {
+        self.nested = nested;
+        self
+    }
+
+    pub(crate) fn align_comments(mut self, align_comments: bool) -> Self {
+        self.align_comments = align_comments;
+        self
+    }
+
+    pub(crate) fn needs_trailing_separator(&self) -> bool {
         match self.trailing_separator {
             // We always put separator in front.
             SeparatorTactic::Always => true,
@@ -59,7 +106,7 @@ fn as_ref(&self) -> &ListItem {
 }
 
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
-pub enum ListItemCommentStyle {
+pub(crate) enum ListItemCommentStyle {
     // Try to keep the comment on the same line with the item.
     SameLine,
     // Put the comment on the previous or the next line of the item.
@@ -69,20 +116,20 @@ pub enum ListItemCommentStyle {
 }
 
 #[derive(Debug, Clone)]
-pub struct ListItem {
+pub(crate) struct ListItem {
     // None for comments mean that they are not present.
-    pub pre_comment: Option<String>,
-    pub pre_comment_style: ListItemCommentStyle,
+    pub(crate) pre_comment: Option<String>,
+    pub(crate) pre_comment_style: ListItemCommentStyle,
     // Item should include attributes and doc comments. None indicates a failed
     // rewrite.
-    pub item: Option<String>,
-    pub post_comment: Option<String>,
+    pub(crate) item: Option<String>,
+    pub(crate) post_comment: Option<String>,
     // Whether there is extra whitespace before this item.
-    pub new_lines: bool,
+    pub(crate) new_lines: bool,
 }
 
 impl ListItem {
-    pub fn empty() -> ListItem {
+    pub(crate) fn empty() -> ListItem {
         ListItem {
             pre_comment: None,
             pre_comment_style: ListItemCommentStyle::None,
@@ -92,19 +139,20 @@ pub fn empty() -> ListItem {
         }
     }
 
-    pub fn inner_as_ref(&self) -> &str {
+    pub(crate) fn inner_as_ref(&self) -> &str {
         self.item.as_ref().map_or("", |s| s)
     }
 
-    pub fn is_different_group(&self) -> bool {
-        self.inner_as_ref().contains('\n') || self.pre_comment.is_some()
+    pub(crate) fn is_different_group(&self) -> bool {
+        self.inner_as_ref().contains('\n')
+            || self.pre_comment.is_some()
             || self
                 .post_comment
                 .as_ref()
                 .map_or(false, |s| s.contains('\n'))
     }
 
-    pub fn is_multiline(&self) -> bool {
+    pub(crate) fn is_multiline(&self) -> bool {
         self.inner_as_ref().contains('\n')
             || self
                 .pre_comment
@@ -116,21 +164,21 @@ pub fn is_multiline(&self) -> bool {
                 .map_or(false, |s| s.contains('\n'))
     }
 
-    pub fn has_single_line_comment(&self) -> bool {
+    pub(crate) fn has_single_line_comment(&self) -> bool {
         self.pre_comment
             .as_ref()
-            .map_or(false, |comment| comment.trim_left().starts_with("//"))
+            .map_or(false, |comment| comment.trim_start().starts_with("//"))
             || self
                 .post_comment
                 .as_ref()
-                .map_or(false, |comment| comment.trim_left().starts_with("//"))
+                .map_or(false, |comment| comment.trim_start().starts_with("//"))
     }
 
-    pub fn has_comment(&self) -> bool {
+    pub(crate) fn has_comment(&self) -> bool {
         self.pre_comment.is_some() || self.post_comment.is_some()
     }
 
-    pub fn from_str<S: Into<String>>(s: S) -> ListItem {
+    pub(crate) fn from_str<S: Into<String>>(s: S) -> ListItem {
         ListItem {
             pre_comment: None,
             pre_comment_style: ListItemCommentStyle::None,
@@ -140,7 +188,7 @@ pub fn from_str<S: Into<String>>(s: S) -> ListItem {
         }
     }
 
-    // true if the item causes something to be written.
+    // Returns `true` if the item causes something to be written.
     fn is_substantial(&self) -> bool {
         fn empty(s: &Option<String>) -> bool {
             match *s {
@@ -155,14 +203,14 @@ fn empty(s: &Option<String>) -> bool {
 
 /// The type of separator for lists.
 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
-pub enum Separator {
+pub(crate) enum Separator {
     Comma,
     VerticalBar,
 }
 
 impl Separator {
-    pub fn len(&self) -> usize {
-        match *self {
+    pub(crate) fn len(self) -> usize {
+        match self {
             // 2 = `, `
             Separator::Comma => 2,
             // 3 = ` | `
@@ -171,7 +219,7 @@ pub fn len(&self) -> usize {
     }
 }
 
-pub fn definitive_tactic<I, T>(
+pub(crate) fn definitive_tactic<I, T>(
     items: I,
     tactic: ListTactic,
     sep: Separator,
@@ -212,8 +260,7 @@ pub fn definitive_tactic<I, T>(
 }
 
 // Format a list of commented items into a string.
-// TODO: add unit tests
-pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
+pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Option<String>
 where
     I: IntoIterator<Item = T> + Clone,
     T: AsRef<ListItem>,
@@ -299,17 +346,15 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
                     if formatting.ends_with_newline {
                         trailing_separator = true;
                     }
+                } else if line_len > 0 {
+                    result.push(' ');
+                    line_len += 1;
                 }
 
                 if last && formatting.ends_with_newline {
                     separate = formatting.trailing_separator != SeparatorTactic::Never;
                 }
 
-                if line_len > 0 {
-                    result.push(' ');
-                    line_len += 1;
-                }
-
                 line_len += total_width;
             }
             _ => {}
@@ -343,6 +388,8 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
                     } else {
                         result.push('\n');
                         result.push_str(indent_str);
+                        // This is the width of the item (without comments).
+                        line_len = item.item.as_ref().map_or(0, String::len);
                     }
                 } else {
                     result.push(' ');
@@ -406,7 +453,7 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
                     || comment.trim().len() > width;
 
                 rewrite_comment(
-                    comment.trim_left(),
+                    comment.trim_start(),
                     block_style,
                     comment_shape,
                     formatting.config,
@@ -416,22 +463,31 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
             let mut formatted_comment = rewrite_post_comment(&mut item_max_width)?;
 
             if !starts_with_newline(comment) {
-                let mut comment_alignment =
-                    post_comment_alignment(item_max_width, inner_item.len());
-                if first_line_width(&formatted_comment)
-                    + last_line_width(&result)
-                    + comment_alignment
-                    + 1 > formatting.config.max_width()
-                {
-                    item_max_width = None;
-                    formatted_comment = rewrite_post_comment(&mut item_max_width)?;
-                    comment_alignment = post_comment_alignment(item_max_width, inner_item.len());
-                }
-                for _ in 0..(comment_alignment + 1) {
-                    result.push(' ');
+                if formatting.align_comments {
+                    let mut comment_alignment =
+                        post_comment_alignment(item_max_width, inner_item.len());
+                    if first_line_width(&formatted_comment)
+                        + last_line_width(&result)
+                        + comment_alignment
+                        + 1
+                        > formatting.config.max_width()
+                    {
+                        item_max_width = None;
+                        formatted_comment = rewrite_post_comment(&mut item_max_width)?;
+                        comment_alignment =
+                            post_comment_alignment(item_max_width, inner_item.len());
+                    }
+                    for _ in 0..=comment_alignment {
+                        result.push(' ');
+                    }
                 }
-                // An additional space for the missing trailing separator.
-                if last && item_max_width.is_some() && !separate && !formatting.separator.is_empty()
+                // An additional space for the missing trailing separator (or
+                // if we skipped alignment above).
+                if !formatting.align_comments
+                    || (last
+                        && item_max_width.is_some()
+                        && !separate
+                        && !formatting.separator.is_empty())
                 {
                     result.push(' ');
                 }
@@ -500,7 +556,7 @@ fn post_comment_alignment(item_max_width: Option<usize>, inner_item_len: usize)
     item_max_width.unwrap_or(0).saturating_sub(inner_item_len)
 }
 
-pub struct ListItems<'a, I, F1, F2, F3>
+pub(crate) struct ListItems<'a, I, F1, F2, F3>
 where
     I: Iterator,
 {
@@ -516,6 +572,143 @@ pub struct ListItems<'a, I, F1, F2, F3>
     leave_last: bool,
 }
 
+pub(crate) fn extract_pre_comment(pre_snippet: &str) -> (Option<String>, ListItemCommentStyle) {
+    let trimmed_pre_snippet = pre_snippet.trim();
+    let has_block_comment = trimmed_pre_snippet.ends_with("*/");
+    let has_single_line_comment = trimmed_pre_snippet.starts_with("//");
+    if has_block_comment {
+        let comment_end = pre_snippet.rfind(|c| c == '/').unwrap();
+        if pre_snippet[comment_end..].contains('\n') {
+            (
+                Some(trimmed_pre_snippet.to_owned()),
+                ListItemCommentStyle::DifferentLine,
+            )
+        } else {
+            (
+                Some(trimmed_pre_snippet.to_owned()),
+                ListItemCommentStyle::SameLine,
+            )
+        }
+    } else if has_single_line_comment {
+        (
+            Some(trimmed_pre_snippet.to_owned()),
+            ListItemCommentStyle::DifferentLine,
+        )
+    } else {
+        (None, ListItemCommentStyle::None)
+    }
+}
+
+pub(crate) fn extract_post_comment(
+    post_snippet: &str,
+    comment_end: usize,
+    separator: &str,
+) -> Option<String> {
+    let white_space: &[_] = &[' ', '\t'];
+
+    // Cleanup post-comment: strip separators and whitespace.
+    let post_snippet = post_snippet[..comment_end].trim();
+    let post_snippet_trimmed = if post_snippet.starts_with(|c| c == ',' || c == ':') {
+        post_snippet[1..].trim_matches(white_space)
+    } else if post_snippet.starts_with(separator) {
+        post_snippet[separator.len()..].trim_matches(white_space)
+    } else if post_snippet.ends_with(',') && !post_snippet.trim().starts_with("//") {
+        post_snippet[..(post_snippet.len() - 1)].trim_matches(white_space)
+    } else {
+        post_snippet
+    };
+    // FIXME(#3441): post_snippet includes 'const' now
+    // it should not include here
+    let removed_newline_snippet = post_snippet_trimmed.trim();
+    if !post_snippet_trimmed.is_empty()
+        && (removed_newline_snippet.starts_with("//") || removed_newline_snippet.starts_with("/*"))
+    {
+        Some(post_snippet_trimmed.to_owned())
+    } else {
+        None
+    }
+}
+
+pub(crate) fn get_comment_end(
+    post_snippet: &str,
+    separator: &str,
+    terminator: &str,
+    is_last: bool,
+) -> usize {
+    if is_last {
+        return post_snippet
+            .find_uncommented(terminator)
+            .unwrap_or_else(|| post_snippet.len());
+    }
+
+    let mut block_open_index = post_snippet.find("/*");
+    // check if it really is a block comment (and not `//*` or a nested comment)
+    if let Some(i) = block_open_index {
+        match post_snippet.find('/') {
+            Some(j) if j < i => block_open_index = None,
+            _ if post_snippet[..i].ends_with('/') => block_open_index = None,
+            _ => (),
+        }
+    }
+    let newline_index = post_snippet.find('\n');
+    if let Some(separator_index) = post_snippet.find_uncommented(separator) {
+        match (block_open_index, newline_index) {
+            // Separator before comment, with the next item on same line.
+            // Comment belongs to next item.
+            (Some(i), None) if i > separator_index => separator_index + 1,
+            // Block-style post-comment before the separator.
+            (Some(i), None) => cmp::max(
+                find_comment_end(&post_snippet[i..]).unwrap() + i,
+                separator_index + 1,
+            ),
+            // Block-style post-comment. Either before or after the separator.
+            (Some(i), Some(j)) if i < j => cmp::max(
+                find_comment_end(&post_snippet[i..]).unwrap() + i,
+                separator_index + 1,
+            ),
+            // Potential *single* line comment.
+            (_, Some(j)) if j > separator_index => j + 1,
+            _ => post_snippet.len(),
+        }
+    } else if let Some(newline_index) = newline_index {
+        // Match arms may not have trailing comma. In any case, for match arms,
+        // we will assume that the post comment belongs to the next arm if they
+        // do not end with trailing comma.
+        newline_index + 1
+    } else {
+        0
+    }
+}
+
+// Account for extra whitespace between items. This is fiddly
+// because of the way we divide pre- and post- comments.
+pub(crate) fn has_extra_newline(post_snippet: &str, comment_end: usize) -> bool {
+    if post_snippet.is_empty() || comment_end == 0 {
+        return false;
+    }
+
+    let len_last = post_snippet[..comment_end]
+        .chars()
+        .last()
+        .unwrap()
+        .len_utf8();
+    // Everything from the separator to the next item.
+    let test_snippet = &post_snippet[comment_end - len_last..];
+    let first_newline = test_snippet
+        .find('\n')
+        .unwrap_or_else(|| test_snippet.len());
+    // From the end of the first line of comments.
+    let test_snippet = &test_snippet[first_newline..];
+    let first = test_snippet
+        .find(|c: char| !c.is_whitespace())
+        .unwrap_or_else(|| test_snippet.len());
+    // From the end of the first line of comments to the next non-whitespace char.
+    let test_snippet = &test_snippet[..first];
+
+    // There were multiple line breaks which got trimmed to nothing.
+    count_newlines(test_snippet) > 1
+}
+
 impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
 where
     I: Iterator<Item = T>,
@@ -526,44 +719,13 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
     type Item = ListItem;
 
     fn next(&mut self) -> Option<Self::Item> {
-        let white_space: &[_] = &[' ', '\t'];
-
         self.inner.next().map(|item| {
-            let mut new_lines = false;
             // Pre-comment
             let pre_snippet = self
                 .snippet_provider
                 .span_to_snippet(mk_sp(self.prev_span_end, (self.get_lo)(&item)))
-                .unwrap();
-            let trimmed_pre_snippet = pre_snippet.trim();
-            let has_single_line_comment = trimmed_pre_snippet.starts_with("//");
-            let has_block_comment = trimmed_pre_snippet.starts_with("/*");
-            let (pre_comment, pre_comment_style) = if has_single_line_comment {
-                (
-                    Some(trimmed_pre_snippet.to_owned()),
-                    ListItemCommentStyle::DifferentLine,
-                )
-            } else if has_block_comment {
-                let comment_end = pre_snippet.chars().rev().position(|c| c == '/').unwrap();
-                if pre_snippet
-                    .chars()
-                    .rev()
-                    .take(comment_end + 1)
-                    .any(|c| c == '\n')
-                {
-                    (
-                        Some(trimmed_pre_snippet.to_owned()),
-                        ListItemCommentStyle::DifferentLine,
-                    )
-                } else {
-                    (
-                        Some(trimmed_pre_snippet.to_owned()),
-                        ListItemCommentStyle::SameLine,
-                    )
-                }
-            } else {
-                (None, ListItemCommentStyle::None)
-            };
+                .unwrap_or("");
+            let (pre_comment, pre_comment_style) = extract_pre_comment(pre_snippet);
 
             // Post-comment
             let next_start = match self.inner.peek() {
@@ -573,95 +735,17 @@ fn next(&mut self) -> Option<Self::Item> {
             let post_snippet = self
                 .snippet_provider
                 .span_to_snippet(mk_sp((self.get_hi)(&item), next_start))
-                .unwrap();
-
-            let comment_end = match self.inner.peek() {
-                Some(..) => {
-                    let mut block_open_index = post_snippet.find("/*");
-                    // check if it really is a block comment (and not `//*` or a nested comment)
-                    if let Some(i) = block_open_index {
-                        match post_snippet.find('/') {
-                            Some(j) if j < i => block_open_index = None,
-                            _ if i > 0 && &post_snippet[i - 1..i] == "/" => block_open_index = None,
-                            _ => (),
-                        }
-                    }
-                    let newline_index = post_snippet.find('\n');
-                    if let Some(separator_index) = post_snippet.find_uncommented(self.separator) {
-                        match (block_open_index, newline_index) {
-                            // Separator before comment, with the next item on same line.
-                            // Comment belongs to next item.
-                            (Some(i), None) if i > separator_index => separator_index + 1,
-                            // Block-style post-comment before the separator.
-                            (Some(i), None) => cmp::max(
-                                find_comment_end(&post_snippet[i..]).unwrap() + i,
-                                separator_index + 1,
-                            ),
-                            // Block-style post-comment. Either before or after the separator.
-                            (Some(i), Some(j)) if i < j => cmp::max(
-                                find_comment_end(&post_snippet[i..]).unwrap() + i,
-                                separator_index + 1,
-                            ),
-                            // Potential *single* line comment.
-                            (_, Some(j)) if j > separator_index => j + 1,
-                            _ => post_snippet.len(),
-                        }
-                    } else if let Some(newline_index) = newline_index {
-                        // Match arms may not have trailing comma. In any case, for match arms,
-                        // we will assume that the post comment belongs to the next arm if they
-                        // do not end with trailing comma.
-                        newline_index + 1
-                    } else {
-                        0
-                    }
-                }
-                None => post_snippet
-                    .find_uncommented(self.terminator)
-                    .unwrap_or_else(|| post_snippet.len()),
-            };
-
-            if !post_snippet.is_empty() && comment_end > 0 {
-                // Account for extra whitespace between items. This is fiddly
-                // because of the way we divide pre- and post- comments.
-
-                // Everything from the separator to the next item.
-                let test_snippet = &post_snippet[comment_end - 1..];
-                let first_newline = test_snippet
-                    .find('\n')
-                    .unwrap_or_else(|| test_snippet.len());
-                // From the end of the first line of comments.
-                let test_snippet = &test_snippet[first_newline..];
-                let first = test_snippet
-                    .find(|c: char| !c.is_whitespace())
-                    .unwrap_or_else(|| test_snippet.len());
-                // From the end of the first line of comments to the next non-whitespace char.
-                let test_snippet = &test_snippet[..first];
-
-                if count_newlines(test_snippet) > 1 {
-                    // There were multiple line breaks which got trimmed to nothing.
-                    new_lines = true;
-                }
-            }
+                .unwrap_or("");
+            let comment_end = get_comment_end(
+                post_snippet,
+                self.separator,
+                self.terminator,
+                self.inner.peek().is_none(),
+            );
+            let new_lines = has_extra_newline(post_snippet, comment_end);
+            let post_comment = extract_post_comment(post_snippet, comment_end, self.separator);
 
-            // Cleanup post-comment: strip separators and whitespace.
             self.prev_span_end = (self.get_hi)(&item) + BytePos(comment_end as u32);
-            let post_snippet = post_snippet[..comment_end].trim();
-
-            let post_snippet_trimmed = if post_snippet.starts_with(|c| c == ',' || c == ':') {
-                post_snippet[1..].trim_matches(white_space)
-            } else if post_snippet.starts_with(self.separator) {
-                post_snippet[self.separator.len()..].trim_matches(white_space)
-            } else if post_snippet.ends_with(',') {
-                post_snippet[..(post_snippet.len() - 1)].trim_matches(white_space)
-            } else {
-                post_snippet
-            };
-
-            let post_comment = if !post_snippet_trimmed.is_empty() {
-                Some(post_snippet_trimmed.to_owned())
-            } else {
-                None
-            };
 
             ListItem {
                 pre_comment,
@@ -678,10 +762,10 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
-#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
+#[allow(clippy::too_many_arguments)]
 // Creates an iterator over a list's items with associated comments.
-pub fn itemize_list<'a, T, I, F1, F2, F3>(
-    snippet_provider: &'a SnippetProvider,
+pub(crate) fn itemize_list<'a, T, I, F1, F2, F3>(
+    snippet_provider: &'a SnippetProvider<'_>,
     inner: I,
     terminator: &'a str,
     separator: &'a str,
@@ -724,10 +808,10 @@ fn calculate_width<I, T>(items: I) -> (usize, usize)
         .fold((0, 0), |acc, l| (acc.0 + 1, acc.1 + l))
 }
 
-pub fn total_item_width(item: &ListItem) -> usize {
+pub(crate) fn total_item_width(item: &ListItem) -> usize {
     comment_len(item.pre_comment.as_ref().map(|x| &(*x)[..]))
         + comment_len(item.post_comment.as_ref().map(|x| &(*x)[..]))
-        + item.item.as_ref().map_or(0, |str| str.len())
+        + item.item.as_ref().map_or(0, String::len)
 }
 
 fn comment_len(comment: Option<&str>) -> usize {
@@ -746,9 +830,9 @@ fn comment_len(comment: Option<&str>) -> usize {
 }
 
 // Compute horizontal and vertical shapes for a struct-lit-like thing.
-pub fn struct_lit_shape(
+pub(crate) fn struct_lit_shape(
     shape: Shape,
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     prefix_width: usize,
     suffix_width: usize,
 ) -> Option<(Option<Shape>, Shape)> {
@@ -775,9 +859,9 @@ pub fn struct_lit_shape(
 }
 
 // Compute the tactic for the internals of a struct-lit-like thing.
-pub fn struct_lit_tactic(
+pub(crate) fn struct_lit_tactic(
     h_shape: Option<Shape>,
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     items: &[ListItem],
 ) -> DefinitiveListTactic {
     if let Some(h_shape) = h_shape {
@@ -794,7 +878,7 @@ pub fn struct_lit_tactic(
 
 // Given a tactic and possible shapes for horizontal and vertical layout,
 // come up with the actual shape to use.
-pub fn shape_for_tactic(
+pub(crate) fn shape_for_tactic(
     tactic: DefinitiveListTactic,
     h_shape: Option<Shape>,
     v_shape: Shape,
@@ -807,10 +891,10 @@ pub fn shape_for_tactic(
 
 // Create a ListFormatting object for formatting the internals of a
 // struct-lit-like thing, that is a series of fields.
-pub fn struct_lit_formatting<'a>(
+pub(crate) fn struct_lit_formatting<'a>(
     shape: Shape,
     tactic: DefinitiveListTactic,
-    context: &'a RewriteContext,
+    context: &'a RewriteContext<'_>,
     force_no_trailing_comma: bool,
 ) -> ListFormatting<'a> {
     let ends_with_newline = context.config.indent_style() != IndentStyle::Visual
@@ -828,6 +912,7 @@ pub fn struct_lit_formatting<'a>(
         ends_with_newline,
         preserve_newline: true,
         nested: false,
+        align_comments: true,
         config: context.config,
     }
 }