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