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