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