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