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