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