From 1f9e7c25c95b1cd267c0e54669021e0b56462d94 Mon Sep 17 00:00:00 2001
From: topecongiro <seuchida@gmail.com>
Date: Fri, 25 Aug 2017 08:19:51 +0900
Subject: [PATCH 1/2] Implement Rewrite trait for ast::ForeignItem

---
 src/items.rs   | 126 +++++++++++++++++++++++++++----------------------
 src/lib.rs     |   7 +++
 src/visitor.rs |   2 +-
 3 files changed, 77 insertions(+), 58 deletions(-)

diff --git a/src/items.rs b/src/items.rs
index c42ef7f971c..9dd1972670a 100644
--- a/src/items.rs
+++ b/src/items.rs
@@ -185,64 +185,11 @@ impl<'a> FmtVisitor<'a> {
         self.format_item(item);
     }
 
+
     fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
-        self.format_missing_with_indent(item.span.lo);
-        // Drop semicolon or it will be interpreted as comment.
-        // FIXME: this may be a faulty span from libsyntax.
-        let span = mk_sp(item.span.lo, item.span.hi - BytePos(1));
-
-        match item.node {
-            ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
-                let indent = self.block_indent;
-                let rewrite = rewrite_fn_base(
-                    &self.get_context(),
-                    indent,
-                    item.ident,
-                    fn_decl,
-                    generics,
-                    ast::Unsafety::Normal,
-                    ast::Constness::NotConst,
-                    ast::Defaultness::Final,
-                    // These are not actually rust functions,
-                    // but we format them as such.
-                    abi::Abi::Rust,
-                    &item.vis,
-                    span,
-                    false,
-                    false,
-                    false,
-                );
-
-                match rewrite {
-                    Some((new_fn, _)) => {
-                        self.buffer.push_str(&new_fn);
-                        self.buffer.push_str(";");
-                    }
-                    None => self.format_missing(item.span.hi),
-                }
-            }
-            ast::ForeignItemKind::Static(ref ty, is_mutable) => {
-                // FIXME(#21): we're dropping potential comments in between the
-                // function keywords here.
-                let vis = format_visibility(&item.vis);
-                let mut_str = if is_mutable { "mut " } else { "" };
-                let prefix = format!("{}static {}{}: ", vis, mut_str, item.ident);
-                let offset = self.block_indent + prefix.len();
-                // 1 = ;
-                let shape = Shape::indented(offset, self.config).sub_width(1).unwrap();
-                let rewrite = ty.rewrite(&self.get_context(), shape);
-
-                match rewrite {
-                    Some(result) => {
-                        self.buffer.push_str(&prefix);
-                        self.buffer.push_str(&result);
-                        self.buffer.push_str(";");
-                    }
-                    None => self.format_missing(item.span.hi),
-                }
-            }
-        }
-
+        let shape = Shape::indented(self.block_indent, self.config);
+        let rewrite = item.rewrite(&self.get_context(), shape);
+        self.push_rewrite(item.span(), rewrite);
         self.last_pos = item.span.hi;
     }
 
@@ -2837,3 +2784,68 @@ fn format_generics(
 
     Some(result)
 }
