]> git.lizzy.rs Git - rust.git/blobdiff - src/items.rs
Remove wrap_str() from recover_comment_removed()
[rust.git] / src / items.rs
index 3c4aab69fcc61bbd23b1f2ace895cf43721b3491..13c669d698f59437a0098b52e4acbf97c6740442 100644 (file)
@@ -55,18 +55,37 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 
         skip_out_of_file_lines_range!(context, self.span);
 
-        let mut result = "let ".to_owned();
+        if contains_skip(&self.attrs) {
+            return None;
+        }
+
+        let attrs_str = try_opt!(self.attrs.rewrite(context, shape));
+        let mut result = if attrs_str.is_empty() {
+            "let ".to_owned()
+        } else {
+            try_opt!(combine_strs_with_missing_comments(
+                context,
+                &attrs_str,
+                "let ",
+                mk_sp(
+                    self.attrs.last().map(|a| a.span.hi()).unwrap(),
+                    self.span.lo(),
+                ),
+                shape,
+                false,
+            ))
+        };
 
         // 4 = "let ".len()
         let pat_shape = try_opt!(shape.offset_left(4));
         // 1 = ;
         let pat_shape = try_opt!(pat_shape.sub_width(1));
-        let pat_str = try_opt!(self.pat.rewrite(&context, pat_shape));
+        let pat_str = try_opt!(self.pat.rewrite(context, pat_shape));
         result.push_str(&pat_str);
 
         // String that is placed within the assignment pattern and expression.
         let infix = {
-            let mut infix = String::new();
+            let mut infix = String::with_capacity(32);
 
             if let Some(ref ty) = self.ty {
                 let separator = type_annotation_separator(context.config);
@@ -92,7 +111,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
             // 1 = trailing semicolon;
             let nested_shape = try_opt!(shape.sub_width(1));
 
-            result = try_opt!(rewrite_assign_rhs(&context, result, ex, nested_shape));
+            result = try_opt!(rewrite_assign_rhs(context, result, ex, nested_shape));
         }
 
         result.push(';');
@@ -151,11 +170,11 @@ fn format_item(&mut self, item: Item) {
         if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
             // FIXME: this skips comments between the extern keyword and the opening
             // brace.
-            self.last_pos = item.span.lo + BytePos(brace_pos as u32 + 1);
+            self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
             self.block_indent = self.block_indent.block_indent(self.config);
 
             if item.body.is_empty() {
-                self.format_missing_no_indent(item.span.hi - BytePos(1));
+                self.format_missing_no_indent(item.span.hi() - BytePos(1));
                 self.block_indent = self.block_indent.block_unindent(self.config);
 
                 self.buffer
@@ -166,17 +185,17 @@ fn format_item(&mut self, item: Item) {
                 }
 
                 self.block_indent = self.block_indent.block_unindent(self.config);
-                self.format_missing_with_indent(item.span.hi - BytePos(1));
+                self.format_missing_with_indent(item.span.hi() - BytePos(1));
             }
         }
 
         self.buffer.push_str("}");
-        self.last_pos = item.span.hi;
+        self.last_pos = item.span.hi();
     }
 
     fn format_body_element(&mut self, element: &BodyElement) {
         match *element {
-            BodyElement::ForeignItem(ref item) => self.format_foreign_item(item),
+            BodyElement::ForeignItem(item) => self.format_foreign_item(item),
         }
     }
 
@@ -187,10 +206,9 @@ pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
 
 
     fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
-        let shape = Shape::indented(self.block_indent, self.config);
-        let rewrite = item.rewrite(&self.get_context(), shape);
+        let rewrite = item.rewrite(&self.get_context(), self.shape());
         self.push_rewrite(item.span(), rewrite);
