1 // Formatting top-level items - functions, structs, enums, traits, impls.
4 use std::cmp::{max, min, Ordering};
7 use rustc_span::{source_map, symbol, BytePos, Span, DUMMY_SP};
9 use syntax::{ast, ptr};
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, RhsTactics,
22 use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
23 use crate::macros::{rewrite_macro, MacroPosition};
25 use crate::rewrite::{Rewrite, RewriteContext};
26 use crate::shape::{Indent, Shape};
27 use crate::source_map::{LineRangeUtils, SpanUtils};
28 use crate::spanned::Spanned;
29 use crate::stmt::Stmt;
31 use crate::vertical::rewrite_with_alignment;
32 use crate::visitor::FmtVisitor;
34 const DEFAULT_VISIBILITY: ast::Visibility = source_map::Spanned {
35 node: ast::VisibilityKind::Inherited,
39 fn type_annotation_separator(config: &Config) -> &str {
43 // Statements of the form
44 // let pat: ty = init;
45 impl Rewrite for ast::Local {
46 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
48 "Local::rewrite {:?} {} {:?}",
49 self, shape.width, shape.indent
52 skip_out_of_file_lines_range!(context, self.span);
54 if contains_skip(&self.attrs) {
58 let attrs_str = self.attrs.rewrite(context, shape)?;
59 let mut result = if attrs_str.is_empty() {
62 combine_strs_with_missing_comments(
67 self.attrs.last().map(|a| a.span.hi()).unwrap(),
76 let pat_shape = shape.offset_left(4)?;
78 let pat_shape = pat_shape.sub_width(1)?;
79 let pat_str = self.pat.rewrite(context, pat_shape)?;
80 result.push_str(&pat_str);
82 // String that is placed within the assignment pattern and expression.
84 let mut infix = String::with_capacity(32);
86 if let Some(ref ty) = self.ty {
87 let separator = type_annotation_separator(context.config);
88 let ty_shape = if pat_str.contains('\n') {
89 shape.with_max_width(context.config)
93 .offset_left(last_line_width(&result) + separator.len())?
97 let rewrite = ty.rewrite(context, ty_shape)?;
99 infix.push_str(separator);
100 infix.push_str(&rewrite);
103 if self.init.is_some() {
104 infix.push_str(" =");
110 result.push_str(&infix);
112 if let Some(ref ex) = self.init {
113 // 1 = trailing semicolon;
114 let nested_shape = shape.sub_width(1)?;
116 result = rewrite_assign_rhs(context, result, &**ex, nested_shape)?;
124 // FIXME convert to using rewrite style rather than visitor
125 // FIXME format modules in this style
128 keyword: &'static str,
129 abi: Cow<'static, str>,
130 vis: Option<&'a ast::Visibility>,
131 body: Vec<BodyElement<'a>>,
136 fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
140 ast::Extern::from_abi(fm.abi),
141 config.force_explicit_abi(),
148 .map(|i| BodyElement::ForeignItem(i))
155 enum BodyElement<'a> {
156 // Stmt(&'a ast::Stmt),
157 // Field(&'a ast::Field),
158 // Variant(&'a ast::Variant),
159 // Item(&'a ast::Item),
160 ForeignItem(&'a ast::ForeignItem),
163 /// Represents a fn's signature.
164 pub(crate) struct FnSig<'a> {
165 decl: &'a ast::FnDecl,
166 generics: &'a ast::Generics,
168 is_async: Cow<'a, ast::IsAsync>,
169 constness: ast::Constness,
170 defaultness: ast::Defaultness,
171 unsafety: ast::Unsafety,
172 visibility: ast::Visibility,
177 decl: &'a ast::FnDecl,
178 generics: &'a ast::Generics,
179 vis: ast::Visibility,
184 ext: ast::Extern::None,
185 is_async: Cow::Owned(ast::IsAsync::NotAsync),
186 constness: ast::Constness::NotConst,
187 defaultness: ast::Defaultness::Final,
188 unsafety: ast::Unsafety::Normal,
193 pub(crate) fn from_method_sig(
194 method_sig: &'a ast::FnSig,
195 generics: &'a ast::Generics,
198 unsafety: method_sig.header.unsafety,
199 is_async: Cow::Borrowed(&method_sig.header.asyncness.node),
200 constness: method_sig.header.constness.node,
201 defaultness: ast::Defaultness::Final,
202 ext: method_sig.header.ext,
203 decl: &*method_sig.decl,
205 visibility: DEFAULT_VISIBILITY,
209 pub(crate) fn from_fn_kind(
210 fn_kind: &'a visit::FnKind<'_>,
211 generics: &'a ast::Generics,
212 decl: &'a ast::FnDecl,
213 defaultness: ast::Defaultness,
216 visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
217 visit::FnCtxt::Assoc(..) => {
218 let mut fn_sig = FnSig::from_method_sig(fn_sig, generics);
219 fn_sig.defaultness = defaultness;
220 fn_sig.visibility = vis.clone();
226 ext: fn_sig.header.ext,
227 constness: fn_sig.header.constness.node,
228 is_async: Cow::Borrowed(&fn_sig.header.asyncness.node),
230 unsafety: fn_sig.header.unsafety,
231 visibility: vis.clone(),
238 fn to_str(&self, context: &RewriteContext<'_>) -> String {
239 let mut result = String::with_capacity(128);
240 // Vis defaultness constness unsafety abi.
241 result.push_str(&*format_visibility(context, &self.visibility));
242 result.push_str(format_defaultness(self.defaultness));
243 result.push_str(format_constness(self.constness));
244 result.push_str(format_async(&self.is_async));
245 result.push_str(format_unsafety(self.unsafety));
246 result.push_str(&format_extern(
248 context.config.force_explicit_abi(),
255 impl<'a> FmtVisitor<'a> {
256 fn format_item(&mut self, item: &Item<'_>) {
257 self.buffer.push_str(&item.abi);
259 let snippet = self.snippet(item.span);
260 let brace_pos = snippet.find_uncommented("{").unwrap();
263 if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
264 // FIXME: this skips comments between the extern keyword and the opening
266 self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
267 self.block_indent = self.block_indent.block_indent(self.config);
269 if item.body.is_empty() {
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);
275 for item in &item.body {
276 self.format_body_element(item);
279 self.block_indent = self.block_indent.block_unindent(self.config);
280 self.format_missing_with_indent(item.span.hi() - BytePos(1));
285 self.last_pos = item.span.hi();
288 fn format_body_element(&mut self, element: &BodyElement<'_>) {
290 BodyElement::ForeignItem(item) => self.format_foreign_item(item),
294 pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
295 let item = Item::from_foreign_mod(fm, span, self.config);
296 self.format_item(&item);
299 fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
300 let rewrite = item.rewrite(&self.get_context(), self.shape());
301 self.push_rewrite(item.span(), rewrite);
302 self.last_pos = item.span.hi();
305 pub(crate) fn rewrite_fn_before_block(
311 ) -> Option<(String, FnBraceStyle)> {
312 let context = self.get_context();
314 let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause);
315 let (result, force_newline_brace) =
316 rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style)?;
319 if self.config.brace_style() == BraceStyle::AlwaysNextLine
320 || force_newline_brace
321 || last_line_width(&result) + 2 > self.shape().width
323 fn_brace_style = FnBraceStyle::NextLine
326 Some((result, fn_brace_style))
329 pub(crate) fn rewrite_required_fn(
334 generics: &ast::Generics,
336 ) -> Option<String> {
337 // Drop semicolon or it will be interpreted as comment.
338 let span = mk_sp(span.lo(), span.hi() - BytePos(1));
339 let context = self.get_context();
341 let (mut result, _) = rewrite_fn_base(
345 &FnSig::from_method_sig(sig, generics),
350 // Re-attach semicolon
356 pub(crate) fn single_line_fn(
360 inner_attrs: Option<&[ast::Attribute]>,
361 ) -> Option<String> {
362 if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) {
366 let source_map = self.get_context().source_map;
368 if self.config.empty_item_single_line()
369 && is_empty_block(block, None, source_map)
370 && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
371 && !last_line_contains_single_line_comment(fn_str)
373 return Some(format!("{} {{}}", fn_str));
376 if !self.config.fn_single_line() || !is_simple_block_stmt(block, None, source_map) {
380 let res = Stmt::from_ast_node(block.stmts.first()?, true)
381 .rewrite(&self.get_context(), self.shape())?;
383 let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
384 if !res.contains('\n') && width <= self.config.max_width() {
385 Some(format!("{} {{ {} }}", fn_str, res))
391 pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) {
392 let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent);
393 self.push_rewrite(static_parts.span, rewrite);
396 pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) {
397 let is_tuple = match struct_parts.def {
398 ast::VariantData::Tuple(..) => true,
401 let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None)
402 .map(|s| if is_tuple { s + ";" } else { s });
403 self.push_rewrite(struct_parts.span, rewrite);
406 pub(crate) fn visit_enum(
409 vis: &ast::Visibility,
410 enum_def: &ast::EnumDef,
411 generics: &ast::Generics,
414 let enum_header = format_header(&self.get_context(), "enum ", ident, vis);
415 self.push_str(&enum_header);
417 let enum_snippet = self.snippet(span);
418 let brace_pos = enum_snippet.find_uncommented("{").unwrap();
419 let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
420 let generics_str = format_generics(
423 self.config.brace_style(),
424 if enum_def.variants.is_empty() {
425 BracePos::ForceSameLine
430 // make a span that starts right after `enum Foo`
431 mk_sp(ident.span.hi(), body_start),
432 last_line_width(&enum_header),
435 self.push_str(&generics_str);
437 self.last_pos = body_start;
439 match self.format_variant_list(enum_def, body_start, span.hi()) {
440 Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
442 self.push_rewrite(mk_sp(body_start, span.hi()), rw);
443 self.block_indent = self.block_indent.block_unindent(self.config);
448 // Format the body of an enum definition
449 fn format_variant_list(
451 enum_def: &ast::EnumDef,
454 ) -> Option<String> {
455 if enum_def.variants.is_empty() {
456 let mut buffer = String::with_capacity(128);
458 let span = mk_sp(body_lo, body_hi - BytePos(1));
459 format_empty_struct_or_tuple(
469 let mut result = String::with_capacity(1024);
470 let original_offset = self.block_indent;
471 self.block_indent = self.block_indent.block_indent(self.config);
473 // If enum variants have discriminants, try to vertically align those,
474 // provided the discrims are not shifted too much to the right
475 let align_threshold: usize = self.config.enum_discrim_align_threshold();
476 let discr_ident_lens: Vec<usize> = enum_def
479 .filter(|var| var.disr_expr.is_some())
480 .map(|var| rewrite_ident(&self.get_context(), var.ident).len())
482 // cut the list at the point of longest discrim shorter than the threshold
483 // All of the discrims under the threshold will get padded, and all above - left as is.
484 let pad_discrim_ident_to = *discr_ident_lens
486 .filter(|&l| *l <= align_threshold)
490 let itemize_list_with = |one_line_width: usize| {
492 self.snippet_provider,
493 enum_def.variants.iter(),
497 if !f.attrs.is_empty() {
504 |f| self.format_variant(f, one_line_width, pad_discrim_ident_to),
511 let mut items: Vec<_> =
512 itemize_list_with(self.config.width_heuristics().struct_variant_width);
513 // If one of the variants use multiple lines, use multi-lined formatting for all variants.
514 let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n'));
515 let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n'));
516 if has_multiline_variant && has_single_line_variant {
517 items = itemize_list_with(0);
520 let shape = self.shape().sub_width(2)?;
521 let fmt = ListFormatting::new(shape, self.config)
522 .trailing_separator(self.config.trailing_comma())
523 .preserve_newline(true);
525 let list = write_list(&items, &fmt)?;
526 result.push_str(&list);
527 result.push_str(&original_offset.to_string_with_newline(self.config));
532 // Variant of an enum.
535 field: &ast::Variant,
536 one_line_width: usize,
537 pad_discrim_ident_to: usize,
538 ) -> Option<String> {
539 if contains_skip(&field.attrs) {
540 let lo = field.attrs[0].span.lo();
541 let span = mk_sp(lo, field.span.hi());
542 return Some(self.snippet(span).to_owned());
545 let context = self.get_context();
547 let shape = self.shape().sub_width(1)?;
548 let attrs_str = field.attrs.rewrite(&context, shape)?;
552 .map_or(field.span.lo(), |attr| attr.span.hi());
553 let span = mk_sp(lo, field.span.lo());
555 let variant_body = match field.data {
556 ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct(
558 &StructParts::from_variant(field),
560 Some(one_line_width),
562 ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(),
565 let variant_body = if let Some(ref expr) = field.disr_expr {
566 let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
567 rewrite_assign_rhs_with(
572 RhsTactics::AllowOverflow,
578 combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
581 fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
582 if self.get_context().config.reorder_impl_items() {
583 // Create visitor for each items, then reorder them.
584 let mut buffer = vec![];
586 self.visit_impl_item(item);
587 buffer.push((self.buffer.clone(), item.clone()));
591 fn is_type(ty: &Option<syntax::ptr::P<ast::Ty>>) -> bool {
594 Some(lty) => match lty.kind.opaque_top_hack() {
601 fn is_opaque(ty: &Option<syntax::ptr::P<ast::Ty>>) -> bool {
604 Some(lty) => match lty.kind.opaque_top_hack() {
612 a: &Option<syntax::ptr::P<ast::Ty>>,
613 b: &Option<syntax::ptr::P<ast::Ty>>,
615 is_type(a) && is_type(b)
619 a: &Option<syntax::ptr::P<ast::Ty>>,
620 b: &Option<syntax::ptr::P<ast::Ty>>,
622 is_opaque(a) && is_opaque(b)
625 // In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but
626 // we still need to differentiate to maintain sorting order.
628 // type -> opaque -> const -> macro -> method
629 use crate::ast::AssocItemKind::*;
630 fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
632 (TyAlias(_, ref lty), TyAlias(_, ref rty))
633 if both_type(lty, rty) || both_opaque(lty, rty) =>
637 (Const(..), Const(..)) => false,
642 buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
643 (TyAlias(_, ref lty), TyAlias(_, ref rty))
644 if both_type(lty, rty) || both_opaque(lty, rty) =>
646 a.ident.as_str().cmp(&b.ident.as_str())
648 (Const(..), Const(..)) | (Macro(..), Macro(..)) => {
649 a.ident.as_str().cmp(&b.ident.as_str())
651 (Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
652 (TyAlias(_, ref ty), _) if is_type(ty) => Ordering::Less,
653 (_, TyAlias(_, ref ty)) if is_type(ty) => Ordering::Greater,
654 (TyAlias(..), _) => Ordering::Less,
655 (_, TyAlias(..)) => Ordering::Greater,
656 (Const(..), _) => Ordering::Less,
657 (_, Const(..)) => Ordering::Greater,
658 (Macro(..), _) => Ordering::Less,
659 (_, Macro(..)) => Ordering::Greater,
661 let mut prev_kind = None;
662 for (buf, item) in buffer {
663 // Make sure that there are at least a single empty line between
664 // different impl items.
667 .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind))
671 let indent_str = self.block_indent.to_string_with_newline(self.config);
672 self.push_str(&indent_str);
673 self.push_str(buf.trim());
674 prev_kind = Some(item.kind.clone());
678 self.visit_impl_item(item);
684 pub(crate) fn format_impl(
685 context: &RewriteContext<'_>,
688 ) -> Option<String> {
689 if let ast::ItemKind::Impl {
696 let mut result = String::with_capacity(128);
697 let ref_and_type = format_impl_ref_and_type(context, item, offset)?;
698 let sep = offset.to_string_with_newline(context.config);
699 result.push_str(&ref_and_type);
701 let where_budget = if result.contains('\n') {
702 context.config.max_width()
704 context.budget(last_line_width(&result))
707 let mut option = WhereClauseOption::snuggled(&ref_and_type);
708 let snippet = context.snippet(item.span);
709 let open_pos = snippet.find_uncommented("{")? + 1;
710 if !contains_comment(&snippet[open_pos..])
712 && generics.where_clause.predicates.len() == 1
713 && !result.contains('\n')
715 option.suppress_comma();
717 option.allow_single_line();
720 let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
721 let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
722 let where_clause_str = rewrite_where_clause(
724 &generics.where_clause,
725 context.config.brace_style(),
726 Shape::legacy(where_budget, offset.block_only()),
734 // If there is no where-clause, we may have missing comments between the trait name and
735 // the opening brace.
736 if generics.where_clause.predicates.is_empty() {
737 if let Some(hi) = where_span_end {
738 match recover_missing_comment_in_span(
739 mk_sp(self_ty.span.hi(), hi),
740 Shape::indented(offset, context.config),
742 last_line_width(&result),
744 Some(ref missing_comment) if !missing_comment.is_empty() => {
745 result.push_str(missing_comment);
752 if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
753 result.push_str(&where_clause_str);
754 if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
755 // if the where_clause contains extra comments AND
756 // there is only one where-clause predicate
757 // recover the suppressed comma in single line where_clause formatting
758 if generics.where_clause.predicates.len() == 1 {
759 result.push_str(",");
761 result.push_str(&format!("{}{{{}}}", sep, sep));
763 result.push_str(" {}");
768 result.push_str(&where_clause_str);
770 let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
771 match context.config.brace_style() {
772 _ if need_newline => result.push_str(&sep),
773 BraceStyle::AlwaysNextLine => result.push_str(&sep),
774 BraceStyle::PreferSameLine => result.push(' '),
775 BraceStyle::SameLineWhere => {
776 if !where_clause_str.is_empty() {
777 result.push_str(&sep);
785 // this is an impl body snippet(impl SampleImpl { /* here */ })
786 let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
787 let snippet = context.snippet(mk_sp(lo, item.span.hi()));
788 let open_pos = snippet.find_uncommented("{")? + 1;
790 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
791 let mut visitor = FmtVisitor::from_context(context);
792 let item_indent = offset.block_only().block_indent(context.config);
793 visitor.block_indent = item_indent;
794 visitor.last_pos = lo + BytePos(open_pos as u32);
796 visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
797 visitor.visit_impl_items(items);
799 visitor.format_missing(item.span.hi() - BytePos(1));
801 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
802 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
804 result.push_str(&inner_indent_str);
805 result.push_str(visitor.buffer.trim());
806 result.push_str(&outer_indent_str);
807 } else if need_newline || !context.config.empty_item_single_line() {
808 result.push_str(&sep);
819 fn is_impl_single_line(
820 context: &RewriteContext<'_>,
821 items: &[ptr::P<ast::AssocItem>],
823 where_clause_str: &str,
826 let snippet = context.snippet(item.span);
827 let open_pos = snippet.find_uncommented("{")? + 1;
830 context.config.empty_item_single_line()
832 && !result.contains('\n')
833 && result.len() + where_clause_str.len() <= context.config.max_width()
834 && !contains_comment(&snippet[open_pos..]),
838 fn format_impl_ref_and_type(
839 context: &RewriteContext<'_>,
842 ) -> Option<String> {
843 if let ast::ItemKind::Impl {
848 of_trait: ref trait_ref,
853 let mut result = String::with_capacity(128);
855 result.push_str(&format_visibility(context, &item.vis));
856 result.push_str(format_defaultness(defaultness));
857 result.push_str(format_unsafety(unsafety));
859 let shape = if context.config.version() == Version::Two {
860 Shape::indented(offset + last_line_width(&result), context.config)
862 generics_shape_from_config(
864 Shape::indented(offset + last_line_width(&result), context.config),
868 let generics_str = rewrite_generics(context, "impl", generics, shape)?;
869 result.push_str(&generics_str);
871 let polarity_str = if polarity == ast::ImplPolarity::Negative {
877 if let Some(ref trait_ref) = *trait_ref {
878 let result_len = last_line_width(&result);
879 result.push_str(&rewrite_trait_ref(
888 // Try to put the self type in a single line.
890 let trait_ref_overhead = if trait_ref.is_some() { 4 } else { 0 };
891 let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
892 // If there is no where-clause adapt budget for type formatting to take space and curly
893 // brace into account.
894 match context.config.brace_style() {
895 BraceStyle::AlwaysNextLine => 0,
901 let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
902 // 1 = space before the type.
903 let budget = context.budget(used_space + 1);
904 if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
905 if !self_ty_str.contains('\n') {
906 if trait_ref.is_some() {
907 result.push_str(" for ");
911 result.push_str(&self_ty_str);
916 // Couldn't fit the self type on a single line, put it on a new line.
918 // Add indentation of one additional tab.
919 let new_line_offset = offset.block_indent(context.config);
920 result.push_str(&new_line_offset.to_string(context.config));
921 if trait_ref.is_some() {
922 result.push_str("for ");
924 let budget = context.budget(last_line_width(&result));
925 let type_offset = match context.config.indent_style() {
926 IndentStyle::Visual => new_line_offset + trait_ref_overhead,
927 IndentStyle::Block => new_line_offset,
929 result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
936 fn rewrite_trait_ref(
937 context: &RewriteContext<'_>,
938 trait_ref: &ast::TraitRef,
942 ) -> Option<String> {
943 // 1 = space between generics and trait_ref
944 let used_space = 1 + polarity_str.len() + result_len;
945 let shape = Shape::indented(offset + used_space, context.config);
946 if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
947 if !trait_ref_str.contains('\n') {
948 return Some(format!(" {}{}", polarity_str, trait_ref_str));
951 // We could not make enough space for trait_ref, so put it on new line.
952 let offset = offset.block_indent(context.config);
953 let shape = Shape::indented(offset, context.config);
954 let trait_ref_str = trait_ref.rewrite(context, shape)?;
957 offset.to_string_with_newline(context.config),
963 pub(crate) struct StructParts<'a> {
966 vis: &'a ast::Visibility,
967 def: &'a ast::VariantData,
968 generics: Option<&'a ast::Generics>,
972 impl<'a> StructParts<'a> {
973 fn format_header(&self, context: &RewriteContext<'_>) -> String {
974 format_header(context, self.prefix, self.ident, self.vis)
977 fn from_variant(variant: &'a ast::Variant) -> Self {
980 ident: variant.ident,
981 vis: &DEFAULT_VISIBILITY,
988 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
989 let (prefix, def, generics) = match item.kind {
990 ast::ItemKind::Struct(ref def, ref generics) => ("struct ", def, generics),
991 ast::ItemKind::Union(ref def, ref generics) => ("union ", def, generics),
999 generics: Some(generics),
1006 context: &RewriteContext<'_>,
1007 struct_parts: &StructParts<'_>,
1009 one_line_width: Option<usize>,
1010 ) -> Option<String> {
1011 match *struct_parts.def {
1012 ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset),
1013 ast::VariantData::Tuple(ref fields, _) => {
1014 format_tuple_struct(context, struct_parts, fields, offset)
1016 ast::VariantData::Struct(ref fields, _) => {
1017 format_struct_struct(context, struct_parts, fields, offset, one_line_width)
1022 pub(crate) fn format_trait(
1023 context: &RewriteContext<'_>,
1026 ) -> Option<String> {
1027 if let ast::ItemKind::Trait(
1035 let mut result = String::with_capacity(128);
1036 let header = format!(
1038 format_visibility(context, &item.vis),
1039 format_unsafety(unsafety),
1040 format_auto(is_auto),
1042 result.push_str(&header);
1044 let body_lo = context.snippet_provider.span_after(item.span, "{");
1046 let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
1048 rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
1049 result.push_str(&generics_str);
1051 // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
1052 if !generic_bounds.is_empty() {
1053 let ident_hi = context
1055 .span_after(item.span, &item.ident.as_str());
1056 let bound_hi = generic_bounds.last().unwrap().span().hi();
1057 let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
1058 if contains_comment(snippet) {
1062 result = rewrite_assign_rhs_with(
1067 RhsTactics::ForceNextLineWithoutIndent,
1071 // Rewrite where-clause.
1072 if !generics.where_clause.predicates.is_empty() {
1073 let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
1075 let where_budget = context.budget(last_line_width(&result));
1076 let pos_before_where = if generic_bounds.is_empty() {
1077 generics.where_clause.span.lo()
1079 generic_bounds[generic_bounds.len() - 1].span().hi()
1081 let option = WhereClauseOption::snuggled(&generics_str);
1082 let where_clause_str = rewrite_where_clause(
1084 &generics.where_clause,
1085 context.config.brace_style(),
1086 Shape::legacy(where_budget, offset.block_only()),
1093 // If the where-clause cannot fit on the same line,
1094 // put the where-clause on a new line
1095 if !where_clause_str.contains('\n')
1096 && last_line_width(&result) + where_clause_str.len() + offset.width()
1097 > context.config.comment_width()
1099 let width = offset.block_indent + context.config.tab_spaces() - 1;
1100 let where_indent = Indent::new(0, width);
1101 result.push_str(&where_indent.to_string_with_newline(context.config));
1103 result.push_str(&where_clause_str);
1105 let item_snippet = context.snippet(item.span);
1106 if let Some(lo) = item_snippet.find('/') {
1108 let comment_hi = body_lo - BytePos(1);
1109 let comment_lo = item.span.lo() + BytePos(lo as u32);
1110 if comment_lo < comment_hi {
1111 match recover_missing_comment_in_span(
1112 mk_sp(comment_lo, comment_hi),
1113 Shape::indented(offset, context.config),
1115 last_line_width(&result),
1117 Some(ref missing_comment) if !missing_comment.is_empty() => {
1118 result.push_str(missing_comment);
1126 match context.config.brace_style() {
1127 _ if last_line_contains_single_line_comment(&result)
1128 || last_line_width(&result) + 2 > context.budget(offset.width()) =>
1130 result.push_str(&offset.to_string_with_newline(context.config));
1132 BraceStyle::AlwaysNextLine => {
1133 result.push_str(&offset.to_string_with_newline(context.config));
1135 BraceStyle::PreferSameLine => result.push(' '),
1136 BraceStyle::SameLineWhere => {
1137 if result.contains('\n')
1138 || (!generics.where_clause.predicates.is_empty() && !trait_items.is_empty())
1140 result.push_str(&offset.to_string_with_newline(context.config));
1148 let snippet = context.snippet(item.span);
1149 let open_pos = snippet.find_uncommented("{")? + 1;
1150 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
1152 if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
1153 let mut visitor = FmtVisitor::from_context(context);
1154 visitor.block_indent = offset.block_only().block_indent(context.config);
1155 visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
1157 for item in trait_items {
1158 visitor.visit_trait_item(item);
1161 visitor.format_missing(item.span.hi() - BytePos(1));
1163 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
1165 result.push_str(&inner_indent_str);
1166 result.push_str(visitor.buffer.trim());
1167 result.push_str(&outer_indent_str);
1168 } else if result.contains('\n') {
1169 result.push_str(&outer_indent_str);
1179 struct OpaqueTypeBounds<'a> {
1180 generic_bounds: &'a ast::GenericBounds,
1183 impl<'a> Rewrite for OpaqueTypeBounds<'a> {
1184 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1186 .rewrite(context, shape)
1187 .map(|s| format!("impl {}", s))
1191 pub(crate) struct TraitAliasBounds<'a> {
1192 generic_bounds: &'a ast::GenericBounds,
1193 generics: &'a ast::Generics,
1196 impl<'a> Rewrite for TraitAliasBounds<'a> {
1197 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1198 let generic_bounds_str = self.generic_bounds.rewrite(context, shape)?;
1200 let mut option = WhereClauseOption::new(true, WhereClauseSpace::None);
1201 option.allow_single_line();
1203 let where_str = rewrite_where_clause(
1205 &self.generics.where_clause,
1206 context.config.brace_style(),
1211 self.generics.where_clause.span.lo(),
1215 let fits_single_line = !generic_bounds_str.contains('\n')
1216 && !where_str.contains('\n')
1217 && generic_bounds_str.len() + where_str.len() + 1 <= shape.width;
1218 let space = if generic_bounds_str.is_empty() || where_str.is_empty() {
1220 } else if fits_single_line {
1223 shape.indent.to_string_with_newline(&context.config)
1226 Some(format!("{}{}{}", generic_bounds_str, space, where_str))
1230 pub(crate) fn format_trait_alias(
1231 context: &RewriteContext<'_>,
1233 vis: &ast::Visibility,
1234 generics: &ast::Generics,
1235 generic_bounds: &ast::GenericBounds,
1237 ) -> Option<String> {
1238 let alias = rewrite_ident(context, ident);
1239 // 6 = "trait ", 2 = " ="
1240 let g_shape = shape.offset_left(6)?.sub_width(2)?;
1241 let generics_str = rewrite_generics(context, &alias, generics, g_shape)?;
1242 let vis_str = format_visibility(context, vis);
1243 let lhs = format!("{}trait {} =", vis_str, generics_str);
1245 let trait_alias_bounds = TraitAliasBounds {
1249 rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";")
1252 fn format_unit_struct(
1253 context: &RewriteContext<'_>,
1254 p: &StructParts<'_>,
1256 ) -> Option<String> {
1257 let header_str = format_header(context, p.prefix, p.ident, p.vis);
1258 let generics_str = if let Some(generics) = p.generics {
1259 let hi = context.snippet_provider.span_before(p.span, ";");
1263 context.config.brace_style(),
1266 // make a span that starts right after `struct Foo`
1267 mk_sp(p.ident.span.hi(), hi),
1268 last_line_width(&header_str),
1273 Some(format!("{}{};", header_str, generics_str))
1276 pub(crate) fn format_struct_struct(
1277 context: &RewriteContext<'_>,
1278 struct_parts: &StructParts<'_>,
1279 fields: &[ast::StructField],
1281 one_line_width: Option<usize>,
1282 ) -> Option<String> {
1283 let mut result = String::with_capacity(1024);
1284 let span = struct_parts.span;
1286 let header_str = struct_parts.format_header(context);
1287 result.push_str(&header_str);
1289 let header_hi = struct_parts.ident.span.hi();
1290 let body_lo = context.snippet_provider.span_after(span, "{");
1292 let generics_str = match struct_parts.generics {
1293 Some(g) => format_generics(
1296 context.config.brace_style(),
1297 if fields.is_empty() {
1298 BracePos::ForceSameLine
1303 // make a span that starts right after `struct Foo`
1304 mk_sp(header_hi, body_lo),
1305 last_line_width(&result),
1308 // 3 = ` {}`, 2 = ` {`.
1309 let overhead = if fields.is_empty() { 3 } else { 2 };
1310 if (context.config.brace_style() == BraceStyle::AlwaysNextLine && !fields.is_empty())
1311 || context.config.max_width() < overhead + result.len()
1313 format!("\n{}{{", offset.block_only().to_string(context.config))
1320 let overhead = if fields.is_empty() { 1 } else { 0 };
1321 let total_width = result.len() + generics_str.len() + overhead;
1322 if !generics_str.is_empty()
1323 && !generics_str.contains('\n')
1324 && total_width > context.config.max_width()
1327 result.push_str(&offset.to_string(context.config));
1328 result.push_str(generics_str.trim_start());
1330 result.push_str(&generics_str);
1333 if fields.is_empty() {
1334 let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
1335 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
1336 return Some(result);
1340 let one_line_budget = context.budget(result.len() + 3 + offset.width());
1341 let one_line_budget =
1342 one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1344 let items_str = rewrite_with_alignment(
1347 Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
1348 mk_sp(body_lo, span.hi()),
1352 if !items_str.contains('\n')
1353 && !result.contains('\n')
1354 && items_str.len() <= one_line_budget
1355 && !last_line_contains_single_line_comment(&items_str)
1357 Some(format!("{} {} }}", result, items_str))
1363 .block_indent(context.config)
1364 .to_string(context.config),
1366 offset.to_string(context.config)
1371 fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> BytePos {
1373 ast::VisibilityKind::Crate(..) | ast::VisibilityKind::Restricted { .. } => vis.span.hi(),
1374 _ => default_span.lo(),
1378 // Format tuple or struct without any fields. We need to make sure that the comments
1379 // inside the delimiters are preserved.
1380 fn format_empty_struct_or_tuple(
1381 context: &RewriteContext<'_>,
1384 result: &mut String,
1388 // 3 = " {}" or "();"
1389 let used_width = last_line_used_width(&result, offset.width()) + 3;
1390 if used_width > context.config.max_width() {
1391 result.push_str(&offset.to_string_with_newline(context.config))
1393 result.push_str(opener);
1394 match rewrite_missing_comment(span, Shape::indented(offset, context.config), context) {
1395 Some(ref s) if s.is_empty() => (),
1397 if !is_single_line(s) || first_line_contains_single_line_comment(s) {
1398 let nested_indent_str = offset
1399 .block_indent(context.config)
1400 .to_string_with_newline(context.config);
1401 result.push_str(&nested_indent_str);
1404 if last_line_contains_single_line_comment(s) {
1405 result.push_str(&offset.to_string_with_newline(context.config));
1408 None => result.push_str(context.snippet(span)),
1410 result.push_str(closer);
1413 fn format_tuple_struct(
1414 context: &RewriteContext<'_>,
1415 struct_parts: &StructParts<'_>,
1416 fields: &[ast::StructField],
1418 ) -> Option<String> {
1419 let mut result = String::with_capacity(1024);
1420 let span = struct_parts.span;
1422 let header_str = struct_parts.format_header(context);
1423 result.push_str(&header_str);
1425 let body_lo = if fields.is_empty() {
1426 let lo = get_bytepos_after_visibility(struct_parts.vis, span);
1429 .span_after(mk_sp(lo, span.hi()), "(")
1433 let body_hi = if fields.is_empty() {
1436 .span_after(mk_sp(body_lo, span.hi()), ")")
1438 // This is a dirty hack to work around a missing `)` from the span of the last field.
1439 let last_arg_span = fields[fields.len() - 1].span;
1442 .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
1443 .unwrap_or_else(|| last_arg_span.hi())
1446 let where_clause_str = match struct_parts.generics {
1448 let budget = context.budget(last_line_width(&header_str));
1449 let shape = Shape::legacy(budget, offset);
1450 let generics_str = rewrite_generics(context, "", generics, shape)?;
1451 result.push_str(&generics_str);
1453 let where_budget = context.budget(last_line_width(&result));
1454 let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1455 rewrite_where_clause(
1457 &generics.where_clause,
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 result = overflow::rewrite_with_parens(
1484 context.config.width_heuristics().fn_call_width,
1489 if !where_clause_str.is_empty()
1490 && !where_clause_str.contains('\n')
1491 && (result.contains('\n')
1492 || offset.block_indent + result.len() + where_clause_str.len() + 1
1493 > context.config.max_width())
1495 // We need to put the where-clause on a new line, but we didn't
1496 // know that earlier, so the where-clause will not be indented properly.
1499 &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config),
1502 result.push_str(&where_clause_str);
1507 fn rewrite_type_prefix(
1508 context: &RewriteContext<'_>,
1512 generics: &ast::Generics,
1513 ) -> Option<String> {
1514 let mut result = String::with_capacity(128);
1515 result.push_str(prefix);
1516 let ident_str = rewrite_ident(context, ident);
1519 if generics.params.is_empty() {
1520 result.push_str(ident_str)
1522 let g_shape = Shape::indented(indent, context.config)
1523 .offset_left(result.len())?
1525 let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
1526 result.push_str(&generics_str);
1529 let where_budget = context.budget(last_line_width(&result));
1530 let option = WhereClauseOption::snuggled(&result);
1531 let where_clause_str = rewrite_where_clause(
1533 &generics.where_clause,
1534 context.config.brace_style(),
1535 Shape::legacy(where_budget, indent),
1542 result.push_str(&where_clause_str);
1547 fn rewrite_type_item<R: Rewrite>(
1548 context: &RewriteContext<'_>,
1554 generics: &ast::Generics,
1555 vis: &ast::Visibility,
1556 ) -> Option<String> {
1557 let mut result = String::with_capacity(128);
1558 result.push_str(&rewrite_type_prefix(
1561 &format!("{}{} ", format_visibility(context, vis), prefix),
1566 if generics.where_clause.predicates.is_empty() {
1567 result.push_str(suffix);
1569 result.push_str(&indent.to_string_with_newline(context.config));
1570 result.push_str(suffix.trim_start());
1574 let rhs_shape = Shape::indented(indent, context.config).sub_width(1)?;
1575 rewrite_assign_rhs(context, result, rhs, rhs_shape).map(|s| s + ";")
1578 pub(crate) fn rewrite_type_alias(
1579 context: &RewriteContext<'_>,
1583 generics: &ast::Generics,
1584 vis: &ast::Visibility,
1585 ) -> Option<String> {
1586 rewrite_type_item(context, indent, "type", " =", ident, ty, generics, vis)
1589 pub(crate) fn rewrite_opaque_type(
1590 context: &RewriteContext<'_>,
1593 generic_bounds: &ast::GenericBounds,
1594 generics: &ast::Generics,
1595 vis: &ast::Visibility,
1596 ) -> Option<String> {
1597 let opaque_type_bounds = OpaqueTypeBounds { generic_bounds };
1604 &opaque_type_bounds,
1610 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1612 if config.space_before_colon() { " " } else { "" },
1613 if config.space_after_colon() { " " } else { "" },
1617 pub(crate) fn rewrite_struct_field_prefix(
1618 context: &RewriteContext<'_>,
1619 field: &ast::StructField,
1620 ) -> Option<String> {
1621 let vis = format_visibility(context, &field.vis);
1622 let type_annotation_spacing = type_annotation_spacing(context.config);
1623 Some(match field.ident {
1624 Some(name) => format!(
1627 rewrite_ident(context, name),
1628 type_annotation_spacing.0
1630 None => vis.to_string(),
1634 impl Rewrite for ast::StructField {
1635 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1636 rewrite_struct_field(context, self, shape, 0)
1640 pub(crate) fn rewrite_struct_field(
1641 context: &RewriteContext<'_>,
1642 field: &ast::StructField,
1644 lhs_max_width: usize,
1645 ) -> Option<String> {
1646 if contains_skip(&field.attrs) {
1647 return Some(context.snippet(field.span()).to_owned());
1650 let type_annotation_spacing = type_annotation_spacing(context.config);
1651 let prefix = rewrite_struct_field_prefix(context, field)?;
1653 let attrs_str = field.attrs.rewrite(context, shape)?;
1654 let attrs_extendable = field.ident.is_none() && is_attributes_extendable(&attrs_str);
1655 let missing_span = if field.attrs.is_empty() {
1656 mk_sp(field.span.lo(), field.span.lo())
1658 mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
1660 let mut spacing = String::from(if field.ident.is_some() {
1661 type_annotation_spacing.1
1665 // Try to put everything on a single line.
1666 let attr_prefix = combine_strs_with_missing_comments(
1674 let overhead = trimmed_last_line_width(&attr_prefix);
1675 let lhs_offset = lhs_max_width.saturating_sub(overhead);
1676 for _ in 0..lhs_offset {
1679 // In this extreme case we will be missing a space between an attribute and a field.
1680 if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1684 .offset_left(overhead + spacing.len())
1685 .and_then(|ty_shape| field.ty.rewrite(context, ty_shape));
1686 if let Some(ref ty) = orig_ty {
1687 if !ty.contains('\n') {
1688 return Some(attr_prefix + &spacing + ty);
1692 let is_prefix_empty = prefix.is_empty();
1693 // We must use multiline. We are going to put attributes and a field on different lines.
1694 let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
1695 // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
1696 let field_str = if is_prefix_empty {
1697 field_str.trim_start()
1701 combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false)
1704 pub(crate) struct StaticParts<'a> {
1706 vis: &'a ast::Visibility,
1709 mutability: ast::Mutability,
1710 expr_opt: Option<&'a ptr::P<ast::Expr>>,
1711 defaultness: Option<ast::Defaultness>,
1715 impl<'a> StaticParts<'a> {
1716 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
1717 let (prefix, ty, mutability, expr) = match item.kind {
1718 ast::ItemKind::Static(ref ty, mutability, ref expr) => ("static", ty, mutability, expr),
1719 ast::ItemKind::Const(ref ty, ref expr) => ("const", ty, ast::Mutability::Not, expr),
1720 _ => unreachable!(),
1728 expr_opt: Some(expr),
1734 pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self {
1735 let (ty, expr_opt) = match ti.kind {
1736 ast::AssocItemKind::Const(ref ty, ref expr_opt) => (ty, expr_opt),
1737 _ => unreachable!(),
1741 vis: &DEFAULT_VISIBILITY,
1744 mutability: ast::Mutability::Not,
1745 expr_opt: expr_opt.as_ref(),
1751 pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self {
1752 let (ty, expr) = match ii.kind {
1753 ast::AssocItemKind::Const(ref ty, ref expr) => (ty, expr),
1754 _ => unreachable!(),
1761 mutability: ast::Mutability::Not,
1762 expr_opt: expr.as_ref(),
1763 defaultness: Some(ii.defaultness),
1770 context: &RewriteContext<'_>,
1771 static_parts: &StaticParts<'_>,
1773 ) -> Option<String> {
1774 let colon = colon_spaces(context.config);
1775 let mut prefix = format!(
1777 format_visibility(context, static_parts.vis),
1778 static_parts.defaultness.map_or("", format_defaultness),
1779 static_parts.prefix,
1780 format_mutability(static_parts.mutability),
1781 rewrite_ident(context, static_parts.ident),
1786 Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?;
1787 let ty_str = match static_parts.ty.rewrite(context, ty_shape) {
1788 Some(ty_str) => ty_str,
1790 if prefix.ends_with(' ') {
1793 let nested_indent = offset.block_indent(context.config);
1794 let nested_shape = Shape::indented(nested_indent, context.config);
1795 let ty_str = static_parts.ty.rewrite(context, nested_shape)?;
1798 nested_indent.to_string_with_newline(context.config),
1804 if let Some(expr) = static_parts.expr_opt {
1805 let lhs = format!("{}{} =", prefix, ty_str);
1807 let remaining_width = context.budget(offset.block_indent + 1);
1812 Shape::legacy(remaining_width, offset.block_only()),
1814 .and_then(|res| recover_comment_removed(res, static_parts.span, context))
1815 .map(|s| if s.ends_with(';') { s } else { s + ";" })
1817 Some(format!("{}{};", prefix, ty_str))
1821 pub(crate) fn rewrite_associated_type(
1823 ty_opt: Option<&ptr::P<ast::Ty>>,
1824 generics: &ast::Generics,
1825 generic_bounds_opt: Option<&ast::GenericBounds>,
1826 context: &RewriteContext<'_>,
1828 ) -> Option<String> {
1829 let ident_str = rewrite_ident(context, ident);
1831 let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
1832 let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
1833 let prefix = format!("type {}", generics_str);
1835 let type_bounds_str = if let Some(bounds) = generic_bounds_opt {
1836 if bounds.is_empty() {
1840 let shape = Shape::indented(indent, context.config).offset_left(prefix.len() + 2)?;
1841 bounds.rewrite(context, shape).map(|s| format!(": {}", s))?
1847 if let Some(ty) = ty_opt {
1849 let shape = Shape::indented(indent, context.config).sub_width(1)?;
1850 let lhs = format!("{}{} =", prefix, type_bounds_str);
1851 rewrite_assign_rhs(context, lhs, &**ty, shape).map(|s| s + ";")
1853 Some(format!("{}{};", prefix, type_bounds_str))
1857 struct OpaqueType<'a> {
1858 bounds: &'a ast::GenericBounds,
1861 impl<'a> Rewrite for OpaqueType<'a> {
1862 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1863 let shape = shape.offset_left(5)?; // `impl `
1865 .rewrite(context, shape)
1866 .map(|s| format!("impl {}", s))
1870 pub(crate) fn rewrite_opaque_impl_type(
1871 context: &RewriteContext<'_>,
1873 generics: &ast::Generics,
1874 generic_bounds: &ast::GenericBounds,
1876 ) -> Option<String> {
1877 let ident_str = rewrite_ident(context, ident);
1879 let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
1880 let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
1881 let prefix = format!("type {} =", generics_str);
1882 let rhs = OpaqueType {
1883 bounds: generic_bounds,
1890 Shape::indented(indent, context.config).sub_width(1)?,
1895 pub(crate) fn rewrite_associated_impl_type(
1897 defaultness: ast::Defaultness,
1898 ty_opt: Option<&ptr::P<ast::Ty>>,
1899 generics: &ast::Generics,
1900 context: &RewriteContext<'_>,
1902 ) -> Option<String> {
1903 let result = rewrite_associated_type(ident, ty_opt, generics, None, context, indent)?;
1906 ast::Defaultness::Default => Some(format!("default {}", result)),
1911 impl Rewrite for ast::FunctionRetTy {
1912 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1914 ast::FunctionRetTy::Default(_) => Some(String::new()),
1915 ast::FunctionRetTy::Ty(ref ty) => {
1916 if context.config.version() == Version::One
1917 || context.config.indent_style() == IndentStyle::Visual
1919 let inner_width = shape.width.checked_sub(3)?;
1921 .rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1922 .map(|r| format!("-> {}", r));
1925 ty.rewrite(context, shape.offset_left(3)?)
1926 .map(|s| format!("-> {}", s))
1932 fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
1934 ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
1939 /// Recover any missing comments between the param and the type.
1943 /// A 2-len tuple with the comment before the colon in first position, and the comment after the
1944 /// colon in second position.
1945 fn get_missing_param_comments(
1946 context: &RewriteContext<'_>,
1950 ) -> (String, String) {
1951 let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo());
1953 let span_before_colon = {
1954 let missing_comment_span_hi = context
1956 .span_before(missing_comment_span, ":");
1957 mk_sp(pat_span.hi(), missing_comment_span_hi)
1959 let span_after_colon = {
1960 let missing_comment_span_lo = context
1962 .span_after(missing_comment_span, ":");
1963 mk_sp(missing_comment_span_lo, ty_span.lo())
1966 let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context)
1967 .filter(|comment| !comment.is_empty())
1968 .map_or(String::new(), |comment| format!(" {}", comment));
1969 let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context)
1970 .filter(|comment| !comment.is_empty())
1971 .map_or(String::new(), |comment| format!("{} ", comment));
1972 (comment_before_colon, comment_after_colon)
1975 impl Rewrite for ast::Param {
1976 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1977 let param_attrs_result = self
1979 .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
1980 let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() {
1981 let num_attrs = self.attrs.len();
1983 mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
1984 param_attrs_result.contains("\n"),
1987 (mk_sp(self.span.lo(), self.span.lo()), false)
1990 if let Some(ref explicit_self) = self.to_self() {
1991 rewrite_explicit_self(
1994 ¶m_attrs_result,
1997 has_multiple_attr_lines,
1999 } else if is_named_param(self) {
2000 let mut result = combine_strs_with_missing_comments(
2002 ¶m_attrs_result,
2005 .rewrite(context, Shape::legacy(shape.width, shape.indent))?,
2008 !has_multiple_attr_lines,
2011 if !is_empty_infer(&*self.ty, self.pat.span) {
2012 let (before_comment, after_comment) =
2013 get_missing_param_comments(context, self.pat.span, self.ty.span, shape);
2014 result.push_str(&before_comment);
2015 result.push_str(colon_spaces(context.config));
2016 result.push_str(&after_comment);
2017 let overhead = last_line_width(&result);
2018 let max_width = shape.width.checked_sub(overhead)?;
2021 .rewrite(context, Shape::legacy(max_width, shape.indent))?;
2022 result.push_str(&ty_str);
2027 self.ty.rewrite(context, shape)
2032 fn rewrite_explicit_self(
2033 context: &RewriteContext<'_>,
2034 explicit_self: &ast::ExplicitSelf,
2038 has_multiple_attr_lines: bool,
2039 ) -> Option<String> {
2040 match explicit_self.node {
2041 ast::SelfKind::Region(lt, m) => {
2042 let mut_str = format_mutability(m);
2045 let lifetime_str = l.rewrite(
2047 Shape::legacy(context.config.max_width(), Indent::empty()),
2049 Some(combine_strs_with_missing_comments(
2052 &format!("&{} {}self", lifetime_str, mut_str),
2055 !has_multiple_attr_lines,
2058 None => Some(combine_strs_with_missing_comments(
2061 &format!("&{}self", mut_str),
2064 !has_multiple_attr_lines,
2068 ast::SelfKind::Explicit(ref ty, mutability) => {
2069 let type_str = ty.rewrite(
2071 Shape::legacy(context.config.max_width(), Indent::empty()),
2074 Some(combine_strs_with_missing_comments(
2077 &format!("{}self: {}", format_mutability(mutability), type_str),
2080 !has_multiple_attr_lines,
2083 ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments(
2086 &format!("{}self", format_mutability(mutability)),
2089 !has_multiple_attr_lines,
2094 pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
2095 if param.attrs.is_empty() {
2096 if is_named_param(param) {
2102 param.attrs[0].span.lo()
2106 pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos {
2107 match param.ty.kind {
2108 ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(),
2109 ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(),
2110 _ => param.ty.span.hi(),
2114 pub(crate) fn is_named_param(param: &ast::Param) -> bool {
2115 if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
2116 ident.name != symbol::kw::Invalid
2122 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
2123 pub(crate) enum FnBraceStyle {
2129 // Return type is (result, force_new_line_for_brace)
2131 context: &RewriteContext<'_>,
2136 fn_brace_style: FnBraceStyle,
2137 ) -> Option<(String, bool)> {
2138 let mut force_new_line_for_brace = false;
2140 let where_clause = &fn_sig.generics.where_clause;
2142 let mut result = String::with_capacity(1024);
2143 result.push_str(&fn_sig.to_str(context));
2146 result.push_str("fn ");
2149 let overhead = if let FnBraceStyle::SameLine = fn_brace_style {
2156 let used_width = last_line_used_width(&result, indent.width());
2157 let one_line_budget = context.budget(used_width + overhead);
2159 width: one_line_budget,
2163 let fd = fn_sig.decl;
2164 let generics_str = rewrite_generics(
2166 rewrite_ident(context, ident),
2170 result.push_str(&generics_str);
2172 let snuggle_angle_bracket = generics_str
2175 .map_or(false, |l| l.trim_start().len() == 1);
2177 // Note that the width and indent don't really matter, we'll re-layout the
2178 // return type later anyway.
2181 .rewrite(context, Shape::indented(indent, context.config))?;
2183 let multi_line_ret_str = ret_str.contains('\n');
2184 let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
2187 let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params(
2197 "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
2198 one_line_budget, multi_line_budget, param_indent
2202 // Check if vertical layout was forced.
2203 if one_line_budget == 0
2204 && !snuggle_angle_bracket
2205 && context.config.indent_style() == IndentStyle::Visual
2207 result.push_str(¶m_indent.to_string_with_newline(context.config));
2210 // Skip `pub(crate)`.
2211 let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span);
2212 // A conservative estimation, to goal is to be over all parens in generics
2213 let params_start = fn_sig
2218 .map_or(lo_after_visibility, |param| param.span().hi());
2219 let params_end = if fd.inputs.is_empty() {
2222 .span_after(mk_sp(params_start, span.hi()), ")")
2224 let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
2225 context.snippet_provider.span_after(last_span, ")")
2227 let params_span = mk_sp(
2230 .span_after(mk_sp(params_start, span.hi()), "("),
2233 let param_str = rewrite_params(
2244 let put_params_in_block = match context.config.indent_style() {
2245 IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget,
2247 } && !fd.inputs.is_empty();
2249 let mut params_last_line_contains_comment = false;
2250 let mut no_params_and_over_max_width = false;
2252 if put_params_in_block {
2253 param_indent = indent.block_indent(context.config);
2254 result.push_str(¶m_indent.to_string_with_newline(context.config));
2255 result.push_str(¶m_str);
2256 result.push_str(&indent.to_string_with_newline(context.config));
2259 result.push_str(¶m_str);
2260 let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
2261 // Put the closing brace on the next line if it overflows the max width.
2263 let closing_paren_overflow_max_width =
2264 fd.inputs.is_empty() && used_width + 1 > context.config.max_width();
2265 // If the last line of params contains comment, we cannot put the closing paren
2266 // on the same line.
2267 params_last_line_contains_comment = param_str
2270 .map_or(false, |last_line| last_line.contains("//"));
2272 if context.config.version() == Version::Two {
2273 if closing_paren_overflow_max_width {
2275 result.push_str(&indent.to_string_with_newline(context.config));
2276 no_params_and_over_max_width = true;
2277 } else if params_last_line_contains_comment {
2278 result.push_str(&indent.to_string_with_newline(context.config));
2280 no_params_and_over_max_width = true;
2285 if closing_paren_overflow_max_width || params_last_line_contains_comment {
2286 result.push_str(&indent.to_string_with_newline(context.config));
2293 if let ast::FunctionRetTy::Ty(..) = fd.output {
2294 let ret_should_indent = match context.config.indent_style() {
2295 // If our params are block layout then we surely must have space.
2296 IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false,
2297 _ if params_last_line_contains_comment => false,
2298 _ if result.contains('\n') || multi_line_ret_str => true,
2300 // If the return type would push over the max width, then put the return type on
2301 // a new line. With the +1 for the signature length an additional space between
2302 // the closing parenthesis of the param and the arrow '->' is considered.
2303 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
2305 // If there is no where-clause, take into account the space after the return type
2307 if where_clause.predicates.is_empty() {
2311 sig_length > context.config.max_width()
2314 let ret_shape = if ret_should_indent {
2315 if context.config.version() == Version::One
2316 || context.config.indent_style() == IndentStyle::Visual
2318 let indent = if param_str.is_empty() {
2319 // Aligning with non-existent params looks silly.
2320 force_new_line_for_brace = true;
2323 // FIXME: we might want to check that using the param indent
2324 // doesn't blow our budget, and if it does, then fallback to
2325 // the where-clause indent.
2329 result.push_str(&indent.to_string_with_newline(context.config));
2330 Shape::indented(indent, context.config)
2332 let mut ret_shape = Shape::indented(indent, context.config);
2333 if param_str.is_empty() {
2334 // Aligning with non-existent params looks silly.
2335 force_new_line_for_brace = true;
2336 ret_shape = if context.use_block_indent() {
2337 ret_shape.offset_left(4).unwrap_or(ret_shape)
2339 ret_shape.indent = ret_shape.indent + 4;
2344 result.push_str(&ret_shape.indent.to_string_with_newline(context.config));
2348 if context.config.version() == Version::Two {
2349 if !param_str.is_empty() || !no_params_and_over_max_width {
2356 let ret_shape = Shape::indented(indent, context.config);
2358 .offset_left(last_line_width(&result))
2359 .unwrap_or(ret_shape)
2362 if multi_line_ret_str || ret_should_indent {
2363 // Now that we know the proper indent and width, we need to
2364 // re-layout the return type.
2365 let ret_str = fd.output.rewrite(context, ret_shape)?;
2366 result.push_str(&ret_str);
2368 result.push_str(&ret_str);
2371 // Comment between return type and the end of the decl.
2372 let snippet_lo = fd.output.span().hi();
2373 if where_clause.predicates.is_empty() {
2374 let snippet_hi = span.hi();
2375 let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
2376 // Try to preserve the layout of the original snippet.
2377 let original_starts_with_newline = snippet
2379 .map_or(false, |i| starts_with_newline(&snippet[i..]));
2380 let original_ends_with_newline = snippet
2381 .rfind(|c| c != ' ')
2382 .map_or(false, |i| snippet[i..].ends_with('\n'));
2383 let snippet = snippet.trim();
2384 if !snippet.is_empty() {
2385 result.push(if original_starts_with_newline {
2390 result.push_str(snippet);
2391 if original_ends_with_newline {
2392 force_new_line_for_brace = true;
2398 let pos_before_where = match fd.output {
2399 ast::FunctionRetTy::Default(..) => params_span.hi(),
2400 ast::FunctionRetTy::Ty(ref ty) => ty.span.hi(),
2403 let is_params_multi_lined = param_str.contains('\n');
2405 let space = if put_params_in_block && ret_str.is_empty() {
2406 WhereClauseSpace::Space
2408 WhereClauseSpace::Newline
2410 let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space);
2411 if is_params_multi_lined {
2412 option.veto_single_line();
2414 let where_clause_str = rewrite_where_clause(
2417 context.config.brace_style(),
2418 Shape::indented(indent, context.config),
2425 // If there are neither where-clause nor return type, we may be missing comments between
2427 if where_clause_str.is_empty() {
2428 if let ast::FunctionRetTy::Default(ret_span) = fd.output {
2429 match recover_missing_comment_in_span(
2430 mk_sp(params_span.hi(), ret_span.hi()),
2433 last_line_width(&result),
2435 Some(ref missing_comment) if !missing_comment.is_empty() => {
2436 result.push_str(missing_comment);
2437 force_new_line_for_brace = true;
2444 result.push_str(&where_clause_str);
2446 force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
2447 force_new_line_for_brace |= is_params_multi_lined && context.config.where_single_line();
2448 Some((result, force_new_line_for_brace))
2451 /// Kind of spaces to put before `where`.
2452 #[derive(Copy, Clone)]
2453 enum WhereClauseSpace {
2462 #[derive(Copy, Clone)]
2463 struct WhereClauseOption {
2464 suppress_comma: bool, // Force no trailing comma
2465 snuggle: WhereClauseSpace,
2466 allow_single_line: bool, // Try single line where-clause instead of vertical layout
2467 veto_single_line: bool, // Disallow a single-line where-clause.
2470 impl WhereClauseOption {
2471 fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
2475 allow_single_line: false,
2476 veto_single_line: false,
2480 fn snuggled(current: &str) -> WhereClauseOption {
2482 suppress_comma: false,
2483 snuggle: if last_line_width(current) == 1 {
2484 WhereClauseSpace::Space
2486 WhereClauseSpace::Newline
2488 allow_single_line: false,
2489 veto_single_line: false,
2493 fn suppress_comma(&mut self) {
2494 self.suppress_comma = true
2497 fn allow_single_line(&mut self) {
2498 self.allow_single_line = true
2501 fn snuggle(&mut self) {
2502 self.snuggle = WhereClauseSpace::Space
2505 fn veto_single_line(&mut self) {
2506 self.veto_single_line = true;
2511 context: &RewriteContext<'_>,
2512 params: &[ast::Param],
2513 one_line_budget: usize,
2514 multi_line_budget: usize,
2516 param_indent: Indent,
2519 ) -> Option<String> {
2520 if params.is_empty() {
2521 let comment = context
2525 span.hi() - BytePos(1),
2528 return Some(comment.to_owned());
2530 let param_items: Vec<_> = itemize_list(
2531 context.snippet_provider,
2535 |param| span_lo_for_param(param),
2536 |param| param.ty.span.hi(),
2539 .rewrite(context, Shape::legacy(multi_line_budget, param_indent))
2540 .or_else(|| Some(context.snippet(param.span()).to_owned()))
2548 let tactic = definitive_tactic(
2553 .to_list_tactic(param_items.len()),
2557 let budget = match tactic {
2558 DefinitiveListTactic::Horizontal => one_line_budget,
2559 _ => multi_line_budget,
2561 let indent = match context.config.indent_style() {
2562 IndentStyle::Block => indent.block_indent(context.config),
2563 IndentStyle::Visual => param_indent,
2565 let trailing_separator = if variadic {
2566 SeparatorTactic::Never
2568 match context.config.indent_style() {
2569 IndentStyle::Block => context.config.trailing_comma(),
2570 IndentStyle::Visual => SeparatorTactic::Never,
2573 let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config)
2575 .trailing_separator(trailing_separator)
2576 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2577 .preserve_newline(true);
2578 write_list(¶m_items, &fmt)
2581 fn compute_budgets_for_params(
2582 context: &RewriteContext<'_>,
2586 fn_brace_style: FnBraceStyle,
2587 force_vertical_layout: bool,
2588 ) -> Option<((usize, usize, Indent))> {
2590 "compute_budgets_for_params {} {:?}, {}, {:?}",
2596 // Try keeping everything on the same line.
2597 if !result.contains('\n') && !force_vertical_layout {
2598 // 2 = `()`, 3 = `() `, space is before ret_string.
2599 let overhead = if ret_str_len == 0 { 2 } else { 3 };
2600 let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2601 match fn_brace_style {
2602 FnBraceStyle::None => used_space += 1, // 1 = `;`
2603 FnBraceStyle::SameLine => used_space += 2, // 2 = `{}`
2604 FnBraceStyle::NextLine => (),
2606 let one_line_budget = context.budget(used_space);
2608 if one_line_budget > 0 {
2610 let (indent, multi_line_budget) = match context.config.indent_style() {
2611 IndentStyle::Block => {
2612 let indent = indent.block_indent(context.config);
2613 (indent, context.budget(indent.width() + 1))
2615 IndentStyle::Visual => {
2616 let indent = indent + result.len() + 1;
2617 let multi_line_overhead = match fn_brace_style {
2618 FnBraceStyle::SameLine => 4,
2621 (indent, context.budget(multi_line_overhead))
2625 return Some((one_line_budget, multi_line_budget, indent));
2629 // Didn't work. we must force vertical layout and put params on a newline.
2630 let new_indent = indent.block_indent(context.config);
2631 let used_space = match context.config.indent_style() {
2633 IndentStyle::Block => new_indent.width() + 1,
2634 // Account for `)` and possibly ` {`.
2635 IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2637 Some((0, context.budget(used_space), new_indent))
2640 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle {
2641 let predicate_count = where_clause.predicates.len();
2643 if config.where_single_line() && predicate_count == 1 {
2644 return FnBraceStyle::SameLine;
2646 let brace_style = config.brace_style();
2648 let use_next_line = brace_style == BraceStyle::AlwaysNextLine
2649 || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0);
2651 FnBraceStyle::NextLine
2653 FnBraceStyle::SameLine
2657 fn rewrite_generics(
2658 context: &RewriteContext<'_>,
2660 generics: &ast::Generics,
2662 ) -> Option<String> {
2663 // FIXME: convert bounds to where-clauses where they get too big or if
2664 // there is a where-clause at all.
2666 if generics.params.is_empty() {
2667 return Some(ident.to_owned());
2670 let params = generics.params.iter();
2671 overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
2674 fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2675 match config.indent_style() {
2676 IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2677 IndentStyle::Block => {
2681 .block_indent(config.tab_spaces())
2682 .with_max_width(config)
2688 fn rewrite_where_clause_rfc_style(
2689 context: &RewriteContext<'_>,
2690 where_clause: &ast::WhereClause,
2693 span_end: Option<BytePos>,
2694 span_end_before_where: BytePos,
2695 where_clause_option: WhereClauseOption,
2696 ) -> Option<String> {
2697 let (where_keyword, allow_single_line) = rewrite_where_keyword(
2701 span_end_before_where,
2702 where_clause_option,
2706 let clause_shape = shape
2708 .with_max_width(context.config)
2709 .block_left(context.config.tab_spaces())?
2711 let force_single_line = context.config.where_single_line()
2712 && where_clause.predicates.len() == 1
2713 && !where_clause_option.veto_single_line;
2715 let preds_str = rewrite_bounds_on_where_clause(
2721 where_clause_option,
2727 if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
2728 || force_single_line
2732 clause_shape.indent.to_string_with_newline(context.config)
2735 Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
2738 /// Rewrite `where` and comment around it.
2739 fn rewrite_where_keyword(
2740 context: &RewriteContext<'_>,
2741 where_clause: &ast::WhereClause,
2743 span_end_before_where: BytePos,
2744 where_clause_option: WhereClauseOption,
2745 ) -> Option<(String, bool)> {
2746 let block_shape = shape.block().with_max_width(context.config);
2748 let clause_shape = block_shape
2749 .block_left(context.config.tab_spaces())?
2752 let comment_separator = |comment: &str, shape: Shape| {
2753 if comment.is_empty() {
2756 shape.indent.to_string_with_newline(context.config)
2760 let (span_before, span_after) =
2761 missing_span_before_after_where(span_end_before_where, where_clause);
2762 let (comment_before, comment_after) =
2763 rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
2765 let starting_newline = match where_clause_option.snuggle {
2766 WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
2767 WhereClauseSpace::None => Cow::from(""),
2768 _ => block_shape.indent.to_string_with_newline(context.config),
2771 let newline_before_where = comment_separator(&comment_before, shape);
2772 let newline_after_where = comment_separator(&comment_after, clause_shape);
2773 let result = format!(
2775 starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
2777 let allow_single_line = where_clause_option.allow_single_line
2778 && comment_before.is_empty()
2779 && comment_after.is_empty();
2781 Some((result, allow_single_line))
2784 /// Rewrite bounds on a where clause.
2785 fn rewrite_bounds_on_where_clause(
2786 context: &RewriteContext<'_>,
2787 where_clause: &ast::WhereClause,
2790 span_end: Option<BytePos>,
2791 where_clause_option: WhereClauseOption,
2792 force_single_line: bool,
2793 ) -> Option<String> {
2794 let span_start = where_clause.predicates[0].span().lo();
2795 // If we don't have the start of the next span, then use the end of the
2796 // predicates, but that means we miss comments.
2797 let len = where_clause.predicates.len();
2798 let end_of_preds = where_clause.predicates[len - 1].span().hi();
2799 let span_end = span_end.unwrap_or(end_of_preds);
2800 let items = itemize_list(
2801 context.snippet_provider,
2802 where_clause.predicates.iter(),
2805 |pred| pred.span().lo(),
2806 |pred| pred.span().hi(),
2807 |pred| pred.rewrite(context, shape),
2812 let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
2813 SeparatorTactic::Never
2815 context.config.trailing_comma()
2818 // shape should be vertical only and only if we have `force_single_line` option enabled
2819 // and the number of items of the where-clause is equal to 1
2820 let shape_tactic = if force_single_line {
2821 DefinitiveListTactic::Horizontal
2823 DefinitiveListTactic::Vertical
2826 let fmt = ListFormatting::new(shape, context.config)
2827 .tactic(shape_tactic)
2828 .trailing_separator(comma_tactic)
2829 .preserve_newline(true);
2830 write_list(&items.collect::<Vec<_>>(), &fmt)
2833 fn rewrite_where_clause(
2834 context: &RewriteContext<'_>,
2835 where_clause: &ast::WhereClause,
2836 brace_style: BraceStyle,
2840 span_end: Option<BytePos>,
2841 span_end_before_where: BytePos,
2842 where_clause_option: WhereClauseOption,
2843 ) -> Option<String> {
2844 if where_clause.predicates.is_empty() {
2845 return Some(String::new());
2848 if context.config.indent_style() == IndentStyle::Block {
2849 return rewrite_where_clause_rfc_style(
2855 span_end_before_where,
2856 where_clause_option,
2860 let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2862 let offset = match context.config.indent_style() {
2863 IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2864 // 6 = "where ".len()
2865 IndentStyle::Visual => shape.indent + extra_indent + 6,
2867 // FIXME: if indent_style != Visual, then the budgets below might
2868 // be out by a char or two.
2870 let budget = context.config.max_width() - offset.width();
2871 let span_start = where_clause.predicates[0].span().lo();
2872 // If we don't have the start of the next span, then use the end of the
2873 // predicates, but that means we miss comments.
2874 let len = where_clause.predicates.len();
2875 let end_of_preds = where_clause.predicates[len - 1].span().hi();
2876 let span_end = span_end.unwrap_or(end_of_preds);
2877 let items = itemize_list(
2878 context.snippet_provider,
2879 where_clause.predicates.iter(),
2882 |pred| pred.span().lo(),
2883 |pred| pred.span().hi(),
2884 |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2889 let item_vec = items.collect::<Vec<_>>();
2890 // FIXME: we don't need to collect here
2891 let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget);
2893 let mut comma_tactic = context.config.trailing_comma();
2894 // Kind of a hack because we don't usually have trailing commas in where-clauses.
2895 if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
2896 comma_tactic = SeparatorTactic::Never;
2899 let fmt = ListFormatting::new(Shape::legacy(budget, offset), context.config)
2901 .trailing_separator(comma_tactic)
2902 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2903 .preserve_newline(true);
2904 let preds_str = write_list(&item_vec, &fmt)?;
2906 let end_length = if terminator == "{" {
2907 // If the brace is on the next line we don't need to count it otherwise it needs two
2910 BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
2911 BraceStyle::PreferSameLine => 2,
2913 } else if terminator == "=" {
2919 || preds_str.contains('\n')
2920 || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
2924 (shape.indent + extra_indent).to_string(context.config),
2928 Some(format!(" where {}", preds_str))
2932 fn missing_span_before_after_where(
2933 before_item_span_end: BytePos,
2934 where_clause: &ast::WhereClause,
2936 let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
2938 let pos_after_where = where_clause.span.lo() + BytePos(5);
2939 let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
2940 (missing_span_before, missing_span_after)
2943 fn rewrite_comments_before_after_where(
2944 context: &RewriteContext<'_>,
2945 span_before_where: Span,
2946 span_after_where: Span,
2948 ) -> Option<(String, String)> {
2949 let before_comment = rewrite_missing_comment(span_before_where, shape, context)?;
2950 let after_comment = rewrite_missing_comment(
2952 shape.block_indent(context.config.tab_spaces()),
2955 Some((before_comment, after_comment))
2959 context: &RewriteContext<'_>,
2962 vis: &ast::Visibility,
2966 format_visibility(context, vis),
2968 rewrite_ident(context, ident)
2972 #[derive(PartialEq, Eq, Clone, Copy)]
2980 context: &RewriteContext<'_>,
2981 generics: &ast::Generics,
2982 brace_style: BraceStyle,
2983 brace_pos: BracePos,
2987 ) -> Option<String> {
2988 let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
2989 let mut result = rewrite_generics(context, "", generics, shape)?;
2991 // If the generics are not parameterized then generics.span.hi() == 0,
2992 // so we use span.lo(), which is the position after `struct Foo`.
2993 let span_end_before_where = if !generics.params.is_empty() {
2998 let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() {
2999 let budget = context.budget(last_line_used_width(&result, offset.width()));
3000 let mut option = WhereClauseOption::snuggled(&result);
3001 if brace_pos == BracePos::None {
3002 option.suppress_comma = true;
3004 let where_clause_str = rewrite_where_clause(
3006 &generics.where_clause,
3008 Shape::legacy(budget, offset.block_only()),
3012 span_end_before_where,
3015 result.push_str(&where_clause_str);
3017 brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine,
3018 // missed comments are taken care of in #rewrite_where_clause
3023 brace_pos == BracePos::ForceSameLine
3024 || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine
3025 || brace_style != BraceStyle::AlwaysNextLine)
3026 || trimmed_last_line_width(&result) == 1,
3027 rewrite_missing_comment(
3029 span_end_before_where,
3030 if brace_pos == BracePos::None {
3033 context.snippet_provider.span_before(span, "{")
3041 // add missing comments
3042 let missed_line_comments = missed_comments
3043 .filter(|missed_comments| !missed_comments.is_empty())
3044 .map_or(false, |missed_comments| {
3045 let is_block = is_last_comment_block(&missed_comments);
3046 let sep = if is_block { " " } else { "\n" };
3047 result.push_str(sep);
3048 result.push_str(&missed_comments);
3051 if brace_pos == BracePos::None {
3052 return Some(result);
3054 let total_used_width = last_line_used_width(&result, used_width);
3055 let remaining_budget = context.budget(total_used_width);
3056 // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
3057 // and hence we take the closer into account as well for one line budget.
3058 // We assume that the closer has the same length as the opener.
3059 let overhead = if brace_pos == BracePos::ForceSameLine {
3066 let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget;
3067 if !forbid_same_line_brace && same_line_brace {
3071 result.push_str(&offset.block_only().to_string(context.config));
3078 impl Rewrite for ast::ForeignItem {
3079 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
3080 let attrs_str = self.attrs.rewrite(context, shape)?;
3081 // Drop semicolon or it will be interpreted as comment.
3082 // FIXME: this may be a faulty span from libsyntax.
3083 let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
3085 let item_str = match self.kind {
3086 ast::ForeignItemKind::Fn(ref fn_sig, ref generics, _) => rewrite_fn_base(
3090 &FnSig::new(&fn_sig.decl, generics, self.vis.clone()),
3094 .map(|(s, _)| format!("{};", s)),
3095 ast::ForeignItemKind::Static(ref ty, mutability) => {
3096 // FIXME(#21): we're dropping potential comments in between the
3097 // function kw here.
3098 let vis = format_visibility(context, &self.vis);
3099 let mut_str = format_mutability(mutability);
3100 let prefix = format!(
3104 rewrite_ident(context, self.ident)
3107 rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
3109 ast::ForeignItemKind::Ty => {
3110 let vis = format_visibility(context, &self.vis);
3114 rewrite_ident(context, self.ident)
3117 ast::ForeignItemKind::Macro(ref mac) => {
3118 rewrite_macro(mac, None, context, shape, MacroPosition::Item)
3122 let missing_span = if self.attrs.is_empty() {
3123 mk_sp(self.span.lo(), self.span.lo())
3125 mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
3127 combine_strs_with_missing_comments(
3138 /// Rewrite the attributes of an item.
3140 context: &RewriteContext<'_>,
3144 ) -> Option<String> {
3145 let attrs = filter_inline_attrs(&item.attrs, item.span());
3146 let attrs_str = attrs.rewrite(context, shape)?;
3148 let missed_span = if attrs.is_empty() {
3149 mk_sp(item.span.lo(), item.span.lo())
3151 mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo())
3154 let allow_extend = if attrs.len() == 1 {
3155 let line_len = attrs_str.len() + 1 + item_str.len();
3156 !attrs.first().unwrap().is_doc_comment()
3157 && context.config.inline_attribute_width() >= line_len
3162 combine_strs_with_missing_comments(
3172 /// Rewrite an inline mod.
3173 /// The given shape is used to format the mod's attributes.
3174 pub(crate) fn rewrite_mod(
3175 context: &RewriteContext<'_>,
3178 ) -> Option<String> {
3179 let mut result = String::with_capacity(32);
3180 result.push_str(&*format_visibility(context, &item.vis));
3181 result.push_str("mod ");
3182 result.push_str(rewrite_ident(context, item.ident));
3184 rewrite_attrs(context, item, &result, attrs_shape)
3187 /// Rewrite `extern crate foo;`.
3188 /// The given shape is used to format the extern crate's attributes.
3189 pub(crate) fn rewrite_extern_crate(
3190 context: &RewriteContext<'_>,
3193 ) -> Option<String> {
3194 assert!(is_extern_crate(item));
3195 let new_str = context.snippet(item.span);
3196 let item_str = if contains_comment(new_str) {
3199 let no_whitespace = &new_str.split_whitespace().collect::<Vec<&str>>().join(" ");
3200 String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
3202 rewrite_attrs(context, item, &item_str, attrs_shape)
3205 /// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
3206 pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
3208 ast::ItemKind::Mod(ref m) => m.inner.hi() != item.span.hi(),
3213 pub(crate) fn is_use_item(item: &ast::Item) -> bool {
3215 ast::ItemKind::Use(_) => true,
3220 pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
3222 ast::ItemKind::ExternCrate(..) => true,