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