-        self.last_pos = item.span.hi;
+        self.last_pos = item.span.hi();
     }
 
     pub fn rewrite_fn(
@@ -209,9 +227,9 @@ pub fn rewrite_fn(
     ) -> Option<String> {
         let context = self.get_context();
 
-        let block_snippet = self.snippet(mk_sp(block.span.lo, block.span.hi));
-        let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty() ||
-            !context.config.fn_empty_single_line();
+        let block_snippet = self.snippet(mk_sp(block.span.lo(), block.span.hi()));
+        let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty()
+            || !context.config.fn_empty_single_line();
         let mut newline_brace = newline_for_brace(self.config, &generics.where_clause, has_body);
 
         let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(
@@ -233,8 +251,8 @@ pub fn rewrite_fn(
 
         if force_newline_brace {
             newline_brace = true;
-        } else if self.config.fn_brace_style() != BraceStyle::AlwaysNextLine &&
-            !result.contains('\n')
+        } else if self.config.fn_brace_style() != BraceStyle::AlwaysNextLine
+            && !result.contains('\n')
         {
             newline_brace = false;
         }
@@ -262,7 +280,7 @@ pub fn rewrite_required_fn(
         span: Span,
     ) -> Option<String> {
         // Drop semicolon or it will be interpreted as comment.
-        let span = mk_sp(span.lo, span.hi - BytePos(1));
+        let span = mk_sp(span.lo(), span.hi() - BytePos(1));
         let context = self.get_context();
 
         let (mut result, _) = try_opt!(rewrite_fn_base(
@@ -295,15 +313,15 @@ fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
 
         let codemap = self.get_context().codemap;
 
-        if self.config.fn_empty_single_line() && is_empty_block(block, codemap) &&
-            self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width()
+        if self.config.fn_empty_single_line() && is_empty_block(block, codemap)
+            && self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width()
         {
             return Some(format!("{}{{}}", fn_str));
         }
 
         if self.config.fn_single_line() && is_simple_block_stmt(block, codemap) {
             let rewrite = {
-                if let Some(ref stmt) = block.stmts.first() {
+                if let Some(stmt) = block.stmts.first() {
                     match stmt_expr(stmt) {
                         Some(e) => {
                             let suffix = if semicolon_for_expr(&self.get_context(), e) {
@@ -312,18 +330,11 @@ fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
                                 ""
                             };
 
-                            format_expr(
-                                &e,
-                                ExprType::Statement,
-                                &self.get_context(),
-                                Shape::indented(self.block_indent, self.config),
-                            ).map(|s| s + suffix)
+                            format_expr(e, ExprType::Statement, &self.get_context(), self.shape())
+                                .map(|s| s + suffix)
                                 .or_else(|| Some(self.snippet(e.span)))
                         }
-                        None => stmt.rewrite(
-                            &self.get_context(),
-                            Shape::indented(self.block_indent, self.config),
-                        ),
+                        None => stmt.rewrite(&self.get_context(), self.shape()),
                     }
                 } else {
                     None
@@ -354,7 +365,7 @@ pub fn visit_enum(
 
         let enum_snippet = self.snippet(span);
         let brace_pos = enum_snippet.find_uncommented("{").unwrap();
-        let body_start = span.lo + BytePos(brace_pos as u32 + 1);
+        let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
         let generics_str = format_generics(
             &self.get_context(),
             generics,
@@ -363,7 +374,7 @@ pub fn visit_enum(
             self.config.item_brace_style(),
             enum_def.variants.is_empty(),
             self.block_indent,
-            mk_sp(span.lo, body_start),
+            mk_sp(span.lo(), body_start),
             last_line_width(&enum_header),
         ).unwrap();
         self.buffer.push_str(&generics_str);
@@ -371,13 +382,11 @@ pub fn visit_enum(
         self.last_pos = body_start;
 
         self.block_indent = self.block_indent.block_indent(self.config);
-        let variant_list = self.format_variant_list(enum_def, body_start, span.hi - BytePos(1));
+        let variant_list = self.format_variant_list(enum_def, body_start, span.hi() - BytePos(1));
         match variant_list {
             Some(ref body_str) => self.buffer.push_str(body_str),
             None => if contains_comment(&enum_snippet[brace_pos..]) {
-                self.format_missing_no_indent(span.hi - BytePos(1))
-            } else {
-                self.format_missing(span.hi - BytePos(1))
+                self.format_missing_no_indent(span.hi() - BytePos(1))
             },
         }
         self.block_indent = self.block_indent.block_unindent(self.config);
@@ -387,7 +396,7 @@ pub fn visit_enum(
                 .push_str(&self.block_indent.to_string(self.config));
         }
         self.buffer.push_str("}");
-        self.last_pos = span.hi;
+        self.last_pos = span.hi();
     }
 
     // Format the body of an enum definition
@@ -410,20 +419,18 @@ fn format_variant_list(
             enum_def.variants.iter(),
             "}",
             |f| if !f.node.attrs.is_empty() {
-                f.node.attrs[0].span.lo
+                f.node.attrs[0].span.lo()
             } else {
-                f.span.lo
+                f.span.lo()
             },
-            |f| f.span.hi,
+            |f| f.span.hi(),
             |f| self.format_variant(f),
             body_lo,
             body_hi,
             false,
         );
 
-        let shape = Shape::indented(self.block_indent, self.config)
-            .sub_width(2)
-            .unwrap();
+        let shape = self.shape().sub_width(2).unwrap();
         let fmt = ListFormatting {
             tactic: DefinitiveListTactic::Vertical,
             separator: ",",
@@ -444,21 +451,21 @@ fn format_variant_list(
     // Variant of an enum.
     fn format_variant(&self, field: &ast::Variant) -> Option<String> {
         if contains_skip(&field.node.attrs) {
-            let lo = field.node.attrs[0].span.lo;
-            let span = mk_sp(lo, field.span.hi);
+            let lo = field.node.attrs[0].span.lo();
+            let span = mk_sp(lo, field.span.hi());
             return Some(self.snippet(span));
         }
 
         let context = self.get_context();
         let indent = self.block_indent;
-        let shape = Shape::indented(indent, self.config);
+        let shape = self.shape();
         let attrs_str = try_opt!(field.node.attrs.rewrite(&context, shape));
         let lo = field
             .node
             .attrs
             .last()
-            .map_or(field.span.lo, |attr| attr.span.hi);
-        let span = mk_sp(lo, field.span.lo);
+            .map_or(field.span.lo(), |attr| attr.span.hi());
+        let span = mk_sp(lo, field.span.lo());
 
         let variant_body = match field.node.data {
             ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => {
@@ -496,9 +503,9 @@ fn format_variant(&self, field: &ast::Variant) -> Option<String> {
             },
         };
 
-        let attrs_extendable = attrs_str.is_empty() ||
-            (context.config.attributes_on_same_line_as_variant() &&
-                is_attributes_extendable(&attrs_str));
+        let attrs_extendable = attrs_str.is_empty()
+            || (context.config.attributes_on_same_line_as_variant()
+                && is_attributes_extendable(&attrs_str));
         combine_strs_with_missing_comments(
             &context,
             &attrs_str,
@@ -526,11 +533,7 @@ pub fn format_impl(
         let where_budget = if result.contains('\n') {
             context.config.max_width()
         } else {
-            context
-                .config
-                .max_width()
-                .checked_sub(last_line_width(&result))
-                .unwrap_or(0)
+            context.budget(last_line_width(&result))
         };
         let option = WhereClauseOption::snuggled(&ref_and_type);
         let where_clause_str = try_opt!(rewrite_where_clause(
@@ -541,7 +544,7 @@ pub fn format_impl(
             context.config.where_density(),
             "{",
             where_span_end,
-            self_ty.span.hi,
+            self_ty.span.hi(),
             option,
         ));
 
@@ -550,7 +553,7 @@ pub fn format_impl(
         if generics.where_clause.predicates.is_empty() {
             if let Some(hi) = where_span_end {
                 match recover_missing_comment_in_span(
-                    mk_sp(self_ty.span.hi, hi),
+                    mk_sp(self_ty.span.hi(), hi),
                     Shape::indented(offset, context.config),
                     context,
                     last_line_width(&result),
@@ -565,10 +568,10 @@ pub fn format_impl(
 
         if try_opt!(is_impl_single_line(
             context,
-            &items,
+            items,
             &result,
             &where_clause_str,
-            &item,
+            item,
         )) {
             result.push_str(&where_clause_str);
             if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
@@ -606,14 +609,14 @@ pub fn format_impl(
         if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
             visitor.block_indent = offset.block_only().block_indent(context.config);
-            visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
+            visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
 
             visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
             for item in items {
                 visitor.visit_impl_item(item);
             }
 
-            visitor.format_missing(item.span.hi - BytePos(1));
+            visitor.format_missing(item.span.hi() - BytePos(1));
 
             let inner_indent_str = visitor.block_indent.to_string(context.config);
             let outer_indent_str = offset.block_only().to_string(context.config);
@@ -647,9 +650,9 @@ fn is_impl_single_line(
     let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
 
     Some(
-        context.config.impl_empty_single_line() && items.is_empty() && !result.contains('\n') &&
-            result.len() + where_clause_str.len() <= context.config.max_width() &&
-            !contains_comment(&snippet[open_pos..]),
+        context.config.impl_empty_single_line() && items.is_empty() && !result.contains('\n')
+            && result.len() + where_clause_str.len() <= context.config.max_width()
+            && !contains_comment(&snippet[open_pos..]),
     )
 }
 
@@ -668,17 +671,17 @@ fn format_impl_ref_and_type(
         _,
     ) = item.node
     {
-        let mut result = String::new();
+        let mut result = String::with_capacity(128);
 
         result.push_str(&format_visibility(&item.vis));
-        result.push_str(&format_defaultness(defaultness));
+        result.push_str(format_defaultness(defaultness));
         result.push_str(format_unsafety(unsafety));
         result.push_str("impl");
 
         let lo = context.codemap.span_after(item.span, "impl");
         let hi = match *trait_ref {
-            Some(ref tr) => tr.path.span.lo,
-            None => self_ty.span.lo,
+            Some(ref tr) => tr.path.span.lo(),
+            None => self_ty.span.lo(),
         };
         let shape = try_opt!(generics_shape_from_config(
             context.config,
@@ -704,7 +707,7 @@ fn format_impl_ref_and_type(
             let result_len = result.len();
             if let Some(trait_ref_str) = rewrite_trait_ref(
                 context,
-                &trait_ref,
+                trait_ref,
                 offset,
                 &generics_str,
                 true,
@@ -722,7 +725,7 @@ fn format_impl_ref_and_type(
                 ));
                 result.push_str(&try_opt!(rewrite_trait_ref(
                     context,
-                    &trait_ref,
+                    trait_ref,
                     offset,
                     &generics_str,
                     false,
@@ -749,11 +752,7 @@ fn format_impl_ref_and_type(
         };
         let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
         // 1 = space before the type.
-        let budget = context
-            .config
-            .max_width()
-            .checked_sub(used_space + 1)
-            .unwrap_or(0);
+        let budget = context.budget(used_space + 1);
         if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
             if !self_ty_str.contains('\n') {
                 if trait_ref.is_some() {
@@ -774,7 +773,7 @@ fn format_impl_ref_and_type(
         if trait_ref.is_some() {
             result.push_str("for ");
         }
-        let budget = context.config.max_width() - last_line_width(&result);
+        let budget = context.budget(last_line_width(&result));
         let type_offset = match context.config.where_style() {
             Style::Legacy => new_line_offset + trait_ref_overhead,
             Style::Rfc => new_line_offset,
@@ -885,7 +884,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
             context,
             generics,
             shape,
-            mk_sp(item.span.lo, body_lo),
+            mk_sp(item.span.lo(), body_lo),
         ));
         result.push_str(&generics_str);
 
@@ -896,8 +895,8 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
         ));
         // If the trait, generics, and trait bound cannot fit on the same line,
         // put the trait bounds on an indented new line
-        if offset.width() + last_line_width(&result) + trait_bound_str.len() >
-            context.config.comment_width()
+        if offset.width() + last_line_width(&result) + trait_bound_str.len()
+            context.config.comment_width()
         {
             result.push('\n');
             let trait_indent = offset.block_only().block_indent(context.config);
@@ -907,27 +906,22 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
 
         let has_body = !trait_items.is_empty();
 
-        let where_density = if (context.config.where_density() == Density::Compressed &&
-            (!result.contains('\n') || context.config.fn_args_layout() == IndentStyle::Block)) ||
-            (context.config.fn_args_layout() == IndentStyle::Block && result.is_empty()) ||
-            (context.config.where_density() == Density::CompressedIfEmpty && !has_body &&
-                !result.contains('\n'))
+        let where_density = if (context.config.where_density() == Density::Compressed
+            && (!result.contains('\n') || context.config.fn_args_layout() == IndentStyle::Block))
+            || (context.config.fn_args_layout() == IndentStyle::Block && result.is_empty())
+            || (context.config.where_density() == Density::CompressedIfEmpty && !has_body
+                && !result.contains('\n'))
         {
             Density::Compressed
         } else {
             Density::Tall
         };
 
-        let where_budget = try_opt!(
-            context
-                .config
-                .max_width()
-                .checked_sub(last_line_width(&result))
-        );
+        let where_budget = context.budget(last_line_width(&result));
         let pos_before_where = if type_param_bounds.is_empty() {
-            generics.where_clause.span.lo
+            generics.where_clause.span.lo()
         } else {
-            type_param_bounds[type_param_bounds.len() - 1].span().hi
+            type_param_bounds[type_param_bounds.len() - 1].span().hi()
         };
         let option = WhereClauseOption::snuggled(&generics_str);
         let where_clause_str = try_opt!(rewrite_where_clause(
@@ -943,9 +937,9 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
         ));
         // If the where clause cannot fit on the same line,
         // put the where clause on a new line
-        if !where_clause_str.contains('\n') &&
-            last_line_width(&result) + where_clause_str.len() + offset.width() >
-                context.config.comment_width()
+        if !where_clause_str.contains('\n')
+            && last_line_width(&result) + where_clause_str.len() + offset.width()
+                context.config.comment_width()
         {
             result.push('\n');
             let width = offset.block_indent + context.config.tab_spaces() - 1;
@@ -959,7 +953,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
             if let Some(lo) = item_snippet.chars().position(|c| c == '/') {
                 // 1 = `{`
                 let comment_hi = body_lo - BytePos(1);
-                let comment_lo = item.span.lo + BytePos(lo as u32);
+                let comment_lo = item.span.lo() + BytePos(lo as u32);
                 if comment_lo < comment_hi {
                     match recover_missing_comment_in_span(
                         mk_sp(comment_lo, comment_hi),
@@ -986,8 +980,8 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
                 result.push_str(&offset.to_string(context.config));
             }
             BraceStyle::PreferSameLine => result.push(' '),
-            BraceStyle::SameLineWhere => if !where_clause_str.is_empty() &&
-                (!trait_items.is_empty() || result.contains('\n'))
+            BraceStyle::SameLineWhere => if !where_clause_str.is_empty()
+                && (!trait_items.is_empty() || result.contains('\n'))
             {
                 result.push('\n');
                 result.push_str(&offset.to_string(context.config));
@@ -1003,13 +997,13 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
         if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
             visitor.block_indent = offset.block_only().block_indent(context.config);
-            visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
+            visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
 
             for item in trait_items {
                 visitor.visit_trait_item(item);
             }
 
-            visitor.format_missing(item.span.hi - BytePos(1));
+            visitor.format_missing(item.span.hi() - BytePos(1));
 
             let inner_indent_str = visitor.block_indent.to_string(context.config);
             let outer_indent_str = offset.block_only().to_string(context.config);
@@ -1061,19 +1055,15 @@ pub fn format_struct_struct(
             context.config.item_brace_style(),
             fields.is_empty(),
             offset,
-            mk_sp(span.lo, body_lo),
+            mk_sp(span.lo(), body_lo),
             last_line_width(&result),
         )),
         None => {
             // 3 = ` {}`, 2 = ` {`.
             let overhead = if fields.is_empty() { 3 } else { 2 };
-            if (context.config.item_brace_style() == BraceStyle::AlwaysNextLine &&
-                !fields.is_empty()) ||
-                context
-                    .config
-                    .max_width()
-                    .checked_sub(result.len())
-                    .unwrap_or(0) < overhead
+            if (context.config.item_brace_style() == BraceStyle::AlwaysNextLine
+                && !fields.is_empty())
+                || context.config.max_width() < overhead + result.len()
             {
                 format!("\n{}{{", offset.block_only().to_string(context.config))
             } else {
@@ -1083,26 +1073,24 @@ pub fn format_struct_struct(
     };
     // 1 = `}`
     let overhead = if fields.is_empty() { 1 } else { 0 };
-    let max_len = context
-        .config
-        .max_width()
-        .checked_sub(offset.width())
-        .unwrap_or(0);
-    if !generics_str.contains('\n') && result.len() + generics_str.len() + overhead > max_len {
+    let total_width = result.len() + generics_str.len() + overhead;
+    if !generics_str.is_empty() && !generics_str.contains('\n')
+        && total_width > context.config.max_width()
+    {
         result.push('\n');
         result.push_str(&offset.to_string(context.config));
-        result.push_str(&generics_str.trim_left());
+        result.push_str(generics_str.trim_left());
     } else {
         result.push_str(&generics_str);
     }
 
     if fields.is_empty() {
-        let snippet = context.snippet(mk_sp(body_lo, span.hi - BytePos(1)));
+        let snippet = context.snippet(mk_sp(body_lo, span.hi() - BytePos(1)));
         if snippet.trim().is_empty() {
             // `struct S {}`
         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
             // fix indent
-            result.push_str(&snippet.trim_right());
+            result.push_str(snippet.trim_right());
             result.push('\n');
             result.push_str(&offset.to_string(context.config));
         } else {
@@ -1113,11 +1101,7 @@ pub fn format_struct_struct(
     }
 
     // 3 = ` ` and ` }`
-    let one_line_budget = context
-        .config
-        .max_width()
-        .checked_sub(result.len() + 3 + offset.width())
-        .unwrap_or(0);
+    let one_line_budget = context.budget(result.len() + 3 + offset.width());
     let one_line_budget =
         one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
 
@@ -1125,7 +1109,7 @@ pub fn format_struct_struct(
         fields,
         context,
         Shape::indented(offset, context.config),
-        mk_sp(body_lo, span.hi),
+        mk_sp(body_lo, span.hi()),
         one_line_budget,
     ));
 
@@ -1162,19 +1146,19 @@ fn format_tuple_struct(
     let body_lo = if fields.is_empty() {
         context.codemap.span_after(span, "(")
     } else {
-        fields[0].span.lo
+        fields[0].span.lo()
     };
     let body_hi = if fields.is_empty() {
         context.codemap.span_after(span, ")")
     } else {
         // This is a dirty hack to work around a missing `)` from the span of the last field.
         let last_arg_span = fields[fields.len() - 1].span;
-        if context.snippet(last_arg_span).ends_with(")") {
-            last_arg_span.hi
+        if context.snippet(last_arg_span).ends_with(')') {
+            last_arg_span.hi()
         } else {
             context
                 .codemap
-                .span_after(mk_sp(last_arg_span.hi, span.hi), ")")
+                .span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
         }
     };
 
@@ -1182,7 +1166,7 @@ fn format_tuple_struct(
         Some(generics) => {
             let budget = context.budget(last_line_width(&header_str));
             let shape = Shape::legacy(budget, offset);
-            let g_span = mk_sp(span.lo, body_lo);
+            let g_span = mk_sp(span.lo(), body_lo);
             let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
             result.push_str(&generics_str);
 
@@ -1217,7 +1201,7 @@ fn format_tuple_struct(
         if snippet.is_empty() {
             // `struct S ()`
         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
-            result.push_str(&snippet.trim_right());
+            result.push_str(snippet.trim_right());
             result.push('\n');
             result.push_str(&offset.to_string(context.config));
         } else {
@@ -1240,10 +1224,10 @@ fn format_tuple_struct(
         result.push_str(&body);
     }
 
-    if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
-        (result.contains('\n') ||
-            offset.block_indent + result.len() + where_clause_str.len() + 1 >
-                context.config.max_width())
+    if !where_clause_str.is_empty() && !where_clause_str.contains('\n')
+        && (result.contains('\n')
+            || offset.block_indent + result.len() + where_clause_str.len() + 1
+                context.config.max_width())
     {
         // We need to put the where clause on a new line, but we didn't
         // know that earlier, so the where clause will not be indented properly.
@@ -1265,7 +1249,7 @@ pub fn rewrite_type_alias(
     vis: &ast::Visibility,
     span: Span,
 ) -> Option<String> {
-    let mut result = String::new();
+    let mut result = String::with_capacity(128);
 
     result.push_str(&format_visibility(vis));
     result.push_str("type ");
@@ -1273,16 +1257,11 @@ pub fn rewrite_type_alias(
 
     // 2 = `= `
     let shape = try_opt!(Shape::indented(indent + result.len(), context.config).sub_width(2));
-    let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo);
+    let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo());
     let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
     result.push_str(&generics_str);
 
-    let where_budget = try_opt!(
-        context
-            .config
-            .max_width()
-            .checked_sub(last_line_width(&result))
-    );
+    let where_budget = context.budget(last_line_width(&result));
     let option = WhereClauseOption::snuggled(&result);
     let where_clause_str = try_opt!(rewrite_where_clause(
         context,
@@ -1291,8 +1270,8 @@ pub fn rewrite_type_alias(
         Shape::legacy(where_budget, indent),
         context.config.where_density(),
         "=",
-        Some(span.hi),
-        generics.span.hi,
+        Some(span.hi()),
+        generics.span.hi(),
         option,
     ));
     result.push_str(&where_clause_str);
@@ -1305,11 +1284,7 @@ pub fn rewrite_type_alias(
     let line_width = last_line_width(&result);
     // This checked_sub may fail as the extra space after '=' is not taken into account
     // In that case the budget is set to 0 which will make ty.rewrite retry on a new line
-    let budget = context
-        .config
-        .max_width()
-        .checked_sub(indent.width() + line_width + ";".len())
-        .unwrap_or(0);
+    let budget = context.budget(indent.width() + line_width + ";".len());
     let type_indent = indent + line_width;
     // Try to fit the type on the same line
     let ty_str = try_opt!(
@@ -1322,12 +1297,7 @@ pub fn rewrite_type_alias(
                 let type_indent = indent.block_indent(context.config);
                 result.push('\n');
                 result.push_str(&type_indent.to_string(context.config));
-                let budget = try_opt!(
-                    context
-                        .config
-                        .max_width()
-                        .checked_sub(type_indent.width() + ";".len())
-                );
+                let budget = context.budget(type_indent.width() + ";".len());
                 ty.rewrite(context, Shape::legacy(budget, type_indent))
             })
     );
@@ -1390,7 +1360,7 @@ pub fn rewrite_struct_field(
     lhs_max_width: usize,
 ) -> Option<String> {
     if contains_skip(&field.attrs) {
-        let span = context.snippet(mk_sp(field.attrs[0].span.lo, field.span.hi));
+        let span = context.snippet(mk_sp(field.attrs[0].span.lo(), field.span.hi()));
         return wrap_str(span, context.config.max_width(), shape);
     }
 
@@ -1398,12 +1368,13 @@ pub fn rewrite_struct_field(
     let prefix = try_opt!(rewrite_struct_field_prefix(context, field));
 
     let attrs_str = try_opt!(field.attrs.rewrite(context, shape));
-    let attrs_extendable = attrs_str.is_empty() ||
-        (context.config.attributes_on_same_line_as_field() && is_attributes_extendable(&attrs_str));
+    let attrs_extendable = attrs_str.is_empty()
+        || (context.config.attributes_on_same_line_as_field()
+            && is_attributes_extendable(&attrs_str));
     let missing_span = if field.attrs.is_empty() {
-        mk_sp(field.span.lo, field.span.lo)
+        mk_sp(field.span.lo(), field.span.lo())
     } else {
-        mk_sp(field.attrs.last().unwrap().span.hi, field.span.lo)
+        mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
     };
     let mut spacing = String::from(if field.ident.is_some() {
         type_annotation_spacing.1
@@ -1431,7 +1402,7 @@ pub fn rewrite_struct_field(
     let ty_rewritten = rewrite_struct_field_type(context, overhead, field, &spacing, shape);
     if let Some(ref ty) = ty_rewritten {
         if !ty.contains('\n') {
-            return Some(attr_prefix + &ty);
+            return Some(attr_prefix + ty);
         }
     }
 
@@ -1452,17 +1423,17 @@ pub fn rewrite_struct_field(
             Some(ref new_ty) if !new_ty.contains('\n') => format!(
                 "{}\n{}{}",
                 prefix,
-                type_offset.to_string(&context.config),
+                type_offset.to_string(context.config),
                 &new_ty
             ),
-            _ => prefix + &ty,
+            _ => prefix + ty,
         },
         _ => {
             let ty = try_opt!(rewrite_type_in_next_line());
             format!(
                 "{}\n{}{}",
                 prefix,
-                type_offset.to_string(&context.config),
+                type_offset.to_string(context.config),
                 &ty
             )
         }
@@ -1511,15 +1482,13 @@ pub fn rewrite_static(
     if let Some(expr) = expr_opt {
         let lhs = format!("{}{} =", prefix, ty_str);
         // 1 = ;
-        let remaining_width = context.config.max_width() - offset.block_indent - 1;
+        let remaining_width = context.budget(offset.block_indent + 1);
         rewrite_assign_rhs(
             context,
             lhs,
             expr,
             Shape::legacy(remaining_width, offset.block_only()),
-        ).and_then(|res| {
-            recover_comment_removed(res, span, context, Shape::indented(offset, context.config))
-        })
+        ).and_then(|res| recover_comment_removed(res, span, context))
             .map(|s| if s.ends_with(';') { s } else { s + ";" })
     } else {
         Some(format!("{}{};", prefix, ty_str))
@@ -1545,7 +1514,7 @@ pub fn rewrite_associated_type(
                 .map(|ty_bound| ty_bound.rewrite(context, shape))
                 .collect::<Option<Vec<_>>>()
         );
-        if bounds.len() > 0 {
+        if !bounds.is_empty() {
             format!(": {}", join_bounds(context, shape, &bound_str))
         } else {
             String::new()
@@ -1558,7 +1527,7 @@ pub fn rewrite_associated_type(
         let ty_str = try_opt!(ty.rewrite(
             context,
             Shape::legacy(
-                context.config.max_width() - indent.block_indent - prefix.len() - 2,
+                context.budget(indent.block_indent + prefix.len() + 2),
                 indent.block_only(),
             ),
         ));
@@ -1700,17 +1669,17 @@ fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
 
 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
     if is_named_arg(arg) {
-        arg.pat.span.lo
+        arg.pat.span.lo()
     } else {
-        arg.ty.span.lo
+        arg.ty.span.lo()
     }
 }
 
 pub fn span_hi_for_arg(context: &RewriteContext, arg: &ast::Arg) -> BytePos {
     match arg.ty.node {
-        ast::TyKind::Infer if context.snippet(arg.ty.span) == "_" => arg.ty.span.hi,
-        ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi,
-        _ => arg.ty.span.hi,
+        ast::TyKind::Infer if context.snippet(arg.ty.span) == "_" => arg.ty.span.hi(),
+        ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi(),
+        _ => arg.ty.span.hi(),
     }
 }
 
@@ -1766,17 +1735,13 @@ fn rewrite_fn_base(
         2
     };
     let used_width = last_line_used_width(&result, indent.width());
-    let one_line_budget = context
-        .config
-        .max_width()
-        .checked_sub(used_width + overhead)
-        .unwrap_or(0);
+    let one_line_budget = context.budget(used_width + overhead);
     let shape = Shape {
         width: one_line_budget,
         indent: indent,
         offset: used_width,
     };
-    let g_span = mk_sp(span.lo, fd.output.span().lo);
+    let g_span = mk_sp(span.lo(), fd.output.span().lo());
     let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
     result.push_str(&generics_str);
 
@@ -1789,7 +1754,7 @@ fn rewrite_fn_base(
     // return type later anyway.
     let ret_str = try_opt!(
         fd.output
-            .rewrite(&context, Shape::indented(indent, context.config))
+            .rewrite(context, Shape::indented(indent, context.config))
     );
 
     let multi_line_ret_str = ret_str.contains('\n');
@@ -1817,26 +1782,24 @@ fn rewrite_fn_base(
     if one_line_budget == 0 {
         if snuggle_angle_bracket {
             result.push('(');
+        } else if context.config.fn_args_paren_newline() {
+            result.push('\n');
+            result.push_str(&arg_indent.to_string(context.config));
+            if context.config.fn_args_layout() == IndentStyle::Visual {
+                arg_indent = arg_indent + 1; // extra space for `(`
+            }
+            result.push('(');
         } else {
-            if context.config.fn_args_paren_newline() {
+            result.push_str("(");
+            if context.config.fn_args_layout() == IndentStyle::Visual {
                 result.push('\n');
                 result.push_str(&arg_indent.to_string(context.config));
-                if context.config.fn_args_layout() == IndentStyle::Visual {
-                    arg_indent = arg_indent + 1; // extra space for `(`
-                }
-                result.push('(');
-            } else {
-                result.push_str("(");
-                if context.config.fn_args_layout() == IndentStyle::Visual {
-                    result.push('\n');
-                    result.push_str(&arg_indent.to_string(context.config));
-                }
             }
         }
     } else {
         result.push('(');
     }
-    if context.config.spaces_within_parens() && fd.inputs.len() > 0 && result.ends_with('(') {
+    if context.config.spaces_within_parens() && !fd.inputs.is_empty() && result.ends_with('(') {
         result.push(' ')
     }
 
@@ -1844,15 +1807,19 @@ fn rewrite_fn_base(
     let args_start = generics
         .ty_params
         .last()
-        .map_or(span.lo, |tp| end_typaram(tp));
+        .map_or(span.lo(), |tp| end_typaram(tp));
     let args_end = if fd.inputs.is_empty() {
-        context.codemap.span_after(mk_sp(args_start, span.hi), ")")
+        context
+            .codemap
+            .span_after(mk_sp(args_start, span.hi()), ")")
     } else {
-        let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi, span.hi);
+        let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
         context.codemap.span_after(last_span, ")")
     };
     let args_span = mk_sp(
-        context.codemap.span_after(mk_sp(args_start, span.hi), "("),
+        context
+            .codemap
+            .span_after(mk_sp(args_start, span.hi()), "("),
         args_end,
     );
     let arg_str = try_opt!(rewrite_args(
@@ -1887,10 +1854,10 @@ fn rewrite_fn_base(
         let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
         // Put the closing brace on the next line if it overflows the max width.
         // 1 = `)`
-        if fd.inputs.len() == 0 && used_width + 1 > context.config.max_width() {
+        if fd.inputs.is_empty() && used_width + 1 > context.config.max_width() {
             result.push('\n');
         }
-        if context.config.spaces_within_parens() && fd.inputs.len() > 0 {
+        if context.config.spaces_within_parens() && !fd.inputs.is_empty() {
             result.push(' ')
         }
         // If the last line of args contains comment, we cannot put the closing paren
@@ -1911,7 +1878,7 @@ fn rewrite_fn_base(
     if let ast::FunctionRetTy::Ty(..) = fd.output {
         let ret_should_indent = match context.config.fn_args_layout() {
             // If our args are block layout then we surely must have space.
-            IndentStyle::Block if put_args_in_block || fd.inputs.len() == 0 => false,
+            IndentStyle::Block if put_args_in_block || fd.inputs.is_empty() => false,
             _ if args_last_line_contains_comment => false,
             _ if result.contains('\n') || multi_line_ret_str => true,
             _ => {
@@ -1964,9 +1931,9 @@ fn rewrite_fn_base(
         }
 
         // Comment between return type and the end of the decl.
-        let snippet_lo = fd.output.span().hi;
+        let snippet_lo = fd.output.span().hi();
         if where_clause.predicates.is_empty() {
-            let snippet_hi = span.hi;
+            let snippet_hi = span.hi();
             let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
             // Try to preserve the layout of the original snippet.
             let original_starts_with_newline = snippet
@@ -1997,16 +1964,12 @@ fn rewrite_fn_base(
     };
 
     let pos_before_where = match fd.output {
-        ast::FunctionRetTy::Default(..) => args_span.hi,
-        ast::FunctionRetTy::Ty(ref ty) => ty.span.hi,
+        ast::FunctionRetTy::Default(..) => args_span.hi(),
+        ast::FunctionRetTy::Ty(ref ty) => ty.span.hi(),
     };
 
     if where_clause.predicates.len() == 1 && should_compress_where {
-        let budget = context
-            .config
-            .max_width()
-            .checked_sub(last_line_used_width(&result, indent.width()))
-            .unwrap_or(0);
+        let budget = context.budget(last_line_used_width(&result, indent.width()));
         if let Some(where_clause_str) = rewrite_where_clause(
             context,
             where_clause,
@@ -2014,7 +1977,7 @@ fn rewrite_fn_base(
             Shape::legacy(budget, indent),
             Density::Compressed,
             "{",
-            Some(span.hi),
+            Some(span.hi()),
             pos_before_where,
             WhereClauseOption::compressed(),
         ) {
@@ -2032,7 +1995,7 @@ fn rewrite_fn_base(
         Shape::indented(indent, context.config),
         Density::Tall,
         "{",
-        Some(span.hi),
+        Some(span.hi()),
         pos_before_where,
         option,
     ));
@@ -2041,7 +2004,7 @@ fn rewrite_fn_base(
     if where_clause_str.is_empty() {
         if let ast::FunctionRetTy::Default(ret_span) = fd.output {
             match recover_missing_comment_in_span(
-                mk_sp(args_span.hi, ret_span.hi),
+                mk_sp(args_span.hi(), ret_span.hi()),
                 shape,
                 context,
                 last_line_width(&result),
@@ -2058,9 +2021,10 @@ fn rewrite_fn_base(
     result.push_str(&where_clause_str);
 
     force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
-    return Some((result, force_new_line_for_brace));
+    Some((result, force_new_line_for_brace))
 }
 
+#[derive(Copy, Clone)]
 struct WhereClauseOption {
     suppress_comma: bool, // Force no trailing comma
     snuggle: bool,        // Do not insert newline before `where`
@@ -2108,7 +2072,7 @@ fn rewrite_args(
     let mut arg_item_strs = try_opt!(
         args.iter()
             .map(|arg| {
-                arg.rewrite(&context, Shape::legacy(multi_line_budget, arg_indent))
+                arg.rewrite(context, Shape::legacy(multi_line_budget, arg_indent))
             })
             .collect::<Option<Vec<_>>>()
     );
@@ -2138,15 +2102,15 @@ fn rewrite_args(
     if args.len() >= min_args || variadic {
         let comment_span_start = if min_args == 2 {
             let second_arg_start = if arg_has_pattern(&args[1]) {
-                args[1].pat.span.lo
+                args[1].pat.span.lo()
             } else {
-                args[1].ty.span.lo
+                args[1].ty.span.lo()
             };
-            let reduced_span = mk_sp(span.lo, second_arg_start);
+            let reduced_span = mk_sp(span.lo(), second_arg_start);
 
             context.codemap.span_after_last(reduced_span, ",")
         } else {
-            span.lo
+            span.lo()
         };
 
         enum ArgumentKind<'a> {
@@ -2155,7 +2119,7 @@ enum ArgumentKind<'a> {
         }
 
         let variadic_arg = if variadic {
-            let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
+            let variadic_span = mk_sp(args.last().unwrap().ty.span.hi(), span.hi());
             let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
             Some(ArgumentKind::Variadic(variadic_start))
         } else {
@@ -2174,7 +2138,7 @@ enum ArgumentKind<'a> {
                 ArgumentKind::Variadic(start) => start,
             },
             |arg| match *arg {
-                ArgumentKind::Regular(arg) => arg.ty.span.hi,
+                ArgumentKind::Regular(arg) => arg.ty.span.hi(),
                 ArgumentKind::Variadic(start) => start + BytePos(3),
             },
             |arg| match *arg {
@@ -2182,15 +2146,16 @@ enum ArgumentKind<'a> {
                 ArgumentKind::Variadic(..) => Some("...".to_owned()),
             },
             comment_span_start,
-            span.hi,
+            span.hi(),
             false,
         );
 
         arg_items.extend(more_items);
     }
 
-    let fits_in_one_line = !generics_str_contains_newline &&
-        (arg_items.len() == 0 || arg_items.len() == 1 && arg_item_strs[0].len() <= one_line_budget);
+    let fits_in_one_line = !generics_str_contains_newline
+        && (arg_items.is_empty()
+            || arg_items.len() == 1 && arg_item_strs[0].len() <= one_line_budget);
 
     for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
         item.item = Some(arg);
@@ -2285,28 +2250,19 @@ fn compute_budgets_for_args(
             // 1 = `;`
             used_space += 1;
         }
-        let one_line_budget = context
-            .config
-            .max_width()
-            .checked_sub(used_space)
-            .unwrap_or(0);
+        let one_line_budget = context.budget(used_space);
 
         if one_line_budget > 0 {
             // 4 = "() {".len()
             let (indent, multi_line_budget) = match context.config.fn_args_layout() {
                 IndentStyle::Block => {
                     let indent = indent.block_indent(context.config);
-                    let budget =
-                        try_opt!(context.config.max_width().checked_sub(indent.width() + 1));
-                    (indent, budget)
+                    (indent, context.budget(indent.width() + 1))
                 }
                 IndentStyle::Visual => {
                     let indent = indent + result.len() + 1;
-                    let multi_line_overhead =
-                        indent.width() + result.len() + if newline_brace { 2 } else { 4 };
-                    let budget =
-                        try_opt!(context.config.max_width().checked_sub(multi_line_overhead));
-                    (indent, budget)
+                    let multi_line_overhead = indent.width() + if newline_brace { 2 } else { 4 };
+                    (indent, context.budget(multi_line_overhead))
                 }
             };
 
@@ -2322,8 +2278,7 @@ fn compute_budgets_for_args(
         // Account for `)` and possibly ` {`.
         IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
     };
-    let max_space = try_opt!(context.config.max_width().checked_sub(used_space));
-    Some((0, max_space, new_indent))
+    Some((0, context.budget(used_space), new_indent))
 }
 
 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause, has_body: bool) -> bool {
@@ -2358,37 +2313,47 @@ fn rewrite_generics_inner(
 ) -> Option<String> {
     // FIXME: convert bounds to where clauses where they get too big or if
     // there is a where clause at all.
-    let lifetimes: &[_] = &generics.lifetimes;
-    let tys: &[_] = &generics.ty_params;
-    if lifetimes.is_empty() && tys.is_empty() {
-        return Some(String::new());
-    }
 
-    // Strings for the generics.
-    let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, shape));
-    let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, shape));
+    // Wrapper type
+    enum GenericsArg<'a> {
+        Lifetime(&'a ast::LifetimeDef),
+        TyParam(&'a ast::TyParam),
+    }
+    impl<'a> Rewrite for GenericsArg<'a> {
+        fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+            match *self {
+                GenericsArg::Lifetime(ref lifetime) => lifetime.rewrite(context, shape),
+                GenericsArg::TyParam(ref ty) => ty.rewrite(context, shape),
+            }
+        }
+    }
+    impl<'a> Spanned for GenericsArg<'a> {
+        fn span(&self) -> Span {
+            match *self {
+                GenericsArg::Lifetime(ref lifetime) => lifetime.span(),
+                GenericsArg::TyParam(ref ty) => ty.span(),
+            }
+        }
+    }
 
-    // Extract comments between generics.
-    let lt_spans = lifetimes.iter().map(|l| {
-        let hi = if l.bounds.is_empty() {
-            l.lifetime.span.hi
-        } else {
-            l.bounds[l.bounds.len() - 1].span.hi
-        };
-        mk_sp(l.lifetime.span.lo, hi)
-    });
-    let ty_spans = tys.iter().map(|ty| ty.span());
+    if generics.lifetimes.is_empty() && generics.ty_params.is_empty() {
+        return Some(String::new());
+    }
 
+    let generics_args = generics
+        .lifetimes
+        .iter()
+        .map(|lt| GenericsArg::Lifetime(lt))
+        .chain(generics.ty_params.iter().map(|ty| GenericsArg::TyParam(ty)));
     let items = itemize_list(
         context.codemap,
-        lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
+        generics_args,
         ">",
-        |&(sp, _)| sp.lo,
-        |&(sp, _)| sp.hi,
-        // FIXME: don't clone
-        |&(_, ref str)| str.clone(),
+        |arg| arg.span().lo(),
+        |arg| arg.span().hi(),
+        |arg| arg.rewrite(context, shape),
         context.codemap.span_after(span, "<"),
-        span.hi,
+        span.hi(),
         false,
     );
     format_generics_item_list(context, items, shape, one_line_width)
@@ -2454,8 +2419,8 @@ pub fn wrap_generics_with_angle_brackets(
     list_str: &str,
     list_offset: Indent,
 ) -> String {
-    if context.config.generics_indent() == IndentStyle::Block &&
-        (list_str.contains('\n') || list_str.ends_with(','))
+    if context.config.generics_indent() == IndentStyle::Block
+        && (list_str.contains('\n') || list_str.ends_with(','))
     {
         format!(
             "<\n{}{}\n{}>",
@@ -2485,7 +2450,7 @@ fn rewrite_trait_bounds(
     let bound_str = try_opt!(
         bounds
             .iter()
-            .map(|ty_bound| ty_bound.rewrite(&context, shape))
+            .map(|ty_bound| ty_bound.rewrite(context, shape))
             .collect::<Option<Vec<_>>>()
     );
     Some(format!(": {}", join_bounds(context, shape, &bound_str)))
@@ -2519,18 +2484,18 @@ fn rewrite_where_clause_rfc_style(
 
     let clause_shape = block_shape.block_indent(context.config.tab_spaces());
     // each clause on one line, trailing comma (except if suppress_comma)
-    let span_start = where_clause.predicates[0].span().lo;
+    let span_start = where_clause.predicates[0].span().lo();
     // If we don't have the start of the next span, then use the end of the
     // predicates, but that means we miss comments.
     let len = where_clause.predicates.len();
-    let end_of_preds = where_clause.predicates[len - 1].span().hi;
+    let end_of_preds = where_clause.predicates[len - 1].span().hi();
     let span_end = span_end.unwrap_or(end_of_preds);
     let items = itemize_list(
         context.codemap,
         where_clause.predicates.iter(),
         terminator,
-        |pred| pred.span().lo,
-        |pred| pred.span().hi,
+        |pred| pred.span().lo(),
+        |pred| pred.span().hi(),
         |pred| pred.rewrite(context, block_shape),
         span_start,
         span_end,
@@ -2563,9 +2528,9 @@ fn rewrite_where_clause_rfc_style(
     let newline_after_where = comment_separator(&comment_after, clause_shape);
 
     // 6 = `where `
-    let clause_sep = if where_clause_option.compress_where && comment_before.is_empty() &&
-        comment_after.is_empty() && !preds_str.contains('\n') &&
-        6 + preds_str.len() <= shape.width
+    let clause_sep = if where_clause_option.compress_where && comment_before.is_empty()
+        && comment_after.is_empty() && !preds_str.contains('\n')
+        && 6 + preds_str.len() <= shape.width
     {
         String::from(" ")
     } else {
@@ -2621,18 +2586,18 @@ fn rewrite_where_clause(
     // be out by a char or two.
 
     let budget = context.config.max_width() - offset.width();
-    let span_start = where_clause.predicates[0].span().lo;
+    let span_start = where_clause.predicates[0].span().lo();
     // If we don't have the start of the next span, then use the end of the
     // predicates, but that means we miss comments.
     let len = where_clause.predicates.len();
-    let end_of_preds = where_clause.predicates[len - 1].span().hi;
+    let end_of_preds = where_clause.predicates[len - 1].span().hi();
     let span_end = span_end.unwrap_or(end_of_preds);
     let items = itemize_list(
         context.codemap,
         where_clause.predicates.iter(),
         terminator,
-        |pred| pred.span().lo,
-        |pred| pred.span().hi,
+        |pred| pred.span().lo(),
+        |pred| pred.span().hi(),
         |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
         span_start,
         span_end,
@@ -2678,8 +2643,8 @@ fn rewrite_where_clause(
     } else {
         terminator.len()
     };
-    if density == Density::Tall || preds_str.contains('\n') ||
-        shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
+    if density == Density::Tall || preds_str.contains('\n')
+        || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
     {
         Some(format!(
             "\n{}where {}",
@@ -2695,10 +2660,10 @@ fn missing_span_before_after_where(
     before_item_span_end: BytePos,
     where_clause: &ast::WhereClause,
 ) -> (Span, Span) {
-    let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo);
+    let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
     // 5 = `where`
-    let pos_after_where = where_clause.span.lo + BytePos(5);
-    let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo);
+    let pos_after_where = where_clause.span.lo() + BytePos(5);
+    let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
     (missing_span_before, missing_span_after)
 }
 
@@ -2736,11 +2701,7 @@ fn format_generics(
     let mut result = try_opt!(rewrite_generics(context, generics, shape, span));
 
     let same_line_brace = if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
-        let budget = context
-            .config
-            .max_width()
-            .checked_sub(last_line_used_width(&result, offset.width()))
-            .unwrap_or(0);
+        let budget = context.budget(last_line_used_width(&result, offset.width()));
         let option = WhereClauseOption::snuggled(&result);
         let where_clause_str = try_opt!(rewrite_where_clause(
             context,
@@ -2749,23 +2710,20 @@ fn format_generics(
             Shape::legacy(budget, offset.block_only()),
             Density::Tall,
             terminator,
-            Some(span.hi),
-            generics.span.hi,
+            Some(span.hi()),
+            generics.span.hi(),
             option,
         ));
         result.push_str(&where_clause_str);
-        force_same_line_brace || brace_style == BraceStyle::PreferSameLine ||
-            (generics.where_clause.predicates.is_empty() && trimmed_last_line_width(&result) == 1)
+        force_same_line_brace || brace_style == BraceStyle::PreferSameLine
+            || (generics.where_clause.predicates.is_empty()
+                && trimmed_last_line_width(&result) == 1)
     } else {
-        force_same_line_brace || trimmed_last_line_width(&result) == 1 ||
-            brace_style != BraceStyle::AlwaysNextLine
+        force_same_line_brace || trimmed_last_line_width(&result) == 1
+            || brace_style != BraceStyle::AlwaysNextLine
     };
     let total_used_width = last_line_used_width(&result, used_width);
-    let remaining_budget = context
-        .config
-        .max_width()
-        .checked_sub(total_used_width)
-        .unwrap_or(0);
+    let remaining_budget = context.budget(total_used_width);
     // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
     // and hence we take the closer into account as well for one line budget.
     // We assume that the closer has the same length as the opener.
@@ -2791,7 +2749,7 @@ 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 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) => {
@@ -2836,9 +2794,9 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         });
 
         let missing_span = if self.attrs.is_empty() {
-            mk_sp(self.span.lo, self.span.lo)
+            mk_sp(self.span.lo(), self.span.lo())
         } else {
-            mk_sp(self.attrs[self.attrs.len() - 1].span.hi, self.span.lo)
+            mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
         };
         combine_strs_with_missing_comments(
             context,