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