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