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