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