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