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