]> git.lizzy.rs Git - rust.git/blob - src/items.rs
Merge pull request #309 from marcusklaas/array-literals
[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 {ReturnIndent, BraceStyle, StructLitStyle};
14 use utils::{format_mutability, format_visibility, make_indent, contains_skip, span_after,
15             end_typaram, wrap_str};
16 use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
17 use expr::rewrite_assign_rhs;
18 use comment::FindUncommented;
19 use visitor::FmtVisitor;
20 use rewrite::{Rewrite, RewriteContext};
21 use config::{Config, BlockIndentStyle, Density};
22
23 use syntax::{ast, abi};
24 use syntax::codemap::{self, Span, BytePos};
25 use syntax::print::pprust;
26 use syntax::parse::token;
27
28 impl<'a> FmtVisitor<'a> {
29     pub fn visit_let(&mut self, local: &ast::Local, span: Span) {
30         self.format_missing_with_indent(span.lo);
31
32         // String that is placed within the assignment pattern and expression.
33         let infix = {
34             let mut infix = String::new();
35
36             if let Some(ref ty) = local.ty {
37                 infix.push_str(": ");
38                 // FIXME silly width, indent
39                 infix.push_str(&ty.rewrite(&self.get_context(), 1000, 0).unwrap());
40             }
41
42             if local.init.is_some() {
43                 infix.push_str(" =");
44             }
45
46             infix
47         };
48
49         // New scope so we drop the borrow of self (context) in time to mutably
50         // borrow self to mutate its buffer.
51         let result = {
52             let context = self.get_context();
53             let mut result = "let ".to_owned();
54             let pattern_offset = self.block_indent + result.len() + infix.len();
55             // 1 = ;
56             let pattern_width = match self.config.max_width.checked_sub(pattern_offset + 1) {
57                 Some(width) => width,
58                 None => return,
59             };
60
61             match local.pat.rewrite(&context, pattern_offset, pattern_width) {
62                 Some(ref pat_string) => result.push_str(pat_string),
63                 None => return,
64             }
65
66             result.push_str(&infix);
67
68             if let Some(ref ex) = local.init {
69                 let max_width = match self.config.max_width.checked_sub(context.block_indent + 1) {
70                     Some(width) => width,
71                     None => return,
72                 };
73
74                 // 1 = trailing semicolon;
75                 let rhs = rewrite_assign_rhs(&context, result, ex, max_width, context.block_indent);
76
77                 match rhs {
78                     Some(result) => result,
79                     None => return,
80                 }
81             } else {
82                 result
83             }
84         };
85
86         self.buffer.push_str(&result);
87         self.buffer.push_str(";");
88         self.last_pos = span.hi;
89     }
90
91     pub fn rewrite_fn(&mut self,
92                       indent: usize,
93                       ident: ast::Ident,
94                       fd: &ast::FnDecl,
95                       explicit_self: Option<&ast::ExplicitSelf>,
96                       generics: &ast::Generics,
97                       unsafety: &ast::Unsafety,
98                       constness: &ast::Constness,
99                       abi: &abi::Abi,
100                       vis: ast::Visibility,
101                       span: Span)
102                       -> Option<String> {
103         let mut newline_brace = self.newline_for_brace(&generics.where_clause);
104
105         let mut result = try_opt!(self.rewrite_fn_base(indent,
106                                                        ident,
107                                                        fd,
108                                                        explicit_self,
109                                                        generics,
110                                                        unsafety,
111                                                        constness,
112                                                        abi,
113                                                        vis,
114                                                        span,
115                                                        newline_brace));
116
117         if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
118             newline_brace = false;
119         }
120
121         // Prepare for the function body by possibly adding a newline and
122         // indent.
123         // FIXME we'll miss anything between the end of the signature and the
124         // start of the body, but we need more spans from the compiler to solve
125         // this.
126         if newline_brace {
127             result.push('\n');
128             result.push_str(&make_indent(indent));
129         } else {
130             result.push(' ');
131         }
132
133         Some(result)
134     }
135
136     pub fn rewrite_required_fn(&mut self,
137                                indent: usize,
138                                ident: ast::Ident,
139                                sig: &ast::MethodSig,
140                                span: Span)
141                                -> Option<String> {
142         // Drop semicolon or it will be interpreted as comment
143         let span = codemap::mk_sp(span.lo, span.hi - BytePos(1));
144
145         let mut result = try_opt!(self.rewrite_fn_base(indent,
146                                                        ident,
147                                                        &sig.decl,
148                                                        Some(&sig.explicit_self),
149                                                        &sig.generics,
150                                                        &sig.unsafety,
151                                                        &sig.constness,
152                                                        &sig.abi,
153                                                        ast::Visibility::Inherited,
154                                                        span,
155                                                        false));
156
157         // Re-attach semicolon
158         result.push(';');
159
160         Some(result)
161     }
162
163     fn rewrite_fn_base(&mut self,
164                        indent: usize,
165                        ident: ast::Ident,
166                        fd: &ast::FnDecl,
167                        explicit_self: Option<&ast::ExplicitSelf>,
168                        generics: &ast::Generics,
169                        unsafety: &ast::Unsafety,
170                        constness: &ast::Constness,
171                        abi: &abi::Abi,
172                        vis: ast::Visibility,
173                        span: Span,
174                        newline_brace: bool)
175                        -> Option<String> {
176         // FIXME we'll lose any comments in between parts of the function decl, but anyone
177         // who comments there probably deserves what they get.
178
179         let where_clause = &generics.where_clause;
180
181         let mut result = String::with_capacity(1024);
182         // Vis unsafety abi.
183         result.push_str(format_visibility(vis));
184
185         if let &ast::Unsafety::Unsafe = unsafety {
186             result.push_str("unsafe ");
187         }
188         if let &ast::Constness::Const = constness {
189             result.push_str("const ");
190         }
191         if *abi != abi::Rust {
192             result.push_str("extern ");
193             result.push_str(&abi.to_string());
194             result.push(' ');
195         }
196
197         // fn foo
198         result.push_str("fn ");
199         result.push_str(&ident.to_string());
200
201         // Generics.
202         let generics_indent = indent + result.len();
203         let generics_span = codemap::mk_sp(span.lo, span_for_return(&fd.output).lo);
204         let generics_str = try_opt!(self.rewrite_generics(generics,
205                                                           indent,
206                                                           generics_indent,
207                                                           generics_span));
208         result.push_str(&generics_str);
209
210         let context = self.get_context();
211         let ret_str = fd.output.rewrite(&context, self.config.max_width - indent, indent).unwrap();
212
213         // Args.
214         let (one_line_budget, multi_line_budget, mut arg_indent) =
215             self.compute_budgets_for_args(&result, indent, ret_str.len(), newline_brace);
216
217         debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {}",
218                one_line_budget, multi_line_budget, arg_indent);
219
220         // Check if vertical layout was forced by compute_budget_for_args.
221         if one_line_budget <= 0 {
222             if self.config.fn_args_paren_newline {
223                 result.push('\n');
224                 result.push_str(&make_indent(arg_indent));
225                 arg_indent = arg_indent + 1; // extra space for `(`
226                 result.push('(');
227             } else {
228                 result.push_str("(\n");
229                 result.push_str(&make_indent(arg_indent));
230             }
231         } else if self.config.fn_args_layout == StructLitStyle::Block {
232             arg_indent = indent + self.config.tab_spaces;
233             result.push_str("(\n");
234             result.push_str(&make_indent(arg_indent));
235         } else {
236             result.push('(');
237         }
238
239         // A conservative estimation, to goal is to be over all parens in generics
240         let args_start = generics.ty_params
241                                  .last()
242                                  .map(|tp| end_typaram(tp))
243                                  .unwrap_or(span.lo);
244         let args_span = codemap::mk_sp(span_after(codemap::mk_sp(args_start, span.hi),
245                                                   "(",
246                                                   self.codemap),
247                                        span_for_return(&fd.output).lo);
248         let arg_str = try_opt!(self.rewrite_args(&fd.inputs,
249                                                  explicit_self,
250                                                  one_line_budget,
251                                                  multi_line_budget,
252                                                  indent,
253                                                  arg_indent,
254                                                  args_span));
255         result.push_str(&arg_str);
256         if self.config.fn_args_layout == StructLitStyle::Block {
257             result.push('\n');
258         }
259         result.push(')');
260
261         // Return type.
262         if !ret_str.is_empty() {
263             // If we've already gone multi-line, or the return type would push
264             // over the max width, then put the return type on a new line.
265             // Unless we are formatting args like a block, in which case there
266             // should always be room for the return type.
267             if (result.contains("\n") ||
268                 result.len() + indent + ret_str.len() > self.config.max_width) &&
269                self.config.fn_args_layout != StructLitStyle::Block {
270                 let indent = match self.config.fn_return_indent {
271                     ReturnIndent::WithWhereClause => indent + 4,
272                     // TODO we might want to check that using the arg indent doesn't
273                     // blow our budget, and if it does, then fallback to the where
274                     // clause indent.
275                     _ => arg_indent,
276                 };
277
278                 result.push('\n');
279                 result.push_str(&make_indent(indent));
280             } else {
281                 result.push(' ');
282             }
283             result.push_str(&ret_str);
284
285             // Comment between return type and the end of the decl.
286             let snippet_lo = fd.output.span().hi;
287             if where_clause.predicates.is_empty() {
288                 let snippet_hi = span.hi;
289                 let snippet = self.snippet(codemap::mk_sp(snippet_lo, snippet_hi));
290                 let snippet = snippet.trim();
291                 if !snippet.is_empty() {
292                     result.push(' ');
293                     result.push_str(snippet);
294                 }
295             } else {
296                 // FIXME it would be nice to catch comments between the return type
297                 // and the where clause, but we don't have a span for the where
298                 // clause.
299             }
300         }
301
302         let where_density = if (self.config.where_density == Density::Compressed &&
303                                 (!result.contains('\n') ||
304                                  self.config.fn_args_layout == StructLitStyle::Block)) ||
305                                (self.config.fn_args_layout == StructLitStyle::Block &&
306                                 ret_str.is_empty()) {
307             Density::Compressed
308         } else {
309             Density::Tall
310         };
311
312         // Where clause.
313         let where_clause_str = try_opt!(self.rewrite_where_clause(where_clause,
314                                                                   self.config,
315                                                                   indent,
316                                                                   where_density,
317                                                                   span.hi));
318         result.push_str(&where_clause_str);
319
320         Some(result)
321     }
322
323     fn rewrite_args(&self,
324                     args: &[ast::Arg],
325                     explicit_self: Option<&ast::ExplicitSelf>,
326                     one_line_budget: usize,
327                     multi_line_budget: usize,
328                     indent: usize,
329                     arg_indent: usize,
330                     span: Span)
331                     -> Option<String> {
332         let context = self.get_context();
333         let mut arg_item_strs = try_opt!(args.iter()
334                                              .map(|arg| {
335                                                  arg.rewrite(&context, multi_line_budget, indent)
336                                              })
337                                              .collect::<Option<Vec<_>>>());
338
339         // Account for sugary self.
340         // FIXME: the comment for the self argument is dropped. This is blocked
341         // on rust issue #27522.
342         let min_args = explicit_self.and_then(|explicit_self| {
343                                         rewrite_explicit_self(explicit_self, args)
344                                     })
345                                     .map(|self_str| {
346                                         arg_item_strs[0] = self_str;
347                                         2
348                                     })
349                                     .unwrap_or(1);
350
351         // Comments between args.
352         let mut arg_items = Vec::new();
353         if min_args == 2 {
354             arg_items.push(ListItem::from_str(""));
355         }
356
357         // TODO if there are no args, there might still be a comment, but without
358         // spans for the comment or parens, there is no chance of getting it right.
359         // You also don't get to put a comment on self, unless it is explicit.
360         if args.len() >= min_args {
361             let comment_span_start = if min_args == 2 {
362                 span_after(span, ",", self.codemap)
363             } else {
364                 span.lo
365             };
366
367             let more_items = itemize_list(self.codemap,
368                                           args[min_args-1..].iter(),
369                                           ")",
370                                           |arg| span_lo_for_arg(arg),
371                                           |arg| arg.ty.span.hi,
372                                           |_| String::new(),
373                                           comment_span_start,
374                                           span.hi);
375
376             arg_items.extend(more_items);
377         }
378
379         assert_eq!(arg_item_strs.len(), arg_items.len());
380
381         for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
382             item.item = arg;
383         }
384
385         let indent = match self.config.fn_arg_indent {
386             BlockIndentStyle::Inherit => indent,
387             BlockIndentStyle::Tabbed => indent + self.config.tab_spaces,
388             BlockIndentStyle::Visual => arg_indent,
389         };
390
391         let fmt = ListFormatting {
392             tactic: self.config.fn_args_density.to_list_tactic(),
393             separator: ",",
394             trailing_separator: SeparatorTactic::Never,
395             indent: indent,
396             h_width: one_line_budget,
397             v_width: multi_line_budget,
398             ends_with_newline: false,
399         };
400
401         write_list(&arg_items, &fmt)
402     }
403
404     fn compute_budgets_for_args(&self,
405                                 result: &str,
406                                 indent: usize,
407                                 ret_str_len: usize,
408                                 newline_brace: bool)
409                                 -> (usize, usize, usize) {
410         let mut budgets = None;
411
412         // Try keeping everything on the same line
413         if !result.contains("\n") {
414             // 3 = `() `, space is before ret_string
415             let mut used_space = indent + result.len() + ret_str_len + 3;
416             if !newline_brace {
417                 used_space += 2;
418             }
419             let one_line_budget = if used_space > self.config.max_width {
420                 0
421             } else {
422                 self.config.max_width - used_space
423             };
424
425             // 2 = `()`
426             let used_space = indent + result.len() + 2;
427             let max_space = self.config.ideal_width + self.config.leeway;
428             debug!("compute_budgets_for_args: used_space: {}, max_space: {}",
429                    used_space, max_space);
430             if used_space < max_space {
431                 budgets = Some((one_line_budget,
432                                 max_space - used_space,
433                                 indent + result.len() + 1));
434             }
435         }
436
437         // Didn't work. we must force vertical layout and put args on a newline.
438         if let None = budgets {
439             let new_indent = indent + self.config.tab_spaces;
440             let used_space = new_indent + 2; // account for `(` and `)`
441             let max_space = self.config.ideal_width + self.config.leeway;
442             if used_space > max_space {
443                 // Whoops! bankrupt.
444                 // TODO take evasive action, perhaps kill the indent or something.
445             } else {
446                 budgets = Some((0, max_space - used_space, new_indent));
447             }
448         }
449
450         budgets.unwrap()
451     }
452
453     fn newline_for_brace(&self, where_clause: &ast::WhereClause) -> bool {
454         match self.config.fn_brace_style {
455             BraceStyle::AlwaysNextLine => true,
456             BraceStyle::SameLineWhere if !where_clause.predicates.is_empty() => true,
457             _ => false,
458         }
459     }
460
461     pub fn visit_enum(&mut self,
462                       ident: ast::Ident,
463                       vis: ast::Visibility,
464                       enum_def: &ast::EnumDef,
465                       generics: &ast::Generics,
466                       span: Span) {
467         let header_str = self.format_header("enum ", ident, vis);
468         self.buffer.push_str(&header_str);
469
470         let enum_snippet = self.snippet(span);
471         let body_start = span.lo + BytePos(enum_snippet.find_uncommented("{").unwrap() as u32 + 1);
472         let generics_str = self.format_generics(generics,
473                                                 " {",
474                                                 self.block_indent,
475                                                 self.block_indent + self.config.tab_spaces,
476                                                 codemap::mk_sp(span.lo, body_start))
477                                .unwrap();
478         self.buffer.push_str(&generics_str);
479
480         self.last_pos = body_start;
481         self.block_indent += self.config.tab_spaces;
482         for (i, f) in enum_def.variants.iter().enumerate() {
483             let next_span_start: BytePos = if i == enum_def.variants.len() - 1 {
484                 span.hi
485             } else {
486                 enum_def.variants[i + 1].span.lo
487             };
488
489             self.visit_variant(f, i == enum_def.variants.len() - 1, next_span_start);
490         }
491         self.block_indent -= self.config.tab_spaces;
492
493         self.format_missing_with_indent(span.lo + BytePos(enum_snippet.rfind('}').unwrap() as u32));
494         self.buffer.push_str("}");
495     }
496
497     // Variant of an enum
498     fn visit_variant(&mut self, field: &ast::Variant, last_field: bool, next_span_start: BytePos) {
499         if self.visit_attrs(&field.node.attrs) {
500             return;
501         }
502
503         self.format_missing_with_indent(field.span.lo);
504
505         let result = match field.node.kind {
506             ast::VariantKind::TupleVariantKind(ref types) => {
507                 let vis = format_visibility(field.node.vis);
508                 self.buffer.push_str(vis);
509                 let name = field.node.name.to_string();
510                 self.buffer.push_str(&name);
511
512                 let mut result = String::new();
513
514                 if !types.is_empty() {
515                     let items = itemize_list(self.codemap,
516                                              types.iter(),
517                                              ")",
518                                              |arg| arg.ty.span.lo,
519                                              |arg| arg.ty.span.hi,
520                                              |arg| {
521                                                  // FIXME silly width, indent
522                                                  arg.ty
523                                                     .rewrite(&self.get_context(), 1000, 0)
524                                                     .unwrap()
525                                              },
526                                              span_after(field.span, "(", self.codemap),
527                                              next_span_start);
528
529                     result.push('(');
530
531                     let indent = self.block_indent + vis.len() + field.node.name.to_string().len() +
532                                  1; // Open paren
533
534                     let comma_cost = if self.config.enum_trailing_comma {
535                         1
536                     } else {
537                         0
538                     };
539                     let budget = self.config.ideal_width - indent - comma_cost - 1; // 1 = )
540
541                     let fmt = ListFormatting {
542                         tactic: ListTactic::HorizontalVertical,
543                         separator: ",",
544                         trailing_separator: SeparatorTactic::Never,
545                         indent: indent,
546                         h_width: budget,
547                         v_width: budget,
548                         ends_with_newline: true,
549                     };
550                     let list_str = match write_list(&items.collect::<Vec<_>>(), &fmt) {
551                         Some(list_str) => list_str,
552                         None => return,
553                     };
554
555                     result.push_str(&list_str);
556                     result.push(')');
557                 }
558
559                 if let Some(ref expr) = field.node.disr_expr {
560                     result.push_str(" = ");
561                     let expr_snippet = self.snippet(expr.span);
562                     result.push_str(&expr_snippet);
563
564                     // Make sure we do not exceed column limit
565                     // 4 = " = ,"
566                     assert!(
567                         self.config.max_width >= vis.len() + name.len() + expr_snippet.len() + 4,
568                         "Enum variant exceeded column limit");
569                 }
570
571                 result
572             }
573             ast::VariantKind::StructVariantKind(ref struct_def) => {
574                 // TODO Should limit the width, as we have a trailing comma
575                 let struct_rewrite = self.format_struct("",
576                                                         field.node.name,
577                                                         field.node.vis,
578                                                         struct_def,
579                                                         None,
580                                                         field.span,
581                                                         self.block_indent);
582
583                 match struct_rewrite {
584                     Some(struct_str) => struct_str,
585                     None => return,
586                 }
587             }
588         };
589         self.buffer.push_str(&result);
590
591         if !last_field || self.config.enum_trailing_comma {
592             self.buffer.push_str(",");
593         }
594
595         self.last_pos = field.span.hi + BytePos(1);
596     }
597
598     fn format_struct(&self,
599                      item_name: &str,
600                      ident: ast::Ident,
601                      vis: ast::Visibility,
602                      struct_def: &ast::StructDef,
603                      generics: Option<&ast::Generics>,
604                      span: Span,
605                      offset: usize)
606                      -> Option<String> {
607         let mut result = String::with_capacity(1024);
608
609         let header_str = self.format_header(item_name, ident, vis);
610         result.push_str(&header_str);
611
612         if struct_def.fields.is_empty() {
613             result.push(';');
614             return Some(result);
615         }
616
617         let is_tuple = match struct_def.fields[0].node.kind {
618             ast::StructFieldKind::NamedField(..) => false,
619             ast::StructFieldKind::UnnamedField(..) => true,
620         };
621
622         let (opener, terminator) = if is_tuple {
623             ("(", ")")
624         } else {
625             (" {", "}")
626         };
627
628         let generics_str = match generics {
629             Some(g) => {
630                 try_opt!(self.format_generics(g,
631                                               opener,
632                                               offset,
633                                               offset + header_str.len(),
634                                               codemap::mk_sp(span.lo,
635                                                              struct_def.fields[0].span.lo)))
636             }
637             None => opener.to_owned(),
638         };
639         result.push_str(&generics_str);
640
641         let items = itemize_list(self.codemap,
642                                  struct_def.fields.iter(),
643                                  terminator,
644                                  |field| {
645                                      // Include attributes and doc comments, if present
646                                      if !field.node.attrs.is_empty() {
647                                          field.node.attrs[0].span.lo
648                                      } else {
649                                          field.span.lo
650                                      }
651                                  },
652                                  |field| field.node.ty.span.hi,
653                                  |field| self.format_field(field),
654                                  span_after(span, opener.trim(), self.codemap),
655                                  span.hi);
656
657         // 2 terminators and a semicolon
658         let used_budget = offset + header_str.len() + generics_str.len() + 3;
659
660         // Conservative approximation
661         let single_line_cost = (span.hi - struct_def.fields[0].span.lo).0;
662         let break_line = !is_tuple || generics_str.contains('\n') ||
663                          single_line_cost as usize + used_budget > self.config.max_width;
664
665         let tactic = if break_line {
666             let indentation = make_indent(offset + self.config.tab_spaces);
667             result.push('\n');
668             result.push_str(&indentation);
669
670             ListTactic::Vertical
671         } else {
672             ListTactic::Horizontal
673         };
674
675         // 1 = ,
676         let budget = self.config.ideal_width - offset + self.config.tab_spaces - 1;
677         let fmt = ListFormatting {
678             tactic: tactic,
679             separator: ",",
680             trailing_separator: self.config.struct_trailing_comma,
681             indent: offset + self.config.tab_spaces,
682             h_width: self.config.max_width,
683             v_width: budget,
684             ends_with_newline: true,
685         };
686         let list_str = write_list(&items.collect::<Vec<_>>(), &fmt).unwrap();
687
688         result.push_str(&list_str);
689
690         if break_line {
691             result.push('\n');
692             result.push_str(&make_indent(offset));
693         }
694
695         result.push_str(terminator);
696
697         if is_tuple {
698             result.push(';');
699         }
700
701         Some(result)
702     }
703
704     pub fn visit_struct(&mut self,
705                         ident: ast::Ident,
706                         vis: ast::Visibility,
707                         struct_def: &ast::StructDef,
708                         generics: &ast::Generics,
709                         span: Span) {
710         let indent = self.block_indent;
711         let result = self.format_struct("struct ",
712                                         ident,
713                                         vis,
714                                         struct_def,
715                                         Some(generics),
716                                         span,
717                                         indent)
718                          .unwrap();
719
720         self.buffer.push_str(&result);
721         self.last_pos = span.hi;
722     }
723
724     fn format_header(&self, item_name: &str, ident: ast::Ident, vis: ast::Visibility) -> String {
725         format!("{}{}{}", format_visibility(vis), item_name, ident)
726     }
727
728     fn format_generics(&self,
729                        generics: &ast::Generics,
730                        opener: &str,
731                        offset: usize,
732                        generics_offset: usize,
733                        span: Span)
734                        -> Option<String> {
735         let mut result = try_opt!(self.rewrite_generics(generics, offset, generics_offset, span));
736
737         if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
738             let where_clause_str = try_opt!(self.rewrite_where_clause(&generics.where_clause,
739                                                                       self.config,
740                                                                       self.block_indent,
741                                                                       Density::Tall,
742                                                                       span.hi));
743             result.push_str(&where_clause_str);
744             result.push_str(&make_indent(self.block_indent));
745             result.push('\n');
746             result.push_str(opener.trim());
747         } else {
748             result.push_str(opener);
749         }
750
751         Some(result)
752     }
753
754     // Field of a struct
755     fn format_field(&self, field: &ast::StructField) -> String {
756         if contains_skip(&field.node.attrs) {
757             return self.snippet(codemap::mk_sp(field.node.attrs[0].span.lo, field.span.hi));
758         }
759
760         let name = match field.node.kind {
761             ast::StructFieldKind::NamedField(ident, _) => Some(ident.to_string()),
762             ast::StructFieldKind::UnnamedField(_) => None,
763         };
764         let vis = match field.node.kind {
765             ast::StructFieldKind::NamedField(_, vis) |
766             ast::StructFieldKind::UnnamedField(vis) => format_visibility(vis),
767         };
768         // FIXME silly width, indent
769         let typ = field.node.ty.rewrite(&self.get_context(), 1000, 0).unwrap();
770
771         let indent = self.block_indent + self.config.tab_spaces;
772         let mut attr_str = field.node
773                                 .attrs
774                                 .rewrite(&self.get_context(),
775                                          self.config.max_width - indent,
776                                          indent)
777                                 .unwrap();
778         if !attr_str.is_empty() {
779             attr_str.push('\n');
780             attr_str.push_str(&make_indent(indent));
781         }
782
783         match name {
784             Some(name) => format!("{}{}{}: {}", attr_str, vis, name, typ),
785             None => format!("{}{}{}", attr_str, vis, typ),
786         }
787     }
788
789     fn rewrite_generics(&self,
790                         generics: &ast::Generics,
791                         offset: usize,
792                         generics_offset: usize,
793                         span: Span)
794                         -> Option<String> {
795         // FIXME convert bounds to where clauses where they get too big or if
796         // there is a where clause at all.
797         let lifetimes: &[_] = &generics.lifetimes;
798         let tys: &[_] = &generics.ty_params;
799         if lifetimes.is_empty() && tys.is_empty() {
800             return Some(String::new());
801         }
802
803         let offset = match self.config.generics_indent {
804             BlockIndentStyle::Inherit => offset,
805             BlockIndentStyle::Tabbed => offset + self.config.tab_spaces,
806             // 1 = <
807             BlockIndentStyle::Visual => generics_offset + 1,
808         };
809
810         let h_budget = self.config.max_width - generics_offset - 2;
811         // TODO might need to insert a newline if the generics are really long
812
813         // Strings for the generics.
814         let context = self.get_context();
815         // FIXME: don't unwrap
816         let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(&context, h_budget, offset).unwrap());
817         let ty_strs = tys.iter()
818                          .map(|ty_param| ty_param.rewrite(&context, h_budget, offset).unwrap());
819
820         // Extract comments between generics.
821         let lt_spans = lifetimes.iter().map(|l| {
822             let hi = if l.bounds.is_empty() {
823                 l.lifetime.span.hi
824             } else {
825                 l.bounds[l.bounds.len() - 1].span.hi
826             };
827             codemap::mk_sp(l.lifetime.span.lo, hi)
828         });
829         let ty_spans = tys.iter().map(span_for_ty_param);
830
831         let items = itemize_list(self.codemap,
832                                  lt_spans.chain(ty_spans),
833                                  ">",
834                                  |sp| sp.lo,
835                                  |sp| sp.hi,
836                                  |_| String::new(),
837                                  span_after(span, "<", self.codemap),
838                                  span.hi);
839         let mut items = items.collect::<Vec<_>>();
840
841         for (item, ty) in items.iter_mut().zip(lt_strs.chain(ty_strs)) {
842             item.item = ty;
843         }
844
845         let fmt = ListFormatting::for_fn(h_budget, offset);
846         let list_str = try_opt!(write_list(&items, &fmt));
847
848         Some(format!("<{}>", list_str))
849     }
850
851     fn rewrite_where_clause(&self,
852                             where_clause: &ast::WhereClause,
853                             config: &Config,
854                             indent: usize,
855                             density: Density,
856                             span_end: BytePos)
857                             -> Option<String> {
858         if where_clause.predicates.is_empty() {
859             return Some(String::new());
860         }
861
862         let extra_indent = match self.config.where_indent {
863             BlockIndentStyle::Inherit => 0,
864             BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => config.tab_spaces,
865         };
866
867         let context = self.get_context();
868
869         let offset = match self.config.where_pred_indent {
870             BlockIndentStyle::Inherit => indent + extra_indent,
871             BlockIndentStyle::Tabbed => indent + extra_indent + config.tab_spaces,
872             // 6 = "where ".len()
873             BlockIndentStyle::Visual => indent + extra_indent + 6,
874         };
875         // FIXME: if where_pred_indent != Visual, then the budgets below might
876         // be out by a char or two.
877
878         let budget = self.config.ideal_width + self.config.leeway - offset;
879         let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
880         let items = itemize_list(self.codemap,
881                                  where_clause.predicates.iter(),
882                                  "{",
883                                  |pred| span_for_where_pred(pred).lo,
884                                  |pred| span_for_where_pred(pred).hi,
885                                  // FIXME: we should handle failure better
886                                  // this will be taken care of when write_list
887                                  // takes Rewrite object: see issue #133
888                                  |pred| pred.rewrite(&context, budget, offset).unwrap(),
889                                  span_start,
890                                  span_end);
891
892         let fmt = ListFormatting {
893             tactic: self.config.where_layout,
894             separator: ",",
895             trailing_separator: SeparatorTactic::Never,
896             indent: offset,
897             h_width: budget,
898             v_width: budget,
899             ends_with_newline: true,
900         };
901         let preds_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
902
903         // 9 = " where ".len() + " {".len()
904         if density == Density::Tall || preds_str.contains('\n') ||
905            indent + 9 + preds_str.len() > self.config.max_width {
906             Some(format!("\n{}where {}",
907                          make_indent(indent + extra_indent),
908                          preds_str))
909         } else {
910             Some(format!(" where {}", preds_str))
911         }
912     }
913 }
914
915 impl Rewrite for ast::FunctionRetTy {
916     fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
917         match *self {
918             ast::FunctionRetTy::DefaultReturn(_) => Some(String::new()),
919             ast::FunctionRetTy::NoReturn(_) => {
920                 if width >= 4 {
921                     Some("-> !".to_owned())
922                 } else {
923                     None
924                 }
925             }
926             ast::FunctionRetTy::Return(ref ty) => {
927                 let inner_width = try_opt!(width.checked_sub(3));
928                 ty.rewrite(context, inner_width, offset + 3).map(|r| format!("-> {}", r))
929             }
930         }
931     }
932 }
933
934 impl Rewrite for ast::Arg {
935     fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
936         if is_named_arg(self) {
937             if let ast::Ty_::TyInfer = self.ty.node {
938                 wrap_str(pprust::pat_to_string(&self.pat), context.config.max_width, width, offset)
939             } else {
940                 let mut result = pprust::pat_to_string(&self.pat);
941                 result.push_str(": ");
942                 let max_width = try_opt!(width.checked_sub(result.len()));
943                 let ty_str = try_opt!(self.ty.rewrite(context, max_width, offset + result.len()));
944                 result.push_str(&ty_str);
945                 Some(result)
946             }
947         } else {
948             self.ty.rewrite(context, width, offset)
949         }
950     }
951 }
952
953 fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf, args: &[ast::Arg]) -> Option<String> {
954     match explicit_self.node {
955         ast::ExplicitSelf_::SelfRegion(lt, m, _) => {
956             let mut_str = format_mutability(m);
957             match lt {
958                 Some(ref l) => Some(format!("&{} {}self", pprust::lifetime_to_string(l), mut_str)),
959                 None => Some(format!("&{}self", mut_str)),
960             }
961         }
962         ast::ExplicitSelf_::SelfExplicit(ref ty, _) => {
963             Some(format!("self: {}", pprust::ty_to_string(ty)))
964         }
965         ast::ExplicitSelf_::SelfValue(_) => {
966             assert!(args.len() >= 1, "&[ast::Arg] shouldn't be empty.");
967
968             // this hacky solution caused by absence of `Mutability` in `SelfValue`.
969             let mut_str = {
970                 if let ast::Pat_::PatIdent(ast::BindingMode::BindByValue(mutability), _, _) =
971                        args[0].pat.node {
972                     format_mutability(mutability)
973                 } else {
974                     panic!("there is a bug or change in structure of AST, aborting.");
975                 }
976             };
977
978             Some(format!("{}self", mut_str))
979         }
980         _ => None,
981     }
982 }
983
984 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
985     if is_named_arg(arg) {
986         arg.pat.span.lo
987     } else {
988         arg.ty.span.lo
989     }
990 }
991
992 pub fn span_hi_for_arg(arg: &ast::Arg) -> BytePos {
993     match arg.ty.node {
994         ast::Ty_::TyInfer if is_named_arg(arg) => arg.pat.span.hi,
995         _ => arg.ty.span.hi,
996     }
997 }
998
999 fn is_named_arg(arg: &ast::Arg) -> bool {
1000     if let ast::Pat_::PatIdent(_, ident, _) = arg.pat.node {
1001         ident.node != token::special_idents::invalid
1002     } else {
1003         true
1004     }
1005 }
1006
1007 fn span_for_return(ret: &ast::FunctionRetTy) -> Span {
1008     match *ret {
1009         ast::FunctionRetTy::NoReturn(ref span) |
1010         ast::FunctionRetTy::DefaultReturn(ref span) => span.clone(),
1011         ast::FunctionRetTy::Return(ref ty) => ty.span,
1012     }
1013 }
1014
1015 fn span_for_ty_param(ty: &ast::TyParam) -> Span {
1016     // Note that ty.span is the span for ty.ident, not the whole item.
1017     let lo = ty.span.lo;
1018     if let Some(ref def) = ty.default {
1019         return codemap::mk_sp(lo, def.span.hi);
1020     }
1021     if ty.bounds.is_empty() {
1022         return ty.span;
1023     }
1024     let hi = match ty.bounds[ty.bounds.len() - 1] {
1025         ast::TyParamBound::TraitTyParamBound(ref ptr, _) => ptr.span.hi,
1026         ast::TyParamBound::RegionTyParamBound(ref l) => l.span.hi,
1027     };
1028     codemap::mk_sp(lo, hi)
1029 }
1030
1031 fn span_for_where_pred(pred: &ast::WherePredicate) -> Span {
1032     match *pred {
1033         ast::WherePredicate::BoundPredicate(ref p) => p.span,
1034         ast::WherePredicate::RegionPredicate(ref p) => p.span,
1035         ast::WherePredicate::EqPredicate(ref p) => p.span,
1036     }
1037 }