]> git.lizzy.rs Git - rust.git/blob - src/items.rs
Force vertical layout when struct_variant_width is 0
[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             visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
644             for item in items {
645                 visitor.visit_impl_item(item);
646             }
647
648             visitor.format_missing(item.span.hi - BytePos(1));
649
650             let inner_indent_str = visitor.block_indent.to_string(context.config);
651             let outer_indent_str = offset.block_only().to_string(context.config);
652
653             result.push('\n');
654             result.push_str(&inner_indent_str);
655             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
656             result.push('\n');
657             result.push_str(&outer_indent_str);
658         }
659
660         if result.chars().last().unwrap() == '{' {
661             result.push('\n');
662             result.push_str(&offset.to_string(context.config));
663         }
664         result.push('}');
665
666         Some(result)
667     } else {
668         unreachable!();
669     }
670 }
671
672 fn is_impl_single_line(
673     context: &RewriteContext,
674     items: &[ImplItem],
675     result: &str,
676     where_clause_str: &str,
677     item: &ast::Item,
678 ) -> Option<bool> {
679     let snippet = context.snippet(item.span);
680     let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
681
682     Some(
683         context.config.impl_empty_single_line() && items.is_empty() &&
684             result.len() + where_clause_str.len() <= context.config.max_width() &&
685             !contains_comment(&snippet[open_pos..]),
686     )
687 }
688
689 fn format_impl_ref_and_type(
690     context: &RewriteContext,
691     item: &ast::Item,
692     offset: Indent,
693 ) -> Option<String> {
694     if let ast::ItemKind::Impl(
695         unsafety,
696         polarity,
697         _,
698         ref generics,
699         ref trait_ref,
700         ref self_ty,
701         _,
702     ) = item.node
703     {
704         let mut result = String::new();
705
706         result.push_str(&format_visibility(&item.vis));
707         result.push_str(format_unsafety(unsafety));
708         result.push_str("impl");
709
710         let lo = context.codemap.span_after(item.span, "impl");
711         let hi = match *trait_ref {
712             Some(ref tr) => tr.path.span.lo,
713             None => self_ty.span.lo,
714         };
715         let shape = try_opt!(generics_shape_from_config(
716             context.config,
717             Shape::indented(offset + last_line_width(&result), context.config),
718             0,
719         ));
720         let one_line_budget = try_opt!(shape.width.checked_sub(last_line_width(&result) + 2));
721         let generics_str = try_opt!(rewrite_generics_inner(
722             context,
723             generics,
724             shape,
725             one_line_budget,
726             mk_sp(lo, hi),
727         ));
728
729         let polarity_str = if polarity == ast::ImplPolarity::Negative {
730             "!"
731         } else {
732             ""
733         };
734
735         if let Some(ref trait_ref) = *trait_ref {
736             let result_len = result.len();
737             if let Some(trait_ref_str) = rewrite_trait_ref(
738                 context,
739                 &trait_ref,
740                 offset,
741                 &generics_str,
742                 true,
743                 polarity_str,
744                 result_len,
745             ) {
746                 result.push_str(&trait_ref_str);
747             } else {
748                 let generics_str = try_opt!(rewrite_generics_inner(
749                     context,
750                     generics,
751                     shape,
752                     0,
753                     mk_sp(lo, hi),
754                 ));
755                 result.push_str(&try_opt!(rewrite_trait_ref(
756                     context,
757                     &trait_ref,
758                     offset,
759                     &generics_str,
760                     false,
761                     polarity_str,
762                     result_len,
763                 )));
764             }
765         } else {
766             result.push_str(&generics_str);
767         }
768
769         // Try to put the self type in a single line.
770         // ` for`
771         let trait_ref_overhead = if trait_ref.is_some() { 4 } else { 0 };
772         let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
773             // If there is no where clause adapt budget for type formatting to take space and curly
774             // brace into account.
775             match context.config.item_brace_style() {
776                 BraceStyle::AlwaysNextLine => 0,
777                 _ => 2,
778             }
779         } else {
780             0
781         };
782         let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
783         // 1 = space before the type.
784         let budget = context
785             .config
786             .max_width()
787             .checked_sub(used_space + 1)
788             .unwrap_or(0);
789         if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
790             if !self_ty_str.contains('\n') {
791                 if trait_ref.is_some() {
792                     result.push_str(" for ");
793                 } else {
794                     result.push(' ');
795                 }
796                 result.push_str(&self_ty_str);
797                 return Some(result);
798             }
799         }
800
801         // Couldn't fit the self type on a single line, put it on a new line.
802         result.push('\n');
803         // Add indentation of one additional tab.
804         let new_line_offset = offset.block_indent(context.config);
805         result.push_str(&new_line_offset.to_string(context.config));
806         if trait_ref.is_some() {
807             result.push_str("for ");
808         }
809         let budget = context.config.max_width() - last_line_width(&result);
810         let type_offset = match context.config.where_style() {
811             Style::Legacy => new_line_offset + trait_ref_overhead,
812             Style::Rfc => new_line_offset,
813         };
814         result.push_str(&*try_opt!(
815             self_ty.rewrite(context, Shape::legacy(budget, type_offset))
816         ));
817         Some(result)
818     } else {
819         unreachable!();
820     }
821 }
822
823 fn rewrite_trait_ref(
824     context: &RewriteContext,
825     trait_ref: &ast::TraitRef,
826     offset: Indent,
827     generics_str: &str,
828     retry: bool,
829     polarity_str: &str,
830     result_len: usize,
831 ) -> Option<String> {
832     // 1 = space between generics and trait_ref
833     let used_space = 1 + polarity_str.len() + 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     let one_line_budget =
1132         one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1133
1134     let items_str = try_opt!(rewrite_with_alignment(
1135         fields,
1136         context,
1137         Shape::indented(offset, context.config),
1138         mk_sp(body_lo, span.hi),
1139         one_line_budget,
1140     ));
1141
1142     if !items_str.contains('\n') && !result.contains('\n') && items_str.len() <= one_line_budget {
1143         Some(format!("{} {} }}", result, items_str))
1144     } else {
1145         Some(format!(
1146             "{}\n{}{}\n{}}}",
1147             result,
1148             offset
1149                 .block_indent(context.config)
1150                 .to_string(context.config),
1151             items_str,
1152             offset.to_string(context.config)
1153         ))
1154     }
1155 }
1156
1157 fn format_tuple_struct(
1158     context: &RewriteContext,
1159     item_name: &str,
1160     ident: ast::Ident,
1161     vis: &ast::Visibility,
1162     fields: &[ast::StructField],
1163     generics: Option<&ast::Generics>,
1164     span: Span,
1165     offset: Indent,
1166 ) -> Option<String> {
1167     let mut result = String::with_capacity(1024);
1168
1169     let header_str = format_header(item_name, ident, vis);
1170     result.push_str(&header_str);
1171
1172     let body_lo = if fields.is_empty() {
1173         context.codemap.span_after(span, "(")
1174     } else {
1175         fields[0].span.lo
1176     };
1177     let body_hi = if fields.is_empty() {
1178         context.codemap.span_after(span, ")")
1179     } else {
1180         // This is a dirty hack to work around a missing `)` from the span of the last field.
1181         let last_arg_span = fields[fields.len() - 1].span;
1182         if context.snippet(last_arg_span).ends_with(")") {
1183             last_arg_span.hi
1184         } else {
1185             context
1186                 .codemap
1187                 .span_after(mk_sp(last_arg_span.hi, span.hi), ")")
1188         }
1189     };
1190
1191     let where_clause_str = match generics {
1192         Some(generics) => {
1193             let budget = context.budget(last_line_width(&header_str));
1194             let shape = Shape::legacy(budget, offset);
1195             let g_span = mk_sp(span.lo, body_lo);
1196             let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1197             result.push_str(&generics_str);
1198
1199             let where_budget = context.budget(last_line_width(&result));
1200             try_opt!(rewrite_where_clause(
1201                 context,
1202                 &generics.where_clause,
1203                 context.config.item_brace_style(),
1204                 Shape::legacy(where_budget, offset.block_only()),
1205                 Density::Compressed,
1206                 ";",
1207                 true,
1208                 false,
1209                 None,
1210                 span,
1211                 body_hi,
1212             ))
1213         }
1214         None => "".to_owned(),
1215     };
1216
1217     if fields.is_empty() {
1218         // 3 = `();`
1219         let used_width = if result.contains('\n') {
1220             last_line_width(&result) + 3
1221         } else {
1222             offset.width() + result.len() + 3
1223         };
1224         if used_width > context.config.max_width() {
1225             result.push('\n');
1226             result.push_str(&offset
1227                 .block_indent(context.config)
1228                 .to_string(context.config))
1229         }
1230         result.push('(');
1231         let snippet = context.snippet(mk_sp(body_lo, context.codemap.span_before(span, ")")));
1232         if snippet.is_empty() {
1233             // `struct S ()`
1234         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1235             result.push_str(&snippet.trim_right());
1236             result.push('\n');
1237             result.push_str(&offset.to_string(context.config));
1238         } else {
1239             result.push_str(&snippet);
1240         }
1241         result.push(')');
1242     } else {
1243         // 3 = `();`
1244         let body = try_opt!(
1245             rewrite_call_inner(
1246                 context,
1247                 "",
1248                 &fields.iter().map(|field| field).collect::<Vec<_>>()[..],
1249                 span,
1250                 Shape::legacy(context.budget(last_line_width(&result) + 3), offset),
1251                 context.config.fn_call_width(),
1252                 false,
1253             ).ok()
1254         );
1255         result.push_str(&body);
1256     }
1257
1258     if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
1259         (result.contains('\n') ||
1260             offset.block_indent + result.len() + where_clause_str.len() + 1 >
1261                 context.config.max_width())
1262     {
1263         // We need to put the where clause on a new line, but we didn't
1264         // know that earlier, so the where clause will not be indented properly.
1265         result.push('\n');
1266         result.push_str(&(offset.block_only() + (context.config.tab_spaces() - 1))
1267             .to_string(context.config));
1268     }
1269     result.push_str(&where_clause_str);
1270
1271     Some(result)
1272 }
1273
1274 pub fn rewrite_type_alias(
1275     context: &RewriteContext,
1276     indent: Indent,
1277     ident: ast::Ident,
1278     ty: &ast::Ty,
1279     generics: &ast::Generics,
1280     vis: &ast::Visibility,
1281     span: Span,
1282 ) -> Option<String> {
1283     let mut result = String::new();
1284
1285     result.push_str(&format_visibility(vis));
1286     result.push_str("type ");
1287     result.push_str(&ident.to_string());
1288
1289     // 2 = `= `
1290     let shape = try_opt!(Shape::indented(indent + result.len(), context.config).sub_width(2));
1291     let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo);
1292     let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1293     result.push_str(&generics_str);
1294
1295     let where_budget = try_opt!(
1296         context
1297             .config
1298             .max_width()
1299             .checked_sub(last_line_width(&result))
1300     );
1301     let where_clause_str = try_opt!(rewrite_where_clause(
1302         context,
1303         &generics.where_clause,
1304         context.config.item_brace_style(),
1305         Shape::legacy(where_budget, indent),
1306         context.config.where_density(),
1307         "=",
1308         true,
1309         true,
1310         Some(span.hi),
1311         span,
1312         generics.span.hi,
1313     ));
1314     result.push_str(&where_clause_str);
1315     result.push_str(" = ");
1316
1317     let line_width = last_line_width(&result);
1318     // This checked_sub may fail as the extra space after '=' is not taken into account
1319     // In that case the budget is set to 0 which will make ty.rewrite retry on a new line
1320     let budget = context
1321         .config
1322         .max_width()
1323         .checked_sub(indent.width() + line_width + ";".len())
1324         .unwrap_or(0);
1325     let type_indent = indent + line_width;
1326     // Try to fit the type on the same line
1327     let ty_str = try_opt!(
1328         ty.rewrite(context, Shape::legacy(budget, type_indent))
1329             .or_else(|| {
1330                 // The line was too short, try to put the type on the next line
1331
1332                 // Remove the space after '='
1333                 result.pop();
1334                 let type_indent = indent.block_indent(context.config);
1335                 result.push('\n');
1336                 result.push_str(&type_indent.to_string(context.config));
1337                 let budget = try_opt!(
1338                     context
1339                         .config
1340                         .max_width()
1341                         .checked_sub(type_indent.width() + ";".len())
1342                 );
1343                 ty.rewrite(context, Shape::legacy(budget, type_indent))
1344             })
1345     );
1346     result.push_str(&ty_str);
1347     result.push_str(";");
1348     Some(result)
1349 }
1350
1351 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1352     (
1353         if config.space_before_type_annotation() {
1354             " "
1355         } else {
1356             ""
1357         },
1358         if config.space_after_type_annotation_colon() {
1359             " "
1360         } else {
1361             ""
1362         },
1363     )
1364 }
1365
1366 fn rewrite_missing_comment_on_field(
1367     context: &RewriteContext,
1368     shape: Shape,
1369     lo: BytePos,
1370     hi: BytePos,
1371     result: &mut String,
1372 ) -> Option<String> {
1373     let possibly_comment_snippet = context.snippet(mk_sp(lo, hi));
1374     let newline_index = possibly_comment_snippet.find('\n');
1375     let comment_index = possibly_comment_snippet.find('/');
1376     match (newline_index, comment_index) {
1377         (Some(i), Some(j)) if i > j => result.push(' '),
1378         _ => {
1379             result.push('\n');
1380             result.push_str(&shape.indent.to_string(context.config));
1381         }
1382     }
1383     let trimmed = possibly_comment_snippet.trim();
1384     if trimmed.is_empty() {
1385         None
1386     } else {
1387         rewrite_comment(trimmed, false, shape, context.config).map(|s| {
1388             format!("{}\n{}", s, shape.indent.to_string(context.config))
1389         })
1390     }
1391 }
1392
1393 pub fn rewrite_struct_field_prefix(
1394     context: &RewriteContext,
1395     field: &ast::StructField,
1396     shape: Shape,
1397 ) -> Option<String> {
1398     let vis = format_visibility(&field.vis);
1399     let mut attr_str = try_opt!(
1400         field
1401             .attrs
1402             .rewrite(context, Shape::indented(shape.indent, context.config))
1403     );
1404     // Try format missing comments after attributes
1405     let missing_comment = if !field.attrs.is_empty() {
1406         rewrite_missing_comment_on_field(
1407             context,
1408             shape,
1409             field.attrs[field.attrs.len() - 1].span.hi,
1410             field.span.lo,
1411             &mut attr_str,
1412         ).unwrap_or(String::new())
1413     } else {
1414         String::new()
1415     };
1416
1417     let type_annotation_spacing = type_annotation_spacing(context.config);
1418     Some(match field.ident {
1419         Some(name) => format!(
1420             "{}{}{}{}{}:",
1421             attr_str,
1422             missing_comment,
1423             vis,
1424             name,
1425             type_annotation_spacing.0
1426         ),
1427         None => format!("{}{}{}", attr_str, missing_comment, vis),
1428     })
1429 }
1430
1431 fn rewrite_struct_field_type(
1432     context: &RewriteContext,
1433     last_line_width: usize,
1434     field: &ast::StructField,
1435     spacing: &str,
1436     shape: Shape,
1437 ) -> Option<String> {
1438     let ty_shape = try_opt!(shape.offset_left(last_line_width + spacing.len()));
1439     field
1440         .ty
1441         .rewrite(context, ty_shape)
1442         .map(|ty| format!("{}{}", spacing, ty))
1443 }
1444
1445 impl Rewrite for ast::StructField {
1446     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1447         rewrite_struct_field(context, self, shape, 0)
1448     }
1449 }
1450
1451 pub fn rewrite_struct_field(
1452     context: &RewriteContext,
1453     field: &ast::StructField,
1454     shape: Shape,
1455     lhs_max_width: usize,
1456 ) -> Option<String> {
1457     if contains_skip(&field.attrs) {
1458         let span = context.snippet(mk_sp(field.attrs[0].span.lo, field.span.hi));
1459         return wrap_str(span, context.config.max_width(), shape);
1460     }
1461
1462     let type_annotation_spacing = type_annotation_spacing(context.config);
1463     let prefix = try_opt!(rewrite_struct_field_prefix(context, field, shape));
1464
1465     // Try to put everything on a single line.
1466     let last_line_width = last_line_width(&prefix);
1467     let mut spacing = String::from(if field.ident.is_some() {
1468         type_annotation_spacing.1
1469     } else {
1470         ""
1471     });
1472     let lhs_offset = lhs_max_width.checked_sub(last_line_width).unwrap_or(0);
1473     for _ in 0..lhs_offset {
1474         spacing.push(' ');
1475     }
1476     let ty_rewritten = rewrite_struct_field_type(context, last_line_width, field, &spacing, shape);
1477     if let Some(ref ty) = ty_rewritten {
1478         if !ty.contains('\n') {
1479             return Some(prefix + &ty);
1480         }
1481     }
1482
1483     // We must use multiline.
1484     let type_offset = shape.indent.block_indent(context.config);
1485     let rewrite_type_in_next_line = || {
1486         field
1487             .ty
1488             .rewrite(context, Shape::indented(type_offset, context.config))
1489     };
1490
1491     match ty_rewritten {
1492         // If we start from the next line and type fits in a single line, then do so.
1493         Some(ref ty) => match rewrite_type_in_next_line() {
1494             Some(ref new_ty) if !new_ty.contains('\n') => Some(format!(
1495                 "{}\n{}{}",
1496                 prefix,
1497                 type_offset.to_string(&context.config),
1498                 &new_ty
1499             )),
1500             _ => Some(prefix + &ty),
1501         },
1502         _ => {
1503             let ty = try_opt!(rewrite_type_in_next_line());
1504             Some(format!(
1505                 "{}\n{}{}",
1506                 prefix,
1507                 type_offset.to_string(&context.config),
1508                 &ty
1509             ))
1510         }
1511     }
1512 }
1513
1514 pub fn rewrite_static(
1515     prefix: &str,
1516     vis: &ast::Visibility,
1517     ident: ast::Ident,
1518     ty: &ast::Ty,
1519     mutability: ast::Mutability,
1520     expr_opt: Option<&ptr::P<ast::Expr>>,
1521     offset: Indent,
1522     span: Span,
1523     context: &RewriteContext,
1524 ) -> Option<String> {
1525     let colon = colon_spaces(
1526         context.config.space_before_type_annotation(),
1527         context.config.space_after_type_annotation_colon(),
1528     );
1529     let prefix = format!(
1530         "{}{} {}{}{}",
1531         format_visibility(vis),
1532         prefix,
1533         format_mutability(mutability),
1534         ident,
1535         colon,
1536     );
1537     // 2 = " =".len()
1538     let ty_str = try_opt!(ty.rewrite(
1539         context,
1540         try_opt!(
1541             Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)
1542         ),
1543     ));
1544
1545     if let Some(expr) = expr_opt {
1546         let lhs = format!("{}{} =", prefix, ty_str);
1547         // 1 = ;
1548         let remaining_width = context.config.max_width() - offset.block_indent - 1;
1549         rewrite_assign_rhs(
1550             context,
1551             lhs,
1552             expr,
1553             Shape::legacy(remaining_width, offset.block_only()),
1554         ).and_then(|res| {
1555             recover_comment_removed(res, span, context, Shape::indented(offset, context.config))
1556         })
1557             .map(|s| if s.ends_with(';') { s } else { s + ";" })
1558     } else {
1559         Some(format!("{}{};", prefix, ty_str))
1560     }
1561 }
1562
1563 pub fn rewrite_associated_type(
1564     ident: ast::Ident,
1565     ty_opt: Option<&ptr::P<ast::Ty>>,
1566     ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1567     context: &RewriteContext,
1568     indent: Indent,
1569 ) -> Option<String> {
1570     let prefix = format!("type {}", ident);
1571
1572     let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
1573         let shape = Shape::indented(indent, context.config);
1574         let bounds: &[_] = ty_param_bounds;
1575         let bound_str = try_opt!(
1576             bounds
1577                 .iter()
1578                 .map(|ty_bound| ty_bound.rewrite(context, shape))
1579                 .collect::<Option<Vec<_>>>()
1580         );
1581         if bounds.len() > 0 {
1582             format!(": {}", join_bounds(context, shape, &bound_str))
1583         } else {
1584             String::new()
1585         }
1586     } else {
1587         String::new()
1588     };
1589
1590     if let Some(ty) = ty_opt {
1591         let ty_str = try_opt!(ty.rewrite(
1592             context,
1593             Shape::legacy(
1594                 context.config.max_width() - indent.block_indent - prefix.len() - 2,
1595                 indent.block_only(),
1596             ),
1597         ));
1598         Some(format!("{} = {};", prefix, ty_str))
1599     } else {
1600         Some(format!("{}{};", prefix, type_bounds_str))
1601     }
1602 }
1603
1604 pub fn rewrite_associated_impl_type(
1605     ident: ast::Ident,
1606     defaultness: ast::Defaultness,
1607     ty_opt: Option<&ptr::P<ast::Ty>>,
1608     ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1609     context: &RewriteContext,
1610     indent: Indent,
1611 ) -> Option<String> {
1612     let result = try_opt!(rewrite_associated_type(
1613         ident,
1614         ty_opt,
1615         ty_param_bounds_opt,
1616         context,
1617         indent,
1618     ));
1619
1620     match defaultness {
1621         ast::Defaultness::Default => Some(format!("default {}", result)),
1622         _ => Some(result),
1623     }
1624 }
1625
1626 impl Rewrite for ast::FunctionRetTy {
1627     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1628         match *self {
1629             ast::FunctionRetTy::Default(_) => Some(String::new()),
1630             ast::FunctionRetTy::Ty(ref ty) => {
1631                 let inner_width = try_opt!(shape.width.checked_sub(3));
1632                 ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1633                     .map(|r| format!("-> {}", r))
1634             }
1635         }
1636     }
1637 }
1638
1639 fn is_empty_infer(context: &RewriteContext, ty: &ast::Ty) -> bool {
1640     match ty.node {
1641         ast::TyKind::Infer => {
1642             let original = context.snippet(ty.span);
1643             original != "_"
1644         }
1645         _ => false,
1646     }
1647 }
1648
1649 impl Rewrite for ast::Arg {
1650     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1651         if is_named_arg(self) {
1652             let mut result = try_opt!(
1653                 self.pat
1654                     .rewrite(context, Shape::legacy(shape.width, shape.indent))
1655             );
1656
1657             if !is_empty_infer(context, &*self.ty) {
1658                 if context.config.space_before_type_annotation() {
1659                     result.push_str(" ");
1660                 }
1661                 result.push_str(":");
1662                 if context.config.space_after_type_annotation_colon() {
1663                     result.push_str(" ");
1664                 }
1665                 let max_width = try_opt!(shape.width.checked_sub(result.len()));
1666                 let ty_str = try_opt!(self.ty.rewrite(
1667                     context,
1668                     Shape::legacy(max_width, shape.indent + result.len()),
1669                 ));
1670                 result.push_str(&ty_str);
1671             }
1672
1673             Some(result)
1674         } else {
1675             self.ty.rewrite(context, shape)
1676         }
1677     }
1678 }
1679
1680 fn rewrite_explicit_self(
1681     explicit_self: &ast::ExplicitSelf,
1682     args: &[ast::Arg],
1683     context: &RewriteContext,
1684 ) -> Option<String> {
1685     match explicit_self.node {
1686         ast::SelfKind::Region(lt, m) => {
1687             let mut_str = format_mutability(m);
1688             match lt {
1689                 Some(ref l) => {
1690                     let lifetime_str = try_opt!(l.rewrite(
1691                         context,
1692                         Shape::legacy(context.config.max_width(), Indent::empty()),
1693                     ));
1694                     Some(format!("&{} {}self", lifetime_str, mut_str))
1695                 }
1696                 None => Some(format!("&{}self", mut_str)),
1697             }
1698         }
1699         ast::SelfKind::Explicit(ref ty, _) => {
1700             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1701
1702             let mutability = explicit_self_mutability(&args[0]);
1703             let type_str = try_opt!(ty.rewrite(
1704                 context,
1705                 Shape::legacy(context.config.max_width(), Indent::empty()),
1706             ));
1707
1708             Some(format!(
1709                 "{}self: {}",
1710                 format_mutability(mutability),
1711                 type_str
1712             ))
1713         }
1714         ast::SelfKind::Value(_) => {
1715             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1716
1717             let mutability = explicit_self_mutability(&args[0]);
1718
1719             Some(format!("{}self", format_mutability(mutability)))
1720         }
1721     }
1722 }
1723
1724 // Hacky solution caused by absence of `Mutability` in `SelfValue` and
1725 // `SelfExplicit` variants of `ast::ExplicitSelf_`.
1726 fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
1727     if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node {
1728         mutability
1729     } else {
1730         unreachable!()
1731     }
1732 }
1733
1734 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
1735     if is_named_arg(arg) {
1736         arg.pat.span.lo
1737     } else {
1738         arg.ty.span.lo
1739     }
1740 }
1741
1742 pub fn span_hi_for_arg(context: &RewriteContext, arg: &ast::Arg) -> BytePos {
1743     match arg.ty.node {
1744         ast::TyKind::Infer if context.snippet(arg.ty.span) == "_" => arg.ty.span.hi,
1745         ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi,
1746         _ => arg.ty.span.hi,
1747     }
1748 }
1749
1750 pub fn is_named_arg(arg: &ast::Arg) -> bool {
1751     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1752         ident.node != symbol::keywords::Invalid.ident()
1753     } else {
1754         true
1755     }
1756 }
1757
1758 // Return type is (result, force_new_line_for_brace)
1759 fn rewrite_fn_base(
1760     context: &RewriteContext,
1761     indent: Indent,
1762     ident: ast::Ident,
1763     fd: &ast::FnDecl,
1764     generics: &ast::Generics,
1765     unsafety: ast::Unsafety,
1766     constness: ast::Constness,
1767     defaultness: ast::Defaultness,
1768     abi: abi::Abi,
1769     vis: &ast::Visibility,
1770     span: Span,
1771     newline_brace: bool,
1772     has_body: bool,
1773     has_braces: bool,
1774 ) -> Option<(String, bool)> {
1775     let mut force_new_line_for_brace = false;
1776
1777     let where_clause = &generics.where_clause;
1778
1779     let mut result = String::with_capacity(1024);
1780     // Vis unsafety abi.
1781     result.push_str(&*format_visibility(vis));
1782
1783     if let ast::Defaultness::Default = defaultness {
1784         result.push_str("default ");
1785     }
1786
1787     if let ast::Constness::Const = constness {
1788         result.push_str("const ");
1789     }
1790
1791     result.push_str(::utils::format_unsafety(unsafety));
1792
1793     if abi != abi::Abi::Rust {
1794         result.push_str(&::utils::format_abi(
1795             abi,
1796             context.config.force_explicit_abi(),
1797         ));
1798     }
1799
1800     // fn foo
1801     result.push_str("fn ");
1802     result.push_str(&ident.to_string());
1803
1804     // Generics.
1805     let overhead = if has_braces && !newline_brace {
1806         // 4 = `() {`
1807         4
1808     } else {
1809         // 2 = `()`
1810         2
1811     };
1812     let shape = try_opt!(
1813         Shape::indented(indent + last_line_width(&result), context.config).sub_width(overhead)
1814     );
1815     let g_span = mk_sp(span.lo, fd.output.span().lo);
1816     let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1817     result.push_str(&generics_str);
1818
1819     let snuggle_angle_bracket = generics_str
1820         .lines()
1821         .last()
1822         .map_or(false, |l| l.trim_left().len() == 1);
1823
1824     // Note that the width and indent don't really matter, we'll re-layout the
1825     // return type later anyway.
1826     let ret_str = try_opt!(
1827         fd.output
1828             .rewrite(&context, Shape::indented(indent, context.config))
1829     );
1830
1831     let multi_line_ret_str = ret_str.contains('\n');
1832     let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
1833
1834     // Args.
1835     let (mut one_line_budget, mut multi_line_budget, mut arg_indent) =
1836         try_opt!(compute_budgets_for_args(
1837             context,
1838             &result,
1839             indent,
1840             ret_str_len,
1841             newline_brace,
1842             has_braces,
1843         ));
1844
1845     if context.config.fn_args_layout() == IndentStyle::Block {
1846         arg_indent = indent.block_indent(context.config);
1847         // 1 = ","
1848         multi_line_budget = context.config.max_width() - (arg_indent.width() + 1);
1849     }
1850
1851     debug!(
1852         "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
1853         one_line_budget,
1854         multi_line_budget,
1855         arg_indent
1856     );
1857
1858     // Check if vertical layout was forced.
1859     if one_line_budget == 0 {
1860         if snuggle_angle_bracket {
1861             result.push('(');
1862         } else {
1863             if context.config.fn_args_paren_newline() {
1864                 result.push('\n');
1865                 result.push_str(&arg_indent.to_string(context.config));
1866                 if context.config.fn_args_layout() == IndentStyle::Visual {
1867                     arg_indent = arg_indent + 1; // extra space for `(`
1868                 }
1869                 result.push('(');
1870             } else {
1871                 result.push_str("(");
1872                 if context.config.fn_args_layout() == IndentStyle::Visual {
1873                     result.push('\n');
1874                     result.push_str(&arg_indent.to_string(context.config));
1875                 }
1876             }
1877         }
1878     } else {
1879         result.push('(');
1880     }
1881     if context.config.spaces_within_parens() && fd.inputs.len() > 0 && result.ends_with('(') {
1882         result.push(' ')
1883     }
1884
1885     if multi_line_ret_str {
1886         one_line_budget = 0;
1887     }
1888
1889     // A conservative estimation, to goal is to be over all parens in generics
1890     let args_start = generics
1891         .ty_params
1892         .last()
1893         .map_or(span.lo, |tp| end_typaram(tp));
1894     let args_end = if fd.inputs.is_empty() {
1895         context.codemap.span_after(mk_sp(args_start, span.hi), ")")
1896     } else {
1897         let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi, span.hi);
1898         context.codemap.span_after(last_span, ")")
1899     };
1900     let args_span = mk_sp(
1901         context.codemap.span_after(mk_sp(args_start, span.hi), "("),
1902         args_end,
1903     );
1904     let arg_str = try_opt!(rewrite_args(
1905         context,
1906         &fd.inputs,
1907         fd.get_self().as_ref(),
1908         one_line_budget,
1909         multi_line_budget,
1910         indent,
1911         arg_indent,
1912         args_span,
1913         fd.variadic,
1914         generics_str.contains('\n'),
1915     ));
1916
1917     let multi_line_arg_str =
1918         arg_str.contains('\n') || arg_str.chars().last().map_or(false, |c| c == ',');
1919
1920     let put_args_in_block = match context.config.fn_args_layout() {
1921         IndentStyle::Block => multi_line_arg_str || generics_str.contains('\n'),
1922         _ => false,
1923     } && !fd.inputs.is_empty();
1924
1925     let mut args_last_line_contains_comment = false;
1926     if put_args_in_block {
1927         arg_indent = indent.block_indent(context.config);
1928         result.push('\n');
1929         result.push_str(&arg_indent.to_string(context.config));
1930         result.push_str(&arg_str);
1931         result.push('\n');
1932         result.push_str(&indent.to_string(context.config));
1933         result.push(')');
1934     } else {
1935         result.push_str(&arg_str);
1936         if context.config.spaces_within_parens() && fd.inputs.len() > 0 {
1937             result.push(' ')
1938         }
1939         // If the last line of args contains comment, we cannot put the closing paren
1940         // on the same line.
1941         if arg_str
1942             .lines()
1943             .last()
1944             .map_or(false, |last_line| last_line.contains("//"))
1945         {
1946             args_last_line_contains_comment = true;
1947             result.push('\n');
1948             result.push_str(&arg_indent.to_string(context.config));
1949         }
1950         result.push(')');
1951     }
1952
1953     // Return type.
1954     if !ret_str.is_empty() {
1955         let ret_should_indent = match context.config.fn_args_layout() {
1956             // If our args are block layout then we surely must have space.
1957             IndentStyle::Block if put_args_in_block => false,
1958             _ => {
1959                 // If we've already gone multi-line, or the return type would push over the max
1960                 // width, then put the return type on a new line. With the +1 for the signature
1961                 // length an additional space between the closing parenthesis of the argument and
1962                 // the arrow '->' is considered.
1963                 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
1964
1965                 // If there is no where clause, take into account the space after the return type
1966                 // and the brace.
1967                 if where_clause.predicates.is_empty() {
1968                     sig_length += 2;
1969                 }
1970
1971                 let overlong_sig = sig_length > context.config.max_width();
1972
1973                 (!args_last_line_contains_comment) &&
1974                     (result.contains('\n') || multi_line_ret_str || overlong_sig)
1975             }
1976         };
1977         let ret_indent = if ret_should_indent {
1978             let indent = match context.config.fn_return_indent() {
1979                 ReturnIndent::WithWhereClause => indent + 4,
1980                 // Aligning with non-existent args looks silly.
1981                 _ if arg_str.is_empty() => {
1982                     force_new_line_for_brace = true;
1983                     indent + 4
1984                 }
1985                 // FIXME: we might want to check that using the arg indent
1986                 // doesn't blow our budget, and if it does, then fallback to
1987                 // the where clause indent.
1988                 _ => arg_indent,
1989             };
1990
1991             result.push('\n');
1992             result.push_str(&indent.to_string(context.config));
1993             indent
1994         } else {
1995             result.push(' ');
1996             Indent::new(indent.block_indent, last_line_width(&result))
1997         };
1998
1999         if multi_line_ret_str || ret_should_indent {
2000             // Now that we know the proper indent and width, we need to
2001             // re-layout the return type.
2002             let ret_str = try_opt!(
2003                 fd.output
2004                     .rewrite(context, Shape::indented(ret_indent, context.config))
2005             );
2006             result.push_str(&ret_str);
2007         } else {
2008             result.push_str(&ret_str);
2009         }
2010
2011         // Comment between return type and the end of the decl.
2012         let snippet_lo = fd.output.span().hi;
2013         if where_clause.predicates.is_empty() {
2014             let snippet_hi = span.hi;
2015             let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
2016             // Try to preserve the layout of the original snippet.
2017             let original_starts_with_newline = snippet
2018                 .find(|c| c != ' ')
2019                 .map_or(false, |i| snippet[i..].starts_with('\n'));
2020             let original_ends_with_newline = snippet
2021                 .rfind(|c| c != ' ')
2022                 .map_or(false, |i| snippet[i..].ends_with('\n'));
2023             let snippet = snippet.trim();
2024             if !snippet.is_empty() {
2025                 result.push(if original_starts_with_newline {
2026                     '\n'
2027                 } else {
2028                     ' '
2029                 });
2030                 result.push_str(snippet);
2031                 if original_ends_with_newline {
2032                     force_new_line_for_brace = true;
2033                 }
2034             }
2035         } else {
2036             // FIXME it would be nice to catch comments between the return type
2037             // and the where clause, but we don't have a span for the where
2038             // clause.
2039         }
2040     }
2041
2042     let should_compress_where = match context.config.where_density() {
2043         Density::Compressed => !result.contains('\n') || put_args_in_block,
2044         Density::CompressedIfEmpty => !has_body && !result.contains('\n'),
2045         _ => false,
2046     } || (put_args_in_block && ret_str.is_empty());
2047
2048     let pos_before_where = match fd.output {
2049         ast::FunctionRetTy::Default(..) => args_span.hi,
2050         ast::FunctionRetTy::Ty(ref ty) => ty.span.hi,
2051     };
2052     if where_clause.predicates.len() == 1 && should_compress_where {
2053         let budget = try_opt!(
2054             context
2055                 .config
2056                 .max_width()
2057                 .checked_sub(last_line_width(&result))
2058         );
2059         if let Some(where_clause_str) = rewrite_where_clause(
2060             context,
2061             where_clause,
2062             context.config.fn_brace_style(),
2063             Shape::legacy(budget, indent),
2064             Density::Compressed,
2065             "{",
2066             !has_braces,
2067             put_args_in_block && ret_str.is_empty(),
2068             Some(span.hi),
2069             span,
2070             pos_before_where,
2071         ) {
2072             if !where_clause_str.contains('\n') {
2073                 if last_line_width(&result) + where_clause_str.len() > context.config.max_width() {
2074                     result.push('\n');
2075                 }
2076
2077                 result.push_str(&where_clause_str);
2078
2079                 force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
2080                 return Some((result, force_new_line_for_brace));
2081             }
2082         }
2083     }
2084
2085     let where_clause_str = try_opt!(rewrite_where_clause(
2086         context,
2087         where_clause,
2088         context.config.fn_brace_style(),
2089         Shape::indented(indent, context.config),
2090         Density::Tall,
2091         "{",
2092         !has_braces,
2093         put_args_in_block && ret_str.is_empty(),
2094         Some(span.hi),
2095         span,
2096         pos_before_where,
2097     ));
2098
2099     result.push_str(&where_clause_str);
2100
2101     force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
2102     return Some((result, force_new_line_for_brace));
2103 }
2104
2105 fn last_line_contains_single_line_comment(s: &str) -> bool {
2106     s.lines().last().map_or(false, |l| l.contains("//"))
2107 }
2108
2109 fn rewrite_args(
2110     context: &RewriteContext,
2111     args: &[ast::Arg],
2112     explicit_self: Option<&ast::ExplicitSelf>,
2113     one_line_budget: usize,
2114     multi_line_budget: usize,
2115     indent: Indent,
2116     arg_indent: Indent,
2117     span: Span,
2118     variadic: bool,
2119     generics_str_contains_newline: bool,
2120 ) -> Option<String> {
2121     let mut arg_item_strs = try_opt!(
2122         args.iter()
2123             .map(|arg| {
2124                 arg.rewrite(&context, Shape::legacy(multi_line_budget, arg_indent))
2125             })
2126             .collect::<Option<Vec<_>>>()
2127     );
2128
2129     // Account for sugary self.
2130     // FIXME: the comment for the self argument is dropped. This is blocked
2131     // on rust issue #27522.
2132     let min_args = explicit_self
2133         .and_then(|explicit_self| {
2134             rewrite_explicit_self(explicit_self, args, context)
2135         })
2136         .map_or(1, |self_str| {
2137             arg_item_strs[0] = self_str;
2138             2
2139         });
2140
2141     // Comments between args.
2142     let mut arg_items = Vec::new();
2143     if min_args == 2 {
2144         arg_items.push(ListItem::from_str(""));
2145     }
2146
2147     // FIXME(#21): if there are no args, there might still be a comment, but
2148     // without spans for the comment or parens, there is no chance of
2149     // getting it right. You also don't get to put a comment on self, unless
2150     // it is explicit.
2151     if args.len() >= min_args || variadic {
2152         let comment_span_start = if min_args == 2 {
2153             let second_arg_start = if arg_has_pattern(&args[1]) {
2154                 args[1].pat.span.lo
2155             } else {
2156                 args[1].ty.span.lo
2157             };
2158             let reduced_span = mk_sp(span.lo, second_arg_start);
2159
2160             context.codemap.span_after_last(reduced_span, ",")
2161         } else {
2162             span.lo
2163         };
2164
2165         enum ArgumentKind<'a> {
2166             Regular(&'a ast::Arg),
2167             Variadic(BytePos),
2168         }
2169
2170         let variadic_arg = if variadic {
2171             let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
2172             let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
2173             Some(ArgumentKind::Variadic(variadic_start))
2174         } else {
2175             None
2176         };
2177
2178         let more_items = itemize_list(
2179             context.codemap,
2180             args[min_args - 1..]
2181                 .iter()
2182                 .map(ArgumentKind::Regular)
2183                 .chain(variadic_arg),
2184             ")",
2185             |arg| match *arg {
2186                 ArgumentKind::Regular(arg) => span_lo_for_arg(arg),
2187                 ArgumentKind::Variadic(start) => start,
2188             },
2189             |arg| match *arg {
2190                 ArgumentKind::Regular(arg) => arg.ty.span.hi,
2191                 ArgumentKind::Variadic(start) => start + BytePos(3),
2192             },
2193             |arg| match *arg {
2194                 ArgumentKind::Regular(..) => None,
2195                 ArgumentKind::Variadic(..) => Some("...".to_owned()),
2196             },
2197             comment_span_start,
2198             span.hi,
2199         );
2200
2201         arg_items.extend(more_items);
2202     }
2203
2204     let fits_in_one_line = !generics_str_contains_newline &&
2205         (arg_items.len() == 0 || arg_items.len() == 1 && arg_item_strs[0].len() <= one_line_budget);
2206
2207     for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
2208         item.item = Some(arg);
2209     }
2210
2211     let last_line_ends_with_comment = arg_items
2212         .iter()
2213         .last()
2214         .and_then(|item| item.post_comment.as_ref())
2215         .map_or(false, |s| s.trim().starts_with("//"));
2216
2217     let (indent, trailing_comma) = match context.config.fn_args_layout() {
2218         IndentStyle::Block if fits_in_one_line => {
2219             (indent.block_indent(context.config), SeparatorTactic::Never)
2220         }
2221         IndentStyle::Block => (
2222             indent.block_indent(context.config),
2223             context.config.trailing_comma(),
2224         ),
2225         IndentStyle::Visual if last_line_ends_with_comment => {
2226             (arg_indent, context.config.trailing_comma())
2227         }
2228         IndentStyle::Visual => (arg_indent, SeparatorTactic::Never),
2229     };
2230
2231     let tactic = definitive_tactic(
2232         &arg_items,
2233         context.config.fn_args_density().to_list_tactic(),
2234         one_line_budget,
2235     );
2236     let budget = match tactic {
2237         DefinitiveListTactic::Horizontal => one_line_budget,
2238         _ => multi_line_budget,
2239     };
2240
2241     debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
2242
2243     let fmt = ListFormatting {
2244         tactic: tactic,
2245         separator: ",",
2246         trailing_separator: if variadic {
2247             SeparatorTactic::Never
2248         } else {
2249             trailing_comma
2250         },
2251         shape: Shape::legacy(budget, indent),
2252         ends_with_newline: tactic.ends_with_newline(context.config.fn_args_layout()),
2253         config: context.config,
2254     };
2255
2256     write_list(&arg_items, &fmt)
2257 }
2258
2259 fn arg_has_pattern(arg: &ast::Arg) -> bool {
2260     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
2261         ident.node != symbol::keywords::Invalid.ident()
2262     } else {
2263         true
2264     }
2265 }
2266
2267 fn compute_budgets_for_args(
2268     context: &RewriteContext,
2269     result: &str,
2270     indent: Indent,
2271     ret_str_len: usize,
2272     newline_brace: bool,
2273     has_braces: bool,
2274 ) -> Option<((usize, usize, Indent))> {
2275     debug!(
2276         "compute_budgets_for_args {} {:?}, {}, {}",
2277         result.len(),
2278         indent,
2279         ret_str_len,
2280         newline_brace
2281     );
2282     // Try keeping everything on the same line.
2283     if !result.contains('\n') {
2284         // 2 = `()`, 3 = `() `, space is before ret_string.
2285         let overhead = if ret_str_len == 0 { 2 } else { 3 };
2286         let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2287         if has_braces {
2288             if !newline_brace {
2289                 // 2 = `{}`
2290                 used_space += 2;
2291             }
2292         } else {
2293             // 1 = `;`
2294             used_space += 1;
2295         }
2296         let one_line_budget = context
2297             .config
2298             .max_width()
2299             .checked_sub(used_space)
2300             .unwrap_or(0);
2301
2302         if one_line_budget > 0 {
2303             // 4 = "() {".len()
2304             let multi_line_overhead =
2305                 indent.width() + result.len() + if newline_brace { 2 } else { 4 };
2306             let multi_line_budget =
2307                 try_opt!(context.config.max_width().checked_sub(multi_line_overhead));
2308
2309             return Some((
2310                 one_line_budget,
2311                 multi_line_budget,
2312                 indent + result.len() + 1,
2313             ));
2314         }
2315     }
2316
2317     // Didn't work. we must force vertical layout and put args on a newline.
2318     let new_indent = indent.block_indent(context.config);
2319     // Account for `)` and possibly ` {`.
2320     let used_space = new_indent.width() + if ret_str_len == 0 { 1 } else { 3 };
2321     let max_space = try_opt!(context.config.max_width().checked_sub(used_space));
2322     Some((0, max_space, new_indent))
2323 }
2324
2325 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool {
2326     match config.fn_brace_style() {
2327         BraceStyle::AlwaysNextLine => true,
2328         BraceStyle::SameLineWhere if !where_clause.predicates.is_empty() => true,
2329         _ => false,
2330     }
2331 }
2332
2333 fn rewrite_generics(
2334     context: &RewriteContext,
2335     generics: &ast::Generics,
2336     shape: Shape,
2337     span: Span,
2338 ) -> Option<String> {
2339     let g_shape = try_opt!(generics_shape_from_config(context.config, shape, 0));
2340     let one_line_width = shape.width.checked_sub(2).unwrap_or(0);
2341     rewrite_generics_inner(context, generics, g_shape, one_line_width, span).or_else(|| {
2342         rewrite_generics_inner(context, generics, g_shape, 0, span)
2343     })
2344 }
2345
2346 fn rewrite_generics_inner(
2347     context: &RewriteContext,
2348     generics: &ast::Generics,
2349     shape: Shape,
2350     one_line_width: usize,
2351     span: Span,
2352 ) -> Option<String> {
2353     // FIXME: convert bounds to where clauses where they get too big or if
2354     // there is a where clause at all.
2355     let lifetimes: &[_] = &generics.lifetimes;
2356     let tys: &[_] = &generics.ty_params;
2357     if lifetimes.is_empty() && tys.is_empty() {
2358         return Some(String::new());
2359     }
2360
2361     // Strings for the generics.
2362     let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, shape));
2363     let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, shape));
2364
2365     // Extract comments between generics.
2366     let lt_spans = lifetimes.iter().map(|l| {
2367         let hi = if l.bounds.is_empty() {
2368             l.lifetime.span.hi
2369         } else {
2370             l.bounds[l.bounds.len() - 1].span.hi
2371         };
2372         mk_sp(l.lifetime.span.lo, hi)
2373     });
2374     let ty_spans = tys.iter().map(|ty| ty.span());
2375
2376     let items = itemize_list(
2377         context.codemap,
2378         lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
2379         ">",
2380         |&(sp, _)| sp.lo,
2381         |&(sp, _)| sp.hi,
2382         // FIXME: don't clone
2383         |&(_, ref str)| str.clone(),
2384         context.codemap.span_after(span, "<"),
2385         span.hi,
2386     );
2387     format_generics_item_list(context, items, shape, one_line_width)
2388 }
2389
2390 pub fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2391     match config.generics_indent() {
2392         IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2393         IndentStyle::Block => {
2394             // 1 = ","
2395             shape
2396                 .block()
2397                 .block_indent(config.tab_spaces())
2398                 .with_max_width(config)
2399                 .sub_width(1)
2400         }
2401     }
2402 }
2403
2404 pub fn format_generics_item_list<I>(
2405     context: &RewriteContext,
2406     items: I,
2407     shape: Shape,
2408     one_line_budget: usize,
2409 ) -> Option<String>
2410 where
2411     I: Iterator<Item = ListItem>,
2412 {
2413     let item_vec = items.collect::<Vec<_>>();
2414
2415     let tactic = definitive_tactic(&item_vec, ListTactic::HorizontalVertical, one_line_budget);
2416     let fmt = ListFormatting {
2417         tactic: tactic,
2418         separator: ",",
2419         trailing_separator: if context.config.generics_indent() == IndentStyle::Visual {
2420             SeparatorTactic::Never
2421         } else {
2422             context.config.trailing_comma()
2423         },
2424         shape: shape,
2425         ends_with_newline: tactic.ends_with_newline(context.config.generics_indent()),
2426         config: context.config,
2427     };
2428
2429     let list_str = try_opt!(write_list(&item_vec, &fmt));
2430
2431     Some(wrap_generics_with_angle_brackets(
2432         context,
2433         &list_str,
2434         shape.indent,
2435     ))
2436 }
2437
2438 pub fn wrap_generics_with_angle_brackets(
2439     context: &RewriteContext,
2440     list_str: &str,
2441     list_offset: Indent,
2442 ) -> String {
2443     if context.config.generics_indent() == IndentStyle::Block &&
2444         (list_str.contains('\n') || list_str.ends_with(','))
2445     {
2446         format!(
2447             "<\n{}{}\n{}>",
2448             list_offset.to_string(context.config),
2449             list_str,
2450             list_offset
2451                 .block_unindent(context.config)
2452                 .to_string(context.config)
2453         )
2454     } else if context.config.spaces_within_angle_brackets() {
2455         format!("< {} >", list_str)
2456     } else {
2457         format!("<{}>", list_str)
2458     }
2459 }
2460
2461 fn rewrite_trait_bounds(
2462     context: &RewriteContext,
2463     type_param_bounds: &ast::TyParamBounds,
2464     shape: Shape,
2465 ) -> Option<String> {
2466     let bounds: &[_] = type_param_bounds;
2467
2468     if bounds.is_empty() {
2469         return Some(String::new());
2470     }
2471     let bound_str = try_opt!(
2472         bounds
2473             .iter()
2474             .map(|ty_bound| ty_bound.rewrite(&context, shape))
2475             .collect::<Option<Vec<_>>>()
2476     );
2477     Some(format!(": {}", join_bounds(context, shape, &bound_str)))
2478 }
2479
2480 fn rewrite_where_clause_rfc_style(
2481     context: &RewriteContext,
2482     where_clause: &ast::WhereClause,
2483     shape: Shape,
2484     terminator: &str,
2485     suppress_comma: bool,
2486     // where clause can be kept on the current line.
2487     snuggle: bool,
2488     span_end: Option<BytePos>,
2489     span: Span,
2490     span_end_before_where: BytePos,
2491 ) -> Option<String> {
2492     let block_shape = shape.block().with_max_width(context.config);
2493
2494     let (span_before, span_after) =
2495         missing_span_before_after_where(context, span.hi, span_end_before_where, where_clause);
2496     let (comment_before, comment_after) = try_opt!(rewrite_comments_before_after_where(
2497         context,
2498         span_before,
2499         span_after,
2500         shape,
2501     ));
2502
2503     let starting_newline = if snuggle && comment_before.is_empty() {
2504         " ".to_owned()
2505     } else {
2506         "\n".to_owned() + &block_shape.indent.to_string(context.config)
2507     };
2508
2509     let clause_shape = block_shape.block_indent(context.config.tab_spaces());
2510     // each clause on one line, trailing comma (except if suppress_comma)
2511     let span_start = where_clause.predicates[0].span().lo;
2512     // If we don't have the start of the next span, then use the end of the
2513     // predicates, but that means we miss comments.
2514     let len = where_clause.predicates.len();
2515     let end_of_preds = where_clause.predicates[len - 1].span().hi;
2516     let span_end = span_end.unwrap_or(end_of_preds);
2517     let items = itemize_list(
2518         context.codemap,
2519         where_clause.predicates.iter(),
2520         terminator,
2521         |pred| pred.span().lo,
2522         |pred| pred.span().hi,
2523         |pred| pred.rewrite(context, block_shape),
2524         span_start,
2525         span_end,
2526     );
2527     let comma_tactic = if suppress_comma {
2528         SeparatorTactic::Never
2529     } else {
2530         context.config.trailing_comma()
2531     };
2532
2533     let fmt = ListFormatting {
2534         tactic: DefinitiveListTactic::Vertical,
2535         separator: ",",
2536         trailing_separator: comma_tactic,
2537         shape: clause_shape,
2538         ends_with_newline: true,
2539         config: context.config,
2540     };
2541     let preds_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
2542
2543     let newline_before_where = if comment_before.is_empty() || comment_before.ends_with('\n') {
2544         String::new()
2545     } else {
2546         "\n".to_owned() + &shape.indent.to_string(context.config)
2547     };
2548     let newline_after_where = if comment_after.is_empty() {
2549         String::new()
2550     } else {
2551         "\n".to_owned() + &clause_shape.indent.to_string(context.config)
2552     };
2553     Some(format!(
2554         "{}{}{}where{}{}\n{}{}",
2555         starting_newline,
2556         comment_before,
2557         newline_before_where,
2558         newline_after_where,
2559         comment_after,
2560         clause_shape.indent.to_string(context.config),
2561         preds_str
2562     ))
2563 }
2564
2565 fn rewrite_where_clause(
2566     context: &RewriteContext,
2567     where_clause: &ast::WhereClause,
2568     brace_style: BraceStyle,
2569     shape: Shape,
2570     density: Density,
2571     terminator: &str,
2572     suppress_comma: bool,
2573     snuggle: bool,
2574     span_end: Option<BytePos>,
2575     span: Span,
2576     span_end_before_where: BytePos,
2577 ) -> Option<String> {
2578     if where_clause.predicates.is_empty() {
2579         return Some(String::new());
2580     }
2581
2582     if context.config.where_style() == Style::Rfc {
2583         return rewrite_where_clause_rfc_style(
2584             context,
2585             where_clause,
2586             shape,
2587             terminator,
2588             suppress_comma,
2589             snuggle,
2590             span_end,
2591             span,
2592             span_end_before_where,
2593         );
2594     }
2595
2596     let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2597
2598     let offset = match context.config.where_pred_indent() {
2599         IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2600         // 6 = "where ".len()
2601         IndentStyle::Visual => shape.indent + extra_indent + 6,
2602     };
2603     // FIXME: if where_pred_indent != Visual, then the budgets below might
2604     // be out by a char or two.
2605
2606     let budget = context.config.max_width() - offset.width();
2607     let span_start = where_clause.predicates[0].span().lo;
2608     // If we don't have the start of the next span, then use the end of the
2609     // predicates, but that means we miss comments.
2610     let len = where_clause.predicates.len();
2611     let end_of_preds = where_clause.predicates[len - 1].span().hi;
2612     let span_end = span_end.unwrap_or(end_of_preds);
2613     let items = itemize_list(
2614         context.codemap,
2615         where_clause.predicates.iter(),
2616         terminator,
2617         |pred| pred.span().lo,
2618         |pred| pred.span().hi,
2619         |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2620         span_start,
2621         span_end,
2622     );
2623     let item_vec = items.collect::<Vec<_>>();
2624     // FIXME: we don't need to collect here if the where_layout isn't
2625     // HorizontalVertical.
2626     let tactic = definitive_tactic(&item_vec, context.config.where_layout(), budget);
2627
2628     let mut comma_tactic = context.config.trailing_comma();
2629     // Kind of a hack because we don't usually have trailing commas in where clauses.
2630     if comma_tactic == SeparatorTactic::Vertical || suppress_comma {
2631         comma_tactic = SeparatorTactic::Never;
2632     }
2633
2634     let fmt = ListFormatting {
2635         tactic: tactic,
2636         separator: ",",
2637         trailing_separator: comma_tactic,
2638         shape: Shape::legacy(budget, offset),
2639         ends_with_newline: tactic.ends_with_newline(context.config.where_pred_indent()),
2640         config: context.config,
2641     };
2642     let preds_str = try_opt!(write_list(&item_vec, &fmt));
2643
2644     let end_length = if terminator == "{" {
2645         // If the brace is on the next line we don't need to count it otherwise it needs two
2646         // characters " {"
2647         match brace_style {
2648             BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
2649             BraceStyle::PreferSameLine => 2,
2650         }
2651     } else if terminator == "=" {
2652         2
2653     } else {
2654         terminator.len()
2655     };
2656     if density == Density::Tall || preds_str.contains('\n') ||
2657         shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
2658     {
2659         Some(format!(
2660             "\n{}where {}",
2661             (shape.indent + extra_indent).to_string(context.config),
2662             preds_str
2663         ))
2664     } else {
2665         Some(format!(" where {}", preds_str))
2666     }
2667 }
2668
2669 fn missing_span_before_after_where(
2670     context: &RewriteContext,
2671     item_end: BytePos,
2672     before_item_span_end: BytePos,
2673     where_clause: &ast::WhereClause,
2674 ) -> (Span, Span) {
2675     let snippet = context.snippet(mk_sp(before_item_span_end, item_end));
2676     let pos_before_where =
2677         before_item_span_end + BytePos(snippet.find_uncommented("where").unwrap() as u32);
2678     let missing_span_before = mk_sp(before_item_span_end, pos_before_where);
2679     // 5 = `where`
2680     let pos_after_where = pos_before_where + BytePos(5);
2681     let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo);
2682     (missing_span_before, missing_span_after)
2683 }
2684
2685 fn rewrite_missing_comment_in_where(
2686     context: &RewriteContext,
2687     comment: &str,
2688     shape: Shape,
2689 ) -> Option<String> {
2690     let comment = comment.trim();
2691     if comment.is_empty() {
2692         Some(String::new())
2693     } else {
2694         rewrite_comment(comment, false, shape, context.config)
2695     }
2696 }
2697
2698 fn rewrite_comments_before_after_where(
2699     context: &RewriteContext,
2700     span_before_where: Span,
2701     span_after_where: Span,
2702     shape: Shape,
2703 ) -> Option<(String, String)> {
2704     let before_comment = try_opt!(rewrite_missing_comment_in_where(
2705         context,
2706         &context.snippet(span_before_where),
2707         shape,
2708     ));
2709     let after_comment = try_opt!(rewrite_missing_comment_in_where(
2710         context,
2711         &context.snippet(span_after_where),
2712         shape.block_indent(context.config.tab_spaces()),
2713     ));
2714     Some((before_comment, after_comment))
2715 }
2716
2717 fn format_header(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
2718     format!("{}{}{}", format_visibility(vis), item_name, ident)
2719 }
2720
2721 fn format_generics(
2722     context: &RewriteContext,
2723     generics: &ast::Generics,
2724     opener: &str,
2725     terminator: &str,
2726     brace_style: BraceStyle,
2727     force_same_line_brace: bool,
2728     offset: Indent,
2729     span: Span,
2730     used_width: usize,
2731 ) -> Option<String> {
2732     let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
2733     let mut result = try_opt!(rewrite_generics(context, generics, shape, span));
2734
2735     if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
2736         let budget = try_opt!(
2737             context
2738                 .config
2739                 .max_width()
2740                 .checked_sub(last_line_width(&result))
2741         );
2742         let where_clause_str = try_opt!(rewrite_where_clause(
2743             context,
2744             &generics.where_clause,
2745             brace_style,
2746             Shape::legacy(budget, offset.block_only()),
2747             Density::Tall,
2748             terminator,
2749             false,
2750             trimmed_last_line_width(&result) == 1,
2751             Some(span.hi),
2752             span,
2753             generics.span.hi,
2754         ));
2755         result.push_str(&where_clause_str);
2756         let same_line_brace = force_same_line_brace ||
2757             (generics.where_clause.predicates.is_empty() && trimmed_last_line_width(&result) == 1);
2758         if !same_line_brace &&
2759             (brace_style == BraceStyle::SameLineWhere ||
2760                 brace_style == BraceStyle::AlwaysNextLine)
2761         {
2762             result.push('\n');
2763             result.push_str(&offset.block_only().to_string(context.config));
2764         } else {
2765             result.push(' ');
2766         }
2767         result.push_str(opener);
2768     } else {
2769         if force_same_line_brace || trimmed_last_line_width(&result) == 1 ||
2770             brace_style != BraceStyle::AlwaysNextLine
2771         {
2772             result.push(' ');
2773         } else {
2774             result.push('\n');
2775             result.push_str(&offset.block_only().to_string(context.config));
2776         }
2777         result.push_str(opener);
2778     }
2779
2780     Some(result)
2781 }