+
+impl Rewrite for ast::ForeignItem {
+    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+        let attrs_str = try_opt!(self.attrs.rewrite(context, shape));
+        // Drop semicolon or it will be interpreted as comment.
+        // FIXME: this may be a faulty span from libsyntax.
+        let span = mk_sp(self.span.lo, self.span.hi - BytePos(1));
+
+        let item_str = try_opt!(match self.node {
+            ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
+                rewrite_fn_base(
+                    context,
+                    shape.indent,
+                    self.ident,
+                    fn_decl,
+                    generics,
+                    ast::Unsafety::Normal,
+                    ast::Constness::NotConst,
+                    ast::Defaultness::Final,
+                    // These are not actually rust functions,
+                    // but we format them as such.
+                    abi::Abi::Rust,
+                    &self.vis,
+                    span,
+                    false,
+                    false,
+                    false,
+                ).map(|(s, _)| format!("{};", s))
+            }
+            ast::ForeignItemKind::Static(ref ty, is_mutable) => {
+                // FIXME(#21): we're dropping potential comments in between the
+                // function keywords here.
+                let vis = format_visibility(&self.vis);
+                let mut_str = if is_mutable { "mut " } else { "" };
+                let prefix = format!("{}static {}{}:", vis, mut_str, self.ident);
+                // 1 = ;
+                let shape = try_opt!(shape.sub_width(1));
+                ty.rewrite(context, shape).map(|ty_str| {
+                    // 1 = space between prefix and type.
+                    let sep = if prefix.len() + ty_str.len() + 1 <= shape.width {
+                        String::from(" ")
+                    } else {
+                        let nested_indent = shape.indent.block_indent(context.config);
+                        format!("\n{}", nested_indent.to_string(context.config))
+                    };
+                    format!("{}{}{};", prefix, sep, ty_str)
+                })
+            }
+        });
+
+        let missing_span = if self.attrs.is_empty() {
+            mk_sp(self.span.lo, self.span.lo)
+        } else {
+            mk_sp(self.attrs[self.attrs.len() - 1].span.hi, self.span.lo)
+        };
+        combine_strs_with_missing_comments(
+            context,
+            &attrs_str,
+            &item_str,
+            missing_span,
+            shape,
+            false,
+        )
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 1b19689b660..432e61e874b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -74,6 +74,7 @@ mod patterns;
 mod summary;
 mod vertical;
 
+/// Spanned returns a span including attributes, if available.
 pub trait Spanned {
     fn span(&self) -> Span;
 }
@@ -207,6 +208,12 @@ impl Spanned for ast::TyParamBound {
     }
 }
 
+impl Spanned for ast::ForeignItem {
+    fn span(&self) -> Span {
+        span_with_attrs!(self)
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 pub struct Indent {
     // Width of the block indent, in characters. Must be a multiple of
diff --git a/src/visitor.rs b/src/visitor.rs
index 2f6a503dc13..bf1afb0c3f0 100644
--- a/src/visitor.rs
+++ b/src/visitor.rs
@@ -641,7 +641,7 @@ impl<'a> FmtVisitor<'a> {
         self.push_rewrite(mac.span, rewrite);
     }
 
-    fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) {
+    pub fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) {
         self.format_missing_with_indent(source!(self, span).lo);
         let result = rewrite.unwrap_or_else(|| self.snippet(span));
         self.buffer.push_str(&result);

From 34cf16436ac8cd25a490f678848af2e620dea84f Mon Sep 17 00:00:00 2001
From: topecongiro <seuchida@gmail.com>
Date: Fri, 25 Aug 2017 08:20:11 +0900
Subject: [PATCH 2/2] Add a test for #1914 and #1915

---
 tests/source/issue-1914.rs | 6 ++++++
 tests/target/issue-1914.rs | 7 +++++++
 2 files changed, 13 insertions(+)
 create mode 100644 tests/source/issue-1914.rs
 create mode 100644 tests/target/issue-1914.rs

diff --git a/tests/source/issue-1914.rs b/tests/source/issue-1914.rs
new file mode 100644
index 00000000000..447296c4b87
--- /dev/null
+++ b/tests/source/issue-1914.rs
@@ -0,0 +1,6 @@
+// rustfmt-max_width: 80
+
+extern "C" {
+#[link_name = "_ZN7MyClass26example_check_no_collisionE"]
+    pub static mut  MyClass_example_check_no_collision  :  * const :: std :: os :: raw :: c_int ;
+}
diff --git a/tests/target/issue-1914.rs b/tests/target/issue-1914.rs
new file mode 100644
index 00000000000..d2d532af1dc
--- /dev/null
+++ b/tests/target/issue-1914.rs
@@ -0,0 +1,7 @@
+// rustfmt-max_width: 80
+
+extern "C" {
+    #[link_name = "_ZN7MyClass26example_check_no_collisionE"]
+    pub static mut MyClass_example_check_no_collision:
+        *const ::std::os::raw::c_int;
+}