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