]> git.lizzy.rs Git - rust.git/blob - src/items.rs
Run clippy
[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;
14 use codemap::SpanUtils;
15 use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wrap_str,
16             last_line_width, semicolon_for_expr, format_unsafety, trim_newlines};
17 use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
18             DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list};
19 use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, type_annotation_separator};
20 use comment::{FindUncommented, contains_comment};
21 use visitor::FmtVisitor;
22 use rewrite::{Rewrite, RewriteContext};
23 use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, FnArgLayoutStyle};
24 use itertools::Itertools;
25
26 use syntax::{ast, abi, ptr, codemap};
27 use syntax::codemap::{Span, BytePos, mk_sp};
28 use syntax::parse::token;
29 use syntax::ast::ImplItem;
30
31 // Statements of the form
32 // let pat: ty = init;
33 impl Rewrite for ast::Local {
34     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
35         let mut result = "let ".to_owned();
36         let pattern_offset = offset + result.len();
37         // 1 = ;
38         let pattern_width = try_opt!(width.checked_sub(pattern_offset.width() + 1));
39
40         let pat_str = try_opt!(self.pat.rewrite(&context, pattern_width, pattern_offset));
41         result.push_str(&pat_str);
42
43         // String that is placed within the assignment pattern and expression.
44         let infix = {
45             let mut infix = String::new();
46
47             if let Some(ref ty) = self.ty {
48                 let separator = type_annotation_separator(context.config);
49                 let indent = offset + last_line_width(&result) + separator.len();
50                 // 1 = ;
51                 let budget = try_opt!(width.checked_sub(indent.width() + 1));
52                 let rewrite = try_opt!(ty.rewrite(context, budget, indent));
53
54                 infix.push_str(separator);
55                 infix.push_str(&rewrite);
56             }
57
58             if self.init.is_some() {
59                 infix.push_str(" =");
60             }
61
62             infix
63         };
64
65         result.push_str(&infix);
66
67         if let Some(ref ex) = self.init {
68             let budget = try_opt!(width.checked_sub(context.block_indent.width() + 1));
69
70             // 1 = trailing semicolon;
71             result =
72                 try_opt!(rewrite_assign_rhs(&context, result, ex, budget, context.block_indent));
73         }
74
75         result.push(';');
76         Some(result)
77     }
78 }
79
80 impl<'a> FmtVisitor<'a> {
81     pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
82         let abi_str = ::utils::format_abi(fm.abi, self.config.force_explicit_abi);
83         self.buffer.push_str(&abi_str);
84
85         let snippet = self.snippet(span);
86         let brace_pos = snippet.find_uncommented("{").unwrap();
87
88         self.buffer.push_str("{");
89         if !fm.items.is_empty() || contains_comment(&snippet[brace_pos..]) {
90             // FIXME: this skips comments between the extern keyword and the opening
91             // brace.
92             self.last_pos = span.lo + BytePos(brace_pos as u32 + 1);
93             self.block_indent = self.block_indent.block_indent(self.config);
94
95             if fm.items.is_empty() {
96                 self.format_missing_no_indent(span.hi - BytePos(1));
97                 self.block_indent = self.block_indent.block_unindent(self.config);
98
99                 self.buffer.push_str(&self.block_indent.to_string(self.config));
100             } else {
101                 for item in &fm.items {
102                     self.format_foreign_item(&*item);
103                 }
104
105                 self.block_indent = self.block_indent.block_unindent(self.config);
106                 self.format_missing_with_indent(span.hi - BytePos(1));
107             }
108         }
109
110         self.buffer.push_str("}");
111         self.last_pos = span.hi;
112     }
113
114     fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
115         self.format_missing_with_indent(item.span.lo);
116         // Drop semicolon or it will be interpreted as comment.
117         // FIXME: this may be a faulty span from libsyntax.
118         let span = mk_sp(item.span.lo, item.span.hi - BytePos(1));
119
120         match item.node {
121             ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
122                 let indent = self.block_indent;
123                 let rewrite = rewrite_fn_base(&self.get_context(),
124                                               indent,
125                                               item.ident,
126                                               fn_decl,
127                                               generics,
128                                               ast::Unsafety::Normal,
129                                               ast::Constness::NotConst,
130                                               ast::Defaultness::Final,
131                                               // These are not actually rust functions,
132                                               // but we format them as such.
133                                               abi::Abi::Rust,
134                                               &item.vis,
135                                               span,
136                                               false,
137                                               false);
138
139                 match rewrite {
140                     Some((new_fn, _)) => {
141                         self.buffer.push_str(&new_fn);
142                         self.buffer.push_str(";");
143                     }
144                     None => self.format_missing(item.span.hi),
145                 }
146             }
147             ast::ForeignItemKind::Static(ref ty, is_mutable) => {
148                 // FIXME(#21): we're dropping potential comments in between the
149                 // function keywords here.
150                 let vis = format_visibility(&item.vis);
151                 let mut_str = if is_mutable { "mut " } else { "" };
152                 let prefix = format!("{}static {}{}: ", vis, mut_str, item.ident);
153                 let offset = self.block_indent + prefix.len();
154                 // 1 = ;
155                 let width = self.config.max_width - offset.width() - 1;
156                 let rewrite = ty.rewrite(&self.get_context(), width, offset);
157
158                 match rewrite {
159                     Some(result) => {
160                         self.buffer.push_str(&prefix);
161                         self.buffer.push_str(&result);
162                         self.buffer.push_str(";");
163                     }
164                     None => self.format_missing(item.span.hi),
165                 }
166             }
167         }
168
169         self.last_pos = item.span.hi;
170     }
171
172     pub fn rewrite_fn(&mut self,
173                       indent: Indent,
174                       ident: ast::Ident,
175                       fd: &ast::FnDecl,
176                       generics: &ast::Generics,
177                       unsafety: ast::Unsafety,
178                       constness: ast::Constness,
179                       defaultness: ast::Defaultness,
180                       abi: abi::Abi,
181                       vis: &ast::Visibility,
182                       span: Span,
183                       block: &ast::Block)
184                       -> Option<String> {
185         let mut newline_brace = newline_for_brace(self.config, &generics.where_clause);
186         let context = self.get_context();
187
188         let block_snippet = self.snippet(codemap::mk_sp(block.span.lo, block.span.hi));
189         let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty() ||
190                        !context.config.fn_empty_single_line;
191
192         let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(&context,
193                                                                          indent,
194                                                                          ident,
195                                                                          fd,
196                                                                          generics,
197                                                                          unsafety,
198                                                                          constness,
199                                                                          defaultness,
200                                                                          abi,
201                                                                          vis,
202                                                                          span,
203                                                                          newline_brace,
204                                                                          has_body));
205
206         if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
207             newline_brace = false;
208         } else if force_newline_brace {
209             newline_brace = true;
210         }
211
212         // Prepare for the function body by possibly adding a newline and
213         // indent.
214         // FIXME we'll miss anything between the end of the signature and the
215         // start of the body, but we need more spans from the compiler to solve
216         // this.
217         if newline_brace {
218             result.push('\n');
219             result.push_str(&indent.to_string(self.config));
220         } else {
221             result.push(' ');
222         }
223
224         self.single_line_fn(&result, block).or_else(|| Some(result))
225     }
226
227     pub fn rewrite_required_fn(&mut self,
228                                indent: Indent,
229                                ident: ast::Ident,
230                                sig: &ast::MethodSig,
231                                span: Span)
232                                -> Option<String> {
233         // Drop semicolon or it will be interpreted as comment.
234         let span = mk_sp(span.lo, span.hi - BytePos(1));
235         let context = self.get_context();
236
237         let (mut result, _) = try_opt!(rewrite_fn_base(&context,
238                                                        indent,
239                                                        ident,
240                                                        &sig.decl,
241                                                        &sig.generics,
242                                                        sig.unsafety,
243                                                        sig.constness,
244                                                        ast::Defaultness::Final,
245                                                        sig.abi,
246                                                        &ast::Visibility::Inherited,
247                                                        span,
248                                                        false,
249                                                        false));
250
251         // Re-attach semicolon
252         result.push(';');
253
254         Some(result)
255     }
256
257     fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
258         if fn_str.contains('\n') {
259             return None;
260         }
261
262         let codemap = self.get_context().codemap;
263
264         if self.config.fn_empty_single_line && is_empty_block(block, codemap) &&
265            self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width {
266             return Some(format!("{}{{}}", fn_str));
267         }
268
269         if self.config.fn_single_line && is_simple_block_stmt(block, codemap) {
270             let rewrite = {
271                 if let Some(ref e) = block.expr {
272                     let suffix = if semicolon_for_expr(e) { ";" } else { "" };
273
274                     e.rewrite(&self.get_context(),
275                                  self.config.max_width - self.block_indent.width(),
276                                  self.block_indent)
277                         .map(|s| s + suffix)
278                         .or_else(|| Some(self.snippet(e.span)))
279                 } else if let Some(stmt) = block.stmts.first() {
280                     stmt.rewrite(&self.get_context(),
281                                  self.config.max_width - self.block_indent.width(),
282                                  self.block_indent)
283                 } else {
284                     None
285                 }
286             };
287
288             if let Some(res) = rewrite {
289                 let width = self.block_indent.width() + fn_str.len() + res.len() + 4;
290                 if !res.contains('\n') && width <= self.config.max_width {
291                     return Some(format!("{}{{ {} }}", fn_str, res));
292                 }
293             }
294         }
295
296         None
297     }
298
299     pub fn visit_enum(&mut self,
300                       ident: ast::Ident,
301                       vis: &ast::Visibility,
302                       enum_def: &ast::EnumDef,
303                       generics: &ast::Generics,
304                       span: Span) {
305         self.buffer.push_str(&format_header("enum ", ident, vis));
306
307         let enum_snippet = self.snippet(span);
308         let brace_pos = enum_snippet.find_uncommented("{").unwrap();
309         let body_start = span.lo + BytePos(brace_pos as u32 + 1);
310         let generics_str = format_generics(&self.get_context(),
311                                            generics,
312                                            "{",
313                                            "{",
314                                            self.config.item_brace_style,
315                                            enum_def.variants.is_empty(),
316                                            self.block_indent,
317                                            self.block_indent.block_indent(self.config),
318                                            mk_sp(span.lo, body_start))
319             .unwrap();
320         self.buffer.push_str(&generics_str);
321
322         self.last_pos = body_start;
323
324         self.block_indent = self.block_indent.block_indent(self.config);
325         let variant_list = self.format_variant_list(enum_def, body_start, span.hi - BytePos(1));
326         match variant_list {
327             Some(ref body_str) => self.buffer.push_str(body_str),
328             None => {
329                 if contains_comment(&enum_snippet[brace_pos..]) {
330                     self.format_missing_no_indent(span.hi - BytePos(1))
331                 } else {
332                     self.format_missing(span.hi - BytePos(1))
333                 }
334             }
335         }
336         self.block_indent = self.block_indent.block_unindent(self.config);
337
338         if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
339             self.buffer.push_str(&self.block_indent.to_string(self.config));
340         }
341         self.buffer.push_str("}");
342         self.last_pos = span.hi;
343     }
344
345     // Format the body of an enum definition
346     fn format_variant_list(&self,
347                            enum_def: &ast::EnumDef,
348                            body_lo: BytePos,
349                            body_hi: BytePos)
350                            -> Option<String> {
351         if enum_def.variants.is_empty() {
352             return None;
353         }
354         let mut result = String::with_capacity(1024);
355         result.push('\n');
356         let indentation = self.block_indent.to_string(self.config);
357         result.push_str(&indentation);
358
359         let items = itemize_list(self.codemap,
360                                  enum_def.variants.iter(),
361                                  "}",
362                                  |f| {
363             if !f.node.attrs.is_empty() {
364                 f.node.attrs[0].span.lo
365             } else {
366                 f.span.lo
367             }
368         },
369                                  |f| f.span.hi,
370                                  |f| self.format_variant(f),
371                                  body_lo,
372                                  body_hi);
373
374         let budget = self.config.max_width - self.block_indent.width() - 2;
375         let fmt = ListFormatting {
376             tactic: DefinitiveListTactic::Vertical,
377             separator: ",",
378             trailing_separator: SeparatorTactic::from_bool(self.config.enum_trailing_comma),
379             indent: self.block_indent,
380             width: budget,
381             ends_with_newline: true,
382             config: self.config,
383         };
384
385         let list = try_opt!(write_list(items, &fmt));
386         result.push_str(&list);
387         result.push('\n');
388         Some(result)
389     }
390
391     // Variant of an enum.
392     fn format_variant(&self, field: &ast::Variant) -> Option<String> {
393         if contains_skip(&field.node.attrs) {
394             let lo = field.node.attrs[0].span.lo;
395             let span = mk_sp(lo, field.span.hi);
396             return Some(self.snippet(span));
397         }
398
399         let indent = self.block_indent;
400         let mut result = try_opt!(field.node
401             .attrs
402             .rewrite(&self.get_context(),
403                      self.config.max_width - indent.width(),
404                      indent));
405         if !result.is_empty() {
406             result.push('\n');
407             result.push_str(&indent.to_string(self.config));
408         }
409
410         let context = self.get_context();
411         let variant_body = match field.node.data {
412             ast::VariantData::Tuple(..) |
413             ast::VariantData::Struct(..) => {
414                 // FIXME: Should limit the width, as we have a trailing comma
415                 format_struct(&context,
416                               "",
417                               field.node.name,
418                               &ast::Visibility::Inherited,
419                               &field.node.data,
420                               None,
421                               field.span,
422                               indent,
423                               Some(self.config.struct_variant_width))
424             }
425             ast::VariantData::Unit(..) => {
426                 let tag = if let Some(ref expr) = field.node.disr_expr {
427                     format!("{} = {}", field.node.name, self.snippet(expr.span))
428                 } else {
429                     field.node.name.to_string()
430                 };
431
432                 wrap_str(tag,
433                          self.config.max_width,
434                          self.config.max_width - indent.width(),
435                          indent)
436             }
437         };
438
439         if let Some(variant_str) = variant_body {
440             result.push_str(&variant_str);
441             Some(result)
442         } else {
443             None
444         }
445     }
446 }
447
448 pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
449     if let ast::ItemKind::Impl(unsafety,
450                                polarity,
451                                ref generics,
452                                ref trait_ref,
453                                ref self_ty,
454                                ref items) = item.node {
455         let mut result = String::new();
456
457         result.push_str(&*format_visibility(&item.vis));
458         result.push_str(format_unsafety(unsafety));
459         result.push_str("impl");
460
461         let lo = context.codemap.span_after(item.span, "impl");
462         let hi = match *trait_ref {
463             Some(ref tr) => tr.path.span.lo,
464             None => self_ty.span.lo,
465         };
466         let generics_str = try_opt!(rewrite_generics(context,
467                                                      generics,
468                                                      offset,
469                                                      context.config.max_width,
470                                                      offset + result.len(),
471                                                      mk_sp(lo, hi)));
472         result.push_str(&generics_str);
473
474         // FIXME might need to linebreak in the impl header, here would be a
475         // good place.
476         result.push(' ');
477         if polarity == ast::ImplPolarity::Negative {
478             result.push_str("!");
479         }
480         if let Some(ref trait_ref) = *trait_ref {
481             let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
482             let indent = offset + result.len();
483             result.push_str(&*try_opt!(trait_ref.rewrite(context, budget, indent)));
484             result.push_str(" for ");
485         }
486
487         let mut used_space = result.len();
488         if generics.where_clause.predicates.is_empty() {
489             // If there is no where clause adapt budget for type formatting to take space and curly
490             // brace into account.
491             match context.config.item_brace_style {
492                 BraceStyle::AlwaysNextLine => {}
493                 BraceStyle::PreferSameLine => used_space += 2,
494                 BraceStyle::SameLineWhere => used_space += 2,
495             }
496         }
497
498         let budget = try_opt!(context.config.max_width.checked_sub(used_space));
499         let indent = offset + result.len();
500         result.push_str(&*try_opt!(self_ty.rewrite(context, budget, indent)));
501
502         let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
503         let where_clause_str = try_opt!(rewrite_where_clause(context,
504                                                              &generics.where_clause,
505                                                              context.config,
506                                                              context.config.item_brace_style,
507                                                              context.block_indent,
508                                                              where_budget,
509                                                              context.config.where_density,
510                                                              "{",
511                                                              true,
512                                                              None));
513
514         if try_opt!(is_impl_single_line(context, &items, &result, &where_clause_str, &item)) {
515             result.push_str(&where_clause_str);
516             if where_clause_str.contains('\n') {
517                 let white_space = offset.to_string(context.config);
518                 result.push_str(&format!("\n{}{{\n{}}}", &white_space, &white_space));
519             } else {
520                 result.push_str(" {}");
521             }
522             return Some(result);
523         }
524
525         if !where_clause_str.is_empty() && !where_clause_str.contains('\n') {
526             result.push('\n');
527             let width = context.block_indent.width() + context.config.tab_spaces - 1;
528             let where_indent = Indent::new(0, width);
529             result.push_str(&where_indent.to_string(context.config));
530         }
531         result.push_str(&where_clause_str);
532
533         match context.config.item_brace_style {
534             BraceStyle::AlwaysNextLine => result.push('\n'),
535             BraceStyle::PreferSameLine => result.push(' '),
536             BraceStyle::SameLineWhere => {
537                 if !where_clause_str.is_empty() {
538                     result.push('\n');
539                     result.push_str(&offset.to_string(context.config));
540                 } else {
541                     result.push(' ');
542                 }
543             }
544         }
545
546         result.push('{');
547
548         let snippet = context.snippet(item.span);
549         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
550
551         if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
552             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
553             visitor.block_indent = context.block_indent.block_indent(context.config);
554             visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
555
556             for item in items {
557                 visitor.visit_impl_item(item);
558             }
559
560             visitor.format_missing(item.span.hi - BytePos(1));
561
562             let inner_indent_str = visitor.block_indent.to_string(context.config);
563             let outer_indent_str = context.block_indent.to_string(context.config);
564
565             result.push('\n');
566             result.push_str(&inner_indent_str);
567             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
568             result.push('\n');
569             result.push_str(&outer_indent_str);
570         }
571
572         if result.chars().last().unwrap() == '{' {
573             result.push('\n');
574         }
575         result.push('}');
576
577         Some(result)
578     } else {
579         unreachable!();
580     }
581 }
582
583 fn is_impl_single_line(context: &RewriteContext,
584                        items: &[ImplItem],
585                        result: &str,
586                        where_clause_str: &str,
587                        item: &ast::Item)
588                        -> Option<bool> {
589     let snippet = context.snippet(item.span);
590     let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
591
592     Some(context.config.impl_empty_single_line && items.is_empty() &&
593          result.len() + where_clause_str.len() <= context.config.max_width &&
594          !contains_comment(&snippet[open_pos..]))
595 }
596
597 pub fn format_struct(context: &RewriteContext,
598                      item_name: &str,
599                      ident: ast::Ident,
600                      vis: &ast::Visibility,
601                      struct_def: &ast::VariantData,
602                      generics: Option<&ast::Generics>,
603                      span: Span,
604                      offset: Indent,
605                      one_line_width: Option<usize>)
606                      -> Option<String> {
607     match *struct_def {
608         ast::VariantData::Unit(..) => Some(format_unit_struct(item_name, ident, vis)),
609         ast::VariantData::Tuple(ref fields, _) => {
610             format_tuple_struct(context,
611                                 item_name,
612                                 ident,
613                                 vis,
614                                 fields,
615                                 generics,
616                                 span,
617                                 offset)
618         }
619         ast::VariantData::Struct(ref fields, _) => {
620             format_struct_struct(context,
621                                  item_name,
622                                  ident,
623                                  vis,
624                                  fields,
625                                  generics,
626                                  span,
627                                  offset,
628                                  one_line_width)
629         }
630     }
631 }
632
633 pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
634     if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
635            item.node {
636         let mut result = String::new();
637         let header = format!("{}{}trait {}",
638                              format_visibility(&item.vis),
639                              format_unsafety(unsafety),
640                              item.ident);
641
642         result.push_str(&header);
643
644         let body_lo = context.codemap.span_after(item.span, "{");
645
646         let generics_str = try_opt!(rewrite_generics(context,
647                                                      generics,
648                                                      offset,
649                                                      context.config.max_width,
650                                                      offset + result.len(),
651                                                      mk_sp(item.span.lo, body_lo)));
652         result.push_str(&generics_str);
653
654         let trait_bound_str = try_opt!(rewrite_trait_bounds(context,
655                                                             type_param_bounds,
656                                                             offset,
657                                                             context.config.max_width));
658         // If the trait, generics, and trait bound cannot fit on the same line,
659         // put the trait bounds on an indented new line
660         if offset.width() + last_line_width(&result) + trait_bound_str.len() >
661            context.config.ideal_width {
662             result.push('\n');
663             let width = context.block_indent.width() + context.config.tab_spaces;
664             let trait_indent = Indent::new(0, width);
665             result.push_str(&trait_indent.to_string(context.config));
666         }
667         result.push_str(&trait_bound_str);
668
669         let has_body = !trait_items.is_empty();
670
671         let where_density =
672             if (context.config.where_density == Density::Compressed &&
673                 (!result.contains('\n') ||
674                  context.config.fn_args_layout == FnArgLayoutStyle::Block)) ||
675                (context.config.fn_args_layout == FnArgLayoutStyle::Block && result.is_empty()) ||
676                (context.config.where_density == Density::CompressedIfEmpty && !has_body &&
677                 !result.contains('\n')) {
678                 Density::Compressed
679             } else {
680                 Density::Tall
681             };
682
683         let where_budget = try_opt!(context.config
684             .max_width
685             .checked_sub(last_line_width(&result)));
686         let where_clause_str = try_opt!(rewrite_where_clause(context,
687                                                              &generics.where_clause,
688                                                              context.config,
689                                                              context.config.item_brace_style,
690                                                              context.block_indent,
691                                                              where_budget,
692                                                              where_density,
693                                                              "{",
694                                                              has_body,
695                                                              None));
696         // If the where clause cannot fit on the same line,
697         // put the where clause on a new line
698         if !where_clause_str.contains('\n') &&
699            last_line_width(&result) + where_clause_str.len() + offset.width() >
700            context.config.ideal_width {
701             result.push('\n');
702             let width = context.block_indent.width() + context.config.tab_spaces - 1;
703             let where_indent = Indent::new(0, width);
704             result.push_str(&where_indent.to_string(context.config));
705         }
706         result.push_str(&where_clause_str);
707
708         match context.config.item_brace_style {
709             BraceStyle::AlwaysNextLine => {
710                 result.push('\n');
711                 result.push_str(&offset.to_string(context.config));
712             }
713             BraceStyle::PreferSameLine => result.push(' '),
714             BraceStyle::SameLineWhere => {
715                 if !where_clause_str.is_empty() &&
716                    (!trait_items.is_empty() || result.contains('\n')) {
717                     result.push('\n');
718                     result.push_str(&offset.to_string(context.config));
719                 } else {
720                     result.push(' ');
721                 }
722             }
723         }
724         result.push('{');
725
726         let snippet = context.snippet(item.span);
727         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
728
729         if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
730             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
731             visitor.block_indent = context.block_indent.block_indent(context.config);
732             visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
733
734             for item in trait_items {
735                 visitor.visit_trait_item(item);
736             }
737
738             visitor.format_missing(item.span.hi - BytePos(1));
739
740             let inner_indent_str = visitor.block_indent.to_string(context.config);
741             let outer_indent_str = context.block_indent.to_string(context.config);
742
743             result.push('\n');
744             result.push_str(&inner_indent_str);
745             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
746             result.push('\n');
747             result.push_str(&outer_indent_str);
748         } else if result.contains('\n') {
749             result.push('\n');
750         }
751
752         result.push('}');
753         Some(result)
754     } else {
755         unreachable!();
756     }
757 }
758
759 fn format_unit_struct(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
760     format!("{};", format_header(item_name, ident, vis))
761 }
762
763 fn format_struct_struct(context: &RewriteContext,
764                         item_name: &str,
765                         ident: ast::Ident,
766                         vis: &ast::Visibility,
767                         fields: &[ast::StructField],
768                         generics: Option<&ast::Generics>,
769                         span: Span,
770                         offset: Indent,
771                         one_line_width: Option<usize>)
772                         -> Option<String> {
773     let mut result = String::with_capacity(1024);
774
775     let header_str = format_header(item_name, ident, vis);
776     result.push_str(&header_str);
777
778     let body_lo = context.codemap.span_after(span, "{");
779
780     let generics_str = match generics {
781         Some(g) => {
782             try_opt!(format_generics(context,
783                                      g,
784                                      "{",
785                                      "{",
786                                      context.config.item_brace_style,
787                                      fields.is_empty(),
788                                      offset,
789                                      offset + header_str.len(),
790                                      mk_sp(span.lo, body_lo)))
791         }
792         None => {
793             if context.config.item_brace_style == BraceStyle::AlwaysNextLine && !fields.is_empty() {
794                 format!("\n{}{{", context.block_indent.to_string(context.config))
795             } else {
796                 " {".to_owned()
797             }
798         }
799     };
800     result.push_str(&generics_str);
801
802     // FIXME(#919): properly format empty structs and their comments.
803     if fields.is_empty() {
804         result.push_str(&context.snippet(mk_sp(body_lo, span.hi)));
805         return Some(result);
806     }
807
808     let item_indent = offset.block_indent(context.config);
809     // 1 = ","
810     let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 1));
811
812     let items = itemize_list(context.codemap,
813                              fields.iter(),
814                              "}",
815                              |field| {
816         // Include attributes and doc comments, if present
817         if !field.attrs.is_empty() {
818             field.attrs[0].span.lo
819         } else {
820             field.span.lo
821         }
822     },
823                              |field| field.ty.span.hi,
824                              |field| field.rewrite(context, item_budget, item_indent),
825                              context.codemap.span_after(span, "{"),
826                              span.hi)
827         .collect::<Vec<_>>();
828     // 1 = ,
829     let budget = context.config.max_width - offset.width() + context.config.tab_spaces - 1;
830
831     let tactic = match one_line_width {
832         Some(w) => definitive_tactic(&items, ListTactic::LimitedHorizontalVertical(w), budget),
833         None => DefinitiveListTactic::Vertical,
834     };
835
836     let fmt = ListFormatting {
837         tactic: tactic,
838         separator: ",",
839         trailing_separator: context.config.struct_trailing_comma,
840         indent: item_indent,
841         width: budget,
842         ends_with_newline: true,
843         config: context.config,
844     };
845     let items_str = try_opt!(write_list(&items, &fmt));
846     if one_line_width.is_some() && !items_str.contains('\n') {
847         Some(format!("{} {} }}", result, items_str))
848     } else {
849         Some(format!("{}\n{}{}\n{}}}",
850                      result,
851                      offset.block_indent(context.config).to_string(context.config),
852                      items_str,
853                      offset.to_string(context.config)))
854     }
855 }
856
857 fn format_tuple_struct(context: &RewriteContext,
858                        item_name: &str,
859                        ident: ast::Ident,
860                        vis: &ast::Visibility,
861                        fields: &[ast::StructField],
862                        generics: Option<&ast::Generics>,
863                        span: Span,
864                        offset: Indent)
865                        -> Option<String> {
866     let mut result = String::with_capacity(1024);
867
868     let header_str = format_header(item_name, ident, vis);
869     result.push_str(&header_str);
870
871     // FIXME(#919): don't lose comments on empty tuple structs.
872     let body_lo = if fields.is_empty() {
873         span.hi
874     } else {
875         fields[0].span.lo
876     };
877
878     let where_clause_str = match generics {
879         Some(generics) => {
880             let generics_str = try_opt!(rewrite_generics(context,
881                                                          generics,
882                                                          offset,
883                                                          context.config.max_width,
884                                                          offset + header_str.len(),
885                                                          mk_sp(span.lo, body_lo)));
886             result.push_str(&generics_str);
887
888             let where_budget = try_opt!(context.config
889                 .max_width
890                 .checked_sub(last_line_width(&result)));
891             try_opt!(rewrite_where_clause(context,
892                                           &generics.where_clause,
893                                           context.config,
894                                           context.config.item_brace_style,
895                                           context.block_indent,
896                                           where_budget,
897                                           Density::Compressed,
898                                           ";",
899                                           false,
900                                           None))
901         }
902         None => "".to_owned(),
903     };
904     result.push('(');
905
906     let item_indent = context.block_indent + result.len();
907     // 2 = ");"
908     let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 2));
909
910     let items = itemize_list(context.codemap,
911                              fields.iter(),
912                              ")",
913                              |field| {
914         // Include attributes and doc comments, if present
915         if !field.attrs.is_empty() {
916             field.attrs[0].span.lo
917         } else {
918             field.span.lo
919         }
920     },
921                              |field| field.ty.span.hi,
922                              |field| field.rewrite(context, item_budget, item_indent),
923                              context.codemap.span_after(span, "("),
924                              span.hi);
925     let body = try_opt!(format_item_list(items, item_budget, item_indent, context.config));
926     result.push_str(&body);
927     result.push(')');
928
929     if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
930        (result.contains('\n') ||
931         context.block_indent.width() + result.len() + where_clause_str.len() + 1 >
932         context.config.max_width) {
933         // We need to put the where clause on a new line, but we didn'to_string
934         // know that earlier, so the where clause will not be indented properly.
935         result.push('\n');
936         result.push_str(&(context.block_indent + (context.config.tab_spaces - 1))
937             .to_string(context.config));
938     }
939     result.push_str(&where_clause_str);
940
941     Some(result)
942 }
943
944 pub fn rewrite_type_alias(context: &RewriteContext,
945                           indent: Indent,
946                           ident: ast::Ident,
947                           ty: &ast::Ty,
948                           generics: &ast::Generics,
949                           vis: &ast::Visibility,
950                           span: Span)
951                           -> Option<String> {
952     let mut result = String::new();
953
954     result.push_str(&format_visibility(vis));
955     result.push_str("type ");
956     result.push_str(&ident.to_string());
957
958     let generics_indent = indent + result.len();
959     let generics_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo);
960     let generics_width = context.config.max_width - " =".len();
961     let generics_str = try_opt!(rewrite_generics(context,
962                                                  generics,
963                                                  indent,
964                                                  generics_width,
965                                                  generics_indent,
966                                                  generics_span));
967
968     result.push_str(&generics_str);
969
970     let where_budget = try_opt!(context.config
971         .max_width
972         .checked_sub(last_line_width(&result)));
973     let where_clause_str = try_opt!(rewrite_where_clause(context,
974                                                          &generics.where_clause,
975                                                          context.config,
976                                                          context.config.item_brace_style,
977                                                          indent,
978                                                          where_budget,
979                                                          context.config.where_density,
980                                                          "=",
981                                                          false,
982                                                          Some(span.hi)));
983     result.push_str(&where_clause_str);
984     result.push_str(" = ");
985
986     let line_width = last_line_width(&result);
987     // This checked_sub may fail as the extra space after '=' is not taken into account
988     // In that case the budget is set to 0 which will make ty.rewrite retry on a new line
989     let budget = context.config
990         .max_width
991         .checked_sub(indent.width() + line_width + ";".len())
992         .unwrap_or(0);
993     let type_indent = indent + line_width;
994     // Try to fit the type on the same line
995     let ty_str = try_opt!(ty.rewrite(context, budget, type_indent)
996         .or_else(|| {
997             // The line was too short, try to put the type on the next line
998
999             // Remove the space after '='
1000             result.pop();
1001             let type_indent = indent.block_indent(context.config);
1002             result.push('\n');
1003             result.push_str(&type_indent.to_string(context.config));
1004             let budget = try_opt!(context.config
1005                 .max_width
1006                 .checked_sub(type_indent.width() + ";".len()));
1007             ty.rewrite(context, budget, type_indent)
1008         }));
1009     result.push_str(&ty_str);
1010     result.push_str(";");
1011     Some(result)
1012 }
1013
1014 fn type_annotation_spacing(config: &Config) -> &str {
1015     if config.space_before_type_annotation {
1016         " "
1017     } else {
1018         ""
1019     }
1020 }
1021
1022 impl Rewrite for ast::StructField {
1023     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
1024         if contains_skip(&self.attrs) {
1025             let span = context.snippet(mk_sp(self.attrs[0].span.lo, self.span.hi));
1026             return wrap_str(span, context.config.max_width, width, offset);
1027         }
1028
1029         let name = self.ident;
1030         let vis = format_visibility(&self.vis);
1031         let mut attr_str = try_opt!(self.attrs
1032             .rewrite(context, context.config.max_width - offset.width(), offset));
1033         if !attr_str.is_empty() {
1034             attr_str.push('\n');
1035             attr_str.push_str(&offset.to_string(context.config));
1036         }
1037
1038         let type_annotation_spacing = type_annotation_spacing(context.config);
1039         let result = match name {
1040             Some(name) => format!("{}{}{}{}: ", attr_str, vis, name, type_annotation_spacing),
1041             None => format!("{}{}", attr_str, vis),
1042         };
1043
1044         let last_line_width = last_line_width(&result);
1045         let budget = try_opt!(width.checked_sub(last_line_width));
1046         let rewrite = try_opt!(self.ty.rewrite(context, budget, offset + last_line_width));
1047         Some(result + &rewrite)
1048     }
1049 }
1050
1051 pub fn rewrite_static(prefix: &str,
1052                       vis: &ast::Visibility,
1053                       ident: ast::Ident,
1054                       ty: &ast::Ty,
1055                       mutability: ast::Mutability,
1056                       expr_opt: Option<&ptr::P<ast::Expr>>,
1057                       context: &RewriteContext)
1058                       -> Option<String> {
1059     let type_annotation_spacing = type_annotation_spacing(context.config);
1060     let prefix = format!("{}{} {}{}{}: ",
1061                          format_visibility(vis),
1062                          prefix,
1063                          format_mutability(mutability),
1064                          ident,
1065                          type_annotation_spacing);
1066     // 2 = " =".len()
1067     let ty_str = try_opt!(ty.rewrite(context,
1068                                      context.config.max_width - context.block_indent.width() -
1069                                      prefix.len() - 2,
1070                                      context.block_indent));
1071
1072     if let Some(expr) = expr_opt {
1073         let lhs = format!("{}{} =", prefix, ty_str);
1074         // 1 = ;
1075         let remaining_width = context.config.max_width - context.block_indent.width() - 1;
1076         rewrite_assign_rhs(context, lhs, expr, remaining_width, context.block_indent)
1077             .map(|s| s + ";")
1078     } else {
1079         let lhs = format!("{}{};", prefix, ty_str);
1080         Some(lhs)
1081     }
1082 }
1083
1084 pub fn rewrite_associated_type(ident: ast::Ident,
1085                                ty_opt: Option<&ptr::P<ast::Ty>>,
1086                                ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1087                                context: &RewriteContext,
1088                                indent: Indent)
1089                                -> Option<String> {
1090     let prefix = format!("type {}", ident);
1091
1092     let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
1093         let bounds: &[_] = ty_param_bounds;
1094         let bound_str = try_opt!(bounds.iter()
1095             .map(|ty_bound| ty_bound.rewrite(context, context.config.max_width, indent))
1096             .intersperse(Some(" + ".to_string()))
1097             .collect::<Option<String>>());
1098         if bounds.len() > 0 {
1099             format!(": {}", bound_str)
1100         } else {
1101             String::new()
1102         }
1103     } else {
1104         String::new()
1105     };
1106
1107     if let Some(ty) = ty_opt {
1108         let ty_str = try_opt!(ty.rewrite(context,
1109                                          context.config.max_width - context.block_indent.width() -
1110                                          prefix.len() -
1111                                          2,
1112                                          context.block_indent));
1113         Some(format!("{} = {};", prefix, ty_str))
1114     } else {
1115         Some(format!("{}{};", prefix, type_bounds_str))
1116     }
1117 }
1118
1119 impl Rewrite for ast::FunctionRetTy {
1120     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
1121         match *self {
1122             ast::FunctionRetTy::Default(_) => Some(String::new()),
1123             ast::FunctionRetTy::None(_) => {
1124                 if width >= 4 {
1125                     Some("-> !".to_owned())
1126                 } else {
1127                     None
1128                 }
1129             }
1130             ast::FunctionRetTy::Ty(ref ty) => {
1131                 let inner_width = try_opt!(width.checked_sub(3));
1132                 ty.rewrite(context, inner_width, offset + 3).map(|r| format!("-> {}", r))
1133             }
1134         }
1135     }
1136 }
1137
1138 impl Rewrite for ast::Arg {
1139     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
1140         if is_named_arg(self) {
1141             let mut result = try_opt!(self.pat.rewrite(context, width, offset));
1142
1143             if self.ty.node != ast::TyKind::Infer {
1144                 if context.config.space_before_type_annotation {
1145                     result.push_str(" ");
1146                 }
1147                 result.push_str(": ");
1148                 let max_width = try_opt!(width.checked_sub(result.len()));
1149                 let ty_str = try_opt!(self.ty.rewrite(context, max_width, offset + result.len()));
1150                 result.push_str(&ty_str);
1151             }
1152
1153             Some(result)
1154         } else {
1155             self.ty.rewrite(context, width, offset)
1156         }
1157     }
1158 }
1159
1160 fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf,
1161                          args: &[ast::Arg],
1162                          context: &RewriteContext)
1163                          -> Option<String> {
1164     match explicit_self.node {
1165         ast::SelfKind::Region(lt, m) => {
1166             let mut_str = format_mutability(m);
1167             match lt {
1168                 Some(ref l) => {
1169                     let lifetime_str =
1170                         try_opt!(l.rewrite(context, usize::max_value(), Indent::empty()));
1171                     Some(format!("&{} {}self", lifetime_str, mut_str))
1172                 }
1173                 None => Some(format!("&{}self", mut_str)),
1174             }
1175         }
1176         ast::SelfKind::Explicit(ref ty, _) => {
1177             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1178
1179             let mutability = explicit_self_mutability(&args[0]);
1180             let type_str = try_opt!(ty.rewrite(context, usize::max_value(), Indent::empty()));
1181
1182             Some(format!("{}self: {}", format_mutability(mutability), type_str))
1183         }
1184         ast::SelfKind::Value(_) => {
1185             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1186
1187             let mutability = explicit_self_mutability(&args[0]);
1188
1189             Some(format!("{}self", format_mutability(mutability)))
1190         }
1191     }
1192 }
1193
1194 // Hacky solution caused by absence of `Mutability` in `SelfValue` and
1195 // `SelfExplicit` variants of `ast::ExplicitSelf_`.
1196 fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
1197     if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node {
1198         mutability
1199     } else {
1200         unreachable!()
1201     }
1202 }
1203
1204 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
1205     if is_named_arg(arg) {
1206         arg.pat.span.lo
1207     } else {
1208         arg.ty.span.lo
1209     }
1210 }
1211
1212 pub fn span_hi_for_arg(arg: &ast::Arg) -> BytePos {
1213     match arg.ty.node {
1214         ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi,
1215         _ => arg.ty.span.hi,
1216     }
1217 }
1218
1219 pub fn is_named_arg(arg: &ast::Arg) -> bool {
1220     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1221         ident.node != token::keywords::Invalid.ident()
1222     } else {
1223         true
1224     }
1225 }
1226
1227 fn span_for_return(ret: &ast::FunctionRetTy) -> Span {
1228     match *ret {
1229         ast::FunctionRetTy::None(ref span) |
1230         ast::FunctionRetTy::Default(ref span) => span.clone(),
1231         ast::FunctionRetTy::Ty(ref ty) => ty.span,
1232     }
1233 }
1234
1235 fn span_for_ty_param(ty: &ast::TyParam) -> Span {
1236     // Note that ty.span is the span for ty.ident, not the whole item.
1237     let lo = ty.span.lo;
1238     if let Some(ref def) = ty.default {
1239         return mk_sp(lo, def.span.hi);
1240     }
1241     if ty.bounds.is_empty() {
1242         return ty.span;
1243     }
1244     let hi = match ty.bounds[ty.bounds.len() - 1] {
1245         ast::TyParamBound::TraitTyParamBound(ref ptr, _) => ptr.span.hi,
1246         ast::TyParamBound::RegionTyParamBound(ref l) => l.span.hi,
1247     };
1248     mk_sp(lo, hi)
1249 }
1250
1251 fn span_for_where_pred(pred: &ast::WherePredicate) -> Span {
1252     match *pred {
1253         ast::WherePredicate::BoundPredicate(ref p) => p.span,
1254         ast::WherePredicate::RegionPredicate(ref p) => p.span,
1255         ast::WherePredicate::EqPredicate(ref p) => p.span,
1256     }
1257 }
1258
1259 // Return type is (result, force_new_line_for_brace)
1260 fn rewrite_fn_base(context: &RewriteContext,
1261                    indent: Indent,
1262                    ident: ast::Ident,
1263                    fd: &ast::FnDecl,
1264                    generics: &ast::Generics,
1265                    unsafety: ast::Unsafety,
1266                    constness: ast::Constness,
1267                    defaultness: ast::Defaultness,
1268                    abi: abi::Abi,
1269                    vis: &ast::Visibility,
1270                    span: Span,
1271                    newline_brace: bool,
1272                    has_body: bool)
1273                    -> Option<(String, bool)> {
1274     let mut force_new_line_for_brace = false;
1275     // FIXME we'll lose any comments in between parts of the function decl, but
1276     // anyone who comments there probably deserves what they get.
1277
1278     let where_clause = &generics.where_clause;
1279
1280     let mut result = String::with_capacity(1024);
1281     // Vis unsafety abi.
1282     result.push_str(&*format_visibility(vis));
1283
1284     if let ast::Defaultness::Default = defaultness {
1285         result.push_str("default ");
1286     }
1287
1288     if let ast::Constness::Const = constness {
1289         result.push_str("const ");
1290     }
1291
1292     result.push_str(::utils::format_unsafety(unsafety));
1293
1294     if abi != abi::Abi::Rust {
1295         result.push_str(&::utils::format_abi(abi, context.config.force_explicit_abi));
1296     }
1297
1298     // fn foo
1299     result.push_str("fn ");
1300     result.push_str(&ident.to_string());
1301
1302     // Generics.
1303     let generics_indent = indent + result.len();
1304     let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo);
1305     let generics_str = try_opt!(rewrite_generics(context,
1306                                                  generics,
1307                                                  indent,
1308                                                  context.config.max_width,
1309                                                  generics_indent,
1310                                                  generics_span));
1311     result.push_str(&generics_str);
1312
1313     // Note that if the width and indent really matter, we'll re-layout the
1314     // return type later anyway.
1315     let ret_str = try_opt!(fd.output
1316         .rewrite(&context, context.config.max_width - indent.width(), indent));
1317
1318     let multi_line_ret_str = ret_str.contains('\n');
1319     let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
1320
1321     // Args.
1322     let (mut one_line_budget, mut multi_line_budget, mut arg_indent) =
1323         try_opt!(compute_budgets_for_args(context, &result, indent, ret_str_len, newline_brace));
1324
1325     if context.config.fn_args_layout == FnArgLayoutStyle::Block ||
1326        context.config.fn_args_layout == FnArgLayoutStyle::BlockAlways {
1327         arg_indent = indent.block_indent(context.config);
1328         multi_line_budget = context.config.max_width - arg_indent.width();
1329     }
1330
1331     debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
1332            one_line_budget,
1333            multi_line_budget,
1334            arg_indent);
1335
1336     // Check if vertical layout was forced by compute_budget_for_args.
1337     if one_line_budget == 0 {
1338         if context.config.fn_args_paren_newline {
1339             result.push('\n');
1340             result.push_str(&arg_indent.to_string(context.config));
1341             arg_indent = arg_indent + 1; // extra space for `(`
1342             result.push('(');
1343         } else {
1344             result.push_str("(\n");
1345             result.push_str(&arg_indent.to_string(context.config));
1346         }
1347     } else {
1348         result.push('(');
1349     }
1350
1351     if multi_line_ret_str {
1352         one_line_budget = 0;
1353     }
1354
1355     // A conservative estimation, to goal is to be over all parens in generics
1356     let args_start = generics.ty_params
1357         .last()
1358         .map_or(span.lo, |tp| end_typaram(tp));
1359     let args_span = mk_sp(context.codemap.span_after(mk_sp(args_start, span.hi), "("),
1360                           span_for_return(&fd.output).lo);
1361     let arg_str = try_opt!(rewrite_args(context,
1362                                         &fd.inputs,
1363                                         fd.get_self().as_ref(),
1364                                         one_line_budget,
1365                                         multi_line_budget,
1366                                         indent,
1367                                         arg_indent,
1368                                         args_span,
1369                                         fd.variadic));
1370
1371     let multi_line_arg_str = arg_str.contains('\n');
1372
1373     let put_args_in_block = match context.config.fn_args_layout {
1374         FnArgLayoutStyle::Block => multi_line_arg_str,
1375         FnArgLayoutStyle::BlockAlways => true,
1376         _ => false,
1377     } && !fd.inputs.is_empty();
1378
1379     if put_args_in_block {
1380         arg_indent = indent.block_indent(context.config);
1381         result.push('\n');
1382         result.push_str(&arg_indent.to_string(context.config));
1383         result.push_str(&arg_str);
1384         result.push('\n');
1385         result.push_str(&indent.to_string(context.config));
1386         result.push(')');
1387     } else {
1388         result.push_str(&arg_str);
1389         result.push(')');
1390     }
1391
1392     // Return type.
1393     if !ret_str.is_empty() {
1394         let ret_should_indent = match context.config.fn_args_layout {
1395             // If our args are block layout then we surely must have space.
1396             FnArgLayoutStyle::Block if put_args_in_block => false,
1397             FnArgLayoutStyle::BlockAlways => false,
1398             _ => {
1399                 // If we've already gone multi-line, or the return type would push over the max
1400                 // width, then put the return type on a new line. With the +1 for the signature
1401                 // length an additional space between the closing parenthesis of the argument and
1402                 // the arrow '->' is considered.
1403                 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
1404
1405                 // If there is no where clause, take into account the space after the return type
1406                 // and the brace.
1407                 if where_clause.predicates.is_empty() {
1408                     sig_length += 2;
1409                 }
1410
1411                 let overlong_sig = sig_length > context.config.max_width;
1412
1413                 result.contains('\n') || multi_line_ret_str || overlong_sig
1414             }
1415         };
1416         let ret_indent = if ret_should_indent {
1417             let indent = match context.config.fn_return_indent {
1418                 ReturnIndent::WithWhereClause => indent + 4,
1419                 // Aligning with non-existent args looks silly.
1420                 _ if arg_str.is_empty() => {
1421                     force_new_line_for_brace = true;
1422                     indent + 4
1423                 }
1424                 // FIXME: we might want to check that using the arg indent
1425                 // doesn't blow our budget, and if it does, then fallback to
1426                 // the where clause indent.
1427                 _ => arg_indent,
1428             };
1429
1430             result.push('\n');
1431             result.push_str(&indent.to_string(context.config));
1432             indent
1433         } else {
1434             result.push(' ');
1435             Indent::new(indent.width(), result.len())
1436         };
1437
1438         if multi_line_ret_str {
1439             // Now that we know the proper indent and width, we need to
1440             // re-layout the return type.
1441             let budget = try_opt!(context.config.max_width.checked_sub(ret_indent.width()));
1442             let ret_str = try_opt!(fd.output.rewrite(context, budget, ret_indent));
1443             result.push_str(&ret_str);
1444         } else {
1445             result.push_str(&ret_str);
1446         }
1447
1448         // Comment between return type and the end of the decl.
1449         let snippet_lo = fd.output.span().hi;
1450         if where_clause.predicates.is_empty() {
1451             let snippet_hi = span.hi;
1452             let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
1453             let snippet = snippet.trim();
1454             if !snippet.is_empty() {
1455                 result.push(' ');
1456                 result.push_str(snippet);
1457             }
1458         } else {
1459             // FIXME it would be nice to catch comments between the return type
1460             // and the where clause, but we don't have a span for the where
1461             // clause.
1462         }
1463     }
1464
1465     let should_compress_where = match context.config.where_density {
1466         Density::Compressed => !result.contains('\n') || put_args_in_block,
1467         Density::CompressedIfEmpty => !has_body && !result.contains('\n'),
1468         _ => false,
1469     } || (put_args_in_block && ret_str.is_empty());
1470
1471     let where_density = if should_compress_where {
1472         Density::Compressed
1473     } else {
1474         Density::Tall
1475     };
1476
1477     // Where clause.
1478     let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
1479     let where_clause_str = try_opt!(rewrite_where_clause(context,
1480                                                          where_clause,
1481                                                          context.config,
1482                                                          context.config.fn_brace_style,
1483                                                          indent,
1484                                                          where_budget,
1485                                                          where_density,
1486                                                          "{",
1487                                                          has_body,
1488                                                          Some(span.hi)));
1489
1490     if last_line_width(&result) + where_clause_str.len() > context.config.max_width &&
1491        !where_clause_str.contains('\n') {
1492         result.push('\n');
1493     }
1494
1495     result.push_str(&where_clause_str);
1496
1497     Some((result, force_new_line_for_brace))
1498 }
1499
1500 fn rewrite_args(context: &RewriteContext,
1501                 args: &[ast::Arg],
1502                 explicit_self: Option<&ast::ExplicitSelf>,
1503                 one_line_budget: usize,
1504                 multi_line_budget: usize,
1505                 indent: Indent,
1506                 arg_indent: Indent,
1507                 span: Span,
1508                 variadic: bool)
1509                 -> Option<String> {
1510     let mut arg_item_strs = try_opt!(args.iter()
1511         .map(|arg| arg.rewrite(&context, multi_line_budget, arg_indent))
1512         .collect::<Option<Vec<_>>>());
1513
1514     // Account for sugary self.
1515     // FIXME: the comment for the self argument is dropped. This is blocked
1516     // on rust issue #27522.
1517     let min_args =
1518         explicit_self.and_then(|explicit_self| rewrite_explicit_self(explicit_self, args, context))
1519             .map_or(1, |self_str| {
1520                 arg_item_strs[0] = self_str;
1521                 2
1522             });
1523
1524     // Comments between args.
1525     let mut arg_items = Vec::new();
1526     if min_args == 2 {
1527         arg_items.push(ListItem::from_str(""));
1528     }
1529
1530     // FIXME(#21): if there are no args, there might still be a comment, but
1531     // without spans for the comment or parens, there is no chance of
1532     // getting it right. You also don't get to put a comment on self, unless
1533     // it is explicit.
1534     if args.len() >= min_args || variadic {
1535         let comment_span_start = if min_args == 2 {
1536             let second_arg_start = if arg_has_pattern(&args[1]) {
1537                 args[1].pat.span.lo
1538             } else {
1539                 args[1].ty.span.lo
1540             };
1541             let reduced_span = mk_sp(span.lo, second_arg_start);
1542
1543             context.codemap.span_after_last(reduced_span, ",")
1544         } else {
1545             span.lo
1546         };
1547
1548         enum ArgumentKind<'a> {
1549             Regular(&'a ast::Arg),
1550             Variadic(BytePos),
1551         }
1552
1553         let variadic_arg = if variadic {
1554             let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
1555             let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
1556             Some(ArgumentKind::Variadic(variadic_start))
1557         } else {
1558             None
1559         };
1560
1561         let more_items = itemize_list(context.codemap,
1562                                       args[min_args - 1..]
1563                                           .iter()
1564                                           .map(ArgumentKind::Regular)
1565                                           .chain(variadic_arg),
1566                                       ")",
1567                                       |arg| {
1568                                           match *arg {
1569                                               ArgumentKind::Regular(arg) => span_lo_for_arg(arg),
1570                                               ArgumentKind::Variadic(start) => start,
1571                                           }
1572                                       },
1573                                       |arg| {
1574                                           match *arg {
1575                                               ArgumentKind::Regular(arg) => arg.ty.span.hi,
1576                                               ArgumentKind::Variadic(start) => start + BytePos(3),
1577                                           }
1578                                       },
1579                                       |arg| {
1580                                           match *arg {
1581                                               ArgumentKind::Regular(..) => None,
1582                                               ArgumentKind::Variadic(..) => Some("...".to_owned()),
1583                                           }
1584                                       },
1585                                       comment_span_start,
1586                                       span.hi);
1587
1588         arg_items.extend(more_items);
1589     }
1590
1591     for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
1592         item.item = Some(arg);
1593     }
1594
1595     let indent = match context.config.fn_arg_indent {
1596         BlockIndentStyle::Inherit => indent,
1597         BlockIndentStyle::Tabbed => indent.block_indent(context.config),
1598         BlockIndentStyle::Visual => arg_indent,
1599     };
1600
1601     let tactic = definitive_tactic(&arg_items,
1602                                    context.config.fn_args_density.to_list_tactic(),
1603                                    one_line_budget);
1604     let budget = match tactic {
1605         DefinitiveListTactic::Horizontal => one_line_budget,
1606         _ => multi_line_budget,
1607     };
1608
1609     debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
1610
1611     let end_with_newline = match context.config.fn_args_layout {
1612         FnArgLayoutStyle::Block |
1613         FnArgLayoutStyle::BlockAlways => true,
1614         _ => false,
1615     };
1616
1617     let fmt = ListFormatting {
1618         tactic: tactic,
1619         separator: ",",
1620         trailing_separator: SeparatorTactic::Never,
1621         indent: indent,
1622         width: budget,
1623         ends_with_newline: end_with_newline,
1624         config: context.config,
1625     };
1626
1627     write_list(&arg_items, &fmt)
1628 }
1629
1630 fn arg_has_pattern(arg: &ast::Arg) -> bool {
1631     if let ast::PatKind::Ident(_,
1632                                codemap::Spanned {
1633                                    node: ast::Ident { name: ast::Name(0u32), .. },
1634                                    ..
1635                                },
1636                                _) = arg.pat.node {
1637         false
1638     } else {
1639         true
1640     }
1641 }
1642
1643 fn compute_budgets_for_args(context: &RewriteContext,
1644                             result: &str,
1645                             indent: Indent,
1646                             ret_str_len: usize,
1647                             newline_brace: bool)
1648                             -> Option<((usize, usize, Indent))> {
1649     // Try keeping everything on the same line.
1650     if !result.contains('\n') {
1651         // 3 = `() `, space is before ret_string.
1652         let mut used_space = indent.width() + result.len() + ret_str_len + 3;
1653         if !newline_brace {
1654             used_space += 2;
1655         }
1656         let one_line_budget = context.config.max_width.checked_sub(used_space).unwrap_or(0);
1657
1658         if one_line_budget > 0 {
1659             // 4 = "() {".len()
1660             let multi_line_budget =
1661                 try_opt!(context.config.max_width.checked_sub(indent.width() + result.len() + 4));
1662
1663             return Some((one_line_budget, multi_line_budget, indent + result.len() + 1));
1664         }
1665     }
1666
1667     // Didn't work. we must force vertical layout and put args on a newline.
1668     let new_indent = indent.block_indent(context.config);
1669     let used_space = new_indent.width() + 4; // Account for `(` and `)` and possibly ` {`.
1670     let max_space = context.config.max_width;
1671     if used_space <= max_space {
1672         Some((0, max_space - used_space, new_indent))
1673     } else {
1674         // Whoops! bankrupt.
1675         None
1676     }
1677 }
1678
1679 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool {
1680     match config.fn_brace_style {
1681         BraceStyle::AlwaysNextLine => true,
1682         BraceStyle::SameLineWhere if !where_clause.predicates.is_empty() => true,
1683         _ => false,
1684     }
1685 }
1686
1687 fn rewrite_generics(context: &RewriteContext,
1688                     generics: &ast::Generics,
1689                     offset: Indent,
1690                     width: usize,
1691                     generics_offset: Indent,
1692                     span: Span)
1693                     -> Option<String> {
1694     // FIXME: convert bounds to where clauses where they get too big or if
1695     // there is a where clause at all.
1696     let lifetimes: &[_] = &generics.lifetimes;
1697     let tys: &[_] = &generics.ty_params;
1698     if lifetimes.is_empty() && tys.is_empty() {
1699         return Some(String::new());
1700     }
1701
1702     let offset = match context.config.generics_indent {
1703         BlockIndentStyle::Inherit => offset,
1704         BlockIndentStyle::Tabbed => offset.block_indent(context.config),
1705         // 1 = <
1706         BlockIndentStyle::Visual => generics_offset + 1,
1707     };
1708
1709     let h_budget = try_opt!(width.checked_sub(generics_offset.width() + 2));
1710     // FIXME: might need to insert a newline if the generics are really long.
1711
1712     // Strings for the generics.
1713     let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, h_budget, offset));
1714     let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, h_budget, offset));
1715
1716     // Extract comments between generics.
1717     let lt_spans = lifetimes.iter().map(|l| {
1718         let hi = if l.bounds.is_empty() {
1719             l.lifetime.span.hi
1720         } else {
1721             l.bounds[l.bounds.len() - 1].span.hi
1722         };
1723         mk_sp(l.lifetime.span.lo, hi)
1724     });
1725     let ty_spans = tys.iter().map(span_for_ty_param);
1726
1727     let items = itemize_list(context.codemap,
1728                              lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
1729                              ">",
1730                              |&(sp, _)| sp.lo,
1731                              |&(sp, _)| sp.hi,
1732                              // FIXME: don't clone
1733                              |&(_, ref str)| str.clone(),
1734                              context.codemap.span_after(span, "<"),
1735                              span.hi);
1736     let list_str = try_opt!(format_item_list(items, h_budget, offset, context.config));
1737
1738     Some(format!("<{}>", list_str))
1739 }
1740
1741 fn rewrite_trait_bounds(context: &RewriteContext,
1742                         type_param_bounds: &ast::TyParamBounds,
1743                         indent: Indent,
1744                         width: usize)
1745                         -> Option<String> {
1746     let bounds: &[_] = type_param_bounds;
1747
1748     if bounds.is_empty() {
1749         return Some(String::new());
1750     }
1751
1752     let bound_str = try_opt!(bounds.iter()
1753         .map(|ty_bound| ty_bound.rewrite(&context, width, indent))
1754         .intersperse(Some(" + ".to_string()))
1755         .collect::<Option<String>>());
1756
1757     let mut result = String::new();
1758     result.push_str(": ");
1759     result.push_str(&bound_str);
1760     Some(result)
1761 }
1762
1763 fn rewrite_where_clause(context: &RewriteContext,
1764                         where_clause: &ast::WhereClause,
1765                         config: &Config,
1766                         brace_style: BraceStyle,
1767                         indent: Indent,
1768                         width: usize,
1769                         density: Density,
1770                         terminator: &str,
1771                         allow_trailing_comma: bool,
1772                         span_end: Option<BytePos>)
1773                         -> Option<String> {
1774     if where_clause.predicates.is_empty() {
1775         return Some(String::new());
1776     }
1777
1778     let extra_indent = match context.config.where_indent {
1779         BlockIndentStyle::Inherit => Indent::empty(),
1780         BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => Indent::new(config.tab_spaces, 0),
1781     };
1782
1783     let offset = match context.config.where_pred_indent {
1784         BlockIndentStyle::Inherit => indent + extra_indent,
1785         BlockIndentStyle::Tabbed => indent + extra_indent.block_indent(config),
1786         // 6 = "where ".len()
1787         BlockIndentStyle::Visual => indent + extra_indent + 6,
1788     };
1789     // FIXME: if where_pred_indent != Visual, then the budgets below might
1790     // be out by a char or two.
1791
1792     let budget = context.config.max_width - offset.width();
1793     let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
1794     // If we don't have the start of the next span, then use the end of the
1795     // predicates, but that means we miss comments.
1796     let len = where_clause.predicates.len();
1797     let end_of_preds = span_for_where_pred(&where_clause.predicates[len - 1]).hi;
1798     let span_end = span_end.unwrap_or(end_of_preds);
1799     let items = itemize_list(context.codemap,
1800                              where_clause.predicates.iter(),
1801                              terminator,
1802                              |pred| span_for_where_pred(pred).lo,
1803                              |pred| span_for_where_pred(pred).hi,
1804                              |pred| pred.rewrite(context, budget, offset),
1805                              span_start,
1806                              span_end);
1807     let item_vec = items.collect::<Vec<_>>();
1808     // FIXME: we don't need to collect here if the where_layout isn't
1809     // HorizontalVertical.
1810     let tactic = definitive_tactic(&item_vec, context.config.where_layout, budget);
1811     let use_trailing_comma = allow_trailing_comma && context.config.where_trailing_comma;
1812
1813     let fmt = ListFormatting {
1814         tactic: tactic,
1815         separator: ",",
1816         trailing_separator: SeparatorTactic::from_bool(use_trailing_comma),
1817         indent: offset,
1818         width: budget,
1819         ends_with_newline: true,
1820         config: context.config,
1821     };
1822     let preds_str = try_opt!(write_list(&item_vec, &fmt));
1823
1824     let end_length = if terminator == "{" {
1825         // If the brace is on the next line we don't need to count it otherwise it needs two
1826         // characters " {"
1827         match brace_style {
1828             BraceStyle::AlwaysNextLine |
1829             BraceStyle::SameLineWhere => 0,
1830             BraceStyle::PreferSameLine => 2,
1831         }
1832     } else if terminator == "=" {
1833         2
1834     } else {
1835         terminator.len()
1836     };
1837     if density == Density::Tall || preds_str.contains('\n') ||
1838        indent.width() + " where ".len() + preds_str.len() + end_length > width {
1839         Some(format!("\n{}where {}",
1840                      (indent + extra_indent).to_string(context.config),
1841                      preds_str))
1842     } else {
1843         Some(format!(" where {}", preds_str))
1844     }
1845 }
1846
1847 fn format_header(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
1848     format!("{}{}{}", format_visibility(vis), item_name, ident)
1849 }
1850
1851 fn format_generics(context: &RewriteContext,
1852                    generics: &ast::Generics,
1853                    opener: &str,
1854                    terminator: &str,
1855                    brace_style: BraceStyle,
1856                    force_same_line_brace: bool,
1857                    offset: Indent,
1858                    generics_offset: Indent,
1859                    span: Span)
1860                    -> Option<String> {
1861     let mut result = try_opt!(rewrite_generics(context,
1862                                                generics,
1863                                                offset,
1864                                                context.config.max_width,
1865                                                generics_offset,
1866                                                span));
1867
1868     if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
1869         let budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
1870         let where_clause_str = try_opt!(rewrite_where_clause(context,
1871                                                              &generics.where_clause,
1872                                                              context.config,
1873                                                              brace_style,
1874                                                              context.block_indent,
1875                                                              budget,
1876                                                              Density::Tall,
1877                                                              terminator,
1878                                                              true,
1879                                                              Some(span.hi)));
1880         result.push_str(&where_clause_str);
1881         if !force_same_line_brace &&
1882            (brace_style == BraceStyle::SameLineWhere || brace_style == BraceStyle::AlwaysNextLine) {
1883             result.push('\n');
1884             result.push_str(&context.block_indent.to_string(context.config));
1885         } else {
1886             result.push(' ');
1887         }
1888         result.push_str(opener);
1889     } else {
1890         if !force_same_line_brace && brace_style == BraceStyle::AlwaysNextLine {
1891             result.push('\n');
1892             result.push_str(&context.block_indent.to_string(context.config));
1893         } else {
1894             result.push(' ');
1895         }
1896         result.push_str(opener);
1897     }
1898
1899     Some(result)
1900 }