]> git.lizzy.rs Git - rust.git/blobdiff - src/imports.rs
Preserve comments between attribute and use item
[rust.git] / src / imports.rs
index 76fa7816f0d8511587274c086815c45eaaf50c80..9fd844a2c35b6ceec489b43dec87a990969d7c22 100644 (file)
@@ -15,6 +15,7 @@
 use syntax::codemap::{self, BytePos, Span, DUMMY_SP};
 
 use codemap::SpanUtils;
+use comment::combine_strs_with_missing_comments;
 use config::IndentStyle;
 use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator};
 use rewrite::{Rewrite, RewriteContext};
@@ -172,13 +173,13 @@ fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree) {
 
 impl fmt::Debug for UseTree {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self)
+        fmt::Display::fmt(self, f)
     }
 }
 
 impl fmt::Debug for UseSegment {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self)
+        fmt::Display::fmt(self, f)
     }
 }
 
@@ -219,29 +220,33 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl UseTree {
     // Rewrite use tree with `use ` and a trailing `;`.
     pub fn rewrite_top_level(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
-        let mut result = String::with_capacity(256);
-        if let Some(ref attrs) = self.attrs {
-            result.push_str(&attrs.rewrite(context, shape).expect("rewrite attr"));
-            if !result.is_empty() {
-                result.push_str(&shape.indent.to_string_with_newline(context.config));
-            }
-        }
-
         let vis = self.visibility
             .as_ref()
             .map_or(Cow::from(""), |vis| ::utils::format_visibility(&vis));
-        result.push_str(&self.rewrite(context, shape.offset_left(vis.len())?)
+        let use_str = self.rewrite(context, shape.offset_left(vis.len())?)
             .map(|s| {
                 if s.is_empty() {
                     s.to_owned()
                 } else {
                     format!("{}use {};", vis, s)
                 }
-            })?);
-        Some(result)
+            })?;
+        if let Some(ref attrs) = self.attrs {
+            let attr_str = attrs.rewrite(context, shape)?;
+            let lo = attrs.last().as_ref()?.span().hi();
+            let hi = self.span.lo();
+            let span = mk_sp(lo, hi);
+            combine_strs_with_missing_comments(context, &attr_str, &use_str, span, shape, false)
+        } else {
+            Some(use_str)
+        }
     }
 
     // FIXME: Use correct span?
+    // The given span is essentially incorrect, since we are reconstructing
+    // use statements. This should not be a problem, though, since we have
+    // already tried to extract comment and observed that there are no comment
+    // around the given use item, and the span will not be used afterward.
     fn from_path(path: Vec<UseSegment>, span: Span) -> UseTree {
         UseTree {
             path,
@@ -269,7 +274,7 @@ pub fn from_ast_with_normalization(
                     } else {
                         Some(item.attrs.clone())
                     },
-                ).normalize(context.config.reorder_imported_names()),
+                ).normalize(),
             ),
             _ => None,
         }
@@ -355,7 +360,7 @@ fn from_ast(
     }
 
     // Do the adjustments that rustfmt does elsewhere to use paths.
