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