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