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