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