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