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