about summary refs log tree commit diff
diff options
context:
space:
mode:
authorValentine Valyaeff <valentine.valyaeff@gmail.com>2019-08-27 05:23:55 +0300
committerSeiichi Uchida <seuchida@gmail.com>2019-08-27 11:23:55 +0900
commitef00f74ce335e9f050c21a28126602454e78083e (patch)
tree86e9e6fdec658ff7750d35dbce5317350389335e
parentc26c0e5abf6b7730a6614ee8b448b0018336a285 (diff)
Merge imports fix (#3753)
-rw-r--r--src/imports.rs69
-rw-r--r--tests/source/issue-3750.rs16
-rw-r--r--tests/target/issue-3750.rs15
3 files changed, 64 insertions, 36 deletions
diff --git a/src/imports.rs b/src/imports.rs
index a85889884ca..9fd541c61d8 100644
--- a/src/imports.rs
+++ b/src/imports.rs
@@ -573,56 +573,53 @@ impl UseTree {
     }
 
     fn merge(&mut self, other: &UseTree) {
-        let mut new_path = vec![];
-        for (a, b) in self
-            .path
-            .clone()
-            .iter_mut()
-            .zip(other.path.clone().into_iter())
-        {
-            if *a == b {
-                new_path.push(b);
+        let mut prefix = 0;
+        for (a, b) in self.path.iter().zip(other.path.iter()) {
+            if *a == *b {
+                prefix += 1;
             } else {
                 break;
             }
         }
-        if let Some(merged) = merge_rest(&self.path, &other.path, new_path.len()) {
-            new_path.push(merged);
+        if let Some(new_path) = merge_rest(&self.path, &other.path, prefix) {
+            self.path = new_path;
             self.span = self.span.to(other.span);
         }
-        self.path = new_path;
     }
 }
 
-fn merge_rest(a: &[UseSegment], b: &[UseSegment], len: usize) -> Option<UseSegment> {
-    let a_rest = &a[len..];
-    let b_rest = &b[len..];
-    if a_rest.is_empty() && b_rest.is_empty() {
+fn merge_rest(a: &[UseSegment], b: &[UseSegment], mut len: usize) -> Option<Vec<UseSegment>> {
+    if a.len() == len && b.len() == len {
         return None;
     }
-    if a_rest.is_empty() {
-        return Some(UseSegment::List(vec![
-            UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
-            UseTree::from_path(b_rest.to_vec(), DUMMY_SP),
-        ]));
-    }
-    if b_rest.is_empty() {
-        return Some(UseSegment::List(vec![
-            UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
-            UseTree::from_path(a_rest.to_vec(), DUMMY_SP),
-        ]));
-    }
-    if let UseSegment::List(mut list) = a_rest[0].clone() {
-        merge_use_trees_inner(&mut list, UseTree::from_path(b_rest.to_vec(), DUMMY_SP));
-        list.sort();
-        return Some(UseSegment::List(list));
+    if a.len() != len && b.len() != len {
+        if let UseSegment::List(mut list) = a[len].clone() {
+            merge_use_trees_inner(&mut list, UseTree::from_path(b[len..].to_vec(), DUMMY_SP));
+            list.sort();
+            let mut new_path = b[..len].to_vec();
+            new_path.push(UseSegment::List(list));
+            return Some(new_path);
+        }
+    } else if len == 1 {
+        let rest = if a.len() == len { &b[1..] } else { &a[1..] };
+        return Some(vec![
+            b[0].clone(),
+            UseSegment::List(vec![
+                UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
+                UseTree::from_path(rest.to_vec(), DUMMY_SP),
+            ]),
+        ]);
+    } else {
+        len -= 1;
     }
     let mut list = vec![
-        UseTree::from_path(a_rest.to_vec(), DUMMY_SP),
-        UseTree::from_path(b_rest.to_vec(), DUMMY_SP),
+        UseTree::from_path(a[len..].to_vec(), DUMMY_SP),
+        UseTree::from_path(b[len..].to_vec(), DUMMY_SP),
     ];
     list.sort();
-    Some(UseSegment::List(list))
+    let mut new_path = b[..len].to_vec();
+    new_path.push(UseSegment::List(list));
+    Some(new_path)
 }
 
 impl PartialOrd for UseSegment {
@@ -989,7 +986,7 @@ mod test {
         }
 
         test_merge!(["a::b::{c, d}", "a::b::{e, f}"], ["a::b::{c, d, e, f}"]);
-        test_merge!(["a::b::c", "a::b"], ["a::b::{self, c}"]);
+        test_merge!(["a::b::c", "a::b"], ["a::{b, b::c}"]);
         test_merge!(["a::b", "a::b"], ["a::b"]);
         test_merge!(["a", "a::b", "a::b::c"], ["a::{self, b::{self, c}}"]);
         test_merge!(
diff --git a/tests/source/issue-3750.rs b/tests/source/issue-3750.rs
new file mode 100644
index 00000000000..e11d9ab062a
--- /dev/null
+++ b/tests/source/issue-3750.rs
@@ -0,0 +1,16 @@
+// rustfmt-merge_imports: true
+
+pub mod foo {
+    pub mod bar {
+        pub struct Bar;
+    }
+
+    pub fn bar() {}
+}
+
+use foo::bar;
+use foo::bar::Bar;
+
+fn main() {
+    bar();
+}
diff --git a/tests/target/issue-3750.rs b/tests/target/issue-3750.rs
new file mode 100644
index 00000000000..93d4dc6df25
--- /dev/null
+++ b/tests/target/issue-3750.rs
@@ -0,0 +1,15 @@
+// rustfmt-merge_imports: true
+
+pub mod foo {
+    pub mod bar {
+        pub struct Bar;
+    }
+
+    pub fn bar() {}
+}
+
+use foo::{bar, bar::Bar};
+
+fn main() {
+    bar();
+}