]> git.lizzy.rs Git - rust.git/blobdiff - src/items.rs
Merge pull request #3266 from wada314/fix-2973
[rust.git] / src / items.rs
index d1522d4648182cdc4459de9128cd66f087b88312..8298ffee7fa4363e7866b5048e117b8194e9097f 100644 (file)
@@ -94,10 +94,16 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 
             if let Some(ref ty) = self.ty {
                 let separator = type_annotation_separator(context.config);
-                let indent = shape.indent + last_line_width(&result) + separator.len();
-                // 1 = ;
-                let budget = shape.width.checked_sub(indent.width() + 1)?;
-                let rewrite = ty.rewrite(context, Shape::legacy(budget, indent))?;
+                let ty_shape = if pat_str.contains('\n') {
+                    shape.with_max_width(context.config)
+                } else {
+                    shape
+                }
+                .offset_left(last_line_width(&result) + separator.len())?
+                // 2 = ` =`
+                .sub_width(2)?;
+
+                let rewrite = ty.rewrite(context, ty_shape)?;
 
                 infix.push_str(separator);
                 infix.push_str(&rewrite);
@@ -458,9 +464,11 @@ pub fn visit_enum(
                 BracePos::Auto
             },
             self.block_indent,
-            mk_sp(span.lo(), body_start),
+            // make a span that starts right after `enum Foo`
+            mk_sp(ident.span.hi(), body_start),
             last_line_width(&enum_header),
-        ).unwrap();
+        )
+        .unwrap();
         self.push_str(&generics_str);
 
         self.last_pos = body_start;
@@ -499,6 +507,23 @@ fn format_variant_list(
         let original_offset = self.block_indent;
         self.block_indent = self.block_indent.block_indent(self.config);
 
+        // If enum variants have discriminants, try to vertically align those,
+        // provided the discrims are not shifted too much  to the right
+        let align_threshold: usize = self.config.enum_discrim_align_threshold();
+        let discr_ident_lens: Vec<usize> = enum_def
+            .variants
+            .iter()
+            .filter(|var| var.node.disr_expr.is_some())
+            .map(|var| rewrite_ident(&self.get_context(), var.node.ident).len())
+            .collect();
+        // cut the list at the point of longest discrim shorter than the threshold
+        // All of the discrims under the threshold will get padded, and all above - left as is.
+        let pad_discrim_ident_to = *discr_ident_lens
+            .iter()
+            .filter(|&l| *l <= align_threshold)
+            .max()
+            .unwrap_or(&0);
+
         let itemize_list_with = |one_line_width: usize| {
             itemize_list(
                 self.snippet_provider,
@@ -513,11 +538,12 @@ fn format_variant_list(
                     }
                 },
                 |f| f.span.hi(),
-                |f| self.format_variant(f, one_line_width),
+                |f| self.format_variant(f, one_line_width, pad_discrim_ident_to),
                 body_lo,
                 body_hi,
                 false,
-            ).collect()
+            )
+            .collect()
         };
         let mut items: Vec<_> =
             itemize_list_with(self.config.width_heuristics().struct_variant_width);
@@ -541,7 +567,12 @@ fn format_variant_list(
     }
 
     // Variant of an enum.