-    pub fn normalize(mut self, do_sort: bool) -> UseTree {
+    pub fn normalize(mut self) -> UseTree {
         let mut last = self.path.pop().expect("Empty use tree?");
         // Hack around borrow checker.
         let mut normalize_sole_list = false;
@@ -377,7 +382,7 @@ pub fn normalize(mut self, do_sort: bool) -> UseTree {
 
         // Normalise foo::self -> foo.
         if let UseSegment::Slf(None) = last {
-            if self.path.len() > 0 {
+            if !self.path.is_empty() {
                 return self;
             }
         }
@@ -424,7 +429,7 @@ pub fn normalize(mut self, do_sort: bool) -> UseTree {
                     for seg in &list[0].path {
                         self.path.push(seg.clone());
                     }
-                    return self.normalize(do_sort);
+                    return self.normalize();
                 }
                 _ => unreachable!(),
             }
@@ -433,11 +438,9 @@ pub fn normalize(mut self, do_sort: bool) -> UseTree {
         // Recursively normalize elements of a list use (including sorting the list).
         if let UseSegment::List(list) = last {
             let mut list = list.into_iter()
-                .map(|ut| ut.normalize(do_sort))
+                .map(|ut| ut.normalize())
                 .collect::<Vec<_>>();
-            if do_sort {
-                list.sort();
-            }
+            list.sort();
             last = UseSegment::List(list);
         }
 
@@ -446,9 +449,7 @@ pub fn normalize(mut self, do_sort: bool) -> UseTree {
     }
 
     fn has_comment(&self) -> bool {
-        self.list_item.as_ref().map_or(false, |list_item| {
-            list_item.pre_comment.is_some() || list_item.post_comment.is_some()
-        })
+        self.list_item.as_ref().map_or(false, ListItem::has_comment)
     }
 
     fn same_visibility(&self, other: &UseTree) -> bool {
@@ -494,8 +495,8 @@ fn flatten(self) -> Vec<UseTree> {
             UseSegment::List(list) => {
                 let prefix = &self.path[..self.path.len() - 1];
                 let mut result = vec![];
-                for nested_use_tree in list.into_iter() {
-                    for mut flattend in nested_use_tree.clone().flatten().iter_mut() {
+                for nested_use_tree in list {
+                    for mut flattend in &mut nested_use_tree.clone().flatten() {
                         let mut new_path = prefix.to_vec();
                         new_path.append(&mut flattend.path);
                         result.push(UseTree {
@@ -516,23 +517,18 @@ fn flatten(self) -> Vec<UseTree> {
 
     fn merge(&mut self, other: UseTree) {
         let mut new_path = vec![];
-        let mut len = 0;
-        for (i, (mut a, b)) in self.path
+        for (mut a, b) in self.path
             .clone()
             .iter_mut()
             .zip(other.path.clone().into_iter())
-            .enumerate()
         {
             if *a == b {
-                len = i + 1;
                 new_path.push(b);
-                continue;
             } else {
-                len = i;
                 break;
             }
         }
-        if let Some(merged) = merge_rest(&self.path, &other.path, len) {
+        if let Some(merged) = merge_rest(&self.path, &other.path, new_path.len()) {
             new_path.push(merged);
             self.span = self.span.to(other.span);
         }
@@ -677,7 +673,7 @@ fn rewrite_nested_use_tree(
             list_items.push(ListItem::from_str(use_tree.rewrite(context, nested_shape)?));
         }
     }
-    let (tactic, remaining_width) = if use_tree_list.iter().any(|use_segment| {
+    let has_nested_list = use_tree_list.iter().any(|use_segment| {
         use_segment
             .path
             .last()
@@ -685,7 +681,8 @@ fn rewrite_nested_use_tree(
                 UseSegment::List(..) => true,
                 _ => false,
             })
-    }) {
+    });
+    let (tactic, remaining_width) = if has_nested_list {
         (DefinitiveListTactic::Vertical, 0)
     } else {
         let remaining_width = shape.width.checked_sub(2).unwrap_or(0);
@@ -697,6 +694,7 @@ fn rewrite_nested_use_tree(
         );
         (tactic, remaining_width)
     };
+
     let ends_with_newline = context.config.imports_indent() == IndentStyle::Block
         && tactic != DefinitiveListTactic::Horizontal;
     let fmt = ListFormatting {
@@ -951,75 +949,64 @@ fn test_use_tree_flatten() {
 
     #[test]
     fn test_use_tree_normalize() {
+        assert_eq!(parse_use_tree("a::self").normalize(), parse_use_tree("a"));
         assert_eq!(
-            parse_use_tree("a::self").normalize(true),
-            parse_use_tree("a")
-        );
-        assert_eq!(
-            parse_use_tree("a::self as foo").normalize(true),
+            parse_use_tree("a::self as foo").normalize(),
             parse_use_tree("a as foo")
         );
+        assert_eq!(parse_use_tree("a::{self}").normalize(), parse_use_tree("a"));
+        assert_eq!(parse_use_tree("a::{b}").normalize(), parse_use_tree("a::b"));
         assert_eq!(
-            parse_use_tree("a::{self}").normalize(true),
-            parse_use_tree("a")
-        );
-        assert_eq!(
-            parse_use_tree("a::{b}").normalize(true),
-            parse_use_tree("a::b")
-        );
-        assert_eq!(
-            parse_use_tree("a::{b, c::self}").normalize(true),
+            parse_use_tree("a::{b, c::self}").normalize(),
             parse_use_tree("a::{b, c}")
         );
         assert_eq!(
-            parse_use_tree("a::{b as bar, c::self}").normalize(true),
+            parse_use_tree("a::{b as bar, c::self}").normalize(),
             parse_use_tree("a::{b as bar, c}")
         );
     }
 
     #[test]
     fn test_use_tree_ord() {
-        assert!(parse_use_tree("a").normalize(true) < parse_use_tree("aa").normalize(true));
-        assert!(parse_use_tree("a").normalize(true) < parse_use_tree("a::a").normalize(true));
-        assert!(parse_use_tree("a").normalize(true) < parse_use_tree("*").normalize(true));
-        assert!(parse_use_tree("a").normalize(true) < parse_use_tree("{a, b}").normalize(true));
-        assert!(parse_use_tree("*").normalize(true) < parse_use_tree("{a, b}").normalize(true));
+        assert!(parse_use_tree("a").normalize() < parse_use_tree("aa").normalize());
+        assert!(parse_use_tree("a").normalize() < parse_use_tree("a::a").normalize());
+        assert!(parse_use_tree("a").normalize() < parse_use_tree("*").normalize());
+        assert!(parse_use_tree("a").normalize() < parse_use_tree("{a, b}").normalize());
+        assert!(parse_use_tree("*").normalize() < parse_use_tree("{a, b}").normalize());
 
         assert!(
-            parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, dddddddd}").normalize(true)
-                < parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, ddddddddd}").normalize(true)
-        );
-        assert!(
-            parse_use_tree("serde::de::{Deserialize}").normalize(true)
-                < parse_use_tree("serde_json").normalize(true)
+            parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, dddddddd}").normalize()
+                < parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, ddddddddd}").normalize()
         );
         assert!(
-            parse_use_tree("a::b::c").normalize(true) < parse_use_tree("a::b::*").normalize(true)
+            parse_use_tree("serde::de::{Deserialize}").normalize()
+                < parse_use_tree("serde_json").normalize()
         );
+        assert!(parse_use_tree("a::b::c").normalize() < parse_use_tree("a::b::*").normalize());
         assert!(
-            parse_use_tree("foo::{Bar, Baz}").normalize(true)
-                < parse_use_tree("{Bar, Baz}").normalize(true)
+            parse_use_tree("foo::{Bar, Baz}").normalize()
+                < parse_use_tree("{Bar, Baz}").normalize()
         );
 
         assert!(
-            parse_use_tree("foo::{self as bar}").normalize(true)
-                < parse_use_tree("foo::{qux as bar}").normalize(true)
+            parse_use_tree("foo::{self as bar}").normalize()
+                < parse_use_tree("foo::{qux as bar}").normalize()
         );
         assert!(
-            parse_use_tree("foo::{qux as bar}").normalize(true)
-                < parse_use_tree("foo::{baz, qux as bar}").normalize(true)
+            parse_use_tree("foo::{qux as bar}").normalize()
+                < parse_use_tree("foo::{baz, qux as bar}").normalize()
         );
         assert!(
-            parse_use_tree("foo::{self as bar, baz}").normalize(true)
-                < parse_use_tree("foo::{baz, qux as bar}").normalize(true)
+            parse_use_tree("foo::{self as bar, baz}").normalize()
+                < parse_use_tree("foo::{baz, qux as bar}").normalize()
         );
 
-        assert!(parse_use_tree("foo").normalize(true) < parse_use_tree("Foo").normalize(true));
-        assert!(parse_use_tree("foo").normalize(true) < parse_use_tree("foo::Bar").normalize(true));
+        assert!(parse_use_tree("foo").normalize() < parse_use_tree("Foo").normalize());
+        assert!(parse_use_tree("foo").normalize() < parse_use_tree("foo::Bar").normalize());
 
         assert!(
-            parse_use_tree("std::cmp::{d, c, b, a}").normalize(true)
-                < parse_use_tree("std::cmp::{b, e, g, f}").normalize(true)
+            parse_use_tree("std::cmp::{d, c, b, a}").normalize()
+                < parse_use_tree("std::cmp::{b, e, g, f}").normalize()
         );
     }
 }