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