-    fn format_variant(&self, field: &ast::Variant, one_line_width: usize) -> Option<String> {
+    fn format_variant(
+        &self,
+        field: &ast::Variant,
+        one_line_width: usize,
+        pad_discrim_ident_to: usize,
+    ) -> Option<String> {
         if contains_skip(&field.node.attrs) {
             let lo = field.node.attrs[0].span.lo();
             let span = mk_sp(lo, field.span.hi());
@@ -568,7 +599,11 @@ fn format_variant(&self, field: &ast::Variant, one_line_width: usize) -> Option<
             )?,
             ast::VariantData::Unit(..) => {
                 if let Some(ref expr) = field.node.disr_expr {
-                    let lhs = format!("{} =", rewrite_ident(&context, field.node.ident));
+                    let lhs = format!(
+                        "{:1$} =",
+                        rewrite_ident(&context, field.node.ident),
+                        pad_discrim_ident_to
+                    );
                     rewrite_assign_rhs(&context, lhs, &*expr.value, shape)?
                 } else {
                     rewrite_ident(&context, field.node.ident).to_owned()
@@ -751,13 +786,12 @@ pub fn format_impl(
             let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
 
             result.push_str(&inner_indent_str);
-            result.push_str(visitor.buffer.to_string().trim());
+            result.push_str(visitor.buffer.trim());
             result.push_str(&outer_indent_str);
-        }
-
-        if result.ends_with('{') && !context.config.empty_item_single_line() {
+        } else if need_newline || !context.config.empty_item_single_line() {
             result.push_str(&sep);
         }
+
         result.push('}');
 
         Some(result)
@@ -1094,6 +1128,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
 
         let snippet = context.snippet(item.span);
         let open_pos = snippet.find_uncommented("{")? + 1;
+        let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
 
         if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
             let mut visitor = FmtVisitor::from_context(context);
@@ -1107,13 +1142,12 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
             visitor.format_missing(item.span.hi() - BytePos(1));
 
             let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
-            let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
 
             result.push_str(&inner_indent_str);
-            result.push_str(visitor.buffer.to_string().trim());
+            result.push_str(visitor.buffer.trim());
             result.push_str(&outer_indent_str);
         } else if result.contains('\n') {
-            result.push('\n');
+            result.push_str(&outer_indent_str);
         }
 
         result.push('}');
@@ -1153,7 +1187,8 @@ fn format_unit_struct(context: &RewriteContext, p: &StructParts, offset: Indent)
             context.config.brace_style(),
             BracePos::None,
             offset,
-            mk_sp(generics.span.lo(), hi),
+            // make a span that starts right after `struct Foo`
+            mk_sp(p.ident.span.hi(), hi),
             last_line_width(&header_str),
         )?
     } else {
@@ -1175,7 +1210,7 @@ pub fn format_struct_struct(
     let header_str = struct_parts.format_header(context);
     result.push_str(&header_str);
 
-    let header_hi = span.lo() + BytePos(header_str.len() as u32);
+    let header_hi = struct_parts.ident.span.hi();
     let body_lo = context.snippet_provider.span_after(span, "{");
 
     let generics_str = match struct_parts.generics {
@@ -1189,6 +1224,7 @@ pub fn format_struct_struct(
                 BracePos::Auto
             },
             offset,
+            // make a span that starts right after `struct Foo`
             mk_sp(header_hi, body_lo),
             last_line_width(&result),
         )?,
@@ -1213,7 +1249,7 @@ pub fn format_struct_struct(
     {
         result.push('\n');
         result.push_str(&offset.to_string(context.config));
-        result.push_str(generics_str.trim_left());
+        result.push_str(generics_str.trim_start());
     } else {
         result.push_str(&generics_str);
     }
@@ -1232,7 +1268,7 @@ pub fn format_struct_struct(
     let items_str = rewrite_with_alignment(
         fields,
         context,
-        Shape::indented(offset, context.config).sub_width(1)?,
+        Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
         mk_sp(body_lo, span.hi()),
         one_line_budget,
     )?;
@@ -1364,11 +1400,10 @@ fn format_tuple_struct(
         format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
     } else {
         let shape = Shape::indented(offset, context.config).sub_width(1)?;
-        let fields = &fields.iter().collect::<Vec<_>>();
         result = overflow::rewrite_with_parens(
             context,
             &result,
-            fields,
+            fields.iter(),
             shape,
             span,
             context.config.width_heuristics().fn_call_width,
@@ -1458,7 +1493,7 @@ fn rewrite_type_item<R: Rewrite>(
         result.push_str(suffix);
     } else {
         result.push_str(&indent.to_string_with_newline(context.config));
-        result.push_str(suffix.trim_left());
+        result.push_str(suffix.trim_start());
     }
 
     // 1 = ";"
@@ -1517,7 +1552,7 @@ pub fn rewrite_struct_field_prefix(
             rewrite_ident(context, name),
             type_annotation_spacing.0
         ),
-        None => format!("{}", vis),
+        None => vis.to_string(),
     })
 }
 
@@ -1566,7 +1601,7 @@ pub fn rewrite_struct_field(
     for _ in 0..lhs_offset {
         spacing.push(' ');
     }
-    // In this extreme case we will be missing a space betweeen an attribute and a field.
+    // In this extreme case we will be missing a space between an attribute and a field.
     if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
         spacing.push(' ');
     }
@@ -1584,7 +1619,7 @@ pub fn rewrite_struct_field(
     let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
     // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
     let field_str = if is_prefix_empty {
-        field_str.trim_left()
+        field_str.trim_start()
     } else {
         &field_str
     };
@@ -1705,7 +1740,8 @@ fn rewrite_static(
             lhs,
             &**expr,
             Shape::legacy(remaining_width, offset.block_only()),
-        ).and_then(|res| recover_comment_removed(res, static_parts.span, context))
+        )
+        .and_then(|res| recover_comment_removed(res, static_parts.span, context))
         .map(|s| if s.ends_with(';') { s } else { s + ";" })
     } else {
         Some(format!("{}{};", prefix, ty_str))
@@ -1788,12 +1824,9 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
     }
 }
 
-fn is_empty_infer(context: &RewriteContext, ty: &ast::Ty) -> bool {
+fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
     match ty.node {
-        ast::TyKind::Infer => {
-            let original = context.snippet(ty.span);
-            original != "_"
-        }
+        ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
         _ => false,
     }
 }
@@ -1805,7 +1838,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
                 .pat
                 .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
 
-            if !is_empty_infer(context, &*self.ty) {
+            if !is_empty_infer(&*self.ty, self.pat.span) {
                 if context.config.space_before_colon() {
                     result.push_str(" ");
                 }
@@ -1953,7 +1986,7 @@ fn rewrite_fn_base(
     let snuggle_angle_bracket = generics_str
         .lines()
         .last()
-        .map_or(false, |l| l.trim_left().len() == 1);
+        .map_or(false, |l| l.trim_start().len() == 1);
 
     // Note that the width and indent don't really matter, we'll re-layout the
     // return type later anyway.
@@ -1980,18 +2013,13 @@ fn rewrite_fn_base(
         one_line_budget, multi_line_budget, arg_indent
     );
 
+    result.push('(');
     // Check if vertical layout was forced.
-    if one_line_budget == 0 {
-        if snuggle_angle_bracket {
-            result.push('(');
-        } else {
-            result.push_str("(");
-            if context.config.indent_style() == IndentStyle::Visual {
-                result.push_str(&arg_indent.to_string_with_newline(context.config));
-            }
-        }
-    } else {
-        result.push('(');
+    if one_line_budget == 0
+        && !snuggle_angle_bracket
+        && context.config.indent_style() == IndentStyle::Visual
+    {
+        result.push_str(&arg_indent.to_string_with_newline(context.config));
     }
 
     // Skip `pub(crate)`.
@@ -2240,7 +2268,8 @@ fn rewrite_args(
         .map(|arg| {
             arg.rewrite(context, Shape::legacy(multi_line_budget, arg_indent))
                 .unwrap_or_else(|| context.snippet(arg.span()).to_owned())
-        }).collect::<Vec<_>>();
+        })
+        .collect::<Vec<_>>();
 
     // Account for sugary self.
     // FIXME: the comment for the self argument is dropped. This is blocked
@@ -2466,7 +2495,7 @@ fn rewrite_generics(
         return Some(ident.to_owned());
     }
 
-    let params = &generics.params.iter().map(|e| &*e).collect::<Vec<_>>();
+    let params = generics.params.iter();
     overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
 }
 
@@ -2822,7 +2851,8 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
                 span,
                 false,
                 false,
-            ).map(|(s, _)| format!("{};", s)),
+            )
+            .map(|(s, _)| format!("{};", s)),
             ast::ForeignItemKind::Static(ref ty, is_mutable) => {
                 // FIXME(#21): we're dropping potential comments in between the
                 // function keywords here.