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