1 // Formatting top-level items - functions, structs, enums, traits, impls.
4 use std::cmp::{max, min, Ordering};
8 use rustc_ast::{ast, ptr};
9 use rustc_span::{symbol, BytePos, Span, DUMMY_SP};
11 use crate::attr::filter_inline_attrs;
13 combine_strs_with_missing_comments, contains_comment, is_last_comment_block,
14 recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment,
17 use crate::config::lists::*;
18 use crate::config::{BraceStyle, Config, IndentStyle, Version};
20 is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with,
21 rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics,
23 use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
24 use crate::macros::{rewrite_macro, MacroPosition};
26 use crate::rewrite::{Rewrite, RewriteContext};
27 use crate::shape::{Indent, Shape};
28 use crate::source_map::{LineRangeUtils, SpanUtils};
29 use crate::spanned::Spanned;
30 use crate::stmt::Stmt;
31 use crate::types::opaque_ty;
33 use crate::vertical::rewrite_with_alignment;
34 use crate::visitor::FmtVisitor;
36 const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility {
37 kind: ast::VisibilityKind::Inherited,
42 fn type_annotation_separator(config: &Config) -> &str {
46 // Statements of the form
47 // let pat: ty = init;
48 impl Rewrite for ast::Local {
49 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
51 "Local::rewrite {:?} {} {:?}",
52 self, shape.width, shape.indent
55 skip_out_of_file_lines_range!(context, self.span);
57 if contains_skip(&self.attrs) || matches!(self.kind, ast::LocalKind::InitElse(..)) {
61 let attrs_str = self.attrs.rewrite(context, shape)?;
62 let mut result = if attrs_str.is_empty() {
65 combine_strs_with_missing_comments(
70 self.attrs.last().map(|a| a.span.hi()).unwrap(),
79 let pat_shape = shape.offset_left(4)?;
81 let pat_shape = pat_shape.sub_width(1)?;
82 let pat_str = self.pat.rewrite(context, pat_shape)?;
83 result.push_str(&pat_str);
85 // String that is placed within the assignment pattern and expression.
87 let mut infix = String::with_capacity(32);
89 if let Some(ref ty) = self.ty {
90 let separator = type_annotation_separator(context.config);
91 let ty_shape = if pat_str.contains('\n') {
92 shape.with_max_width(context.config)
96 .offset_left(last_line_width(&result) + separator.len())?
100 let rewrite = ty.rewrite(context, ty_shape)?;
102 infix.push_str(separator);
103 infix.push_str(&rewrite);
106 if self.kind.init().is_some() {
107 infix.push_str(" =");
113 result.push_str(&infix);
115 if let Some((init, _els)) = self.kind.init_else_opt() {
116 // 1 = trailing semicolon;
117 let nested_shape = shape.sub_width(1)?;
119 result = rewrite_assign_rhs(
123 &RhsAssignKind::Expr(&init.kind, init.span),
134 // FIXME convert to using rewrite style rather than visitor
135 // FIXME format modules in this style
139 unsafety: ast::Unsafe,
140 abi: Cow<'static, str>,
141 vis: Option<&'a ast::Visibility>,
142 body: Vec<BodyElement<'a>>,
147 fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
149 unsafety: fm.unsafety,
151 ast::Extern::from_abi(fm.abi, DUMMY_SP),
152 config.force_explicit_abi(),
159 .map(|i| BodyElement::ForeignItem(i))
167 enum BodyElement<'a> {
168 // Stmt(&'a ast::Stmt),
169 // Field(&'a ast::ExprField),
170 // Variant(&'a ast::Variant),
171 // Item(&'a ast::Item),
172 ForeignItem(&'a ast::ForeignItem),
175 /// Represents a fn's signature.
176 pub(crate) struct FnSig<'a> {
177 decl: &'a ast::FnDecl,
178 generics: &'a ast::Generics,
180 is_async: Cow<'a, ast::Async>,
181 constness: ast::Const,
182 defaultness: ast::Defaultness,
183 unsafety: ast::Unsafe,
184 visibility: &'a ast::Visibility,
188 pub(crate) fn from_method_sig(
189 method_sig: &'a ast::FnSig,
190 generics: &'a ast::Generics,
191 visibility: &'a ast::Visibility,
194 unsafety: method_sig.header.unsafety,
195 is_async: Cow::Borrowed(&method_sig.header.asyncness),
196 constness: method_sig.header.constness,
197 defaultness: ast::Defaultness::Final,
198 ext: method_sig.header.ext,
199 decl: &*method_sig.decl,
205 pub(crate) fn from_fn_kind(
206 fn_kind: &'a visit::FnKind<'_>,
207 decl: &'a ast::FnDecl,
208 defaultness: ast::Defaultness,
211 visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt {
212 visit::FnCtxt::Assoc(..) => {
213 let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
214 fn_sig.defaultness = defaultness;
220 ext: fn_sig.header.ext,
221 constness: fn_sig.header.constness,
222 is_async: Cow::Borrowed(&fn_sig.header.asyncness),
224 unsafety: fn_sig.header.unsafety,
232 fn to_str(&self, context: &RewriteContext<'_>) -> String {
233 let mut result = String::with_capacity(128);
234 // Vis defaultness constness unsafety abi.
235 result.push_str(&*format_visibility(context, self.visibility));
236 result.push_str(format_defaultness(self.defaultness));
237 result.push_str(format_constness(self.constness));
238 result.push_str(format_async(&self.is_async));
239 result.push_str(format_unsafety(self.unsafety));
240 result.push_str(&format_extern(
242 context.config.force_explicit_abi(),
249 impl<'a> FmtVisitor<'a> {
250 fn format_item(&mut self, item: &Item<'_>) {
251 self.buffer.push_str(format_unsafety(item.unsafety));
252 self.buffer.push_str(&item.abi);
254 let snippet = self.snippet(item.span);
255 let brace_pos = snippet.find_uncommented("{").unwrap();
258 if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
259 // FIXME: this skips comments between the extern keyword and the opening
261 self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
262 self.block_indent = self.block_indent.block_indent(self.config);
264 if !item.body.is_empty() {
265 for item in &item.body {
266 self.format_body_element(item);
270 self.format_missing_no_indent(item.span.hi() - BytePos(1));
271 self.block_indent = self.block_indent.block_unindent(self.config);
272 let indent_str = self.block_indent.to_string(self.config);
273 self.push_str(&indent_str);
277 self.last_pos = item.span.hi();
280 fn format_body_element(&mut self, element: &BodyElement<'_>) {
282 BodyElement::ForeignItem(item) => self.format_foreign_item(item),
286 pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
287 let item = Item::from_foreign_mod(fm, span, self.config);
288 self.format_item(&item);
291 fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
292 let rewrite = item.rewrite(&self.get_context(), self.shape());
293 let hi = item.span.hi();
294 let span = if item.attrs.is_empty() {
297 mk_sp(item.attrs[0].span.lo(), hi)
299 self.push_rewrite(span, rewrite);
303 pub(crate) fn rewrite_fn_before_block(
306 ident: symbol::Ident,
309 ) -> Option<(String, FnBraceStyle)> {
310 let context = self.get_context();
312 let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause);
313 let (result, _, force_newline_brace) =
314 rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style)?;
317 if self.config.brace_style() == BraceStyle::AlwaysNextLine
318 || force_newline_brace
319 || last_line_width(&result) + 2 > self.shape().width
321 fn_brace_style = FnBraceStyle::NextLine
324 Some((result, fn_brace_style))
327 pub(crate) fn rewrite_required_fn(
330 ident: symbol::Ident,
332 vis: &ast::Visibility,
333 generics: &ast::Generics,
335 ) -> Option<String> {
336 // Drop semicolon or it will be interpreted as comment.
337 let span = mk_sp(span.lo(), span.hi() - BytePos(1));
338 let context = self.get_context();
340 let (mut result, ends_with_comment, _) = rewrite_fn_base(
344 &FnSig::from_method_sig(sig, generics, vis),
349 // If `result` ends with a comment, then remember to add a newline
350 if ends_with_comment {
351 result.push_str(&indent.to_string_with_newline(context.config));
354 // Re-attach semicolon
360 pub(crate) fn single_line_fn(
364 inner_attrs: Option<&[ast::Attribute]>,
365 ) -> Option<String> {
366 if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) {
370 let context = self.get_context();
372 if self.config.empty_item_single_line()
373 && is_empty_block(&context, block, None)
374 && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
375 && !last_line_contains_single_line_comment(fn_str)
377 return Some(format!("{} {{}}", fn_str));
380 if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) {
384 let res = Stmt::from_ast_node(block.stmts.first()?, true)
385 .rewrite(&self.get_context(), self.shape())?;
387 let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
388 if !res.contains('\n') && width <= self.config.max_width() {
389 Some(format!("{} {{ {} }}", fn_str, res))
395 pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) {
396 let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent);
397 self.push_rewrite(static_parts.span, rewrite);
400 pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) {
401 let is_tuple = match struct_parts.def {
402 ast::VariantData::Tuple(..) => true,
405 let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None)
406 .map(|s| if is_tuple { s + ";" } else { s });
407 self.push_rewrite(struct_parts.span, rewrite);
410 pub(crate) fn visit_enum(
412 ident: symbol::Ident,
413 vis: &ast::Visibility,
414 enum_def: &ast::EnumDef,
415 generics: &ast::Generics,
419 format_header(&self.get_context(), "enum ", ident, vis, self.block_indent);
420 self.push_str(&enum_header);
422 let enum_snippet = self.snippet(span);
423 let brace_pos = enum_snippet.find_uncommented("{").unwrap();
424 let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
425 let generics_str = format_generics(
428 self.config.brace_style(),
429 if enum_def.variants.is_empty() {
430 BracePos::ForceSameLine
435 // make a span that starts right after `enum Foo`
436 mk_sp(ident.span.hi(), body_start),
437 last_line_width(&enum_header),
440 self.push_str(&generics_str);
442 self.last_pos = body_start;
444 match self.format_variant_list(enum_def, body_start, span.hi()) {
445 Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
447 self.push_rewrite(mk_sp(body_start, span.hi()), rw);
448 self.block_indent = self.block_indent.block_unindent(self.config);
453 // Format the body of an enum definition
454 fn format_variant_list(
456 enum_def: &ast::EnumDef,
459 ) -> Option<String> {
460 if enum_def.variants.is_empty() {
461 let mut buffer = String::with_capacity(128);
463 let span = mk_sp(body_lo, body_hi - BytePos(1));
464 format_empty_struct_or_tuple(
474 let mut result = String::with_capacity(1024);
475 let original_offset = self.block_indent;
476 self.block_indent = self.block_indent.block_indent(self.config);
478 // If enum variants have discriminants, try to vertically align those,
479 // provided the discrims are not shifted too much to the right
480 let align_threshold: usize = self.config.enum_discrim_align_threshold();
481 let discr_ident_lens: Vec<usize> = enum_def
484 .filter(|var| var.disr_expr.is_some())
485 .map(|var| rewrite_ident(&self.get_context(), var.ident).len())
487 // cut the list at the point of longest discrim shorter than the threshold
488 // All of the discrims under the threshold will get padded, and all above - left as is.
489 let pad_discrim_ident_to = *discr_ident_lens
491 .filter(|&l| *l <= align_threshold)
495 let itemize_list_with = |one_line_width: usize| {
497 self.snippet_provider,
498 enum_def.variants.iter(),
502 if !f.attrs.is_empty() {
509 |f| self.format_variant(f, one_line_width, pad_discrim_ident_to),
516 let mut items: Vec<_> = itemize_list_with(self.config.struct_variant_width());
518 // If one of the variants use multiple lines, use multi-lined formatting for all variants.
519 let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n'));
520 let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n'));
521 if has_multiline_variant && has_single_line_variant {
522 items = itemize_list_with(0);
525 let shape = self.shape().sub_width(2)?;
526 let fmt = ListFormatting::new(shape, self.config)
527 .trailing_separator(self.config.trailing_comma())
528 .preserve_newline(true);
530 let list = write_list(&items, &fmt)?;
531 result.push_str(&list);
532 result.push_str(&original_offset.to_string_with_newline(self.config));
537 // Variant of an enum.
540 field: &ast::Variant,
541 one_line_width: usize,
542 pad_discrim_ident_to: usize,
543 ) -> Option<String> {
544 if contains_skip(&field.attrs) {
545 let lo = field.attrs[0].span.lo();
546 let span = mk_sp(lo, field.span.hi());
547 return Some(self.snippet(span).to_owned());
550 let context = self.get_context();
552 let shape = self.shape().sub_width(1)?;
553 let attrs_str = field.attrs.rewrite(&context, shape)?;
557 .map_or(field.span.lo(), |attr| attr.span.hi());
558 let span = mk_sp(lo, field.span.lo());
560 let variant_body = match field.data {
561 ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct(
563 &StructParts::from_variant(field),
565 Some(one_line_width),
567 ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(),
570 let variant_body = if let Some(ref expr) = field.disr_expr {
571 let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
572 let ex = &*expr.value;
573 rewrite_assign_rhs_with(
578 &RhsAssignKind::Expr(&ex.kind, ex.span),
579 RhsTactics::AllowOverflow,
585 combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
588 fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
589 if self.get_context().config.reorder_impl_items() {
590 type TyOpt = Option<ptr::P<ast::Ty>>;
591 use crate::ast::AssocItemKind::*;
592 let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
593 let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
594 let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
595 let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
596 let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
597 (Type(lty), Type(rty))
598 if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
602 (Const(..), Const(..)) => false,
606 // Create visitor for each items, then reorder them.
607 let mut buffer = vec![];
609 self.visit_impl_item(item);
610 buffer.push((self.buffer.clone(), item.clone()));
614 buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
615 (Type(lty), Type(rty))
616 if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
618 a.ident.as_str().cmp(b.ident.as_str())
620 (Const(..), Const(..)) | (MacCall(..), MacCall(..)) => {
621 a.ident.as_str().cmp(b.ident.as_str())
623 (Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
624 (Type(ty), _) if is_type(&ty.ty) => Ordering::Less,
625 (_, Type(ty)) if is_type(&ty.ty) => Ordering::Greater,
626 (Type(..), _) => Ordering::Less,
627 (_, Type(..)) => Ordering::Greater,
628 (Const(..), _) => Ordering::Less,
629 (_, Const(..)) => Ordering::Greater,
630 (MacCall(..), _) => Ordering::Less,
631 (_, MacCall(..)) => Ordering::Greater,
633 let mut prev_kind = None;
634 for (buf, item) in buffer {
635 // Make sure that there are at least a single empty line between
636 // different impl items.
639 .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind))
643 let indent_str = self.block_indent.to_string_with_newline(self.config);
644 self.push_str(&indent_str);
645 self.push_str(buf.trim());
646 prev_kind = Some(item.kind.clone());
650 self.visit_impl_item(item);
656 pub(crate) fn format_impl(
657 context: &RewriteContext<'_>,
661 ) -> Option<String> {
668 let mut result = String::with_capacity(128);
669 let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
670 let sep = offset.to_string_with_newline(context.config);
671 result.push_str(&ref_and_type);
673 let where_budget = if result.contains('\n') {
674 context.config.max_width()
676 context.budget(last_line_width(&result))
679 let mut option = WhereClauseOption::snuggled(&ref_and_type);
680 let snippet = context.snippet(item.span);
681 let open_pos = snippet.find_uncommented("{")? + 1;
682 if !contains_comment(&snippet[open_pos..])
684 && generics.where_clause.predicates.len() == 1
685 && !result.contains('\n')
687 option.suppress_comma();
689 option.allow_single_line();
692 let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
693 let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
694 let where_clause_str = rewrite_where_clause(
696 &generics.where_clause.predicates,
697 generics.where_clause.span,
698 context.config.brace_style(),
699 Shape::legacy(where_budget, offset.block_only()),
707 // If there is no where-clause, we may have missing comments between the trait name and
708 // the opening brace.
709 if generics.where_clause.predicates.is_empty() {
710 if let Some(hi) = where_span_end {
711 match recover_missing_comment_in_span(
712 mk_sp(self_ty.span.hi(), hi),
713 Shape::indented(offset, context.config),
715 last_line_width(&result),
717 Some(ref missing_comment) if !missing_comment.is_empty() => {
718 result.push_str(missing_comment);
725 if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
726 result.push_str(&where_clause_str);
727 if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
728 // if the where_clause contains extra comments AND
729 // there is only one where-clause predicate
730 // recover the suppressed comma in single line where_clause formatting
731 if generics.where_clause.predicates.len() == 1 {
734 result.push_str(&format!("{}{{{}}}", sep, sep));
736 result.push_str(" {}");
741 result.push_str(&where_clause_str);
743 let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
744 match context.config.brace_style() {
745 _ if need_newline => result.push_str(&sep),
746 BraceStyle::AlwaysNextLine => result.push_str(&sep),
747 BraceStyle::PreferSameLine => result.push(' '),
748 BraceStyle::SameLineWhere => {
749 if !where_clause_str.is_empty() {
750 result.push_str(&sep);
758 // this is an impl body snippet(impl SampleImpl { /* here */ })
759 let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
760 let snippet = context.snippet(mk_sp(lo, item.span.hi()));
761 let open_pos = snippet.find_uncommented("{")? + 1;
763 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
764 let mut visitor = FmtVisitor::from_context(context);
765 let item_indent = offset.block_only().block_indent(context.config);
766 visitor.block_indent = item_indent;
767 visitor.last_pos = lo + BytePos(open_pos as u32);
769 visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
770 visitor.visit_impl_items(items);
772 visitor.format_missing(item.span.hi() - BytePos(1));
774 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
775 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
777 result.push_str(&inner_indent_str);
778 result.push_str(visitor.buffer.trim());
779 result.push_str(&outer_indent_str);
780 } else if need_newline || !context.config.empty_item_single_line() {
781 result.push_str(&sep);
789 fn is_impl_single_line(
790 context: &RewriteContext<'_>,
791 items: &[ptr::P<ast::AssocItem>],
793 where_clause_str: &str,
796 let snippet = context.snippet(item.span);
797 let open_pos = snippet.find_uncommented("{")? + 1;
800 context.config.empty_item_single_line()
802 && !result.contains('\n')
803 && result.len() + where_clause_str.len() <= context.config.max_width()
804 && !contains_comment(&snippet[open_pos..]),
808 fn format_impl_ref_and_type(
809 context: &RewriteContext<'_>,
813 ) -> Option<String> {
820 of_trait: ref trait_ref,
824 let mut result = String::with_capacity(128);
826 result.push_str(&format_visibility(context, &item.vis));
827 result.push_str(format_defaultness(defaultness));
828 result.push_str(format_unsafety(unsafety));
830 let shape = if context.config.version() == Version::Two {
831 Shape::indented(offset + last_line_width(&result), context.config)
833 generics_shape_from_config(
835 Shape::indented(offset + last_line_width(&result), context.config),
839 let generics_str = rewrite_generics(context, "impl", generics, shape)?;
840 result.push_str(&generics_str);
841 result.push_str(format_constness_right(constness));
843 let polarity_str = match polarity {
844 ast::ImplPolarity::Negative(_) => "!",
845 ast::ImplPolarity::Positive => "",
848 let polarity_overhead;
849 let trait_ref_overhead;
850 if let Some(ref trait_ref) = *trait_ref {
851 let result_len = last_line_width(&result);
852 result.push_str(&rewrite_trait_ref(
859 polarity_overhead = 0; // already written
860 trait_ref_overhead = " for".len();
862 polarity_overhead = polarity_str.len();
863 trait_ref_overhead = 0;
866 // Try to put the self type in a single line.
867 let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
868 // If there is no where-clause adapt budget for type formatting to take space and curly
869 // brace into account.
870 match context.config.brace_style() {
871 BraceStyle::AlwaysNextLine => 0,
878 last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
879 // 1 = space before the type.
880 let budget = context.budget(used_space + 1);
881 if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
882 if !self_ty_str.contains('\n') {
883 if trait_ref.is_some() {
884 result.push_str(" for ");
887 result.push_str(polarity_str);
889 result.push_str(&self_ty_str);
894 // Couldn't fit the self type on a single line, put it on a new line.
896 // Add indentation of one additional tab.
897 let new_line_offset = offset.block_indent(context.config);
898 result.push_str(&new_line_offset.to_string(context.config));
899 if trait_ref.is_some() {
900 result.push_str("for ");
902 result.push_str(polarity_str);
904 let budget = context.budget(last_line_width(&result) + polarity_overhead);
905 let type_offset = match context.config.indent_style() {
906 IndentStyle::Visual => new_line_offset + trait_ref_overhead,
907 IndentStyle::Block => new_line_offset,
909 result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
913 fn rewrite_trait_ref(
914 context: &RewriteContext<'_>,
915 trait_ref: &ast::TraitRef,
919 ) -> Option<String> {
920 // 1 = space between generics and trait_ref
921 let used_space = 1 + polarity_str.len() + result_len;
922 let shape = Shape::indented(offset + used_space, context.config);
923 if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
924 if !trait_ref_str.contains('\n') {
925 return Some(format!(" {}{}", polarity_str, trait_ref_str));
928 // We could not make enough space for trait_ref, so put it on new line.
929 let offset = offset.block_indent(context.config);
930 let shape = Shape::indented(offset, context.config);
931 let trait_ref_str = trait_ref.rewrite(context, shape)?;
934 offset.to_string_with_newline(context.config),
940 pub(crate) struct StructParts<'a> {
942 ident: symbol::Ident,
943 vis: &'a ast::Visibility,
944 def: &'a ast::VariantData,
945 generics: Option<&'a ast::Generics>,
949 impl<'a> StructParts<'a> {
950 fn format_header(&self, context: &RewriteContext<'_>, offset: Indent) -> String {
951 format_header(context, self.prefix, self.ident, self.vis, offset)
954 fn from_variant(variant: &'a ast::Variant) -> Self {
957 ident: variant.ident,
958 vis: &DEFAULT_VISIBILITY,
965 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
966 let (prefix, def, generics) = match item.kind {
967 ast::ItemKind::Struct(ref def, ref generics) => ("struct ", def, generics),
968 ast::ItemKind::Union(ref def, ref generics) => ("union ", def, generics),
976 generics: Some(generics),
983 context: &RewriteContext<'_>,
984 struct_parts: &StructParts<'_>,
986 one_line_width: Option<usize>,
987 ) -> Option<String> {
988 match *struct_parts.def {
989 ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset),
990 ast::VariantData::Tuple(ref fields, _) => {
991 format_tuple_struct(context, struct_parts, fields, offset)
993 ast::VariantData::Struct(ref fields, _) => {
994 format_struct_struct(context, struct_parts, fields, offset, one_line_width)
999 pub(crate) fn format_trait(
1000 context: &RewriteContext<'_>,
1003 ) -> Option<String> {
1004 if let ast::ItemKind::Trait(trait_kind) = &item.kind {
1012 let mut result = String::with_capacity(128);
1013 let header = format!(
1015 format_visibility(context, &item.vis),
1016 format_unsafety(unsafety),
1017 format_auto(is_auto),
1019 result.push_str(&header);
1021 let body_lo = context.snippet_provider.span_after(item.span, "{");
1023 let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
1025 rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
1026 result.push_str(&generics_str);
1028 // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
1029 if !bounds.is_empty() {
1030 let ident_hi = context
1032 .span_after(item.span, item.ident.as_str());
1033 let bound_hi = bounds.last().unwrap().span().hi();
1034 let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
1035 if contains_comment(snippet) {
1039 result = rewrite_assign_rhs_with(
1044 &RhsAssignKind::Bounds,
1045 RhsTactics::ForceNextLineWithoutIndent,
1049 // Rewrite where-clause.
1050 if !generics.where_clause.predicates.is_empty() {
1051 let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
1053 let where_budget = context.budget(last_line_width(&result));
1054 let pos_before_where = if bounds.is_empty() {
1055 generics.where_clause.span.lo()
1057 bounds[bounds.len() - 1].span().hi()
1059 let option = WhereClauseOption::snuggled(&generics_str);
1060 let where_clause_str = rewrite_where_clause(
1062 &generics.where_clause.predicates,
1063 generics.where_clause.span,
1064 context.config.brace_style(),
1065 Shape::legacy(where_budget, offset.block_only()),
1072 // If the where-clause cannot fit on the same line,
1073 // put the where-clause on a new line
1074 if !where_clause_str.contains('\n')
1075 && last_line_width(&result) + where_clause_str.len() + offset.width()
1076 > context.config.comment_width()
1078 let width = offset.block_indent + context.config.tab_spaces() - 1;
1079 let where_indent = Indent::new(0, width);
1080 result.push_str(&where_indent.to_string_with_newline(context.config));
1082 result.push_str(&where_clause_str);
1084 let item_snippet = context.snippet(item.span);
1085 if let Some(lo) = item_snippet.find('/') {
1087 let comment_hi = if generics.params.len() > 0 {
1088 generics.span.lo() - BytePos(1)
1090 body_lo - BytePos(1)
1092 let comment_lo = item.span.lo() + BytePos(lo as u32);
1093 if comment_lo < comment_hi {
1094 match recover_missing_comment_in_span(
1095 mk_sp(comment_lo, comment_hi),
1096 Shape::indented(offset, context.config),
1098 last_line_width(&result),
1100 Some(ref missing_comment) if !missing_comment.is_empty() => {
1101 result.push_str(missing_comment);
1109 let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
1110 let snippet = context.snippet(block_span);
1111 let open_pos = snippet.find_uncommented("{")? + 1;
1113 match context.config.brace_style() {
1114 _ if last_line_contains_single_line_comment(&result)
1115 || last_line_width(&result) + 2 > context.budget(offset.width()) =>
1117 result.push_str(&offset.to_string_with_newline(context.config));
1119 _ if context.config.empty_item_single_line()
1121 && !result.contains('\n')
1122 && !contains_comment(&snippet[open_pos..]) =>
1124 result.push_str(" {}");
1125 return Some(result);
1127 BraceStyle::AlwaysNextLine => {
1128 result.push_str(&offset.to_string_with_newline(context.config));
1130 BraceStyle::PreferSameLine => result.push(' '),
1131 BraceStyle::SameLineWhere => {
1132 if result.contains('\n')
1133 || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
1135 result.push_str(&offset.to_string_with_newline(context.config));
1143 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
1145 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
1146 let mut visitor = FmtVisitor::from_context(context);
1147 visitor.block_indent = offset.block_only().block_indent(context.config);
1148 visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
1151 visitor.visit_trait_item(item);
1154 visitor.format_missing(item.span.hi() - BytePos(1));
1156 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
1158 result.push_str(&inner_indent_str);
1159 result.push_str(visitor.buffer.trim());
1160 result.push_str(&outer_indent_str);
1161 } else if result.contains('\n') {
1162 result.push_str(&outer_indent_str);
1172 pub(crate) struct TraitAliasBounds<'a> {
1173 generic_bounds: &'a ast::GenericBounds,
1174 generics: &'a ast::Generics,
1177 impl<'a> Rewrite for TraitAliasBounds<'a> {
1178 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1179 let generic_bounds_str = self.generic_bounds.rewrite(context, shape)?;
1181 let mut option = WhereClauseOption::new(true, WhereClauseSpace::None);
1182 option.allow_single_line();
1184 let where_str = rewrite_where_clause(
1186 &self.generics.where_clause.predicates,
1187 self.generics.where_clause.span,
1188 context.config.brace_style(),
1193 self.generics.where_clause.span.lo(),
1197 let fits_single_line = !generic_bounds_str.contains('\n')
1198 && !where_str.contains('\n')
1199 && generic_bounds_str.len() + where_str.len() < shape.width;
1200 let space = if generic_bounds_str.is_empty() || where_str.is_empty() {
1202 } else if fits_single_line {
1205 shape.indent.to_string_with_newline(context.config)
1208 Some(format!("{}{}{}", generic_bounds_str, space, where_str))
1212 pub(crate) fn format_trait_alias(
1213 context: &RewriteContext<'_>,
1214 ident: symbol::Ident,
1215 vis: &ast::Visibility,
1216 generics: &ast::Generics,
1217 generic_bounds: &ast::GenericBounds,
1219 ) -> Option<String> {
1220 let alias = rewrite_ident(context, ident);
1221 // 6 = "trait ", 2 = " ="
1222 let g_shape = shape.offset_left(6)?.sub_width(2)?;
1223 let generics_str = rewrite_generics(context, alias, generics, g_shape)?;
1224 let vis_str = format_visibility(context, vis);
1225 let lhs = format!("{}trait {} =", vis_str, generics_str);
1227 let trait_alias_bounds = TraitAliasBounds {
1234 &trait_alias_bounds,
1235 &RhsAssignKind::Bounds,
1236 shape.sub_width(1)?,
1241 fn format_unit_struct(
1242 context: &RewriteContext<'_>,
1243 p: &StructParts<'_>,
1245 ) -> Option<String> {
1246 let header_str = format_header(context, p.prefix, p.ident, p.vis, offset);
1247 let generics_str = if let Some(generics) = p.generics {
1248 let hi = context.snippet_provider.span_before_last(p.span, ";");
1252 context.config.brace_style(),
1255 // make a span that starts right after `struct Foo`
1256 mk_sp(p.ident.span.hi(), hi),
1257 last_line_width(&header_str),
1262 Some(format!("{}{};", header_str, generics_str))
1265 pub(crate) fn format_struct_struct(
1266 context: &RewriteContext<'_>,
1267 struct_parts: &StructParts<'_>,
1268 fields: &[ast::FieldDef],
1270 one_line_width: Option<usize>,
1271 ) -> Option<String> {
1272 let mut result = String::with_capacity(1024);
1273 let span = struct_parts.span;
1275 let header_str = struct_parts.format_header(context, offset);
1276 result.push_str(&header_str);
1278 let header_hi = struct_parts.ident.span.hi();
1279 let body_lo = if let Some(generics) = struct_parts.generics {
1280 // Adjust the span to start at the end of the generic arguments before searching for the '{'
1281 let span = span.with_lo(generics.span.hi());
1282 context.snippet_provider.span_after(span, "{")
1284 context.snippet_provider.span_after(span, "{")
1287 let generics_str = match struct_parts.generics {
1288 Some(g) => format_generics(
1291 context.config.brace_style(),
1292 if fields.is_empty() {
1293 BracePos::ForceSameLine
1298 // make a span that starts right after `struct Foo`
1299 mk_sp(header_hi, body_lo),
1300 last_line_width(&result),
1303 // 3 = ` {}`, 2 = ` {`.
1304 let overhead = if fields.is_empty() { 3 } else { 2 };
1305 if (context.config.brace_style() == BraceStyle::AlwaysNextLine && !fields.is_empty())
1306 || context.config.max_width() < overhead + result.len()
1308 format!("\n{}{{", offset.block_only().to_string(context.config))
1315 let overhead = if fields.is_empty() { 1 } else { 0 };
1316 let total_width = result.len() + generics_str.len() + overhead;
1317 if !generics_str.is_empty()
1318 && !generics_str.contains('\n')
1319 && total_width > context.config.max_width()
1322 result.push_str(&offset.to_string(context.config));
1323 result.push_str(generics_str.trim_start());
1325 result.push_str(&generics_str);
1328 if fields.is_empty() {
1329 let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
1330 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
1331 return Some(result);
1335 let one_line_budget = context.budget(result.len() + 3 + offset.width());
1336 let one_line_budget =
1337 one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1339 let items_str = rewrite_with_alignment(
1342 Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
1343 mk_sp(body_lo, span.hi()),
1347 if !items_str.contains('\n')
1348 && !result.contains('\n')
1349 && items_str.len() <= one_line_budget
1350 && !last_line_contains_single_line_comment(&items_str)
1352 Some(format!("{} {} }}", result, items_str))
1358 .block_indent(context.config)
1359 .to_string(context.config),
1361 offset.to_string(context.config)
1366 fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> BytePos {
1368 ast::VisibilityKind::Restricted { .. } => vis.span.hi(),
1369 _ => default_span.lo(),
1373 // Format tuple or struct without any fields. We need to make sure that the comments
1374 // inside the delimiters are preserved.
1375 fn format_empty_struct_or_tuple(
1376 context: &RewriteContext<'_>,
1379 result: &mut String,
1383 // 3 = " {}" or "();"
1384 let used_width = last_line_used_width(result, offset.width()) + 3;
1385 if used_width > context.config.max_width() {
1386 result.push_str(&offset.to_string_with_newline(context.config))
1388 result.push_str(opener);
1390 // indented shape for proper indenting of multi-line comments
1391 let shape = Shape::indented(offset.block_indent(context.config), context.config);
1392 match rewrite_missing_comment(span, shape, context) {
1393 Some(ref s) if s.is_empty() => (),
1395 let is_multi_line = !is_single_line(s);
1396 if is_multi_line || first_line_contains_single_line_comment(s) {
1397 let nested_indent_str = offset
1398 .block_indent(context.config)
1399 .to_string_with_newline(context.config);
1400 result.push_str(&nested_indent_str);
1403 if is_multi_line || last_line_contains_single_line_comment(s) {
1404 result.push_str(&offset.to_string_with_newline(context.config));
1407 None => result.push_str(context.snippet(span)),
1409 result.push_str(closer);
1412 fn format_tuple_struct(
1413 context: &RewriteContext<'_>,
1414 struct_parts: &StructParts<'_>,
1415 fields: &[ast::FieldDef],
1417 ) -> Option<String> {
1418 let mut result = String::with_capacity(1024);
1419 let span = struct_parts.span;
1421 let header_str = struct_parts.format_header(context, offset);
1422 result.push_str(&header_str);
1424 let body_lo = if fields.is_empty() {
1425 let lo = get_bytepos_after_visibility(struct_parts.vis, span);
1428 .span_after(mk_sp(lo, span.hi()), "(")
1432 let body_hi = if fields.is_empty() {
1435 .span_after(mk_sp(body_lo, span.hi()), ")")
1437 // This is a dirty hack to work around a missing `)` from the span of the last field.
1438 let last_arg_span = fields[fields.len() - 1].span;
1441 .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
1442 .unwrap_or_else(|| last_arg_span.hi())
1445 let where_clause_str = match struct_parts.generics {
1447 let budget = context.budget(last_line_width(&header_str));
1448 let shape = Shape::legacy(budget, offset);
1449 let generics_str = rewrite_generics(context, "", generics, shape)?;
1450 result.push_str(&generics_str);
1452 let where_budget = context.budget(last_line_width(&result));
1453 let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1454 rewrite_where_clause(
1456 &generics.where_clause.predicates,
1457 generics.where_clause.span,
1458 context.config.brace_style(),
1459 Shape::legacy(where_budget, offset.block_only()),
1467 None => "".to_owned(),
1470 if fields.is_empty() {
1471 let body_hi = context
1473 .span_before(mk_sp(body_lo, span.hi()), ")");
1474 let inner_span = mk_sp(body_lo, body_hi);
1475 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
1477 let shape = Shape::indented(offset, context.config).sub_width(1)?;
1478 let lo = if let Some(generics) = struct_parts.generics {
1481 struct_parts.ident.span.hi()
1483 result = overflow::rewrite_with_parens(
1488 mk_sp(lo, span.hi()),
1489 context.config.fn_call_width(),
1494 if !where_clause_str.is_empty()
1495 && !where_clause_str.contains('\n')
1496 && (result.contains('\n')
1497 || offset.block_indent + result.len() + where_clause_str.len() + 1
1498 > context.config.max_width())
1500 // We need to put the where-clause on a new line, but we didn't
1501 // know that earlier, so the where-clause will not be indented properly.
1504 &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config),
1507 result.push_str(&where_clause_str);
1512 pub(crate) enum ItemVisitorKind<'a> {
1513 Item(&'a ast::Item),
1514 AssocTraitItem(&'a ast::AssocItem),
1515 AssocImplItem(&'a ast::AssocItem),
1516 ForeignItem(&'a ast::ForeignItem),
1519 struct TyAliasRewriteInfo<'c, 'g>(
1520 &'c RewriteContext<'c>,
1523 (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
1529 pub(crate) fn rewrite_type_alias<'a, 'b>(
1530 ty_alias_kind: &ast::TyAlias,
1531 context: &RewriteContext<'a>,
1533 visitor_kind: &ItemVisitorKind<'b>,
1535 ) -> Option<String> {
1536 use ItemVisitorKind::*;
1544 where_predicates_split,
1546 let ty_opt = ty.as_ref();
1547 let (ident, vis) = match visitor_kind {
1548 Item(i) => (i.ident, &i.vis),
1549 AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
1550 ForeignItem(i) => (i.ident, &i.vis),
1552 let rw_info = &TyAliasRewriteInfo(
1557 where_predicates_split,
1561 let op_ty = opaque_ty(ty);
1562 // Type Aliases are formatted slightly differently depending on the context
1563 // in which they appear, whether they are opaque, and whether they are associated.
1564 // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
1565 // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
1566 match (visitor_kind, &op_ty) {
1567 (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(op_bounds)) => {
1568 let op = OpaqueType { bounds: op_bounds };
1569 rewrite_ty(rw_info, Some(bounds), Some(&op), vis)
1571 (Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => {
1572 rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
1574 (AssocImplItem(_), _) => {
1575 let result = if let Some(op_bounds) = op_ty {
1576 let op = OpaqueType { bounds: op_bounds };
1577 rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY)
1579 rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
1582 ast::Defaultness::Default(..) => Some(format!("default {}", result)),
1589 fn rewrite_ty<R: Rewrite>(
1590 rw_info: &TyAliasRewriteInfo<'_, '_>,
1591 generic_bounds_opt: Option<&ast::GenericBounds>,
1593 vis: &ast::Visibility,
1594 ) -> Option<String> {
1595 let mut result = String::with_capacity(128);
1596 let TyAliasRewriteInfo(
1601 where_predicates_split,
1605 let (before_where_predicates, after_where_predicates) = generics
1608 .split_at(where_predicates_split);
1609 if !after_where_predicates.is_empty() {
1612 result.push_str(&format!("{}type ", format_visibility(context, vis)));
1613 let ident_str = rewrite_ident(context, ident);
1615 if generics.params.is_empty() {
1616 result.push_str(ident_str)
1619 let g_shape = Shape::indented(indent, context.config)
1620 .offset_left(result.len())?
1622 let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
1623 result.push_str(&generics_str);
1626 if let Some(bounds) = generic_bounds_opt {
1627 if !bounds.is_empty() {
1629 let shape = Shape::indented(indent, context.config).offset_left(result.len() + 2)?;
1630 let type_bounds = bounds.rewrite(context, shape).map(|s| format!(": {}", s))?;
1631 result.push_str(&type_bounds);
1635 let where_budget = context.budget(last_line_width(&result));
1636 let mut option = WhereClauseOption::snuggled(&result);
1638 option.suppress_comma();
1640 let where_clause_str = rewrite_where_clause(
1642 before_where_predicates,
1644 context.config.brace_style(),
1645 Shape::legacy(where_budget, indent),
1652 result.push_str(&where_clause_str);
1654 if let Some(ty) = rhs {
1655 // If there's a where clause, add a newline before the assignment. Otherwise just add a
1657 let has_where = !before_where_predicates.is_empty();
1659 result.push_str(&indent.to_string_with_newline(context.config));
1664 let comment_span = context
1666 .opt_span_before(span, "=")
1667 .map(|op_lo| mk_sp(where_clauses.0.1.hi(), op_lo));
1669 let lhs = match comment_span {
1671 if contains_comment(context.snippet_provider.span_to_snippet(comment_span)?) =>
1673 let comment_shape = if has_where {
1674 Shape::indented(indent, context.config)
1676 Shape::indented(indent, context.config)
1677 .block_left(context.config.tab_spaces())?
1680 combine_strs_with_missing_comments(
1689 _ => format!("{}=", result),
1693 let shape = Shape::indented(indent, context.config).sub_width(1)?;
1694 rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
1696 Some(format!("{};", result))
1700 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1702 if config.space_before_colon() { " " } else { "" },
1703 if config.space_after_colon() { " " } else { "" },
1707 pub(crate) fn rewrite_struct_field_prefix(
1708 context: &RewriteContext<'_>,
1709 field: &ast::FieldDef,
1710 ) -> Option<String> {
1711 let vis = format_visibility(context, &field.vis);
1712 let type_annotation_spacing = type_annotation_spacing(context.config);
1713 Some(match field.ident {
1714 Some(name) => format!(
1717 rewrite_ident(context, name),
1718 type_annotation_spacing.0
1720 None => vis.to_string(),
1724 impl Rewrite for ast::FieldDef {
1725 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1726 rewrite_struct_field(context, self, shape, 0)
1730 pub(crate) fn rewrite_struct_field(
1731 context: &RewriteContext<'_>,
1732 field: &ast::FieldDef,
1734 lhs_max_width: usize,
1735 ) -> Option<String> {
1736 if contains_skip(&field.attrs) {
1737 return Some(context.snippet(field.span()).to_owned());
1740 let type_annotation_spacing = type_annotation_spacing(context.config);
1741 let prefix = rewrite_struct_field_prefix(context, field)?;
1743 let attrs_str = field.attrs.rewrite(context, shape)?;
1744 let attrs_extendable = field.ident.is_none() && is_attributes_extendable(&attrs_str);
1745 let missing_span = if field.attrs.is_empty() {
1746 mk_sp(field.span.lo(), field.span.lo())
1748 mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
1750 let mut spacing = String::from(if field.ident.is_some() {
1751 type_annotation_spacing.1
1755 // Try to put everything on a single line.
1756 let attr_prefix = combine_strs_with_missing_comments(
1764 let overhead = trimmed_last_line_width(&attr_prefix);
1765 let lhs_offset = lhs_max_width.saturating_sub(overhead);
1766 for _ in 0..lhs_offset {
1769 // In this extreme case we will be missing a space between an attribute and a field.
1770 if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1774 .offset_left(overhead + spacing.len())
1775 .and_then(|ty_shape| field.ty.rewrite(context, ty_shape));
1776 if let Some(ref ty) = orig_ty {
1777 if !ty.contains('\n') && !contains_comment(context.snippet(missing_span)) {
1778 return Some(attr_prefix + &spacing + ty);
1782 let is_prefix_empty = prefix.is_empty();
1783 // We must use multiline. We are going to put attributes and a field on different lines.
1784 let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
1785 // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
1786 let field_str = if is_prefix_empty {
1787 field_str.trim_start()
1791 combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false)
1794 pub(crate) struct StaticParts<'a> {
1796 vis: &'a ast::Visibility,
1797 ident: symbol::Ident,
1799 mutability: ast::Mutability,
1800 expr_opt: Option<&'a ptr::P<ast::Expr>>,
1801 defaultness: Option<ast::Defaultness>,
1805 impl<'a> StaticParts<'a> {
1806 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
1807 let (defaultness, prefix, ty, mutability, expr) = match item.kind {
1808 ast::ItemKind::Static(ref ty, mutability, ref expr) => {
1809 (None, "static", ty, mutability, expr)
1811 ast::ItemKind::Const(defaultness, ref ty, ref expr) => {
1812 (Some(defaultness), "const", ty, ast::Mutability::Not, expr)
1814 _ => unreachable!(),
1822 expr_opt: expr.as_ref(),
1828 pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self {
1829 let (defaultness, ty, expr_opt) = match ti.kind {
1830 ast::AssocItemKind::Const(defaultness, ref ty, ref expr_opt) => {
1831 (defaultness, ty, expr_opt)
1833 _ => unreachable!(),
1840 mutability: ast::Mutability::Not,
1841 expr_opt: expr_opt.as_ref(),
1842 defaultness: Some(defaultness),
1847 pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self {
1848 let (defaultness, ty, expr) = match ii.kind {
1849 ast::AssocItemKind::Const(defaultness, ref ty, ref expr) => (defaultness, ty, expr),
1850 _ => unreachable!(),
1857 mutability: ast::Mutability::Not,
1858 expr_opt: expr.as_ref(),
1859 defaultness: Some(defaultness),
1866 context: &RewriteContext<'_>,
1867 static_parts: &StaticParts<'_>,
1869 ) -> Option<String> {
1870 let colon = colon_spaces(context.config);
1871 let mut prefix = format!(
1873 format_visibility(context, static_parts.vis),
1874 static_parts.defaultness.map_or("", format_defaultness),
1875 static_parts.prefix,
1876 format_mutability(static_parts.mutability),
1877 rewrite_ident(context, static_parts.ident),
1882 Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?;
1883 let ty_str = match static_parts.ty.rewrite(context, ty_shape) {
1884 Some(ty_str) => ty_str,
1886 if prefix.ends_with(' ') {
1889 let nested_indent = offset.block_indent(context.config);
1890 let nested_shape = Shape::indented(nested_indent, context.config);
1891 let ty_str = static_parts.ty.rewrite(context, nested_shape)?;
1894 nested_indent.to_string_with_newline(context.config),
1900 if let Some(expr) = static_parts.expr_opt {
1901 let comments_lo = context.snippet_provider.span_after(static_parts.span, "=");
1902 let expr_lo = expr.span.lo();
1903 let comments_span = mk_sp(comments_lo, expr_lo);
1905 let lhs = format!("{}{} =", prefix, ty_str);
1908 let remaining_width = context.budget(offset.block_indent + 1);
1909 rewrite_assign_rhs_with_comments(
1913 Shape::legacy(remaining_width, offset.block_only()),
1914 &RhsAssignKind::Expr(&expr.kind, expr.span),
1915 RhsTactics::Default,
1919 .and_then(|res| recover_comment_removed(res, static_parts.span, context))
1920 .map(|s| if s.ends_with(';') { s } else { s + ";" })
1922 Some(format!("{}{};", prefix, ty_str))
1926 // FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
1927 // This should be removed once that bug is resolved, with the type alias formatting using the
1928 // defined Ty for the RHS directly.
1929 // https://github.com/rust-lang/rustfmt/issues/4373
1930 // https://github.com/rust-lang/rustfmt/issues/5027
1931 struct OpaqueType<'a> {
1932 bounds: &'a ast::GenericBounds,
1935 impl<'a> Rewrite for OpaqueType<'a> {
1936 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1937 let shape = shape.offset_left(5)?; // `impl `
1939 .rewrite(context, shape)
1940 .map(|s| format!("impl {}", s))
1944 impl Rewrite for ast::FnRetTy {
1945 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1947 ast::FnRetTy::Default(_) => Some(String::new()),
1948 ast::FnRetTy::Ty(ref ty) => {
1949 if context.config.version() == Version::One
1950 || context.config.indent_style() == IndentStyle::Visual
1952 let inner_width = shape.width.checked_sub(3)?;
1954 .rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1955 .map(|r| format!("-> {}", r));
1958 ty.rewrite(context, shape.offset_left(3)?)
1959 .map(|s| format!("-> {}", s))
1965 fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
1967 ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
1972 /// Recover any missing comments between the param and the type.
1976 /// A 2-len tuple with the comment before the colon in first position, and the comment after the
1977 /// colon in second position.
1978 fn get_missing_param_comments(
1979 context: &RewriteContext<'_>,
1983 ) -> (String, String) {
1984 let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo());
1986 let span_before_colon = {
1987 let missing_comment_span_hi = context
1989 .span_before(missing_comment_span, ":");
1990 mk_sp(pat_span.hi(), missing_comment_span_hi)
1992 let span_after_colon = {
1993 let missing_comment_span_lo = context
1995 .span_after(missing_comment_span, ":");
1996 mk_sp(missing_comment_span_lo, ty_span.lo())
1999 let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context)
2000 .filter(|comment| !comment.is_empty())
2001 .map_or(String::new(), |comment| format!(" {}", comment));
2002 let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context)
2003 .filter(|comment| !comment.is_empty())
2004 .map_or(String::new(), |comment| format!("{} ", comment));
2005 (comment_before_colon, comment_after_colon)
2008 impl Rewrite for ast::Param {
2009 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
2010 let param_attrs_result = self
2012 .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
2013 // N.B. Doc comments aren't typically valid syntax, but could appear
2014 // in the presence of certain macros - https://github.com/rust-lang/rustfmt/issues/4936
2015 let (span, has_multiple_attr_lines, has_doc_comments) = if !self.attrs.is_empty() {
2016 let num_attrs = self.attrs.len();
2018 mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
2019 param_attrs_result.contains('\n'),
2020 self.attrs.iter().any(|a| a.is_doc_comment()),
2023 (mk_sp(self.span.lo(), self.span.lo()), false, false)
2026 if let Some(ref explicit_self) = self.to_self() {
2027 rewrite_explicit_self(
2030 ¶m_attrs_result,
2033 has_multiple_attr_lines,
2035 } else if is_named_param(self) {
2036 let param_name = &self
2038 .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
2039 let mut result = combine_strs_with_missing_comments(
2041 ¶m_attrs_result,
2045 !has_multiple_attr_lines && !has_doc_comments,
2048 if !is_empty_infer(&*self.ty, self.pat.span) {
2049 let (before_comment, after_comment) =
2050 get_missing_param_comments(context, self.pat.span, self.ty.span, shape);
2051 result.push_str(&before_comment);
2052 result.push_str(colon_spaces(context.config));
2053 result.push_str(&after_comment);
2054 let overhead = last_line_width(&result);
2055 let max_width = shape.width.checked_sub(overhead)?;
2056 if let Some(ty_str) = self
2058 .rewrite(context, Shape::legacy(max_width, shape.indent))
2060 result.push_str(&ty_str);
2062 let prev_str = if param_attrs_result.is_empty() {
2065 param_attrs_result + &shape.to_string_with_newline(context.config)
2068 result = combine_strs_with_missing_comments(
2074 !has_multiple_attr_lines,
2076 result.push_str(&before_comment);
2077 result.push_str(colon_spaces(context.config));
2078 result.push_str(&after_comment);
2079 let overhead = last_line_width(&result);
2080 let max_width = shape.width.checked_sub(overhead)?;
2083 .rewrite(context, Shape::legacy(max_width, shape.indent))?;
2084 result.push_str(&ty_str);
2090 self.ty.rewrite(context, shape)
2095 fn rewrite_explicit_self(
2096 context: &RewriteContext<'_>,
2097 explicit_self: &ast::ExplicitSelf,
2101 has_multiple_attr_lines: bool,
2102 ) -> Option<String> {
2103 match explicit_self.node {
2104 ast::SelfKind::Region(lt, m) => {
2105 let mut_str = format_mutability(m);
2108 let lifetime_str = l.rewrite(
2110 Shape::legacy(context.config.max_width(), Indent::empty()),
2112 Some(combine_strs_with_missing_comments(
2115 &format!("&{} {}self", lifetime_str, mut_str),
2118 !has_multiple_attr_lines,
2121 None => Some(combine_strs_with_missing_comments(
2124 &format!("&{}self", mut_str),
2127 !has_multiple_attr_lines,
2131 ast::SelfKind::Explicit(ref ty, mutability) => {
2132 let type_str = ty.rewrite(
2134 Shape::legacy(context.config.max_width(), Indent::empty()),
2137 Some(combine_strs_with_missing_comments(
2140 &format!("{}self: {}", format_mutability(mutability), type_str),
2143 !has_multiple_attr_lines,
2146 ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments(
2149 &format!("{}self", format_mutability(mutability)),
2152 !has_multiple_attr_lines,
2157 pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
2158 if param.attrs.is_empty() {
2159 if is_named_param(param) {
2165 param.attrs[0].span.lo()
2169 pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos {
2170 match param.ty.kind {
2171 ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(),
2172 ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(),
2173 _ => param.ty.span.hi(),
2177 pub(crate) fn is_named_param(param: &ast::Param) -> bool {
2178 if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
2179 ident.name != symbol::kw::Empty
2185 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
2186 pub(crate) enum FnBraceStyle {
2192 // Return type is (result, force_new_line_for_brace)
2194 context: &RewriteContext<'_>,
2196 ident: symbol::Ident,
2199 fn_brace_style: FnBraceStyle,
2200 ) -> Option<(String, bool, bool)> {
2201 let mut force_new_line_for_brace = false;
2203 let where_clause = &fn_sig.generics.where_clause;
2205 let mut result = String::with_capacity(1024);
2206 result.push_str(&fn_sig.to_str(context));
2209 result.push_str("fn ");
2212 let overhead = if let FnBraceStyle::SameLine = fn_brace_style {
2219 let used_width = last_line_used_width(&result, indent.width());
2220 let one_line_budget = context.budget(used_width + overhead);
2222 width: one_line_budget,
2226 let fd = fn_sig.decl;
2227 let generics_str = rewrite_generics(
2229 rewrite_ident(context, ident),
2233 result.push_str(&generics_str);
2235 let snuggle_angle_bracket = generics_str
2238 .map_or(false, |l| l.trim_start().len() == 1);
2240 // Note that the width and indent don't really matter, we'll re-layout the
2241 // return type later anyway.
2244 .rewrite(context, Shape::indented(indent, context.config))?;
2246 let multi_line_ret_str = ret_str.contains('\n');
2247 let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
2250 let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params(
2260 "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
2261 one_line_budget, multi_line_budget, param_indent
2265 // Check if vertical layout was forced.
2266 if one_line_budget == 0
2267 && !snuggle_angle_bracket
2268 && context.config.indent_style() == IndentStyle::Visual
2270 result.push_str(¶m_indent.to_string_with_newline(context.config));
2273 let params_end = if fd.inputs.is_empty() {
2276 .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), ")")
2278 let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
2279 context.snippet_provider.span_after(last_span, ")")
2281 let params_span = mk_sp(
2284 .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), "("),
2287 let param_str = rewrite_params(
2298 let put_params_in_block = match context.config.indent_style() {
2299 IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget,
2301 } && !fd.inputs.is_empty();
2303 let mut params_last_line_contains_comment = false;
2304 let mut no_params_and_over_max_width = false;
2306 if put_params_in_block {
2307 param_indent = indent.block_indent(context.config);
2308 result.push_str(¶m_indent.to_string_with_newline(context.config));
2309 result.push_str(¶m_str);
2310 result.push_str(&indent.to_string_with_newline(context.config));
2313 result.push_str(¶m_str);
2314 let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
2315 // Put the closing brace on the next line if it overflows the max width.
2317 let closing_paren_overflow_max_width =
2318 fd.inputs.is_empty() && used_width + 1 > context.config.max_width();
2319 // If the last line of params contains comment, we cannot put the closing paren
2320 // on the same line.
2321 params_last_line_contains_comment = param_str
2324 .map_or(false, |last_line| last_line.contains("//"));
2326 if context.config.version() == Version::Two {
2327 if closing_paren_overflow_max_width {
2329 result.push_str(&indent.to_string_with_newline(context.config));
2330 no_params_and_over_max_width = true;
2331 } else if params_last_line_contains_comment {
2332 result.push_str(&indent.to_string_with_newline(context.config));
2334 no_params_and_over_max_width = true;
2339 if closing_paren_overflow_max_width || params_last_line_contains_comment {
2340 result.push_str(&indent.to_string_with_newline(context.config));
2347 if let ast::FnRetTy::Ty(..) = fd.output {
2348 let ret_should_indent = match context.config.indent_style() {
2349 // If our params are block layout then we surely must have space.
2350 IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false,
2351 _ if params_last_line_contains_comment => false,
2352 _ if result.contains('\n') || multi_line_ret_str => true,
2354 // If the return type would push over the max width, then put the return type on
2355 // a new line. With the +1 for the signature length an additional space between
2356 // the closing parenthesis of the param and the arrow '->' is considered.
2357 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
2359 // If there is no where-clause, take into account the space after the return type
2361 if where_clause.predicates.is_empty() {
2365 sig_length > context.config.max_width()
2368 let ret_shape = if ret_should_indent {
2369 if context.config.version() == Version::One
2370 || context.config.indent_style() == IndentStyle::Visual
2372 let indent = if param_str.is_empty() {
2373 // Aligning with non-existent params looks silly.
2374 force_new_line_for_brace = true;
2377 // FIXME: we might want to check that using the param indent
2378 // doesn't blow our budget, and if it does, then fallback to
2379 // the where-clause indent.
2383 result.push_str(&indent.to_string_with_newline(context.config));
2384 Shape::indented(indent, context.config)
2386 let mut ret_shape = Shape::indented(indent, context.config);
2387 if param_str.is_empty() {
2388 // Aligning with non-existent params looks silly.
2389 force_new_line_for_brace = true;
2390 ret_shape = if context.use_block_indent() {
2391 ret_shape.offset_left(4).unwrap_or(ret_shape)
2393 ret_shape.indent = ret_shape.indent + 4;
2398 result.push_str(&ret_shape.indent.to_string_with_newline(context.config));
2402 if context.config.version() == Version::Two {
2403 if !param_str.is_empty() || !no_params_and_over_max_width {
2410 let ret_shape = Shape::indented(indent, context.config);
2412 .offset_left(last_line_width(&result))
2413 .unwrap_or(ret_shape)
2416 if multi_line_ret_str || ret_should_indent {
2417 // Now that we know the proper indent and width, we need to
2418 // re-layout the return type.
2419 let ret_str = fd.output.rewrite(context, ret_shape)?;
2420 result.push_str(&ret_str);
2422 result.push_str(&ret_str);
2425 // Comment between return type and the end of the decl.
2426 let snippet_lo = fd.output.span().hi();
2427 if where_clause.predicates.is_empty() {
2428 let snippet_hi = span.hi();
2429 let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
2430 // Try to preserve the layout of the original snippet.
2431 let original_starts_with_newline = snippet
2433 .map_or(false, |i| starts_with_newline(&snippet[i..]));
2434 let original_ends_with_newline = snippet
2435 .rfind(|c| c != ' ')
2436 .map_or(false, |i| snippet[i..].ends_with('\n'));
2437 let snippet = snippet.trim();
2438 if !snippet.is_empty() {
2439 result.push(if original_starts_with_newline {
2444 result.push_str(snippet);
2445 if original_ends_with_newline {
2446 force_new_line_for_brace = true;
2452 let pos_before_where = match fd.output {
2453 ast::FnRetTy::Default(..) => params_span.hi(),
2454 ast::FnRetTy::Ty(ref ty) => ty.span.hi(),
2457 let is_params_multi_lined = param_str.contains('\n');
2459 let space = if put_params_in_block && ret_str.is_empty() {
2460 WhereClauseSpace::Space
2462 WhereClauseSpace::Newline
2464 let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space);
2465 if is_params_multi_lined {
2466 option.veto_single_line();
2468 let where_clause_str = rewrite_where_clause(
2470 &where_clause.predicates,
2472 context.config.brace_style(),
2473 Shape::indented(indent, context.config),
2480 // If there are neither where-clause nor return type, we may be missing comments between
2482 if where_clause_str.is_empty() {
2483 if let ast::FnRetTy::Default(ret_span) = fd.output {
2484 match recover_missing_comment_in_span(
2485 mk_sp(params_span.hi(), ret_span.hi()),
2488 last_line_width(&result),
2490 Some(ref missing_comment) if !missing_comment.is_empty() => {
2491 result.push_str(missing_comment);
2492 force_new_line_for_brace = true;
2499 result.push_str(&where_clause_str);
2501 let ends_with_comment = last_line_contains_single_line_comment(&result);
2502 force_new_line_for_brace |= ends_with_comment;
2503 force_new_line_for_brace |=
2504 is_params_multi_lined && context.config.where_single_line() && !where_clause_str.is_empty();
2505 Some((result, ends_with_comment, force_new_line_for_brace))
2508 /// Kind of spaces to put before `where`.
2509 #[derive(Copy, Clone)]
2510 enum WhereClauseSpace {
2519 #[derive(Copy, Clone)]
2520 struct WhereClauseOption {
2521 suppress_comma: bool, // Force no trailing comma
2522 snuggle: WhereClauseSpace,
2523 allow_single_line: bool, // Try single line where-clause instead of vertical layout
2524 veto_single_line: bool, // Disallow a single-line where-clause.
2527 impl WhereClauseOption {
2528 fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
2532 allow_single_line: false,
2533 veto_single_line: false,
2537 fn snuggled(current: &str) -> WhereClauseOption {
2539 suppress_comma: false,
2540 snuggle: if last_line_width(current) == 1 {
2541 WhereClauseSpace::Space
2543 WhereClauseSpace::Newline
2545 allow_single_line: false,
2546 veto_single_line: false,
2550 fn suppress_comma(&mut self) {
2551 self.suppress_comma = true
2554 fn allow_single_line(&mut self) {
2555 self.allow_single_line = true
2558 fn snuggle(&mut self) {
2559 self.snuggle = WhereClauseSpace::Space
2562 fn veto_single_line(&mut self) {
2563 self.veto_single_line = true;
2568 context: &RewriteContext<'_>,
2569 params: &[ast::Param],
2570 one_line_budget: usize,
2571 multi_line_budget: usize,
2573 param_indent: Indent,
2576 ) -> Option<String> {
2577 if params.is_empty() {
2578 let comment = context
2582 span.hi() - BytePos(1),
2585 return Some(comment.to_owned());
2587 let param_items: Vec<_> = itemize_list(
2588 context.snippet_provider,
2592 |param| span_lo_for_param(param),
2593 |param| param.ty.span.hi(),
2596 .rewrite(context, Shape::legacy(multi_line_budget, param_indent))
2597 .or_else(|| Some(context.snippet(param.span()).to_owned()))
2605 let tactic = definitive_tactic(
2610 .to_list_tactic(param_items.len()),
2614 let budget = match tactic {
2615 DefinitiveListTactic::Horizontal => one_line_budget,
2616 _ => multi_line_budget,
2618 let indent = match context.config.indent_style() {
2619 IndentStyle::Block => indent.block_indent(context.config),
2620 IndentStyle::Visual => param_indent,
2622 let trailing_separator = if variadic {
2623 SeparatorTactic::Never
2625 match context.config.indent_style() {
2626 IndentStyle::Block => context.config.trailing_comma(),
2627 IndentStyle::Visual => SeparatorTactic::Never,
2630 let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config)
2632 .trailing_separator(trailing_separator)
2633 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2634 .preserve_newline(true);
2635 write_list(¶m_items, &fmt)
2638 fn compute_budgets_for_params(
2639 context: &RewriteContext<'_>,
2643 fn_brace_style: FnBraceStyle,
2644 force_vertical_layout: bool,
2645 ) -> Option<(usize, usize, Indent)> {
2647 "compute_budgets_for_params {} {:?}, {}, {:?}",
2653 // Try keeping everything on the same line.
2654 if !result.contains('\n') && !force_vertical_layout {
2655 // 2 = `()`, 3 = `() `, space is before ret_string.
2656 let overhead = if ret_str_len == 0 { 2 } else { 3 };
2657 let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2658 match fn_brace_style {
2659 FnBraceStyle::None => used_space += 1, // 1 = `;`
2660 FnBraceStyle::SameLine => used_space += 2, // 2 = `{}`
2661 FnBraceStyle::NextLine => (),
2663 let one_line_budget = context.budget(used_space);
2665 if one_line_budget > 0 {
2667 let (indent, multi_line_budget) = match context.config.indent_style() {
2668 IndentStyle::Block => {
2669 let indent = indent.block_indent(context.config);
2670 (indent, context.budget(indent.width() + 1))
2672 IndentStyle::Visual => {
2673 let indent = indent + result.len() + 1;
2674 let multi_line_overhead = match fn_brace_style {
2675 FnBraceStyle::SameLine => 4,
2678 (indent, context.budget(multi_line_overhead))
2682 return Some((one_line_budget, multi_line_budget, indent));
2686 // Didn't work. we must force vertical layout and put params on a newline.
2687 let new_indent = indent.block_indent(context.config);
2688 let used_space = match context.config.indent_style() {
2690 IndentStyle::Block => new_indent.width() + 1,
2691 // Account for `)` and possibly ` {`.
2692 IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2694 Some((0, context.budget(used_space), new_indent))
2697 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle {
2698 let predicate_count = where_clause.predicates.len();
2700 if config.where_single_line() && predicate_count == 1 {
2701 return FnBraceStyle::SameLine;
2703 let brace_style = config.brace_style();
2705 let use_next_line = brace_style == BraceStyle::AlwaysNextLine
2706 || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0);
2708 FnBraceStyle::NextLine
2710 FnBraceStyle::SameLine
2714 fn rewrite_generics(
2715 context: &RewriteContext<'_>,
2717 generics: &ast::Generics,
2719 ) -> Option<String> {
2720 // FIXME: convert bounds to where-clauses where they get too big or if
2721 // there is a where-clause at all.
2723 if generics.params.is_empty() {
2724 return Some(ident.to_owned());
2727 let params = generics.params.iter();
2728 overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
2731 fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2732 match config.indent_style() {
2733 IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2734 IndentStyle::Block => {
2738 .block_indent(config.tab_spaces())
2739 .with_max_width(config)
2745 fn rewrite_where_clause_rfc_style(
2746 context: &RewriteContext<'_>,
2747 predicates: &[ast::WherePredicate],
2751 span_end: Option<BytePos>,
2752 span_end_before_where: BytePos,
2753 where_clause_option: WhereClauseOption,
2754 ) -> Option<String> {
2755 let (where_keyword, allow_single_line) = rewrite_where_keyword(
2760 span_end_before_where,
2761 where_clause_option,
2765 let clause_shape = shape
2767 .with_max_width(context.config)
2768 .block_left(context.config.tab_spaces())?
2770 let force_single_line = context.config.where_single_line()
2771 && predicates.len() == 1
2772 && !where_clause_option.veto_single_line;
2774 let preds_str = rewrite_bounds_on_where_clause(
2780 where_clause_option,
2786 if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
2787 || force_single_line
2791 clause_shape.indent.to_string_with_newline(context.config)
2794 Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
2797 /// Rewrite `where` and comment around it.
2798 fn rewrite_where_keyword(
2799 context: &RewriteContext<'_>,
2800 predicates: &[ast::WherePredicate],
2803 span_end_before_where: BytePos,
2804 where_clause_option: WhereClauseOption,
2805 ) -> Option<(String, bool)> {
2806 let block_shape = shape.block().with_max_width(context.config);
2808 let clause_shape = block_shape
2809 .block_left(context.config.tab_spaces())?
2812 let comment_separator = |comment: &str, shape: Shape| {
2813 if comment.is_empty() {
2816 shape.indent.to_string_with_newline(context.config)
2820 let (span_before, span_after) =
2821 missing_span_before_after_where(span_end_before_where, predicates, where_span);
2822 let (comment_before, comment_after) =
2823 rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
2825 let starting_newline = match where_clause_option.snuggle {
2826 WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
2827 WhereClauseSpace::None => Cow::from(""),
2828 _ => block_shape.indent.to_string_with_newline(context.config),
2831 let newline_before_where = comment_separator(&comment_before, shape);
2832 let newline_after_where = comment_separator(&comment_after, clause_shape);
2833 let result = format!(
2835 starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
2837 let allow_single_line = where_clause_option.allow_single_line
2838 && comment_before.is_empty()
2839 && comment_after.is_empty();
2841 Some((result, allow_single_line))
2844 /// Rewrite bounds on a where clause.
2845 fn rewrite_bounds_on_where_clause(
2846 context: &RewriteContext<'_>,
2847 predicates: &[ast::WherePredicate],
2850 span_end: Option<BytePos>,
2851 where_clause_option: WhereClauseOption,
2852 force_single_line: bool,
2853 ) -> Option<String> {
2854 let span_start = predicates[0].span().lo();
2855 // If we don't have the start of the next span, then use the end of the
2856 // predicates, but that means we miss comments.
2857 let len = predicates.len();
2858 let end_of_preds = predicates[len - 1].span().hi();
2859 let span_end = span_end.unwrap_or(end_of_preds);
2860 let items = itemize_list(
2861 context.snippet_provider,
2865 |pred| pred.span().lo(),
2866 |pred| pred.span().hi(),
2867 |pred| pred.rewrite(context, shape),
2872 let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
2873 SeparatorTactic::Never
2875 context.config.trailing_comma()
2878 // shape should be vertical only and only if we have `force_single_line` option enabled
2879 // and the number of items of the where-clause is equal to 1
2880 let shape_tactic = if force_single_line {
2881 DefinitiveListTactic::Horizontal
2883 DefinitiveListTactic::Vertical
2886 let fmt = ListFormatting::new(shape, context.config)
2887 .tactic(shape_tactic)
2888 .trailing_separator(comma_tactic)
2889 .preserve_newline(true);
2890 write_list(&items.collect::<Vec<_>>(), &fmt)
2893 fn rewrite_where_clause(
2894 context: &RewriteContext<'_>,
2895 predicates: &[ast::WherePredicate],
2897 brace_style: BraceStyle,
2901 span_end: Option<BytePos>,
2902 span_end_before_where: BytePos,
2903 where_clause_option: WhereClauseOption,
2904 ) -> Option<String> {
2905 if predicates.is_empty() {
2906 return Some(String::new());
2909 if context.config.indent_style() == IndentStyle::Block {
2910 return rewrite_where_clause_rfc_style(
2917 span_end_before_where,
2918 where_clause_option,
2922 let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2924 let offset = match context.config.indent_style() {
2925 IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2926 // 6 = "where ".len()
2927 IndentStyle::Visual => shape.indent + extra_indent + 6,
2929 // FIXME: if indent_style != Visual, then the budgets below might
2930 // be out by a char or two.
2932 let budget = context.config.max_width() - offset.width();
2933 let span_start = predicates[0].span().lo();
2934 // If we don't have the start of the next span, then use the end of the
2935 // predicates, but that means we miss comments.
2936 let len = predicates.len();
2937 let end_of_preds = predicates[len - 1].span().hi();
2938 let span_end = span_end.unwrap_or(end_of_preds);
2939 let items = itemize_list(
2940 context.snippet_provider,
2944 |pred| pred.span().lo(),
2945 |pred| pred.span().hi(),
2946 |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2951 let item_vec = items.collect::<Vec<_>>();
2952 // FIXME: we don't need to collect here
2953 let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget);
2955 let mut comma_tactic = context.config.trailing_comma();
2956 // Kind of a hack because we don't usually have trailing commas in where-clauses.
2957 if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
2958 comma_tactic = SeparatorTactic::Never;
2961 let fmt = ListFormatting::new(Shape::legacy(budget, offset), context.config)
2963 .trailing_separator(comma_tactic)
2964 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2965 .preserve_newline(true);
2966 let preds_str = write_list(&item_vec, &fmt)?;
2968 let end_length = if terminator == "{" {
2969 // If the brace is on the next line we don't need to count it otherwise it needs two
2972 BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
2973 BraceStyle::PreferSameLine => 2,
2975 } else if terminator == "=" {
2981 || preds_str.contains('\n')
2982 || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
2986 (shape.indent + extra_indent).to_string(context.config),
2990 Some(format!(" where {}", preds_str))
2994 fn missing_span_before_after_where(
2995 before_item_span_end: BytePos,
2996 predicates: &[ast::WherePredicate],
2999 let missing_span_before = mk_sp(before_item_span_end, where_span.lo());
3001 let pos_after_where = where_span.lo() + BytePos(5);
3002 let missing_span_after = mk_sp(pos_after_where, predicates[0].span().lo());
3003 (missing_span_before, missing_span_after)
3006 fn rewrite_comments_before_after_where(
3007 context: &RewriteContext<'_>,
3008 span_before_where: Span,
3009 span_after_where: Span,
3011 ) -> Option<(String, String)> {
3012 let before_comment = rewrite_missing_comment(span_before_where, shape, context)?;
3013 let after_comment = rewrite_missing_comment(
3015 shape.block_indent(context.config.tab_spaces()),
3018 Some((before_comment, after_comment))
3022 context: &RewriteContext<'_>,
3024 ident: symbol::Ident,
3025 vis: &ast::Visibility,
3028 let mut result = String::with_capacity(128);
3029 let shape = Shape::indented(offset, context.config);
3031 result.push_str(format_visibility(context, vis).trim());
3033 // Check for a missing comment between the visibility and the item name.
3034 let after_vis = vis.span.hi();
3035 if let Some(before_item_name) = context
3037 .opt_span_before(mk_sp(vis.span.lo(), ident.span.hi()), item_name.trim())
3039 let missing_span = mk_sp(after_vis, before_item_name);
3040 if let Some(result_with_comment) = combine_strs_with_missing_comments(
3046 /* allow_extend */ true,
3048 result = result_with_comment;
3052 result.push_str(rewrite_ident(context, ident));
3057 #[derive(PartialEq, Eq, Clone, Copy)]
3065 context: &RewriteContext<'_>,
3066 generics: &ast::Generics,
3067 brace_style: BraceStyle,
3068 brace_pos: BracePos,
3072 ) -> Option<String> {
3073 let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
3074 let mut result = rewrite_generics(context, "", generics, shape)?;
3076 // If the generics are not parameterized then generics.span.hi() == 0,
3077 // so we use span.lo(), which is the position after `struct Foo`.
3078 let span_end_before_where = if !generics.params.is_empty() {
3083 let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() {
3084 let budget = context.budget(last_line_used_width(&result, offset.width()));
3085 let mut option = WhereClauseOption::snuggled(&result);
3086 if brace_pos == BracePos::None {
3087 option.suppress_comma = true;
3089 let where_clause_str = rewrite_where_clause(
3091 &generics.where_clause.predicates,
3092 generics.where_clause.span,
3094 Shape::legacy(budget, offset.block_only()),
3098 span_end_before_where,
3101 result.push_str(&where_clause_str);
3103 brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine,
3104 // missed comments are taken care of in #rewrite_where_clause
3109 brace_pos == BracePos::ForceSameLine
3110 || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine
3111 || brace_style != BraceStyle::AlwaysNextLine)
3112 || trimmed_last_line_width(&result) == 1,
3113 rewrite_missing_comment(
3115 span_end_before_where,
3116 if brace_pos == BracePos::None {
3119 context.snippet_provider.span_before(span, "{")
3127 // add missing comments
3128 let missed_line_comments = missed_comments
3129 .filter(|missed_comments| !missed_comments.is_empty())
3130 .map_or(false, |missed_comments| {
3131 let is_block = is_last_comment_block(&missed_comments);
3132 let sep = if is_block { " " } else { "\n" };
3133 result.push_str(sep);
3134 result.push_str(&missed_comments);
3137 if brace_pos == BracePos::None {
3138 return Some(result);
3140 let total_used_width = last_line_used_width(&result, used_width);
3141 let remaining_budget = context.budget(total_used_width);
3142 // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
3143 // and hence we take the closer into account as well for one line budget.
3144 // We assume that the closer has the same length as the opener.
3145 let overhead = if brace_pos == BracePos::ForceSameLine {
3152 let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget;
3153 if !forbid_same_line_brace && same_line_brace {
3157 result.push_str(&offset.block_only().to_string(context.config));
3164 impl Rewrite for ast::ForeignItem {
3165 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
3166 let attrs_str = self.attrs.rewrite(context, shape)?;
3167 // Drop semicolon or it will be interpreted as comment.
3168 // FIXME: this may be a faulty span from libsyntax.
3169 let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
3171 let item_str = match self.kind {
3172 ast::ForeignItemKind::Fn(ref fn_kind) => {
3179 if let Some(ref body) = body {
3180 let mut visitor = FmtVisitor::from_context(context);
3181 visitor.block_indent = shape.indent;
3182 visitor.last_pos = self.span.lo();
3183 let inner_attrs = inner_attributes(&self.attrs);
3184 let fn_ctxt = visit::FnCtxt::Foreign;
3199 Some(visitor.buffer.to_owned())
3205 &FnSig::from_method_sig(sig, generics, &self.vis),
3209 .map(|(s, _, _)| format!("{};", s))
3212 ast::ForeignItemKind::Static(ref ty, mutability, _) => {
3213 // FIXME(#21): we're dropping potential comments in between the
3214 // function kw here.
3215 let vis = format_visibility(context, &self.vis);
3216 let mut_str = format_mutability(mutability);
3217 let prefix = format!(
3221 rewrite_ident(context, self.ident)
3229 shape.sub_width(1)?,
3233 ast::ForeignItemKind::TyAlias(ref ty_alias) => {
3234 let (kind, span) = (&ItemVisitorKind::ForeignItem(self), self.span);
3235 rewrite_type_alias(ty_alias, context, shape.indent, kind, span)
3237 ast::ForeignItemKind::MacCall(ref mac) => {
3238 rewrite_macro(mac, None, context, shape, MacroPosition::Item)
3242 let missing_span = if self.attrs.is_empty() {
3243 mk_sp(self.span.lo(), self.span.lo())
3245 mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
3247 combine_strs_with_missing_comments(
3258 /// Rewrite the attributes of an item.
3260 context: &RewriteContext<'_>,
3264 ) -> Option<String> {
3265 let attrs = filter_inline_attrs(&item.attrs, item.span());
3266 let attrs_str = attrs.rewrite(context, shape)?;
3268 let missed_span = if attrs.is_empty() {
3269 mk_sp(item.span.lo(), item.span.lo())
3271 mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo())
3274 let allow_extend = if attrs.len() == 1 {
3275 let line_len = attrs_str.len() + 1 + item_str.len();
3276 !attrs.first().unwrap().is_doc_comment()
3277 && context.config.inline_attribute_width() >= line_len
3282 combine_strs_with_missing_comments(
3292 /// Rewrite an inline mod.
3293 /// The given shape is used to format the mod's attributes.
3294 pub(crate) fn rewrite_mod(
3295 context: &RewriteContext<'_>,
3298 ) -> Option<String> {
3299 let mut result = String::with_capacity(32);
3300 result.push_str(&*format_visibility(context, &item.vis));
3301 result.push_str("mod ");
3302 result.push_str(rewrite_ident(context, item.ident));
3304 rewrite_attrs(context, item, &result, attrs_shape)
3307 /// Rewrite `extern crate foo;`.
3308 /// The given shape is used to format the extern crate's attributes.
3309 pub(crate) fn rewrite_extern_crate(
3310 context: &RewriteContext<'_>,
3313 ) -> Option<String> {
3314 assert!(is_extern_crate(item));
3315 let new_str = context.snippet(item.span);
3316 let item_str = if contains_comment(new_str) {
3319 let no_whitespace = &new_str.split_whitespace().collect::<Vec<&str>>().join(" ");
3320 String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
3322 rewrite_attrs(context, item, &item_str, attrs_shape)
3325 /// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
3326 pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
3329 ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
3333 pub(crate) fn is_use_item(item: &ast::Item) -> bool {
3334 matches!(item.kind, ast::ItemKind::Use(_))
3337 pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
3338 matches!(item.kind, ast::ItemKind::ExternCrate(..))