]> git.lizzy.rs Git - rust.git/blob - src/items.rs
Handle 'extern "Rust"' in format_abi()
[rust.git] / src / items.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // Formatting top-level items - functions, structs, enums, traits, impls.
12
13 use std::borrow::Cow;
14 use std::cmp::min;
15
16 use syntax::{abi, ast, ptr, symbol};
17 use syntax::ast::ImplItem;
18 use syntax::codemap::{BytePos, Span};
19 use syntax::visit;
20
21 use spanned::Spanned;
22 use codemap::{LineRangeUtils, SpanUtils};
23 use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed,
24               recover_missing_comment_in_span, rewrite_missing_comment, FindUncommented};
25 use config::{BraceStyle, Config, Density, IndentStyle, ReturnIndent, Style};
26 use expr::{format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs,
27            rewrite_call_inner, ExprType};
28 use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
29             ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
30 use rewrite::{Rewrite, RewriteContext};
31 use shape::{Indent, Shape};
32 use types::join_bounds;
33 use utils::{colon_spaces, contains_skip, end_typaram, first_line_width, format_abi,
34             format_constness, format_defaultness, format_mutability, format_unsafety,
35             format_visibility, is_attributes_extendable, last_line_contains_single_line_comment,
36             last_line_used_width, last_line_width, mk_sp, semicolon_for_expr, stmt_expr,
37             trim_newlines, trimmed_last_line_width};
38 use vertical::rewrite_with_alignment;
39 use visitor::FmtVisitor;
40
41 fn type_annotation_separator(config: &Config) -> &str {
42     colon_spaces(
43         config.space_before_type_annotation(),
44         config.space_after_type_annotation_colon(),
45     )
46 }
47
48 // Statements of the form
49 // let pat: ty = init;
50 impl Rewrite for ast::Local {
51     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
52         debug!(
53             "Local::rewrite {:?} {} {:?}",
54             self,
55             shape.width,
56             shape.indent
57         );
58
59         skip_out_of_file_lines_range!(context, self.span);
60
61         if contains_skip(&self.attrs) {
62             return None;
63         }
64
65         let attrs_str = try_opt!(self.attrs.rewrite(context, shape));
66         let mut result = if attrs_str.is_empty() {
67             "let ".to_owned()
68         } else {
69             try_opt!(combine_strs_with_missing_comments(
70                 context,
71                 &attrs_str,
72                 "let ",
73                 mk_sp(
74                     self.attrs.last().map(|a| a.span.hi()).unwrap(),
75                     self.span.lo(),
76                 ),
77                 shape,
78                 false,
79             ))
80         };
81
82         // 4 = "let ".len()
83         let pat_shape = try_opt!(shape.offset_left(4));
84         // 1 = ;
85         let pat_shape = try_opt!(pat_shape.sub_width(1));
86         let pat_str = try_opt!(self.pat.rewrite(context, pat_shape));
87         result.push_str(&pat_str);
88
89         // String that is placed within the assignment pattern and expression.
90         let infix = {
91             let mut infix = String::with_capacity(32);
92
93             if let Some(ref ty) = self.ty {
94                 let separator = type_annotation_separator(context.config);
95                 let indent = shape.indent + last_line_width(&result) + separator.len();
96                 // 1 = ;
97                 let budget = try_opt!(shape.width.checked_sub(indent.width() + 1));
98                 let rewrite = try_opt!(ty.rewrite(context, Shape::legacy(budget, indent)));
99
100                 infix.push_str(separator);
101                 infix.push_str(&rewrite);
102             }
103
104             if self.init.is_some() {
105                 infix.push_str(" =");
106             }
107
108             infix
109         };
110
111         result.push_str(&infix);
112
113         if let Some(ref ex) = self.init {
114             // 1 = trailing semicolon;
115             let nested_shape = try_opt!(shape.sub_width(1));
116
117             result = try_opt!(rewrite_assign_rhs(context, result, ex, nested_shape));
118         }
119
120         result.push(';');
121         Some(result)
122     }
123 }
124
125 // TODO convert to using rewrite style rather than visitor
126 // TODO format modules in this style
127 #[allow(dead_code)]
128 struct Item<'a> {
129     keyword: &'static str,
130     abi: Cow<'static, str>,
131     vis: Option<&'a ast::Visibility>,
132     body: Vec<BodyElement<'a>>,
133     span: Span,
134 }
135
136 impl<'a> Item<'a> {
137     fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
138         Item {
139             keyword: "",
140             abi: format_abi(fm.abi, config.force_explicit_abi(), true),
141             vis: None,
142             body: fm.items
143                 .iter()
144                 .map(|i| BodyElement::ForeignItem(i))
145                 .collect(),
146             span: span,
147         }
148     }
149 }
150
151 enum BodyElement<'a> {
152     // Stmt(&'a ast::Stmt),
153     // Field(&'a ast::Field),
154     // Variant(&'a ast::Variant),
155     // Item(&'a ast::Item),
156     ForeignItem(&'a ast::ForeignItem),
157 }
158
159 /// Represents a fn's signature.
160 pub struct FnSig<'a> {
161     decl: &'a ast::FnDecl,
162     generics: &'a ast::Generics,
163     abi: abi::Abi,
164     constness: ast::Constness,
165     defaultness: ast::Defaultness,
166     unsafety: ast::Unsafety,
167     visibility: ast::Visibility,
168 }
169
170 impl<'a> FnSig<'a> {
171     pub fn new(
172         decl: &'a ast::FnDecl,
173         generics: &'a ast::Generics,
174         vis: ast::Visibility,
175     ) -> FnSig<'a> {
176         FnSig {
177             decl: decl,
178             generics: generics,
179             abi: abi::Abi::Rust,
180             constness: ast::Constness::NotConst,
181             defaultness: ast::Defaultness::Final,
182             unsafety: ast::Unsafety::Normal,
183             visibility: vis,
184         }
185     }
186
187     pub fn from_method_sig(method_sig: &'a ast::MethodSig) -> FnSig {
188         FnSig {
189             unsafety: method_sig.unsafety,
190             constness: method_sig.constness.node,
191             defaultness: ast::Defaultness::Final,
192             abi: method_sig.abi,
193             decl: &*method_sig.decl,
194             generics: &method_sig.generics,
195             visibility: ast::Visibility::Inherited,
196         }
197     }
198
199     pub fn from_fn_kind(
200         fn_kind: &'a visit::FnKind,
201         decl: &'a ast::FnDecl,
202         defualtness: ast::Defaultness,
203     ) -> FnSig<'a> {
204         match *fn_kind {
205             visit::FnKind::ItemFn(_, generics, unsafety, constness, abi, visibility, _) => FnSig {
206                 decl: decl,
207                 generics: generics,
208                 abi: abi,
209                 constness: constness.node,
210                 defaultness: defualtness,
211                 unsafety: unsafety,
212                 visibility: visibility.clone(),
213             },
214             visit::FnKind::Method(_, ref method_sig, vis, _) => {
215                 let mut fn_sig = FnSig::from_method_sig(method_sig);
216                 fn_sig.defaultness = defualtness;
217                 if let Some(vis) = vis {
218                     fn_sig.visibility = vis.clone();
219                 }
220                 fn_sig
221             }
222             _ => unreachable!(),
223         }
224     }
225 }
226
227 impl<'a> FmtVisitor<'a> {
228     fn format_item(&mut self, item: Item) {
229         self.buffer.push_str(&item.abi);
230         self.buffer.push_str(" ");
231
232         let snippet = self.snippet(item.span);
233         let brace_pos = snippet.find_uncommented("{").unwrap();
234
235         self.buffer.push_str("{");
236         if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
237             // FIXME: this skips comments between the extern keyword and the opening
238             // brace.
239             self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
240             self.block_indent = self.block_indent.block_indent(self.config);
241
242             if item.body.is_empty() {
243                 self.format_missing_no_indent(item.span.hi() - BytePos(1));
244                 self.block_indent = self.block_indent.block_unindent(self.config);
245
246                 self.buffer
247                     .push_str(&self.block_indent.to_string(self.config));
248             } else {
249                 for item in &item.body {
250                     self.format_body_element(item);
251                 }
252
253                 self.block_indent = self.block_indent.block_unindent(self.config);
254                 self.format_missing_with_indent(item.span.hi() - BytePos(1));
255             }
256         }
257
258         self.buffer.push_str("}");
259         self.last_pos = item.span.hi();
260     }
261
262     fn format_body_element(&mut self, element: &BodyElement) {
263         match *element {
264             BodyElement::ForeignItem(item) => self.format_foreign_item(item),
265         }
266     }
267
268     pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
269         let item = Item::from_foreign_mod(fm, span, self.config);
270         self.format_item(item);
271     }
272
273
274     fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
275         let rewrite = item.rewrite(&self.get_context(), self.shape());
276         self.push_rewrite(item.span(), rewrite);
277         self.last_pos = item.span.hi();
278     }
279
280     pub fn rewrite_fn(
281         &mut self,
282         indent: Indent,
283         ident: ast::Ident,
284         fn_sig: &FnSig,
285         span: Span,
286         block: &ast::Block,
287     ) -> Option<String> {
288         let context = self.get_context();
289
290         let has_body =
291             !is_empty_block(block, self.codemap) || !context.config.fn_empty_single_line();
292         let mut newline_brace =
293             newline_for_brace(self.config, &fn_sig.generics.where_clause, has_body);
294
295         let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(
296             &context,
297             indent,
298             ident,
299             fn_sig,
300             span,
301             newline_brace,
302             true,
303         ));
304
305         if force_newline_brace {
306             newline_brace = true;
307         } else if self.config.fn_brace_style() != BraceStyle::AlwaysNextLine
308             && !result.contains('\n')
309         {
310             newline_brace = false;
311         }
312
313         // Prepare for the function body by possibly adding a newline and
314         // indent.
315         // FIXME we'll miss anything between the end of the signature and the
316         // start of the body, but we need more spans from the compiler to solve
317         // this.
318         if newline_brace {
319             result.push('\n');
320             result.push_str(&indent.to_string(self.config));
321         } else {
322             result.push(' ');
323         }
324
325         self.single_line_fn(&result, block).or_else(|| Some(result))
326     }
327
328     pub fn rewrite_required_fn(
329         &mut self,
330         indent: Indent,
331         ident: ast::Ident,
332         sig: &ast::MethodSig,
333         span: Span,
334     ) -> Option<String> {
335         // Drop semicolon or it will be interpreted as comment.
336         let span = mk_sp(span.lo(), span.hi() - BytePos(1));
337         let context = self.get_context();
338
339         let (mut result, _) = try_opt!(rewrite_fn_base(
340             &context,
341             indent,
342             ident,
343             &FnSig::from_method_sig(sig),
344             span,
345             false,
346             false,
347         ));
348
349         // Re-attach semicolon
350         result.push(';');
351
352         Some(result)
353     }
354
355     fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
356         if fn_str.contains('\n') {
357             return None;
358         }
359
360         let codemap = self.get_context().codemap;
361
362         if self.config.fn_empty_single_line() && is_empty_block(block, codemap)
363             && self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width()
364         {
365             return Some(format!("{}{{}}", fn_str));
366         }
367
368         if self.config.fn_single_line() && is_simple_block_stmt(block, codemap) {
369             let rewrite = {
370                 if let Some(stmt) = block.stmts.first() {
371                     match stmt_expr(stmt) {
372                         Some(e) => {
373                             let suffix = if semicolon_for_expr(&self.get_context(), e) {
374                                 ";"
375                             } else {
376                                 ""
377                             };
378
379                             format_expr(e, ExprType::Statement, &self.get_context(), self.shape())
380                                 .map(|s| s + suffix)
381                                 .or_else(|| Some(self.snippet(e.span)))
382                         }
383                         None => stmt.rewrite(&self.get_context(), self.shape()),
384                     }
385                 } else {
386                     None
387                 }
388             };
389
390             if let Some(res) = rewrite {
391                 let width = self.block_indent.width() + fn_str.len() + res.len() + 4;
392                 if !res.contains('\n') && width <= self.config.max_width() {
393                     return Some(format!("{}{{ {} }}", fn_str, res));
394                 }
395             }
396         }
397
398         None
399     }
400
401     pub fn visit_enum(
402         &mut self,
403         ident: ast::Ident,
404         vis: &ast::Visibility,
405         enum_def: &ast::EnumDef,
406         generics: &ast::Generics,
407         span: Span,
408     ) {
409         let enum_header = format_header("enum ", ident, vis);
410         self.buffer.push_str(&enum_header);
411
412         let enum_snippet = self.snippet(span);
413         let brace_pos = enum_snippet.find_uncommented("{").unwrap();
414         let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
415         let generics_str = format_generics(
416             &self.get_context(),
417             generics,
418             "{",
419             "{",
420             self.config.item_brace_style(),
421             enum_def.variants.is_empty(),
422             self.block_indent,
423             mk_sp(span.lo(), body_start),
424             last_line_width(&enum_header),
425         ).unwrap();
426         self.buffer.push_str(&generics_str);
427
428         self.last_pos = body_start;
429
430         self.block_indent = self.block_indent.block_indent(self.config);
431         let variant_list = self.format_variant_list(enum_def, body_start, span.hi() - BytePos(1));
432         match variant_list {
433             Some(ref body_str) => self.buffer.push_str(body_str),
434             None => if contains_comment(&enum_snippet[brace_pos..]) {
435                 self.format_missing_no_indent(span.hi() - BytePos(1))
436             },
437         }
438         self.block_indent = self.block_indent.block_unindent(self.config);
439
440         if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
441             self.buffer
442                 .push_str(&self.block_indent.to_string(self.config));
443         }
444         self.buffer.push_str("}");
445         self.last_pos = span.hi();
446     }
447
448     // Format the body of an enum definition
449     fn format_variant_list(
450         &self,
451         enum_def: &ast::EnumDef,
452         body_lo: BytePos,
453         body_hi: BytePos,
454     ) -> Option<String> {
455         if enum_def.variants.is_empty() {
456             return None;
457         }
458         let mut result = String::with_capacity(1024);
459         result.push('\n');
460         let indentation = self.block_indent.to_string(self.config);
461         result.push_str(&indentation);
462
463         let items = itemize_list(
464             self.codemap,
465             enum_def.variants.iter(),
466             "}",
467             |f| if !f.node.attrs.is_empty() {
468                 f.node.attrs[0].span.lo()
469             } else {
470                 f.span.lo()
471             },
472             |f| f.span.hi(),
473             |f| self.format_variant(f),
474             body_lo,
475             body_hi,
476             false,
477         );
478
479         let shape = self.shape().sub_width(2).unwrap();
480         let fmt = ListFormatting {
481             tactic: DefinitiveListTactic::Vertical,
482             separator: ",",
483             trailing_separator: self.config.trailing_comma(),
484             separator_place: SeparatorPlace::Back,
485             shape: shape,
486             ends_with_newline: true,
487             preserve_newline: true,
488             config: self.config,
489         };
490
491         let list = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
492         result.push_str(&list);
493         result.push('\n');
494         Some(result)
495     }
496
497     // Variant of an enum.
498     fn format_variant(&self, field: &ast::Variant) -> Option<String> {
499         if contains_skip(&field.node.attrs) {
500             let lo = field.node.attrs[0].span.lo();
501             let span = mk_sp(lo, field.span.hi());
502             return Some(self.snippet(span));
503         }
504
505         let context = self.get_context();
506         let indent = self.block_indent;
507         let shape = self.shape();
508         let attrs_str = try_opt!(field.node.attrs.rewrite(&context, shape));
509         let lo = field
510             .node
511             .attrs
512             .last()
513             .map_or(field.span.lo(), |attr| attr.span.hi());
514         let span = mk_sp(lo, field.span.lo());
515
516         let variant_body = match field.node.data {
517             ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => {
518                 // FIXME: Should limit the width, as we have a trailing comma
519                 try_opt!(format_struct(
520                     &context,
521                     "",
522                     field.node.name,
523                     &ast::Visibility::Inherited,
524                     &field.node.data,
525                     None,
526                     field.span,
527                     indent,
528                     Some(self.config.struct_variant_width()),
529                 ))
530             }
531             ast::VariantData::Unit(..) => if let Some(ref expr) = field.node.disr_expr {
532                 let one_line_width =
533                     field.node.name.to_string().len() + self.snippet(expr.span).len() + 3;
534                 if one_line_width <= shape.width {
535                     format!("{} = {}", field.node.name, self.snippet(expr.span))
536                 } else {
537                     format!(
538                         "{}\n{}{}",
539                         field.node.name,
540                         shape
541                             .indent
542                             .block_indent(self.config)
543                             .to_string(self.config),
544                         self.snippet(expr.span)
545                     )
546                 }
547             } else {
548                 String::from(field.node.name.to_string())
549             },
550         };
551
552         let attrs_extendable = attrs_str.is_empty()
553             || (context.config.attributes_on_same_line_as_variant()
554                 && is_attributes_extendable(&attrs_str));
555         combine_strs_with_missing_comments(
556             &context,
557             &attrs_str,
558             &variant_body,
559             span,
560             shape,
561             attrs_extendable,
562         )
563     }
564 }
565
566 pub fn format_impl(
567     context: &RewriteContext,
568     item: &ast::Item,
569     offset: Indent,
570     where_span_end: Option<BytePos>,
571 ) -> Option<String> {
572     if let ast::ItemKind::Impl(_, _, _, ref generics, _, ref self_ty, ref items) = item.node {
573         let mut result = String::with_capacity(128);
574         let ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset));
575         let indent_str = offset.to_string(context.config);
576         let sep = format!("\n{}", &indent_str);
577         result.push_str(&ref_and_type);
578
579         let where_budget = if result.contains('\n') {
580             context.config.max_width()
581         } else {
582             context.budget(last_line_width(&result))
583         };
584         let option = WhereClauseOption::snuggled(&ref_and_type);
585         let where_clause_str = try_opt!(rewrite_where_clause(
586             context,
587             &generics.where_clause,
588             context.config.item_brace_style(),
589             Shape::legacy(where_budget, offset.block_only()),
590             context.config.where_density(),
591             "{",
592             where_span_end,
593             self_ty.span.hi(),
594             option,
595         ));
596
597         // If there is no where clause, we may have missing comments between the trait name and
598         // the opening brace.
599         if generics.where_clause.predicates.is_empty() {
600             if let Some(hi) = where_span_end {
601                 match recover_missing_comment_in_span(
602                     mk_sp(self_ty.span.hi(), hi),
603                     Shape::indented(offset, context.config),
604                     context,
605                     last_line_width(&result),
606                 ) {
607                     Some(ref missing_comment) if !missing_comment.is_empty() => {
608                         result.push_str(missing_comment);
609                     }
610                     _ => (),
611                 }
612             }
613         }
614
615         if try_opt!(is_impl_single_line(
616             context,
617             items,
618             &result,
619             &where_clause_str,
620             item,
621         )) {
622             result.push_str(&where_clause_str);
623             if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
624                 result.push_str(&format!("{}{{{}}}", &sep, &sep));
625             } else {
626                 result.push_str(" {}");
627             }
628             return Some(result);
629         }
630
631         if !where_clause_str.is_empty() && !where_clause_str.contains('\n') {
632             result.push('\n');
633             let width = offset.block_indent + context.config.tab_spaces() - 1;
634             let where_indent = Indent::new(0, width);
635             result.push_str(&where_indent.to_string(context.config));
636         }
637         result.push_str(&where_clause_str);
638
639         match context.config.item_brace_style() {
640             _ if last_line_contains_single_line_comment(&result) => result.push_str(&sep),
641             BraceStyle::AlwaysNextLine => result.push_str(&sep),
642             BraceStyle::PreferSameLine => result.push(' '),
643             BraceStyle::SameLineWhere => if !where_clause_str.is_empty() {
644                 result.push_str(&sep);
645             } else {
646                 result.push(' ');
647             },
648         }
649
650         result.push('{');
651
652         let snippet = context.snippet(item.span);
653         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
654
655         if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
656             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
657             visitor.block_indent = offset.block_only().block_indent(context.config);
658             visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
659
660             visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
661             for item in items {
662                 visitor.visit_impl_item(item);
663             }
664
665             visitor.format_missing(item.span.hi() - BytePos(1));
666
667             let inner_indent_str = visitor.block_indent.to_string(context.config);
668             let outer_indent_str = offset.block_only().to_string(context.config);
669
670             result.push('\n');
671             result.push_str(&inner_indent_str);
672             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
673             result.push('\n');
674             result.push_str(&outer_indent_str);
675         }
676
677         if result.chars().last().unwrap() == '{' {
678             result.push_str(&sep);
679         }
680         result.push('}');
681
682         Some(result)
683     } else {
684         unreachable!();
685     }
686 }
687
688 fn is_impl_single_line(
689     context: &RewriteContext,
690     items: &[ImplItem],
691     result: &str,
692     where_clause_str: &str,
693     item: &ast::Item,
694 ) -> Option<bool> {
695     let snippet = context.snippet(item.span);
696     let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
697
698     Some(
699         context.config.impl_empty_single_line() && items.is_empty() && !result.contains('\n')
700             && result.len() + where_clause_str.len() <= context.config.max_width()
701             && !contains_comment(&snippet[open_pos..]),
702     )
703 }
704
705 fn format_impl_ref_and_type(
706     context: &RewriteContext,
707     item: &ast::Item,
708     offset: Indent,
709 ) -> Option<String> {
710     if let ast::ItemKind::Impl(
711         unsafety,
712         polarity,
713         defaultness,
714         ref generics,
715         ref trait_ref,
716         ref self_ty,
717         _,
718     ) = item.node
719     {
720         let mut result = String::with_capacity(128);
721
722         result.push_str(&format_visibility(&item.vis));
723         result.push_str(format_defaultness(defaultness));
724         result.push_str(format_unsafety(unsafety));
725         result.push_str("impl");
726
727         let lo = context.codemap.span_after(item.span, "impl");
728         let hi = match *trait_ref {
729             Some(ref tr) => tr.path.span.lo(),
730             None => self_ty.span.lo(),
731         };
732         let shape = try_opt!(generics_shape_from_config(
733             context.config,
734             Shape::indented(offset + last_line_width(&result), context.config),
735             0,
736         ));
737         let one_line_budget = try_opt!(shape.width.checked_sub(last_line_width(&result) + 2));
738         let generics_str = try_opt!(rewrite_generics_inner(
739             context,
740             generics,
741             shape,
742             one_line_budget,
743             mk_sp(lo, hi),
744         ));
745
746         let polarity_str = if polarity == ast::ImplPolarity::Negative {
747             "!"
748         } else {
749             ""
750         };
751
752         if let Some(ref trait_ref) = *trait_ref {
753             let result_len = result.len();
754             if let Some(trait_ref_str) = rewrite_trait_ref(
755                 context,
756                 trait_ref,
757                 offset,
758                 &generics_str,
759                 true,
760                 polarity_str,
761                 result_len,
762             ) {
763                 result.push_str(&trait_ref_str);
764             } else {
765                 let generics_str = try_opt!(rewrite_generics_inner(
766                     context,
767                     generics,
768                     shape,
769                     0,
770                     mk_sp(lo, hi),
771                 ));
772                 result.push_str(&try_opt!(rewrite_trait_ref(
773                     context,
774                     trait_ref,
775                     offset,
776                     &generics_str,
777                     false,
778                     polarity_str,
779                     result_len,
780                 )));
781             }
782         } else {
783             result.push_str(&generics_str);
784         }
785
786         // Try to put the self type in a single line.
787         // ` for`
788         let trait_ref_overhead = if trait_ref.is_some() { 4 } else { 0 };
789         let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
790             // If there is no where clause adapt budget for type formatting to take space and curly
791             // brace into account.
792             match context.config.item_brace_style() {
793                 BraceStyle::AlwaysNextLine => 0,
794                 _ => 2,
795             }
796         } else {
797             0
798         };
799         let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
800         // 1 = space before the type.
801         let budget = context.budget(used_space + 1);
802         if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
803             if !self_ty_str.contains('\n') {
804                 if trait_ref.is_some() {
805                     result.push_str(" for ");
806                 } else {
807                     result.push(' ');
808                 }
809                 result.push_str(&self_ty_str);
810                 return Some(result);
811             }
812         }
813
814         // Couldn't fit the self type on a single line, put it on a new line.
815         result.push('\n');
816         // Add indentation of one additional tab.
817         let new_line_offset = offset.block_indent(context.config);
818         result.push_str(&new_line_offset.to_string(context.config));
819         if trait_ref.is_some() {
820             result.push_str("for ");
821         }
822         let budget = context.budget(last_line_width(&result));
823         let type_offset = match context.config.where_style() {
824             Style::Legacy => new_line_offset + trait_ref_overhead,
825             Style::Rfc => new_line_offset,
826         };
827         result.push_str(&*try_opt!(
828             self_ty.rewrite(context, Shape::legacy(budget, type_offset))
829         ));
830         Some(result)
831     } else {
832         unreachable!();
833     }
834 }
835
836 fn rewrite_trait_ref(
837     context: &RewriteContext,
838     trait_ref: &ast::TraitRef,
839     offset: Indent,
840     generics_str: &str,
841     retry: bool,
842     polarity_str: &str,
843     result_len: usize,
844 ) -> Option<String> {
845     // 1 = space between generics and trait_ref
846     let used_space = 1 + polarity_str.len() + last_line_used_width(generics_str, result_len);
847     let shape = Shape::indented(offset + used_space, context.config);
848     if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
849         if !(retry && trait_ref_str.contains('\n')) {
850             return Some(format!(
851                 "{} {}{}",
852                 generics_str,
853                 polarity_str,
854                 &trait_ref_str
855             ));
856         }
857     }
858     // We could not make enough space for trait_ref, so put it on new line.
859     if !retry {
860         let offset = offset.block_indent(context.config);
861         let shape = Shape::indented(offset, context.config);
862         let trait_ref_str = try_opt!(trait_ref.rewrite(context, shape));
863         Some(format!(
864             "{}\n{}{}{}",
865             generics_str,
866             &offset.to_string(context.config),
867             polarity_str,
868             &trait_ref_str
869         ))
870     } else {
871         None
872     }
873 }
874
875 pub fn format_struct(
876     context: &RewriteContext,
877     item_name: &str,
878     ident: ast::Ident,
879     vis: &ast::Visibility,
880     struct_def: &ast::VariantData,
881     generics: Option<&ast::Generics>,
882     span: Span,
883     offset: Indent,
884     one_line_width: Option<usize>,
885 ) -> Option<String> {
886     match *struct_def {
887         ast::VariantData::Unit(..) => Some(format_unit_struct(item_name, ident, vis)),
888         ast::VariantData::Tuple(ref fields, _) => format_tuple_struct(
889             context,
890             item_name,
891             ident,
892             vis,
893             fields,
894             generics,
895             span,
896             offset,
897         ),
898         ast::VariantData::Struct(ref fields, _) => format_struct_struct(
899             context,
900             item_name,
901             ident,
902             vis,
903             fields,
904             generics,
905             span,
906             offset,
907             one_line_width,
908         ),
909     }
910 }
911
912 pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
913     if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
914         item.node
915     {
916         let mut result = String::with_capacity(128);
917         let header = format!(
918             "{}{}trait {}",
919             format_visibility(&item.vis),
920             format_unsafety(unsafety),
921             item.ident
922         );
923
924         result.push_str(&header);
925
926         let body_lo = context.codemap.span_after(item.span, "{");
927
928         let shape = Shape::indented(offset + last_line_width(&result), context.config);
929         let generics_str = try_opt!(rewrite_generics(
930             context,
931             generics,
932             shape,
933             mk_sp(item.span.lo(), body_lo),
934         ));
935         result.push_str(&generics_str);
936
937         let trait_bound_str = try_opt!(rewrite_trait_bounds(
938             context,
939             type_param_bounds,
940             Shape::indented(offset, context.config),
941         ));
942         // If the trait, generics, and trait bound cannot fit on the same line,
943         // put the trait bounds on an indented new line
944         if offset.width() + last_line_width(&result) + trait_bound_str.len()
945             > context.config.comment_width()
946         {
947             result.push('\n');
948             let trait_indent = offset.block_only().block_indent(context.config);
949             result.push_str(&trait_indent.to_string(context.config));
950         }
951         result.push_str(&trait_bound_str);
952
953         let has_body = !trait_items.is_empty();
954
955         let where_density = if (context.config.where_density() == Density::Compressed
956             && (!result.contains('\n') || context.config.fn_args_layout() == IndentStyle::Block))
957             || (context.config.fn_args_layout() == IndentStyle::Block && result.is_empty())
958             || (context.config.where_density() == Density::CompressedIfEmpty && !has_body
959                 && !result.contains('\n'))
960         {
961             Density::Compressed
962         } else {
963             Density::Tall
964         };
965
966         let where_budget = context.budget(last_line_width(&result));
967         let pos_before_where = if type_param_bounds.is_empty() {
968             generics.where_clause.span.lo()
969         } else {
970             type_param_bounds[type_param_bounds.len() - 1].span().hi()
971         };
972         let option = WhereClauseOption::snuggled(&generics_str);
973         let where_clause_str = try_opt!(rewrite_where_clause(
974             context,
975             &generics.where_clause,
976             context.config.item_brace_style(),
977             Shape::legacy(where_budget, offset.block_only()),
978             where_density,
979             "{",
980             None,
981             pos_before_where,
982             option,
983         ));
984         // If the where clause cannot fit on the same line,
985         // put the where clause on a new line
986         if !where_clause_str.contains('\n')
987             && last_line_width(&result) + where_clause_str.len() + offset.width()
988                 > context.config.comment_width()
989         {
990             result.push('\n');
991             let width = offset.block_indent + context.config.tab_spaces() - 1;
992             let where_indent = Indent::new(0, width);
993             result.push_str(&where_indent.to_string(context.config));
994         }
995         result.push_str(&where_clause_str);
996
997         if generics.where_clause.predicates.is_empty() {
998             let item_snippet = context.snippet(item.span);
999             if let Some(lo) = item_snippet.chars().position(|c| c == '/') {
1000                 // 1 = `{`
1001                 let comment_hi = body_lo - BytePos(1);
1002                 let comment_lo = item.span.lo() + BytePos(lo as u32);
1003                 if comment_lo < comment_hi {
1004                     match recover_missing_comment_in_span(
1005                         mk_sp(comment_lo, comment_hi),
1006                         Shape::indented(offset, context.config),
1007                         context,
1008                         last_line_width(&result),
1009                     ) {
1010                         Some(ref missing_comment) if !missing_comment.is_empty() => {
1011                             result.push_str(missing_comment);
1012                         }
1013                         _ => (),
1014                     }
1015                 }
1016             }
1017         }
1018
1019         match context.config.item_brace_style() {
1020             _ if last_line_contains_single_line_comment(&result) => {
1021                 result.push('\n');
1022                 result.push_str(&offset.to_string(context.config));
1023             }
1024             BraceStyle::AlwaysNextLine => {
1025                 result.push('\n');
1026                 result.push_str(&offset.to_string(context.config));
1027             }
1028             BraceStyle::PreferSameLine => result.push(' '),
1029             BraceStyle::SameLineWhere => if !where_clause_str.is_empty()
1030                 && (!trait_items.is_empty() || result.contains('\n'))
1031             {
1032                 result.push('\n');
1033                 result.push_str(&offset.to_string(context.config));
1034             } else {
1035                 result.push(' ');
1036             },
1037         }
1038         result.push('{');
1039
1040         let snippet = context.snippet(item.span);
1041         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
1042
1043         if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
1044             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
1045             visitor.block_indent = offset.block_only().block_indent(context.config);
1046             visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
1047
1048             for item in trait_items {
1049                 visitor.visit_trait_item(item);
1050             }
1051
1052             visitor.format_missing(item.span.hi() - BytePos(1));
1053
1054             let inner_indent_str = visitor.block_indent.to_string(context.config);
1055             let outer_indent_str = offset.block_only().to_string(context.config);
1056
1057             result.push('\n');
1058             result.push_str(&inner_indent_str);
1059             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
1060             result.push('\n');
1061             result.push_str(&outer_indent_str);
1062         } else if result.contains('\n') {
1063             result.push('\n');
1064         }
1065
1066         result.push('}');
1067         Some(result)
1068     } else {
1069         unreachable!();
1070     }
1071 }
1072
1073 fn format_unit_struct(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
1074     format!("{};", format_header(item_name, ident, vis))
1075 }
1076
1077 pub fn format_struct_struct(
1078     context: &RewriteContext,
1079     item_name: &str,
1080     ident: ast::Ident,
1081     vis: &ast::Visibility,
1082     fields: &[ast::StructField],
1083     generics: Option<&ast::Generics>,
1084     span: Span,
1085     offset: Indent,
1086     one_line_width: Option<usize>,
1087 ) -> Option<String> {
1088     let mut result = String::with_capacity(1024);
1089
1090     let header_str = format_header(item_name, ident, vis);
1091     result.push_str(&header_str);
1092
1093     let body_lo = context.codemap.span_after(span, "{");
1094
1095     let generics_str = match generics {
1096         Some(g) => try_opt!(format_generics(
1097             context,
1098             g,
1099             "{",
1100             "{",
1101             context.config.item_brace_style(),
1102             fields.is_empty(),
1103             offset,
1104             mk_sp(span.lo(), body_lo),
1105             last_line_width(&result),
1106         )),
1107         None => {
1108             // 3 = ` {}`, 2 = ` {`.
1109             let overhead = if fields.is_empty() { 3 } else { 2 };
1110             if (context.config.item_brace_style() == BraceStyle::AlwaysNextLine
1111                 && !fields.is_empty())
1112                 || context.config.max_width() < overhead + result.len()
1113             {
1114                 format!("\n{}{{", offset.block_only().to_string(context.config))
1115             } else {
1116                 " {".to_owned()
1117             }
1118         }
1119     };
1120     // 1 = `}`
1121     let overhead = if fields.is_empty() { 1 } else { 0 };
1122     let total_width = result.len() + generics_str.len() + overhead;
1123     if !generics_str.is_empty() && !generics_str.contains('\n')
1124         && total_width > context.config.max_width()
1125     {
1126         result.push('\n');
1127         result.push_str(&offset.to_string(context.config));
1128         result.push_str(generics_str.trim_left());
1129     } else {
1130         result.push_str(&generics_str);
1131     }
1132
1133     if fields.is_empty() {
1134         let snippet = context.snippet(mk_sp(body_lo, span.hi() - BytePos(1)));
1135         if snippet.trim().is_empty() {
1136             // `struct S {}`
1137         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1138             // fix indent
1139             result.push_str(snippet.trim_right());
1140             result.push('\n');
1141             result.push_str(&offset.to_string(context.config));
1142         } else {
1143             result.push_str(&snippet);
1144         }
1145         result.push('}');
1146         return Some(result);
1147     }
1148
1149     // 3 = ` ` and ` }`
1150     let one_line_budget = context.budget(result.len() + 3 + offset.width());
1151     let one_line_budget =
1152         one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1153
1154     let items_str = try_opt!(rewrite_with_alignment(
1155         fields,
1156         context,
1157         Shape::indented(offset, context.config),
1158         mk_sp(body_lo, span.hi()),
1159         one_line_budget,
1160     ));
1161
1162     if !items_str.contains('\n') && !result.contains('\n') && items_str.len() <= one_line_budget {
1163         Some(format!("{} {} }}", result, items_str))
1164     } else {
1165         Some(format!(
1166             "{}\n{}{}\n{}}}",
1167             result,
1168             offset
1169                 .block_indent(context.config)
1170                 .to_string(context.config),
1171             items_str,
1172             offset.to_string(context.config)
1173         ))
1174     }
1175 }
1176
1177 fn format_tuple_struct(
1178     context: &RewriteContext,
1179     item_name: &str,
1180     ident: ast::Ident,
1181     vis: &ast::Visibility,
1182     fields: &[ast::StructField],
1183     generics: Option<&ast::Generics>,
1184     span: Span,
1185     offset: Indent,
1186 ) -> Option<String> {
1187     let mut result = String::with_capacity(1024);
1188
1189     let header_str = format_header(item_name, ident, vis);
1190     result.push_str(&header_str);
1191
1192     let body_lo = if fields.is_empty() {
1193         context.codemap.span_after(span, "(")
1194     } else {
1195         fields[0].span.lo()
1196     };
1197     let body_hi = if fields.is_empty() {
1198         context.codemap.span_after(span, ")")
1199     } else {
1200         // This is a dirty hack to work around a missing `)` from the span of the last field.
1201         let last_arg_span = fields[fields.len() - 1].span;
1202         if context.snippet(last_arg_span).ends_with(')') {
1203             last_arg_span.hi()
1204         } else {
1205             context
1206                 .codemap
1207                 .span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
1208         }
1209     };
1210
1211     let where_clause_str = match generics {
1212         Some(generics) => {
1213             let budget = context.budget(last_line_width(&header_str));
1214             let shape = Shape::legacy(budget, offset);
1215             let g_span = mk_sp(span.lo(), body_lo);
1216             let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1217             result.push_str(&generics_str);
1218
1219             let where_budget = context.budget(last_line_width(&result));
1220             let option = WhereClauseOption::new(true, false);
1221             try_opt!(rewrite_where_clause(
1222                 context,
1223                 &generics.where_clause,
1224                 context.config.item_brace_style(),
1225                 Shape::legacy(where_budget, offset.block_only()),
1226                 Density::Compressed,
1227                 ";",
1228                 None,
1229                 body_hi,
1230                 option,
1231             ))
1232         }
1233         None => "".to_owned(),
1234     };
1235
1236     if fields.is_empty() {
1237         // 3 = `();`
1238         let used_width = last_line_used_width(&result, offset.width()) + 3;
1239         if used_width > context.config.max_width() {
1240             result.push('\n');
1241             result.push_str(&offset
1242                 .block_indent(context.config)
1243                 .to_string(context.config))
1244         }
1245         result.push('(');
1246         let snippet = context.snippet(mk_sp(body_lo, context.codemap.span_before(span, ")")));
1247         if snippet.is_empty() {
1248             // `struct S ()`
1249         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1250             result.push_str(snippet.trim_right());
1251             result.push('\n');
1252             result.push_str(&offset.to_string(context.config));
1253         } else {
1254             result.push_str(&snippet);
1255         }
1256         result.push(')');
1257     } else {
1258         // 3 = `();`
1259         let body = try_opt!(
1260             rewrite_call_inner(
1261                 context,
1262                 "",
1263                 &fields.iter().map(|field| field).collect::<Vec<_>>()[..],
1264                 span,
1265                 Shape::legacy(context.budget(last_line_width(&result) + 3), offset),
1266                 context.config.fn_call_width(),
1267                 false,
1268             ).ok()
1269         );
1270         result.push_str(&body);
1271     }
1272
1273     if !where_clause_str.is_empty() && !where_clause_str.contains('\n')
1274         && (result.contains('\n')
1275             || offset.block_indent + result.len() + where_clause_str.len() + 1
1276                 > context.config.max_width())
1277     {
1278         // We need to put the where clause on a new line, but we didn't
1279         // know that earlier, so the where clause will not be indented properly.
1280         result.push('\n');
1281         result.push_str(&(offset.block_only() + (context.config.tab_spaces() - 1))
1282             .to_string(context.config));
1283     }
1284     result.push_str(&where_clause_str);
1285
1286     Some(result)
1287 }
1288
1289 pub fn rewrite_type_alias(
1290     context: &RewriteContext,
1291     indent: Indent,
1292     ident: ast::Ident,
1293     ty: &ast::Ty,
1294     generics: &ast::Generics,
1295     vis: &ast::Visibility,
1296     span: Span,
1297 ) -> Option<String> {
1298     let mut result = String::with_capacity(128);
1299
1300     result.push_str(&format_visibility(vis));
1301     result.push_str("type ");
1302     result.push_str(&ident.to_string());
1303
1304     // 2 = `= `
1305     let shape = try_opt!(Shape::indented(indent + result.len(), context.config).sub_width(2));
1306     let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo());
1307     let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1308     result.push_str(&generics_str);
1309
1310     let where_budget = context.budget(last_line_width(&result));
1311     let option = WhereClauseOption::snuggled(&result);
1312     let where_clause_str = try_opt!(rewrite_where_clause(
1313         context,
1314         &generics.where_clause,
1315         context.config.item_brace_style(),
1316         Shape::legacy(where_budget, indent),
1317         context.config.where_density(),
1318         "=",
1319         Some(span.hi()),
1320         generics.span.hi(),
1321         option,
1322     ));
1323     result.push_str(&where_clause_str);
1324     if where_clause_str.is_empty() {
1325         result.push_str(" = ");
1326     } else {
1327         result.push_str(&format!("\n{}= ", indent.to_string(context.config)));
1328     }
1329
1330     let line_width = last_line_width(&result);
1331     // This checked_sub may fail as the extra space after '=' is not taken into account
1332     // In that case the budget is set to 0 which will make ty.rewrite retry on a new line
1333     let budget = context.budget(indent.width() + line_width + ";".len());
1334     let type_indent = indent + line_width;
1335     // Try to fit the type on the same line
1336     let ty_str = try_opt!(
1337         ty.rewrite(context, Shape::legacy(budget, type_indent))
1338             .or_else(|| {
1339                 // The line was too short, try to put the type on the next line
1340
1341                 // Remove the space after '='
1342                 result.pop();
1343                 let type_indent = indent.block_indent(context.config);
1344                 result.push('\n');
1345                 result.push_str(&type_indent.to_string(context.config));
1346                 let budget = context.budget(type_indent.width() + ";".len());
1347                 ty.rewrite(context, Shape::legacy(budget, type_indent))
1348             })
1349     );
1350     result.push_str(&ty_str);
1351     result.push_str(";");
1352     Some(result)
1353 }
1354
1355 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1356     (
1357         if config.space_before_type_annotation() {
1358             " "
1359         } else {
1360             ""
1361         },
1362         if config.space_after_type_annotation_colon() {
1363             " "
1364         } else {
1365             ""
1366         },
1367     )
1368 }
1369
1370 pub fn rewrite_struct_field_prefix(
1371     context: &RewriteContext,
1372     field: &ast::StructField,
1373 ) -> Option<String> {
1374     let vis = format_visibility(&field.vis);
1375     let type_annotation_spacing = type_annotation_spacing(context.config);
1376     Some(match field.ident {
1377         Some(name) => format!("{}{}{}:", vis, name, type_annotation_spacing.0),
1378         None => format!("{}", vis),
1379     })
1380 }
1381
1382 fn rewrite_struct_field_type(
1383     context: &RewriteContext,
1384     last_line_width: usize,
1385     field: &ast::StructField,
1386     spacing: &str,
1387     shape: Shape,
1388 ) -> Option<String> {
1389     let ty_shape = try_opt!(shape.offset_left(last_line_width + spacing.len()));
1390     field
1391         .ty
1392         .rewrite(context, ty_shape)
1393         .map(|ty| format!("{}{}", spacing, ty))
1394 }
1395
1396 impl Rewrite for ast::StructField {
1397     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1398         rewrite_struct_field(context, self, shape, 0)
1399     }
1400 }
1401
1402 pub fn rewrite_struct_field(
1403     context: &RewriteContext,
1404     field: &ast::StructField,
1405     shape: Shape,
1406     lhs_max_width: usize,
1407 ) -> Option<String> {
1408     if contains_skip(&field.attrs) {
1409         return Some(context.snippet(mk_sp(field.attrs[0].span.lo(), field.span.hi())));
1410     }
1411
1412     let type_annotation_spacing = type_annotation_spacing(context.config);
1413     let prefix = try_opt!(rewrite_struct_field_prefix(context, field));
1414
1415     let attrs_str = try_opt!(field.attrs.rewrite(context, shape));
1416     let attrs_extendable = attrs_str.is_empty()
1417         || (context.config.attributes_on_same_line_as_field()
1418             && is_attributes_extendable(&attrs_str));
1419     let missing_span = if field.attrs.is_empty() {
1420         mk_sp(field.span.lo(), field.span.lo())
1421     } else {
1422         mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
1423     };
1424     let mut spacing = String::from(if field.ident.is_some() {
1425         type_annotation_spacing.1
1426     } else {
1427         ""
1428     });
1429     // Try to put everything on a single line.
1430     let attr_prefix = try_opt!(combine_strs_with_missing_comments(
1431         context,
1432         &attrs_str,
1433         &prefix,
1434         missing_span,
1435         shape,
1436         attrs_extendable,
1437     ));
1438     let overhead = last_line_width(&attr_prefix);
1439     let lhs_offset = lhs_max_width.checked_sub(overhead).unwrap_or(0);
1440     for _ in 0..lhs_offset {
1441         spacing.push(' ');
1442     }
1443     // In this extreme case we will be missing a space betweeen an attribute and a field.
1444     if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1445         spacing.push(' ');
1446     }
1447     let ty_rewritten = rewrite_struct_field_type(context, overhead, field, &spacing, shape);
1448     if let Some(ref ty) = ty_rewritten {
1449         if !ty.contains('\n') {
1450             return Some(attr_prefix + ty);
1451         }
1452     }
1453
1454     // We must use multiline.
1455     let last_line_width = last_line_width(&prefix);
1456     let ty_rewritten = rewrite_struct_field_type(context, last_line_width, field, &spacing, shape);
1457
1458     let type_offset = shape.indent.block_indent(context.config);
1459     let rewrite_type_in_next_line = || {
1460         field
1461             .ty
1462             .rewrite(context, Shape::indented(type_offset, context.config))
1463     };
1464
1465     let field_str = match ty_rewritten {
1466         // If we start from the next line and type fits in a single line, then do so.
1467         Some(ref ty) => match rewrite_type_in_next_line() {
1468             Some(ref new_ty) if !new_ty.contains('\n') => format!(
1469                 "{}\n{}{}",
1470                 prefix,
1471                 type_offset.to_string(context.config),
1472                 &new_ty
1473             ),
1474             _ => prefix + ty,
1475         },
1476         _ => {
1477             let ty = try_opt!(rewrite_type_in_next_line());
1478             format!(
1479                 "{}\n{}{}",
1480                 prefix,
1481                 type_offset.to_string(context.config),
1482                 &ty
1483             )
1484         }
1485     };
1486     combine_strs_with_missing_comments(
1487         context,
1488         &attrs_str,
1489         &field_str,
1490         missing_span,
1491         shape,
1492         attrs_extendable,
1493     )
1494 }
1495
1496 pub fn rewrite_static(
1497     prefix: &str,
1498     vis: &ast::Visibility,
1499     ident: ast::Ident,
1500     ty: &ast::Ty,
1501     mutability: ast::Mutability,
1502     expr_opt: Option<&ptr::P<ast::Expr>>,
1503     offset: Indent,
1504     span: Span,
1505     context: &RewriteContext,
1506 ) -> Option<String> {
1507     let colon = colon_spaces(
1508         context.config.space_before_type_annotation(),
1509         context.config.space_after_type_annotation_colon(),
1510     );
1511     let prefix = format!(
1512         "{}{} {}{}{}",
1513         format_visibility(vis),
1514         prefix,
1515         format_mutability(mutability),
1516         ident,
1517         colon,
1518     );
1519     // 2 = " =".len()
1520     let ty_str = try_opt!(ty.rewrite(
1521         context,
1522         try_opt!(
1523             Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)
1524         ),
1525     ));
1526
1527     if let Some(expr) = expr_opt {
1528         let lhs = format!("{}{} =", prefix, ty_str);
1529         // 1 = ;
1530         let remaining_width = context.budget(offset.block_indent + 1);
1531         rewrite_assign_rhs(
1532             context,
1533             lhs,
1534             expr,
1535             Shape::legacy(remaining_width, offset.block_only()),
1536         ).and_then(|res| recover_comment_removed(res, span, context))
1537             .map(|s| if s.ends_with(';') { s } else { s + ";" })
1538     } else {
1539         Some(format!("{}{};", prefix, ty_str))
1540     }
1541 }
1542
1543 pub fn rewrite_associated_type(
1544     ident: ast::Ident,
1545     ty_opt: Option<&ptr::P<ast::Ty>>,
1546     ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1547     context: &RewriteContext,
1548     indent: Indent,
1549 ) -> Option<String> {
1550     let prefix = format!("type {}", ident);
1551
1552     let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
1553         // 2 = ": ".len()
1554         let shape = try_opt!(Shape::indented(indent, context.config).offset_left(prefix.len() + 2));
1555         let bounds: &[_] = ty_param_bounds;
1556         let bound_str = try_opt!(
1557             bounds
1558                 .iter()
1559                 .map(|ty_bound| ty_bound.rewrite(context, shape))
1560                 .collect::<Option<Vec<_>>>()
1561         );
1562         if !bounds.is_empty() {
1563             format!(": {}", join_bounds(context, shape, &bound_str))
1564         } else {
1565             String::new()
1566         }
1567     } else {
1568         String::new()
1569     };
1570
1571     if let Some(ty) = ty_opt {
1572         let ty_str = try_opt!(ty.rewrite(
1573             context,
1574             Shape::legacy(
1575                 context.budget(indent.block_indent + prefix.len() + 2),
1576                 indent.block_only(),
1577             ),
1578         ));
1579         Some(format!("{}{} = {};", prefix, type_bounds_str, ty_str))
1580     } else {
1581         Some(format!("{}{};", prefix, type_bounds_str))
1582     }
1583 }
1584
1585 pub fn rewrite_associated_impl_type(
1586     ident: ast::Ident,
1587     defaultness: ast::Defaultness,
1588     ty_opt: Option<&ptr::P<ast::Ty>>,
1589     ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1590     context: &RewriteContext,
1591     indent: Indent,
1592 ) -> Option<String> {
1593     let result = try_opt!(rewrite_associated_type(
1594         ident,
1595         ty_opt,
1596         ty_param_bounds_opt,
1597         context,
1598         indent,
1599     ));
1600
1601     match defaultness {
1602         ast::Defaultness::Default => Some(format!("default {}", result)),
1603         _ => Some(result),
1604     }
1605 }
1606
1607 impl Rewrite for ast::FunctionRetTy {
1608     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1609         match *self {
1610             ast::FunctionRetTy::Default(_) => Some(String::new()),
1611             ast::FunctionRetTy::Ty(ref ty) => {
1612                 let inner_width = try_opt!(shape.width.checked_sub(3));
1613                 ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1614                     .map(|r| format!("-> {}", r))
1615             }
1616         }
1617     }
1618 }
1619
1620 fn is_empty_infer(context: &RewriteContext, ty: &ast::Ty) -> bool {
1621     match ty.node {
1622         ast::TyKind::Infer => {
1623             let original = context.snippet(ty.span);
1624             original != "_"
1625         }
1626         _ => false,
1627     }
1628 }
1629
1630 impl Rewrite for ast::Arg {
1631     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1632         if is_named_arg(self) {
1633             let mut result = try_opt!(
1634                 self.pat
1635                     .rewrite(context, Shape::legacy(shape.width, shape.indent))
1636             );
1637
1638             if !is_empty_infer(context, &*self.ty) {
1639                 if context.config.space_before_type_annotation() {
1640                     result.push_str(" ");
1641                 }
1642                 result.push_str(":");
1643                 if context.config.space_after_type_annotation_colon() {
1644                     result.push_str(" ");
1645                 }
1646                 let max_width = try_opt!(shape.width.checked_sub(result.len()));
1647                 let ty_str = try_opt!(self.ty.rewrite(
1648                     context,
1649                     Shape::legacy(max_width, shape.indent + result.len()),
1650                 ));
1651                 result.push_str(&ty_str);
1652             }
1653
1654             Some(result)
1655         } else {
1656             self.ty.rewrite(context, shape)
1657         }
1658     }
1659 }
1660
1661 fn rewrite_explicit_self(
1662     explicit_self: &ast::ExplicitSelf,
1663     args: &[ast::Arg],
1664     context: &RewriteContext,
1665 ) -> Option<String> {
1666     match explicit_self.node {
1667         ast::SelfKind::Region(lt, m) => {
1668             let mut_str = format_mutability(m);
1669             match lt {
1670                 Some(ref l) => {
1671                     let lifetime_str = try_opt!(l.rewrite(
1672                         context,
1673                         Shape::legacy(context.config.max_width(), Indent::empty()),
1674                     ));
1675                     Some(format!("&{} {}self", lifetime_str, mut_str))
1676                 }
1677                 None => Some(format!("&{}self", mut_str)),
1678             }
1679         }
1680         ast::SelfKind::Explicit(ref ty, _) => {
1681             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1682
1683             let mutability = explicit_self_mutability(&args[0]);
1684             let type_str = try_opt!(ty.rewrite(
1685                 context,
1686                 Shape::legacy(context.config.max_width(), Indent::empty()),
1687             ));
1688
1689             Some(format!(
1690                 "{}self: {}",
1691                 format_mutability(mutability),
1692                 type_str
1693             ))
1694         }
1695         ast::SelfKind::Value(_) => {
1696             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1697
1698             let mutability = explicit_self_mutability(&args[0]);
1699
1700             Some(format!("{}self", format_mutability(mutability)))
1701         }
1702     }
1703 }
1704
1705 // Hacky solution caused by absence of `Mutability` in `SelfValue` and
1706 // `SelfExplicit` variants of `ast::ExplicitSelf_`.
1707 fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
1708     if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node {
1709         mutability
1710     } else {
1711         unreachable!()
1712     }
1713 }
1714
1715 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
1716     if is_named_arg(arg) {
1717         arg.pat.span.lo()
1718     } else {
1719         arg.ty.span.lo()
1720     }
1721 }
1722
1723 pub fn span_hi_for_arg(context: &RewriteContext, arg: &ast::Arg) -> BytePos {
1724     match arg.ty.node {
1725         ast::TyKind::Infer if context.snippet(arg.ty.span) == "_" => arg.ty.span.hi(),
1726         ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi(),
1727         _ => arg.ty.span.hi(),
1728     }
1729 }
1730
1731 pub fn is_named_arg(arg: &ast::Arg) -> bool {
1732     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1733         ident.node != symbol::keywords::Invalid.ident()
1734     } else {
1735         true
1736     }
1737 }
1738
1739 // Return type is (result, force_new_line_for_brace)
1740 fn rewrite_fn_base(
1741     context: &RewriteContext,
1742     indent: Indent,
1743     ident: ast::Ident,
1744     fn_sig: &FnSig,
1745     span: Span,
1746     newline_brace: bool,
1747     has_body: bool,
1748 ) -> Option<(String, bool)> {
1749     let mut force_new_line_for_brace = false;
1750
1751     let where_clause = &fn_sig.generics.where_clause;
1752
1753     let mut result = String::with_capacity(1024);
1754     // Vis defaultness constness unsafety abi.
1755     result.push_str(&*format_visibility(&fn_sig.visibility));
1756     result.push_str(format_defaultness(fn_sig.defaultness));
1757     result.push_str(format_constness(fn_sig.constness));
1758     result.push_str(format_unsafety(fn_sig.unsafety));
1759     if fn_sig.abi != abi::Abi::Rust {
1760         result.push_str(&format_abi(fn_sig.abi, context.config.force_explicit_abi()));
1761     }
1762
1763     // fn foo
1764     result.push_str("fn ");
1765     result.push_str(&ident.to_string());
1766
1767     // Generics.
1768     let overhead = if has_body && !newline_brace {
1769         // 4 = `() {`
1770         4
1771     } else {
1772         // 2 = `()`
1773         2
1774     };
1775     let used_width = last_line_used_width(&result, indent.width());
1776     let one_line_budget = context.budget(used_width + overhead);
1777     let shape = Shape {
1778         width: one_line_budget,
1779         indent: indent,
1780         offset: used_width,
1781     };
1782     let fd = fn_sig.decl;
1783     let g_span = mk_sp(span.lo(), fd.output.span().lo());
1784     let generics_str = try_opt!(rewrite_generics(context, fn_sig.generics, shape, g_span));
1785     result.push_str(&generics_str);
1786
1787     let snuggle_angle_bracket = generics_str
1788         .lines()
1789         .last()
1790         .map_or(false, |l| l.trim_left().len() == 1);
1791
1792     // Note that the width and indent don't really matter, we'll re-layout the
1793     // return type later anyway.
1794     let ret_str = try_opt!(
1795         fd.output
1796             .rewrite(context, Shape::indented(indent, context.config))
1797     );
1798
1799     let multi_line_ret_str = ret_str.contains('\n');
1800     let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
1801
1802     // Args.
1803     let (one_line_budget, multi_line_budget, mut arg_indent) = try_opt!(compute_budgets_for_args(
1804         context,
1805         &result,
1806         indent,
1807         ret_str_len,
1808         newline_brace,
1809         has_body,
1810         multi_line_ret_str,
1811     ));
1812
1813     debug!(
1814         "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
1815         one_line_budget,
1816         multi_line_budget,
1817         arg_indent
1818     );
1819
1820     // Check if vertical layout was forced.
1821     if one_line_budget == 0 {
1822         if snuggle_angle_bracket {
1823             result.push('(');
1824         } else if context.config.fn_args_paren_newline() {
1825             result.push('\n');
1826             result.push_str(&arg_indent.to_string(context.config));
1827             if context.config.fn_args_layout() == IndentStyle::Visual {
1828                 arg_indent = arg_indent + 1; // extra space for `(`
1829             }
1830             result.push('(');
1831         } else {
1832             result.push_str("(");
1833             if context.config.fn_args_layout() == IndentStyle::Visual {
1834                 result.push('\n');
1835                 result.push_str(&arg_indent.to_string(context.config));
1836             }
1837         }
1838     } else {
1839         result.push('(');
1840     }
1841     if context.config.spaces_within_parens() && !fd.inputs.is_empty() && result.ends_with('(') {
1842         result.push(' ')
1843     }
1844
1845     // A conservative estimation, to goal is to be over all parens in generics
1846     let args_start = fn_sig
1847         .generics
1848         .ty_params
1849         .last()
1850         .map_or(span.lo(), |tp| end_typaram(tp));
1851     let args_end = if fd.inputs.is_empty() {
1852         context
1853             .codemap
1854             .span_after(mk_sp(args_start, span.hi()), ")")
1855     } else {
1856         let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
1857         context.codemap.span_after(last_span, ")")
1858     };
1859     let args_span = mk_sp(
1860         context
1861             .codemap
1862             .span_after(mk_sp(args_start, span.hi()), "("),
1863         args_end,
1864     );
1865     let arg_str = try_opt!(rewrite_args(
1866         context,
1867         &fd.inputs,
1868         fd.get_self().as_ref(),
1869         one_line_budget,
1870         multi_line_budget,
1871         indent,
1872         arg_indent,
1873         args_span,
1874         fd.variadic,
1875         generics_str.contains('\n'),
1876     ));
1877
1878     let put_args_in_block = match context.config.fn_args_layout() {
1879         IndentStyle::Block => arg_str.contains('\n') || arg_str.len() > one_line_budget,
1880         _ => false,
1881     } && !fd.inputs.is_empty();
1882
1883     let mut args_last_line_contains_comment = false;
1884     if put_args_in_block {
1885         arg_indent = indent.block_indent(context.config);
1886         result.push('\n');
1887         result.push_str(&arg_indent.to_string(context.config));
1888         result.push_str(&arg_str);
1889         result.push('\n');
1890         result.push_str(&indent.to_string(context.config));
1891         result.push(')');
1892     } else {
1893         result.push_str(&arg_str);
1894         let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
1895         // Put the closing brace on the next line if it overflows the max width.
1896         // 1 = `)`
1897         if fd.inputs.is_empty() && used_width + 1 > context.config.max_width() {
1898             result.push('\n');
1899         }
1900         if context.config.spaces_within_parens() && !fd.inputs.is_empty() {
1901             result.push(' ')
1902         }
1903         // If the last line of args contains comment, we cannot put the closing paren
1904         // on the same line.
1905         if arg_str
1906             .lines()
1907             .last()
1908             .map_or(false, |last_line| last_line.contains("//"))
1909         {
1910             args_last_line_contains_comment = true;
1911             result.push('\n');
1912             result.push_str(&arg_indent.to_string(context.config));
1913         }
1914         result.push(')');
1915     }
1916
1917     // Return type.
1918     if let ast::FunctionRetTy::Ty(..) = fd.output {
1919         let ret_should_indent = match context.config.fn_args_layout() {
1920             // If our args are block layout then we surely must have space.
1921             IndentStyle::Block if put_args_in_block || fd.inputs.is_empty() => false,
1922             _ if args_last_line_contains_comment => false,
1923             _ if result.contains('\n') || multi_line_ret_str => true,
1924             _ => {
1925                 // If the return type would push over the max width, then put the return type on
1926                 // a new line. With the +1 for the signature length an additional space between
1927                 // the closing parenthesis of the argument and the arrow '->' is considered.
1928                 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
1929
1930                 // If there is no where clause, take into account the space after the return type
1931                 // and the brace.
1932                 if where_clause.predicates.is_empty() {
1933                     sig_length += 2;
1934                 }
1935
1936                 sig_length > context.config.max_width()
1937             }
1938         };
1939         let ret_indent = if ret_should_indent {
1940             let indent = match context.config.fn_return_indent() {
1941                 ReturnIndent::WithWhereClause => indent + 4,
1942                 // Aligning with non-existent args looks silly.
1943                 _ if arg_str.is_empty() => {
1944                     force_new_line_for_brace = true;
1945                     indent + 4
1946                 }
1947                 // FIXME: we might want to check that using the arg indent
1948                 // doesn't blow our budget, and if it does, then fallback to
1949                 // the where clause indent.
1950                 _ => arg_indent,
1951             };
1952
1953             result.push('\n');
1954             result.push_str(&indent.to_string(context.config));
1955             indent
1956         } else {
1957             result.push(' ');
1958             Indent::new(indent.block_indent, last_line_width(&result))
1959         };
1960
1961         if multi_line_ret_str || ret_should_indent {
1962             // Now that we know the proper indent and width, we need to
1963             // re-layout the return type.
1964             let ret_str = try_opt!(
1965                 fd.output
1966                     .rewrite(context, Shape::indented(ret_indent, context.config))
1967             );
1968             result.push_str(&ret_str);
1969         } else {
1970             result.push_str(&ret_str);
1971         }
1972
1973         // Comment between return type and the end of the decl.
1974         let snippet_lo = fd.output.span().hi();
1975         if where_clause.predicates.is_empty() {
1976             let snippet_hi = span.hi();
1977             let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
1978             // Try to preserve the layout of the original snippet.
1979             let original_starts_with_newline = snippet
1980                 .find(|c| c != ' ')
1981                 .map_or(false, |i| snippet[i..].starts_with('\n'));
1982             let original_ends_with_newline = snippet
1983                 .rfind(|c| c != ' ')
1984                 .map_or(false, |i| snippet[i..].ends_with('\n'));
1985             let snippet = snippet.trim();
1986             if !snippet.is_empty() {
1987                 result.push(if original_starts_with_newline {
1988                     '\n'
1989                 } else {
1990                     ' '
1991                 });
1992                 result.push_str(snippet);
1993                 if original_ends_with_newline {
1994                     force_new_line_for_brace = true;
1995                 }
1996             }
1997         }
1998     }
1999
2000     let should_compress_where = match context.config.where_density() {
2001         Density::Compressed => !result.contains('\n'),
2002         Density::CompressedIfEmpty => !has_body && !result.contains('\n'),
2003         _ => false,
2004     };
2005
2006     let pos_before_where = match fd.output {
2007         ast::FunctionRetTy::Default(..) => args_span.hi(),
2008         ast::FunctionRetTy::Ty(ref ty) => ty.span.hi(),
2009     };
2010
2011     if where_clause.predicates.len() == 1 && should_compress_where {
2012         let budget = context.budget(last_line_used_width(&result, indent.width()));
2013         if let Some(where_clause_str) = rewrite_where_clause(
2014             context,
2015             where_clause,
2016             context.config.fn_brace_style(),
2017             Shape::legacy(budget, indent),
2018             Density::Compressed,
2019             "{",
2020             Some(span.hi()),
2021             pos_before_where,
2022             WhereClauseOption::compressed(),
2023         ) {
2024             result.push_str(&where_clause_str);
2025             force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
2026             return Some((result, force_new_line_for_brace));
2027         }
2028     }
2029
2030     let option = WhereClauseOption::new(!has_body, put_args_in_block && ret_str.is_empty());
2031     let where_clause_str = try_opt!(rewrite_where_clause(
2032         context,
2033         where_clause,
2034         context.config.fn_brace_style(),
2035         Shape::indented(indent, context.config),
2036         Density::Tall,
2037         "{",
2038         Some(span.hi()),
2039         pos_before_where,
2040         option,
2041     ));
2042     // If there are neither where clause nor return type, we may be missing comments between
2043     // args and `{`.
2044     if where_clause_str.is_empty() {
2045         if let ast::FunctionRetTy::Default(ret_span) = fd.output {
2046             match recover_missing_comment_in_span(
2047                 mk_sp(args_span.hi(), ret_span.hi()),
2048                 shape,
2049                 context,
2050                 last_line_width(&result),
2051             ) {
2052                 Some(ref missing_comment) if !missing_comment.is_empty() => {
2053                     result.push_str(missing_comment);
2054                     force_new_line_for_brace = true;
2055                 }
2056                 _ => (),
2057             }
2058         }
2059     }
2060
2061     result.push_str(&where_clause_str);
2062
2063     force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
2064     Some((result, force_new_line_for_brace))
2065 }
2066
2067 #[derive(Copy, Clone)]
2068 struct WhereClauseOption {
2069     suppress_comma: bool, // Force no trailing comma
2070     snuggle: bool,        // Do not insert newline before `where`
2071     compress_where: bool, // Try single line where clause instead of vertical layout
2072 }
2073
2074 impl WhereClauseOption {
2075     pub fn new(suppress_comma: bool, snuggle: bool) -> WhereClauseOption {
2076         WhereClauseOption {
2077             suppress_comma: suppress_comma,
2078             snuggle: snuggle,
2079             compress_where: false,
2080         }
2081     }
2082
2083     pub fn compressed() -> WhereClauseOption {
2084         WhereClauseOption {
2085             suppress_comma: true,
2086             snuggle: false,
2087             compress_where: true,
2088         }
2089     }
2090
2091     pub fn snuggled(current: &str) -> WhereClauseOption {
2092         WhereClauseOption {
2093             suppress_comma: false,
2094             snuggle: trimmed_last_line_width(current) == 1,
2095             compress_where: false,
2096         }
2097     }
2098 }
2099
2100 fn rewrite_args(
2101     context: &RewriteContext,
2102     args: &[ast::Arg],
2103     explicit_self: Option<&ast::ExplicitSelf>,
2104     one_line_budget: usize,
2105     multi_line_budget: usize,
2106     indent: Indent,
2107     arg_indent: Indent,
2108     span: Span,
2109     variadic: bool,
2110     generics_str_contains_newline: bool,
2111 ) -> Option<String> {
2112     let mut arg_item_strs = try_opt!(
2113         args.iter()
2114             .map(|arg| {
2115                 arg.rewrite(context, Shape::legacy(multi_line_budget, arg_indent))
2116             })
2117             .collect::<Option<Vec<_>>>()
2118     );
2119
2120     // Account for sugary self.
2121     // FIXME: the comment for the self argument is dropped. This is blocked
2122     // on rust issue #27522.
2123     let min_args = explicit_self
2124         .and_then(|explicit_self| {
2125             rewrite_explicit_self(explicit_self, args, context)
2126         })
2127         .map_or(1, |self_str| {
2128             arg_item_strs[0] = self_str;
2129             2
2130         });
2131
2132     // Comments between args.
2133     let mut arg_items = Vec::new();
2134     if min_args == 2 {
2135         arg_items.push(ListItem::from_str(""));
2136     }
2137
2138     // FIXME(#21): if there are no args, there might still be a comment, but
2139     // without spans for the comment or parens, there is no chance of
2140     // getting it right. You also don't get to put a comment on self, unless
2141     // it is explicit.
2142     if args.len() >= min_args || variadic {
2143         let comment_span_start = if min_args == 2 {
2144             let second_arg_start = if arg_has_pattern(&args[1]) {
2145                 args[1].pat.span.lo()
2146             } else {
2147                 args[1].ty.span.lo()
2148             };
2149             let reduced_span = mk_sp(span.lo(), second_arg_start);
2150
2151             context.codemap.span_after_last(reduced_span, ",")
2152         } else {
2153             span.lo()
2154         };
2155
2156         enum ArgumentKind<'a> {
2157             Regular(&'a ast::Arg),
2158             Variadic(BytePos),
2159         }
2160
2161         let variadic_arg = if variadic {
2162             let variadic_span = mk_sp(args.last().unwrap().ty.span.hi(), span.hi());
2163             let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
2164             Some(ArgumentKind::Variadic(variadic_start))
2165         } else {
2166             None
2167         };
2168
2169         let more_items = itemize_list(
2170             context.codemap,
2171             args[min_args - 1..]
2172                 .iter()
2173                 .map(ArgumentKind::Regular)
2174                 .chain(variadic_arg),
2175             ")",
2176             |arg| match *arg {
2177                 ArgumentKind::Regular(arg) => span_lo_for_arg(arg),
2178                 ArgumentKind::Variadic(start) => start,
2179             },
2180             |arg| match *arg {
2181                 ArgumentKind::Regular(arg) => arg.ty.span.hi(),
2182                 ArgumentKind::Variadic(start) => start + BytePos(3),
2183             },
2184             |arg| match *arg {
2185                 ArgumentKind::Regular(..) => None,
2186                 ArgumentKind::Variadic(..) => Some("...".to_owned()),
2187             },
2188             comment_span_start,
2189             span.hi(),
2190             false,
2191         );
2192
2193         arg_items.extend(more_items);
2194     }
2195
2196     let fits_in_one_line = !generics_str_contains_newline
2197         && (arg_items.is_empty()
2198             || arg_items.len() == 1 && arg_item_strs[0].len() <= one_line_budget);
2199
2200     for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
2201         item.item = Some(arg);
2202     }
2203
2204     let last_line_ends_with_comment = arg_items
2205         .iter()
2206         .last()
2207         .and_then(|item| item.post_comment.as_ref())
2208         .map_or(false, |s| s.trim().starts_with("//"));
2209
2210     let (indent, trailing_comma) = match context.config.fn_args_layout() {
2211         IndentStyle::Block if fits_in_one_line => {
2212             (indent.block_indent(context.config), SeparatorTactic::Never)
2213         }
2214         IndentStyle::Block => (
2215             indent.block_indent(context.config),
2216             context.config.trailing_comma(),
2217         ),
2218         IndentStyle::Visual if last_line_ends_with_comment => {
2219             (arg_indent, context.config.trailing_comma())
2220         }
2221         IndentStyle::Visual => (arg_indent, SeparatorTactic::Never),
2222     };
2223
2224     let tactic = definitive_tactic(
2225         &arg_items,
2226         context.config.fn_args_density().to_list_tactic(),
2227         Separator::Comma,
2228         one_line_budget,
2229     );
2230     let budget = match tactic {
2231         DefinitiveListTactic::Horizontal => one_line_budget,
2232         _ => multi_line_budget,
2233     };
2234
2235     debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
2236
2237     let fmt = ListFormatting {
2238         tactic: tactic,
2239         separator: ",",
2240         trailing_separator: if variadic {
2241             SeparatorTactic::Never
2242         } else {
2243             trailing_comma
2244         },
2245         separator_place: SeparatorPlace::Back,
2246         shape: Shape::legacy(budget, indent),
2247         ends_with_newline: tactic.ends_with_newline(context.config.fn_args_layout()),
2248         preserve_newline: true,
2249         config: context.config,
2250     };
2251
2252     write_list(&arg_items, &fmt)
2253 }
2254
2255 fn arg_has_pattern(arg: &ast::Arg) -> bool {
2256     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
2257         ident.node != symbol::keywords::Invalid.ident()
2258     } else {
2259         true
2260     }
2261 }
2262
2263 fn compute_budgets_for_args(
2264     context: &RewriteContext,
2265     result: &str,
2266     indent: Indent,
2267     ret_str_len: usize,
2268     newline_brace: bool,
2269     has_braces: bool,
2270     force_vertical_layout: bool,
2271 ) -> Option<((usize, usize, Indent))> {
2272     debug!(
2273         "compute_budgets_for_args {} {:?}, {}, {}",
2274         result.len(),
2275         indent,
2276         ret_str_len,
2277         newline_brace
2278     );
2279     // Try keeping everything on the same line.
2280     if !result.contains('\n') && !force_vertical_layout {
2281         // 2 = `()`, 3 = `() `, space is before ret_string.
2282         let overhead = if ret_str_len == 0 { 2 } else { 3 };
2283         let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2284         if has_braces {
2285             if !newline_brace {
2286                 // 2 = `{}`
2287                 used_space += 2;
2288             }
2289         } else {
2290             // 1 = `;`
2291             used_space += 1;
2292         }
2293         let one_line_budget = context.budget(used_space);
2294
2295         if one_line_budget > 0 {
2296             // 4 = "() {".len()
2297             let (indent, multi_line_budget) = match context.config.fn_args_layout() {
2298                 IndentStyle::Block => {
2299                     let indent = indent.block_indent(context.config);
2300                     (indent, context.budget(indent.width() + 1))
2301                 }
2302                 IndentStyle::Visual => {
2303                     let indent = indent + result.len() + 1;
2304                     let multi_line_overhead = indent.width() + if newline_brace { 2 } else { 4 };
2305                     (indent, context.budget(multi_line_overhead))
2306                 }
2307             };
2308
2309             return Some((one_line_budget, multi_line_budget, indent));
2310         }
2311     }
2312
2313     // Didn't work. we must force vertical layout and put args on a newline.
2314     let new_indent = indent.block_indent(context.config);
2315     let used_space = match context.config.fn_args_layout() {
2316         // 1 = `,`
2317         IndentStyle::Block => new_indent.width() + 1,
2318         // Account for `)` and possibly ` {`.
2319         IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2320     };
2321     Some((0, context.budget(used_space), new_indent))
2322 }
2323
2324 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause, has_body: bool) -> bool {
2325     match (config.fn_brace_style(), config.where_density()) {
2326         (BraceStyle::AlwaysNextLine, _) => true,
2327         (_, Density::Compressed) if where_clause.predicates.len() == 1 => false,
2328         (_, Density::CompressedIfEmpty) if where_clause.predicates.len() == 1 && !has_body => false,
2329         (BraceStyle::SameLineWhere, _) if !where_clause.predicates.is_empty() => true,
2330         _ => false,
2331     }
2332 }
2333
2334 fn rewrite_generics(
2335     context: &RewriteContext,
2336     generics: &ast::Generics,
2337     shape: Shape,
2338     span: Span,
2339 ) -> Option<String> {
2340     let g_shape = try_opt!(generics_shape_from_config(context.config, shape, 0));
2341     let one_line_width = shape.width.checked_sub(2).unwrap_or(0);
2342     rewrite_generics_inner(context, generics, g_shape, one_line_width, span).or_else(|| {
2343         rewrite_generics_inner(context, generics, g_shape, 0, span)
2344     })
2345 }
2346
2347 fn rewrite_generics_inner(
2348     context: &RewriteContext,
2349     generics: &ast::Generics,
2350     shape: Shape,
2351     one_line_width: usize,
2352     span: Span,
2353 ) -> Option<String> {
2354     // FIXME: convert bounds to where clauses where they get too big or if
2355     // there is a where clause at all.
2356
2357     // Wrapper type
2358     enum GenericsArg<'a> {
2359         Lifetime(&'a ast::LifetimeDef),
2360         TyParam(&'a ast::TyParam),
2361     }
2362     impl<'a> Rewrite for GenericsArg<'a> {
2363         fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
2364             match *self {
2365                 GenericsArg::Lifetime(ref lifetime) => lifetime.rewrite(context, shape),
2366                 GenericsArg::TyParam(ref ty) => ty.rewrite(context, shape),
2367             }
2368         }
2369     }
2370     impl<'a> Spanned for GenericsArg<'a> {
2371         fn span(&self) -> Span {
2372             match *self {
2373                 GenericsArg::Lifetime(ref lifetime) => lifetime.span(),
2374                 GenericsArg::TyParam(ref ty) => ty.span(),
2375             }
2376         }
2377     }
2378
2379     if generics.lifetimes.is_empty() && generics.ty_params.is_empty() {
2380         return Some(String::new());
2381     }
2382
2383     let generics_args = generics
2384         .lifetimes
2385         .iter()
2386         .map(|lt| GenericsArg::Lifetime(lt))
2387         .chain(generics.ty_params.iter().map(|ty| GenericsArg::TyParam(ty)));
2388     let items = itemize_list(
2389         context.codemap,
2390         generics_args,
2391         ">",
2392         |arg| arg.span().lo(),
2393         |arg| arg.span().hi(),
2394         |arg| arg.rewrite(context, shape),
2395         context.codemap.span_after(span, "<"),
2396         span.hi(),
2397         false,
2398     );
2399     format_generics_item_list(context, items, shape, one_line_width)
2400 }
2401
2402 pub fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2403     match config.generics_indent() {
2404         IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2405         IndentStyle::Block => {
2406             // 1 = ","
2407             shape
2408                 .block()
2409                 .block_indent(config.tab_spaces())
2410                 .with_max_width(config)
2411                 .sub_width(1)
2412         }
2413     }
2414 }
2415
2416 pub fn format_generics_item_list<I>(
2417     context: &RewriteContext,
2418     items: I,
2419     shape: Shape,
2420     one_line_budget: usize,
2421 ) -> Option<String>
2422 where
2423     I: Iterator<Item = ListItem>,
2424 {
2425     let item_vec = items.collect::<Vec<_>>();
2426
2427     let tactic = definitive_tactic(
2428         &item_vec,
2429         ListTactic::HorizontalVertical,
2430         Separator::Comma,
2431         one_line_budget,
2432     );
2433     let fmt = ListFormatting {
2434         tactic: tactic,
2435         separator: ",",
2436         trailing_separator: if context.config.generics_indent() == IndentStyle::Visual {
2437             SeparatorTactic::Never
2438         } else {
2439             context.config.trailing_comma()
2440         },
2441         separator_place: SeparatorPlace::Back,
2442         shape: shape,
2443         ends_with_newline: tactic.ends_with_newline(context.config.generics_indent()),
2444         preserve_newline: true,
2445         config: context.config,
2446     };
2447
2448     let list_str = try_opt!(write_list(&item_vec, &fmt));
2449
2450     Some(wrap_generics_with_angle_brackets(
2451         context,
2452         &list_str,
2453         shape.indent,
2454     ))
2455 }
2456
2457 pub fn wrap_generics_with_angle_brackets(
2458     context: &RewriteContext,
2459     list_str: &str,
2460     list_offset: Indent,
2461 ) -> String {
2462     if context.config.generics_indent() == IndentStyle::Block
2463         && (list_str.contains('\n') || list_str.ends_with(','))
2464     {
2465         format!(
2466             "<\n{}{}\n{}>",
2467             list_offset.to_string(context.config),
2468             list_str,
2469             list_offset
2470                 .block_unindent(context.config)
2471                 .to_string(context.config)
2472         )
2473     } else if context.config.spaces_within_angle_brackets() {
2474         format!("< {} >", list_str)
2475     } else {
2476         format!("<{}>", list_str)
2477     }
2478 }
2479
2480 fn rewrite_trait_bounds(
2481     context: &RewriteContext,
2482     type_param_bounds: &ast::TyParamBounds,
2483     shape: Shape,
2484 ) -> Option<String> {
2485     let bounds: &[_] = type_param_bounds;
2486
2487     if bounds.is_empty() {
2488         return Some(String::new());
2489     }
2490     let bound_str = try_opt!(
2491         bounds
2492             .iter()
2493             .map(|ty_bound| ty_bound.rewrite(context, shape))
2494             .collect::<Option<Vec<_>>>()
2495     );
2496     Some(format!(": {}", join_bounds(context, shape, &bound_str)))
2497 }
2498
2499 fn rewrite_where_clause_rfc_style(
2500     context: &RewriteContext,
2501     where_clause: &ast::WhereClause,
2502     shape: Shape,
2503     terminator: &str,
2504     span_end: Option<BytePos>,
2505     span_end_before_where: BytePos,
2506     where_clause_option: WhereClauseOption,
2507 ) -> Option<String> {
2508     let block_shape = shape.block().with_max_width(context.config);
2509
2510     let (span_before, span_after) =
2511         missing_span_before_after_where(span_end_before_where, where_clause);
2512     let (comment_before, comment_after) = try_opt!(rewrite_comments_before_after_where(
2513         context,
2514         span_before,
2515         span_after,
2516         shape,
2517     ));
2518
2519     let starting_newline = if where_clause_option.snuggle && comment_before.is_empty() {
2520         " ".to_owned()
2521     } else {
2522         "\n".to_owned() + &block_shape.indent.to_string(context.config)
2523     };
2524
2525     let clause_shape = block_shape.block_indent(context.config.tab_spaces());
2526     // each clause on one line, trailing comma (except if suppress_comma)
2527     let span_start = where_clause.predicates[0].span().lo();
2528     // If we don't have the start of the next span, then use the end of the
2529     // predicates, but that means we miss comments.
2530     let len = where_clause.predicates.len();
2531     let end_of_preds = where_clause.predicates[len - 1].span().hi();
2532     let span_end = span_end.unwrap_or(end_of_preds);
2533     let items = itemize_list(
2534         context.codemap,
2535         where_clause.predicates.iter(),
2536         terminator,
2537         |pred| pred.span().lo(),
2538         |pred| pred.span().hi(),
2539         |pred| pred.rewrite(context, block_shape),
2540         span_start,
2541         span_end,
2542         false,
2543     );
2544     let comma_tactic = if where_clause_option.suppress_comma {
2545         SeparatorTactic::Never
2546     } else {
2547         context.config.trailing_comma()
2548     };
2549
2550     let fmt = ListFormatting {
2551         tactic: DefinitiveListTactic::Vertical,
2552         separator: ",",
2553         trailing_separator: comma_tactic,
2554         separator_place: SeparatorPlace::Back,
2555         shape: clause_shape,
2556         ends_with_newline: true,
2557         preserve_newline: true,
2558         config: context.config,
2559     };
2560     let preds_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
2561
2562     let comment_separator = |comment: &str, shape: Shape| if comment.is_empty() {
2563         String::new()
2564     } else {
2565         format!("\n{}", shape.indent.to_string(context.config))
2566     };
2567     let newline_before_where = comment_separator(&comment_before, shape);
2568     let newline_after_where = comment_separator(&comment_after, clause_shape);
2569
2570     // 6 = `where `
2571     let clause_sep = if where_clause_option.compress_where && comment_before.is_empty()
2572         && comment_after.is_empty() && !preds_str.contains('\n')
2573         && 6 + preds_str.len() <= shape.width
2574     {
2575         String::from(" ")
2576     } else {
2577         format!("\n{}", clause_shape.indent.to_string(context.config))
2578     };
2579     Some(format!(
2580         "{}{}{}where{}{}{}{}",
2581         starting_newline,
2582         comment_before,
2583         newline_before_where,
2584         newline_after_where,
2585         comment_after,
2586         clause_sep,
2587         preds_str
2588     ))
2589 }
2590
2591 fn rewrite_where_clause(
2592     context: &RewriteContext,
2593     where_clause: &ast::WhereClause,
2594     brace_style: BraceStyle,
2595     shape: Shape,
2596     density: Density,
2597     terminator: &str,
2598     span_end: Option<BytePos>,
2599     span_end_before_where: BytePos,
2600     where_clause_option: WhereClauseOption,
2601 ) -> Option<String> {
2602     if where_clause.predicates.is_empty() {
2603         return Some(String::new());
2604     }
2605
2606     if context.config.where_style() == Style::Rfc {
2607         return rewrite_where_clause_rfc_style(
2608             context,
2609             where_clause,
2610             shape,
2611             terminator,
2612             span_end,
2613             span_end_before_where,
2614             where_clause_option,
2615         );
2616     }
2617
2618     let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2619
2620     let offset = match context.config.where_pred_indent() {
2621         IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2622         // 6 = "where ".len()
2623         IndentStyle::Visual => shape.indent + extra_indent + 6,
2624     };
2625     // FIXME: if where_pred_indent != Visual, then the budgets below might
2626     // be out by a char or two.
2627
2628     let budget = context.config.max_width() - offset.width();
2629     let span_start = where_clause.predicates[0].span().lo();
2630     // If we don't have the start of the next span, then use the end of the
2631     // predicates, but that means we miss comments.
2632     let len = where_clause.predicates.len();
2633     let end_of_preds = where_clause.predicates[len - 1].span().hi();
2634     let span_end = span_end.unwrap_or(end_of_preds);
2635     let items = itemize_list(
2636         context.codemap,
2637         where_clause.predicates.iter(),
2638         terminator,
2639         |pred| pred.span().lo(),
2640         |pred| pred.span().hi(),
2641         |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2642         span_start,
2643         span_end,
2644         false,
2645     );
2646     let item_vec = items.collect::<Vec<_>>();
2647     // FIXME: we don't need to collect here if the where_layout isn't
2648     // HorizontalVertical.
2649     let tactic = definitive_tactic(
2650         &item_vec,
2651         context.config.where_layout(),
2652         Separator::Comma,
2653         budget,
2654     );
2655
2656     let mut comma_tactic = context.config.trailing_comma();
2657     // Kind of a hack because we don't usually have trailing commas in where clauses.
2658     if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
2659         comma_tactic = SeparatorTactic::Never;
2660     }
2661
2662     let fmt = ListFormatting {
2663         tactic: tactic,
2664         separator: ",",
2665         trailing_separator: comma_tactic,
2666         separator_place: SeparatorPlace::Back,
2667         shape: Shape::legacy(budget, offset),
2668         ends_with_newline: tactic.ends_with_newline(context.config.where_pred_indent()),
2669         preserve_newline: true,
2670         config: context.config,
2671     };
2672     let preds_str = try_opt!(write_list(&item_vec, &fmt));
2673
2674     let end_length = if terminator == "{" {
2675         // If the brace is on the next line we don't need to count it otherwise it needs two
2676         // characters " {"
2677         match brace_style {
2678             BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
2679             BraceStyle::PreferSameLine => 2,
2680         }
2681     } else if terminator == "=" {
2682         2
2683     } else {
2684         terminator.len()
2685     };
2686     if density == Density::Tall || preds_str.contains('\n')
2687         || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
2688     {
2689         Some(format!(
2690             "\n{}where {}",
2691             (shape.indent + extra_indent).to_string(context.config),
2692             preds_str
2693         ))
2694     } else {
2695         Some(format!(" where {}", preds_str))
2696     }
2697 }
2698
2699 fn missing_span_before_after_where(
2700     before_item_span_end: BytePos,
2701     where_clause: &ast::WhereClause,
2702 ) -> (Span, Span) {
2703     let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
2704     // 5 = `where`
2705     let pos_after_where = where_clause.span.lo() + BytePos(5);
2706     let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
2707     (missing_span_before, missing_span_after)
2708 }
2709
2710 fn rewrite_comments_before_after_where(
2711     context: &RewriteContext,
2712     span_before_where: Span,
2713     span_after_where: Span,
2714     shape: Shape,
2715 ) -> Option<(String, String)> {
2716     let before_comment = try_opt!(rewrite_missing_comment(span_before_where, shape, context));
2717     let after_comment = try_opt!(rewrite_missing_comment(
2718         span_after_where,
2719         shape.block_indent(context.config.tab_spaces()),
2720         context,
2721     ));
2722     Some((before_comment, after_comment))
2723 }
2724
2725 fn format_header(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
2726     format!("{}{}{}", format_visibility(vis), item_name, ident)
2727 }
2728
2729 fn format_generics(
2730     context: &RewriteContext,
2731     generics: &ast::Generics,
2732     opener: &str,
2733     terminator: &str,
2734     brace_style: BraceStyle,
2735     force_same_line_brace: bool,
2736     offset: Indent,
2737     span: Span,
2738     used_width: usize,
2739 ) -> Option<String> {
2740     let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
2741     let mut result = try_opt!(rewrite_generics(context, generics, shape, span));
2742
2743     let same_line_brace = if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
2744         let budget = context.budget(last_line_used_width(&result, offset.width()));
2745         let option = WhereClauseOption::snuggled(&result);
2746         let where_clause_str = try_opt!(rewrite_where_clause(
2747             context,
2748             &generics.where_clause,
2749             brace_style,
2750             Shape::legacy(budget, offset.block_only()),
2751             Density::Tall,
2752             terminator,
2753             Some(span.hi()),
2754             generics.span.hi(),
2755             option,
2756         ));
2757         result.push_str(&where_clause_str);
2758         force_same_line_brace || brace_style == BraceStyle::PreferSameLine
2759             || (generics.where_clause.predicates.is_empty()
2760                 && trimmed_last_line_width(&result) == 1)
2761     } else {
2762         force_same_line_brace || trimmed_last_line_width(&result) == 1
2763             || brace_style != BraceStyle::AlwaysNextLine
2764     };
2765     let total_used_width = last_line_used_width(&result, used_width);
2766     let remaining_budget = context.budget(total_used_width);
2767     // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
2768     // and hence we take the closer into account as well for one line budget.
2769     // We assume that the closer has the same length as the opener.
2770     let overhead = if force_same_line_brace {
2771         1 + opener.len() + opener.len()
2772     } else {
2773         1 + opener.len()
2774     };
2775     let forbid_same_line_brace = overhead > remaining_budget;
2776     if !forbid_same_line_brace && same_line_brace {
2777         result.push(' ');
2778     } else {
2779         result.push('\n');
2780         result.push_str(&offset.block_only().to_string(context.config));
2781     }
2782     result.push_str(opener);
2783
2784     Some(result)
2785 }
2786
2787 impl Rewrite for ast::ForeignItem {
2788     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
2789         let attrs_str = try_opt!(self.attrs.rewrite(context, shape));
2790         // Drop semicolon or it will be interpreted as comment.
2791         // FIXME: this may be a faulty span from libsyntax.
2792         let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
2793
2794         let item_str = try_opt!(match self.node {
2795             ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
2796                 rewrite_fn_base(
2797                     context,
2798                     shape.indent,
2799                     self.ident,
2800                     &FnSig::new(fn_decl, generics, self.vis.clone()),
2801                     span,
2802                     false,
2803                     false,
2804                 ).map(|(s, _)| format!("{};", s))
2805             }
2806             ast::ForeignItemKind::Static(ref ty, is_mutable) => {
2807                 // FIXME(#21): we're dropping potential comments in between the
2808                 // function keywords here.
2809                 let vis = format_visibility(&self.vis);
2810                 let mut_str = if is_mutable { "mut " } else { "" };
2811                 let prefix = format!("{}static {}{}:", vis, mut_str, self.ident);
2812                 // 1 = ;
2813                 let shape = try_opt!(shape.sub_width(1));
2814                 ty.rewrite(context, shape).map(|ty_str| {
2815                     // 1 = space between prefix and type.
2816                     let sep = if prefix.len() + ty_str.len() + 1 <= shape.width {
2817                         String::from(" ")
2818                     } else {
2819                         let nested_indent = shape.indent.block_indent(context.config);
2820                         format!("\n{}", nested_indent.to_string(context.config))
2821                     };
2822                     format!("{}{}{};", prefix, sep, ty_str)
2823                 })
2824             }
2825         });
2826
2827         let missing_span = if self.attrs.is_empty() {
2828             mk_sp(self.span.lo(), self.span.lo())
2829         } else {
2830             mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
2831         };
2832         combine_strs_with_missing_comments(
2833             context,
2834             &attrs_str,
2835             &item_str,
2836             missing_span,
2837             shape,
2838             false,
2839         )
2840     }
2841 }