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