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