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