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