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