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