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